I'm using the jQuery Tools tooltip plugin, which is initialized with $('selector').tooltip(). I'd like to call this on any current or future .tooltipper element. I figured that the following would work:
$('.tooltipper').live('ready', function(){
$(this).tooltip()
}
But it was unsuccessful---the ready event did not fire. The same for load. I've read that livequery can produce the result of I'm looking for, but surely there is a way to use jQuery .live() to pull it off, considering the documentation says that it works for all jQuery events, of which I believe ready is one.
Quoted from the jQ API (http://api.jquery.com/live/):
In jQuery 1.3.x only the following JavaScript events (in addition to custom events) could be bound with .live(): click, dblclick, keydown, keypress, keyup, mousedown, mousemove, mouseout, mouseover, and mouseup.
As of jQuery 1.4 the .live() method supports custom events as well as all JavaScript events.
As of jQuery 1.4.1 even focus and blur work with live (mapping to the more appropriate, bubbling, events focusin and focusout).
As of jQuery 1.4.1 the hover event can be specified (mapping to "mouseenter mouseleave").
.live() does not appear to support the ready event.
To add to HurnsMobile's excellent answer; Looking at bindReady(), which is the internal call that jQuery makes to bind to the document load event every time you call $(some_function) or $(document).ready(some_function) we see why we cannot bind to "ready":
bindReady: function() {
if ( readyBound ) {
return;
}
readyBound = true;
// Catch cases where $(document).ready() is called after the
// browser event has already occurred.
if ( document.readyState === "complete" ) {
return jQuery.ready();
}
// Mozilla, Opera and webkit nightlies currently support this event
if ( document.addEventListener ) {
// Use the handy event callback
document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
// A fallback to window.onload, that will always work
window.addEventListener( "load", jQuery.ready, false );
// If IE event model is used
} else if ( document.attachEvent ) {
// ensure firing before onload,
// maybe late but safe also for iframes
document.attachEvent("onreadystatechange", DOMContentLoaded);
// A fallback to window.onload, that will always work
window.attachEvent( "onload", jQuery.ready );
// If IE and not a frame
// continually check to see if the document is ready
var toplevel = false;
try {
toplevel = window.frameElement == null;
} catch(e) { //and silently drop any errors
}
// If the document supports the scroll check and we're not in a frame:
if ( document.documentElement.doScroll && toplevel ) {
doScrollCheck();
}
}
}
To sum it up, $(some_function) calls a function which binds to:
DOMContentLoaded
onreadystatechange (DOMContentLoaded)
window.load / onload
Your best bet would be to bind to those actions that might create new .tooltipper elements, rather than trying to listen for the ready event (which happens only once).
HurnsMobile is right. JQuery live does not support the ready-event.
This is why I created a plugin that combines the two. You register your callback once, and then you will need to call the plugin once for content you add manually.
$.liveReady('.tooltipper', function(){
this.tooltip()
});
Then when creating new content:
element.html(somehtml);
element.liveReady();
or
$('<div class="tooltipper">...').appendTo($('body')).liveReady();
A demo is available here: http://cdn.bitbucket.org/larscorneliussen/jquery.liveready/downloads/demo.html
Check out the introductory post here: http://startbigthinksmall.wordpress.com/2011/04/20/announcing-jquery-live-ready-1-0-release/
Also have a look at http://docs.jquery.com/Plugins/livequery, which listenes for changes on the dom.
Related
Heads up to anyone who is self hosting who also runs across this bug....
In version 5.6.0 silver theme, the dialog urlinput enable/disable works for the input field but not the browse button of the control. The problem is that the enable/disable events are intercepted by the typeaheadBehaviours portion of the internal object so they never make it to the event handlers for the overall field. The fix is to add the onDisabled and onEnabled handlers to the Disabling.config for typeaheadBehaviours and remove the line of code from each handler that addresses the input field.
Original typeaheadBehaviours Disabling.config....
Disabling.config({
disabled: function () {
return spec.disabled || providersBackstage.isDisabled();
}
})
Amended code....
Disabling.config({
disabled: function () {
return spec.disabled || providersBackstage.isDisabled();
},
onDisabled: function (comp) {
memUrlPickerButton.getOpt(comp).each(Disabling.disable);
},
onEnabled: function (comp) {
memUrlPickerButton.getOpt(comp).each(Disabling.enable);
}
})
Haven't been able to figure out how to get those events to bubble up to the the overall control handlers but this seems to make things work as expected.
When a TinyMCE editor blur occurs, I am trying to find the element id (or name) of the textarea which fired the blur event. I also want the element id (or name) of the element which gains the focus, but that part should be similar.
I'm getting closer in being able to get the iframe id of the tinymce editor, but I've only got it working in Chrome and I'm sure there is a better way of doing it. I need this to work across different browsers and devices.
For example, this below code returns the iframe id in Chrome which is okay since the iframe id only appends a suffix of "_ifr" to my textarea element id. I would prefer the element id of the textarea, but it's okay if I need to remove the iframe suffix.
EDIT: I think it's more clear if I add a complete TinyMCE Fiddle (instead of the code below):
http://fiddle.tinymce.com/HIeaab/1
setup : function(ed) {
ed.onInit.add(function(ed) {
ed.pasteAsPlainText = true;
/* BEGIN: Added this to handle JS blur event */
/* example modified from: http://tehhosh.blogspot.com/2012/06/setting-focus-and-blur-event-for.html */
var dom = ed.dom,
doc = ed.getDoc(),
el = doc.content_editable ? ed.getBody() : (tinymce.isGecko ? doc : ed.getWin());
tinymce.dom.Event.add(el, 'blur', function(e) {
//console.log('blur');
var event = e || window.event;
var target = event.target || event.srcElement;
console.log(event);
console.log(target);
console.log(target.frameElement.id);
console.log('the above outputs the following iframe id which triggered the blur (but only in Chrome): ' + 'idPrimeraVista_ifr');
})
tinymce.dom.Event.add(el, 'focus', function(e) {
//console.log('focus');
})
/* END: Added this to handle JS blur event */
});
}
Maybe it's better to give a background of what I'm trying to accomplish:
We have multiple textareas on a form which we're trying to "grammarcheck" with software called "languagetool" (that uses TinyMCE version 3.5.6). Upon losing focus on a textarea, we would like to invoke the grammarcheck for the textarea that lost focus and then return the focus to where it's supposed to go after the grammar check.
I've struggled with this for quite some time, and would greatly appreciate any feedback (even if it's general advice for doing this differently).
Many Thanks!
Simplify
TinyMCE provides a property on the Editor object for getting the editor instance ID: Editor.id
It also seems overkill to check for doc.content_editable and tinyMCE.isGecko because Editor.getBody() allows for cross-browser compatible event binding already (I checked IE8-11, and latest versions of Firefox and Chrome).
Note: I actually found that the logic was failing to properly assign ed.getBody() to el in Internet Explorer, so it wasn't achieving the cross-browser functionality you need anyway.
Try the following simplified event bindings:
tinyMCE.init({
mode : "textareas",
setup : function (ed) {
ed.onInit.add(function (ed) {
/* onBlur */
tinymce.dom.Event.add(ed.getBody(), 'blur', function (e) {
console.log('Editor with ID "' + ed.id + '" has blur.');
});
/* onFocus */
tinymce.dom.Event.add(ed.getBody(), 'focus', function (e) {
console.log('Editor with ID "' + ed.id + '" has focus.');
});
});
}
});
…or see this working TinyMCE Fiddle »
Aside: Your Fiddle wasn't properly initializing the editors because the plugin was failing to load. Since you don't need the plugin for this example, I removed it from the Fiddle to get it working.
The plugin I'm trying to port(https://github.com/NYTimes/ice) to TinyMCE 4 needs to have access to a keypress event BEFORE it is handled by the MCE editor and works with onEvent(...) in 3.5.8 but needs to be migrated to something more like on('event') in tinymce 4, however there isn't an obvious alternative.
In tiny MCE 3.5.8 I have
ed.onEvent.add(function(ed, e) {
return changeEditor.handleEvent(e);
});
But I need something more like
ed.on('event', function(e) {
return changeEditor.handleEvent(e);
});
However the ed.on('event',...) doesn't seem to exist in tinymce 4.
It needs to be able to catch the delete key before any other event handler for the keydown, keyup, and keypress.
Ok, After 2 workdays trying to get this to work I figured out what the problem was with this particular issue.
For starters there is no equivalent to onEvent(...) in tinymce 4. However the plugin doesn't need access to every event anyway.
If you are going to port any tinymce plugin that uses the onEvent() method then you will need to identify the events the plugin is trying to handle and explicitly set the event handler for each of the events that need to be handled:
ed.on('mousedown', function(e) {
return changeEditor.handleEvent(e);
});
ed.on('keyup', function(e) {
return changeEditor.handleEvent(e);
});
ed.on('keydown', function(e) {
return changeEditor.handleEvent(e);
});
ed.on('keypress', function(e) {
return changeEditor.handleEvent(e);
});
In my case I needed to not only delegate the mousedown,mouseup, keyup,keydown, and keypress events to the plugin I also had to prevent them from being fired prematurely by the editor/textarea:
ed.on('keydown', function(e) {
// prevent the delete key and backspace keys from firing twice
if(e.keyCode == 46 || e.keyCode==8)
e.preventDefault();
});
So keep this in mind if you run into a similar issue.
Oh and I added a fork of this ICE plugin on my github: https://github.com/catsgotmytongue/ice/
Here's a simple fiddle to demo my situation...
http://jsfiddle.net/UnsungHero97/EM6mR/17/
What I'm doing is adding an event handler for current & future elements, using .on(). I want to be able to remove these event handlers for specific elements when something happens; in the case of the fiddle, when the radio button is selected, the event handler for the blue elements should be removed and clicking those elements should not do anything anymore.
It doesn't seem to be working :(
How do I remove the event handler attached to document that I created with .on() for those specific blue elements?
The signature for your .on() and .off() has to match.
These two do not match so the .off() call won't find matching event handlers to remove:
$(document).on('click', '.btn', function() {
update();
});
$(document).off('click', '.blue');
Note, the selector passed to .on() and .off() is different.
When using the dynamic form of .on() (where you pass a selector as an argument to .on()), you can't remove just part of the items. That's because there's only one event handler installed on the root element and jQuery can only remove the entire thing or not at all. So, you can't just .off() some of the dynamic items.
Your options are to remove all the event handlers with:
$(document).off('click', '.btn');
and, then install a new event handler that excludes the items you don't want such as:
$(document).off('click', '.btn:not(.blue)');
Or, teach the event handler itself how to ignore .blue items:
$(document).on('click', '.btn', function() {
if (!$(this).hasClass('blue')) {
update();
}
});
Be careful of how you attach your events; this works fine for me:
$('.btn').on('click', function() {
update();
});
$('#disable').on('change', function() {
$('.btn').off('click');
});
Only way seems to be:
$('#disable').on('change', function() {
$(document)
.off('click', '.btn')
.on('click', '.btn:not(.blue)', update);
});
Assume button A in an HTML5 webapp built with jQuery Mobile.
If someone taps button A, we call foo(). Foo() should get called once even if the user double taps button A.
We tried using event.preventDefault(), but that didn't stop the second tap from invoking foo(). event.stopImmediatePropagation() might work, but it also stops other methods further up the stack and may not lead to clean code maintenance.
Other suggestions? Maintaining a tracking variable seems like an awfully ugly solution and is undesirable.
You can set a flag and check if it's OK to run the foo() function or unbind the event for the time you don't want the user to be able to use it and then re-bind the event handler after a delay (just a couple options).
Here's what I would do. I would use a timeout to exclude the subsequent events:
$(document).delegate('#my-page-id', 'pageinit', function () {
//setup a flag to determine if it's OK to run the event handler
var okFlag = true;
//bind event handler to the element in question for the `click` event
$('#my-button-id').bind('click', function () {
//check to see if the flag is set to `true`, do nothing if it's not
if (okFlag) {
//set the flag to `false` so the event handler will be disabled until the timeout resolves
okFlag = false;
//set a timeout to set the flag back to `true` which enables the event handler once again
//you can change the delay for the timeout to whatever you may need, note that units are in milliseconds
setTimeout(function () {
okFlag = true;
}, 300);
//and now, finally, run your original event handler
foo();
}
});
});
I've created a sample here http://jsfiddle.net/kiliman/kH924/
If you're using <a data-role="button"> type buttons, there is no 'disabled' status, but you can add the appropriate class to give it the disabled look.
In your event handler, check to see if the button has the ui-disabled class, and if so, you can return right away. If it doesn't, add the ui-disabled class, then call foo()
If you want to re-enable the button, simply remove the class.
$(function() {
$('#page').bind('pageinit', function(e, data) {
// initialize page
$('#dofoo').click(function() {
var $btn = $(this),
isDisabled = $btn.hasClass('ui-disabled');
if (isDisabled) {
e.preventDefault();
return;
}
$btn.addClass('ui-disabled');
foo();
});
});
function foo() {
alert('I did foo');
}
});