I got this very weird code: No debug, no work! I am almost crazy about it.
The code is to show an notification in Chrome. That's lot of comments among the code.
Look at the !!IMPORTANT&&WEIRD!!, next line is "console.log(_notification);" that can't be omitted, if it does, no events bind could work.
Though now the code works OK, but I just curious about this, why I can't remove "console.log(_notification);" ?
/**
* Notification
* #author: ijse
* #require: Chrome10+
* #params: same as webkitNotifications.create[HTML]Notification()
* #usage:
* new Notify("http://www.baidu.com").onshow(function() {
* alert("show");
* }).onclose(function() {
* alert("close");
* }).show();
*/
var Notify = function() {
var _params = arguments;
// Validate arguments
if(_params.length == 0) {
console.error("Notify need at least one argument");
return ;
}
// Check browser support
if(!window.webkitNotifications) {
console.error("Your browser does not support webkitNotifications feature!!");
return ;
}
var _onclose, _onclick, _onerror, _onshow;
var _notification, _replaceId, _showFlag = false;
function bindEvents() {
// Add event listeners
// In W3C, display event is called show
_notification.addEventListener("display", _onshow, false);
_notification.addEventListener("click", _onclick, false);
_notification.addEventListener("error", _onerror, false);
_notification.addEventListener("close", _onclose, false);
if(_replaceId)
_notification.replaceId = _replaceId;
// !!IMPORTANT&&WEIRD!! remove next line no events will work
console.log(_notification);
}
function createfn(permission) {
// About permission on Chrome:
// PERMISSION_ALLOWED (0) indicates that the user has granted permission to scripts with this origin to show notifications.
// PERMISSION_NOT_ALLOWED (1) indicates that the user has not taken an action regarding notifications for scripts from this origin.
// PERMISSION_DENIED (2) indicates that the user has explicitly blocked scripts with this origin from showing notifications.
if(permission == 0) {
// If permission is allowed
// Create notification
if(_params.length == 1)
_notification = window.webkitNotifications.createHTMLNotification(_params[0]);
else
_notification = window.webkitNotifications.createNotification(_params[0],_params[1],_params[2]);
// Bind events
console.log("bind event in createfn");
bindEvents();
// Show, if yes flag
!!_showFlag && _notification.show();
} else {
if(_onerror)
_onerror.call(this);
console.error("Notification permission is denied!!");
}
}
// If permission already allowed, do not require again
if(window.webkitNotifications.checkPermission() != 0) {
// Require permission from user
window.webkitNotifications.requestPermission(function() {
createfn.call(this, window.webkitNotifications.checkPermission());
});
} else {
createfn.call(this, window.webkitNotifications.checkPermission());
}
// Return handler methods
return {
onclose: function(fn) { _onclose = fn; console.log(1); return this; },
onclick: function(fn) { _onclick = fn; console.log(2); return this; },
onerror: function(fn) { _onerror = fn; console.log(3); return this; },
onshow : function(fn) { _onshow = fn; console.log(4); return this; },
show: function(replaceId) {
console.log("method show");
_replaceId = replaceId;
if(_notification) {
// Notification already been created
bindEvents();
_notification.show();
} else {
// Flag yes to show
_showFlag = true;
}
return _notification;
},
cancel: function() {
_notification.cancel();
}
} // return handler
}
new Notify("","Success!!", "Welcome to use empcy!!").onshow(function() {
var that = this;
window.setTimeout(function() { that.cancel(); }, 3000);
}).onclose(function() {
alert("close");
}).onclick(function() {
alert("clicked");
}).show("Welcome");
I think it might be an issue with bracketing. Here is the relevant section of code as you have it:
function bindEvents() {
// Add event listeners
// In W3C, display event is called show
_notification.addEventListener("display", _onshow, false);
_notification.addEventListener("click", _onclick, false);
_notification.addEventListener("error", _onerror, false);
_notification.addEventListener("close", _onclose, false);
if(_replaceId)
_notification.replaceId = _replaceId;
// !!IMPORTANT&&WEIRD!! remove next line no events will work
console.log(_notification);
}
If you remove the console.log line it becomes:
function bindEvents() {
// Add event listeners
// In W3C, display event is called show
_notification.addEventListener("display", _onshow, false);
_notification.addEventListener("click", _onclick, false);
_notification.addEventListener("error", _onerror, false);
_notification.addEventListener("close", _onclose, false);
if(_replaceId)
_notification.replaceId = _replaceId;
}
which is probably confusing the JavaScript engine since you have a bracket-less if statement but it's followed by a closing bracket. You should try adding brackets to your if statement so it looks like:
function bindEvents() {
// Add event listeners
// In W3C, display event is called show
_notification.addEventListener("display", _onshow, false);
_notification.addEventListener("click", _onclick, false);
_notification.addEventListener("error", _onerror, false);
_notification.addEventListener("close", _onclose, false);
if(_replaceId) {
_notification.replaceId = _replaceId;
}
}
maybe you could include the following code
https://github.com/h5bp/html5-boilerplate/blob/master/js/plugins.js
this is taken from the html5-boilerplate project an check's if console.log can be called.
Eventually, I didn't work it out, and find no answers for that. I just put that code and it works well, except print a log information.
Related
I created a site that will change images from being displayed on mouse scroll. It was working until this morning on my local machine, but suddenly stopped. When I check the dev console I get an error message that says "[Intervention] Unable to preventDefault inside passive event listener due to target being treated as passive. See https://www.chromestatus.com/features/6662647093133312"
I have read the information at the provided url and I still do not understand how I can turn off this feature. In my code I have the following:
var changeImage = function changeImage(event) {
event.preventDefault();
if (brochure.waitForDelay === false) {
window.onwheel = function () {
return false;
};
brochure.waitForDelay = true;
if (event.deltaY < 0) {
scrollUp();
} else {
scrollDown();
}
setTimeout(function () {
brochure.waitForDelay = false;
window.onwheel = function () {
return true;
};
}, 1250);
} else {
return;
}
};
var determineScrollDirection = function determineScrollDirection() {
document.addEventListener('wheel', changeImage, { passive: false });
};
In determineScrollDirection I set the passive as false and tried to call preventDefault in the changeImage function but I still get the same error message.
I was able to fix this issue by removing the following line:
window.onwheel = function () {
return false;
};
I am trying to make a when statement but it is not working as planned. Basically its a function to call another function when try. First before I explain further here is the syntax
when(function() {
//code here
});
Now basically... Think this way.. We have a progressbar.. We also have a custom event such as...
var pBarEvent = document.createEvent('Event');
pBarEvent.initEvent('pbardone', true, true);
document.addEventListener('pbardone', function() {
//code here
});
//if progress bar reaches 100 dispatchEvent
if (document.querySelector(".progress-bar").style.width === 100 + "%")
{
document.dispatchEvent(pBarEvent);
}
Now that piece of code is an example. If the document loads and its for instance at 50% it wont trigger until you add another event such as keydown or click. I dont want to do that I want to do.... "when" progress bar width equals 100% trigger it. Thats basically what needs to happen. So here is the code for the when statement so far (keep in mind its not the best looking one. As I dont normally do this but I wanted to keep this dynamic and who knows someone who later wants to do this can look at this question)
when function
function when(func)
{
var nowActive = false;
if (!typeof func === 'undefined')
{
func = new Function();
}
if (func)
{
nowActive = true;
clearInterval(whenStatementTimer);
}
else
{
nowActive = false;
var whenStatementTimer = setInterval(function() {
switch(func)
{
case true:
{
nowActive = true;
when();
break;
}
case false:
{
nowActive = false;
when();
break;
}
}
}, 1000);
}
if (nowActive === true)
{
func();
}
}
Now this does not work when I go to try something like....
when(function() {
SmartLeadJS.SmartLeadEvents.customEvents.progressBarFull(function() {
alert("100%");
SmartLeadJS.SmartLeadAds.LeadView.ChromeExtension.General.DynamicStyles.$.style("body", "background", "black");
});
});
It does not trigger. I need help possibly getting this when statement to work. What am I doing wrong? What can I do to fix it? No errors get thrown but it never fires.
edit based on answer
Function tried
function when(currentValue)
{
try
{
var o = {};
o.currentValue = currentValue;
o.do = function(func)
{
if (!typeof func === 'undefined')
{
func = new Function();
}
if (this.currentValue)
{
func();
}
else
{
setTimeout(this.do(func), 100);
}
};
return o;
}
catch(e)
{
console.log(e);
}
}
used as
when(true).do(function() {
SmartLeadJS.SmartLeadEvents.customEvents.progressBarFull(function() {
alert("This divs going through changes!!");
SmartLeadJS.SmartLeadAds.LeadView.ChromeExtension.General.DynamicStyles.$.style(".div", "background", "black");
});
});
This does not work. It never fires. But if I use a onclick listener as such it fires
document.addEventListener("click", function() {
SmartLeadJS.SmartLeadEvents.customEvents.progressBarFull(function() {
alert("This divs going through changes!!");
SmartLeadJS.SmartLeadAds.LeadView.ChromeExtension.General.DynamicStyles.$.style(".div", "background", "black");
});
}, false);
function when(statement){
o={};
o.statement=statement;
o.do=function(func){
awhen(this.statement,func);
};
return o;
}
function awhen(statement,func){
if(eval(statement)){
func();
}else{
window.setTimeout(function(){awhen(statement,func);},100);
}
}
Use:
when("true").do(function(){});
It works now :) . Its important to put the condition in ""!
I can't seem to add these event listeners at page load reliably. Some of the listeners work from the beginning, but others only work after a few clicks. What might be wrong? Could the problem be that I'm mixing native JS with jQuery?
<script>
$(document).ready(function() {
function resetValidation() {
jQuery('#contact-form').validate().resetForm();
};
function resetFormFields() {
document.getElementById('contact-form').reset();
};
function removeValidationClasses() {
jQuery('.control-group').removeClass('success').removeClass('error');
};
function changeHeaderToAdd() {
document.getElementById('contactModalLabel').innerText = 'Add Contact';
};
function changeHeaderToUpdate() {
document.getElementById('contactModalLabel').innerText = 'Update Contact';
};
function clearContactId() {
document.getElementById('contactId').value = '';
};
var ab = document.getElementById('addContactBtn');
if (ab.addEventListener) {
ab.addEventListener('click', resetValidation, false);
ab.addEventListener('click', resetFormFields, false);
ab.addEventListener('click', removeValidationClasses, false);
ab.addEventListener('click', changeHeaderToAdd, false);
ab.addEventListener('click', clearContactId, false);
} else {
ab.attachEvent('onclick', resetValidation);
ab.attachEvent('onclick', resetFormFields);
ab.attachEvent('onclick', removeValidationClasses);
ab.attachEvent('onclick', changeHeaderToAdd);
ab.attachEvent('onclick', clearContactId);
};
var ub = document.getElementById('updateContactBtn');
if (ub.addEventListener) {
ub.addEventListener('click', resetValidation, false);
ub.addEventListener('click', resetFormFields, false);
ub.addEventListener('click', removeValidationClasses, false);
ub.addEventListener('click', changeHeaderToUpdate, false);
} else {
ub.attachEvent('onclick', resetValidation);
ub.attachEvent('onclick', resetFormFields);
ub.attachEvent('onclick', removeValidationClasses);
ub.attachEvent('onclick', changeHeaderToUpdate);
};
});
</script>
Solved!
The JS was fine. However, since #updateContactBtn was created dynamically (one for each contact on the page), the problem was caused by the presence of nonunique id's. Only the first instance of #updateContactBtn worked.
I changed #updateContactBtn to .updateContactBtn.
I'm writing a jQuery plugin where the events which start/stop the plugin are customisable, so potentially the same event could both start and stop the plugin (e.g. click to start and click to stop).
What's an elegant way, ideally not involving timeouts or unbinding and rebinding of listeners (and not too many "isPlaying" "isBeingStarted" flags etc..) to make sure the correct callback is called
(Note: When I posted this answer, the question had a typo in it which made it seem like binding/unbinding would be okay as long as timeouts weren't involved.)
I don't see any need for timeouts, just bind/unbind as appropriate:
this.bind(startEvent, start);
function start() {
$(this).unbind(startEvent).bind(stopEvent, stop);
}
function stop() {
$(this).unbind(stopEvent).bind(startEvent, start);
}
In the above, I assume that startEvent is the configured start event name (and I'd probably add a namespace to it, e.g. the user passes in "click" but you add ".niftyplugin" to it resulting in startEvent containing "click.niftyplugin" so you can bind/unbind at will), and stopEvent is the configured stop event name (with namespace).
Here's a full example, with namespaces and using data to remember the options (you could use a closure if you prefer) - live copy:
// Plugin stuff
(function($) {
$.fn.niftyPlugin = niftyPlugin;
function niftyPlugin(options) {
var data;
data = {
startEvent: (options && options.startEvent || "click") + ".niftyplugin",
stopEvent: (options && options.stopEvent || "click") + ".niftyplugin"
};
this.data("niftyPlugin", data).bind(data.startEvent, start);
return this;
}
function start() {
var $this = $(this),
data = $this.data("niftyPlugin");
$this.unbind(data.startEvent).bind(data.stopEvent, stop);
display("Start");
}
function stop() {
var $this = $(this),
data = $this.data("niftyPlugin");
$this.unbind(data.stopEvent).bind(data.startEvent, start);
display("Stop");
}
function display(msg) {
$("<p>").html(msg).appendTo(document.body);
}
})(jQuery);
// Use
jQuery(function($) {
$("#theButton").click(function() {
$("<p>Non-plugin hook fired</p>").appendTo(document.body);
}).niftyPlugin({
startEvent: "click"
});
});
The only other alternative I see is stopImmediatePropagation - live example:
// Plugin stuff
(function($) {
$.fn.niftyPlugin = niftyPlugin;
function niftyPlugin(options) {
var startEvent, stopEvent, running = false;
startEvent = (options && options.startEvent || "click") + ".niftyplugin";
stopEvent = (options && options.stopEvent || "click") + ".niftyplugin";
this.bind(startEvent, start).bind(stopEvent, stop);
return this;
function start(event) {
if (running) {
return;
}
running = true;
display("Start");
event.stopImmediatePropagation();
}
function stop(event) {
if (!running) {
return;
}
running = false;
display("Stop");
event.stopImmediatePropagation();
}
}
function display(msg) {
$("<p>").html(msg).appendTo(document.body);
}
})(jQuery);
// Use
jQuery(function($) {
$("#theButton").click(function() {
$("<p>Non-plugin hook fired</p>").appendTo(document.body);
}).niftyPlugin({
startEvent: "click"
});
});
I don't like it, though, because it interferes with other handlers for the event. For instance, in the above, if I change the use to this:
// Use
jQuery(function($) {
$("#theButton").niftyPlugin({
startEvent: "click"
}).click(function() {
$("<p>Non-plugin hook fired</p>").appendTo(document.body);
});
});
...so the plug-in grabs the events before the non-plug-in code, boom, the non-plug-in code never sees the event (example).
So despite the overhead, I suspect bind/unbind are your friends here.
It may be overkill, but an elegant way to not have to maintain a bunch of flags (e.g. "isPlaying") is to use a Finite State Machine.
Here's a jQuery implementation: https://github.com/DukeLeNoir/jquery-machine
The eventual solution I've gone for is to do a quick uniqueness test for events used for stopping and starting and if there are any events used for both stopping and starting then a different listener (which does an isPlaying check) is attached to these. There's a small performance hit on loading the plugin, but after that the event handling code is about as efficient as can be.
function processEvents() {
var tempStart = opts.startEvent.split(" ").sort(),
tempStop = opts.stopEvent.split(" ").sort();
startEventLoop: for(var i=0, il = tempStart.length;i<il;i++) {
for(var j=0, jl = tempStop.length;j<jl;j++) {
if(tempStart[i] == tempStop[j]) {
stopStartEvents.push(tempStart[i])
tempStop.splice(j,1);
continue startEventLoop;
}
}
startEvents.push(tempStart[i])
}
startEvents = startEvents.join(" ");
stopEvents = tempStop.join(" ");
stopStartEvents = stopStartEvents.join(" ");
}
$this.on(stopEvents, function() {
$this.trigger("stop.flickBook");
}).on(startEvents, function() {
$this.trigger("start.flickBook");
}).on(stopStartEvents, function() {
playing ? $this.trigger("stop.flickBook") : $this.trigger("start.flickBook");
});
I'm looking for a super simple jQuery extension. Basically I need to use some events that jQuery does not explicitly support. These events are the iPhone touch events like ontouchstart, ontouchend, and ontouchmove.
I have it working via this:
// Sucks
$('.clickable').each(function() {
this.ontouchstart = function(event) {
//do stuff...
};
}
Which kind of sucks and is unjqueryish. Here is what I would like:
// Better
$('.clickable').touchstart(function() {
//do stuff...
}
Or even better with 1.4
// Awesome
$('.clickable').live('touchstart', function() {
//.. do stuff
}
These events need no special handling and should work just like any other events, but I can't seem to figure out how to extend jquery to make them work just like all the other events do.
I wrote the plugin, if the user does have touch available, use, otherwise, call click
jQuery.event.special.tabOrClick = {
setup: function (data, namespaces) {
var elem = this, $elem = jQuery(elem);
if (window.Touch) {
$elem.bind('touchstart', jQuery.event.special.tabOrClick.onTouchStart);
$elem.bind('touchmove', jQuery.event.special.tabOrClick.onTouchMove);
$elem.bind('touchend', jQuery.event.special.tabOrClick.onTouchEnd);
} else {
$elem.bind('click', jQuery.event.special.tabOrClick.click);
}
},
click: function (event) {
event.type = "tabOrClick";
jQuery.event.handle.apply(this, arguments);
},
teardown: function (namespaces) {
var elem = this, $elem = jQuery(elem);
if (window.Touch) {
$elem.unbind('touchstart', jQuery.event.special.tabOrClick.onTouchStart);
$elem.unbind('touchmove', jQuery.event.special.tabOrClick.onTouchMove);
$elem.unbind('touchend', jQuery.event.special.tabOrClick.onTouchEnd);
} else {
$elem.unbind('click', jQuery.event.special.tabOrClick.click);
}
},
onTouchStart: function (e) {
this.moved = false;
},
onTouchMove: function (e) {
this.moved = true;
},
onTouchEnd: function (event) {
if (!this.moved) {
event.type = "tabOrClick";
jQuery.event.handle.apply(this, arguments)
}
}
};
$("#xpto").bind("tabOrClick", function () {
alert("aaaa");
});
I've made a small update to Alexandre's plugin to include Android support. Android's browser does not currently support the window.Touch method of detecting touch support.
I love how Alexandre's script waits to ensure movement didn't occur to prevent triggering the event when the user swipes to scroll across the screen. However a downfall of that approach is that it causes its own delay by waiting for the user to lift their finger off of the screen before triggering. I've updated his plugin to include a "touchactive" class that gets applied to items that a user is currently touching. If you take advantage of that class you can provide immediate visual feedback to users without causing an actual event to get triggered until after movement check has completed.
jQuery.event.special.touchclick = {
setup: function (data, namespaces) {
var elem = this, $elem = jQuery(elem);
var ua = navigator.userAgent.toLowerCase();
var isAndroid = ua.indexOf("android") > -1;
if (window.Touch || isAndroid) {
$elem.bind('touchstart', jQuery.event.special.touchclick.onTouchStart);
$elem.bind('touchmove', jQuery.event.special.touchclick.onTouchMove);
$elem.bind('touchend', jQuery.event.special.touchclick.onTouchEnd);
} else {
$elem.bind('click', jQuery.event.special.touchclick.click);
}
},
click: function (event) {
event.type = "touchclick";
jQuery.event.handle.apply(this, arguments);
},
teardown: function (namespaces) {
var elem = this, $elem = jQuery(elem);
if (window.Touch) {
$elem.unbind('touchstart', jQuery.event.special.touchclick.onTouchStart);
$elem.unbind('touchmove', jQuery.event.special.touchclick.onTouchMove);
$elem.unbind('touchend', jQuery.event.special.touchclick.onTouchEnd);
} else {
$elem.unbind('click', jQuery.event.special.touchclick.click);
}
},
onTouchStart: function (e) {
this.moved = false;
$(this).addClass('touchactive');
},
onTouchMove: function (e) {
this.moved = true;
$(this).removeClass('touchactive');
},
onTouchEnd: function (event) {
if (!this.moved) {
event.type = "touchclick";
jQuery.event.handle.apply(this, arguments)
}
$(this).removeClass('touchactive');
}
};
I've also posted this to github in case there are further caveats that are discovered https://github.com/tuxracer/jquery-touchclick
This now works, just like it's stubbed out above, on the latest jQuery release. Go jQuery!
Here's a start:
$.fn.touchstart = function(fn) { return this[fn ? "bind" : "trigger"]("touchstart", fn); };
$.event.special.touchstart = {
setup: function() {
$.event.add(this, "mouseenter", extendedClickHandler, {});
},
teardown: function() {
$.event.remove(this, "mouseenter", extendedClickHandler);
}
};
Where extendedClickHandler is the function that does what it's suppose to do.
More info here: http://brandonaaron.net/blog/2009/03/26/special-events
jQuery.com is a great source of information like this.
If you build your own plugin you'll be able to use whatever naming you like on your method calls.