So I recently took a closer look at JavaScript and jQuery and after that stumbled over the Firefox extension called Greasemonkey.
Well, let me explain what I mean with the "modifiy"-event: I've got 2-3 userscripts for a certain page installed which automatically look if the page has changed in any way and if it has, they load the new content and append it to the already loaded page (they modify the DOM).
So basically, my userscript needs to know when that happens but I don't know how I should do that. Are there any jQuery events for that? Help would be appreciated.
var orig;
$(function(){
orig = getContent();
})
function watchContent() {
var mod = getContent();
if (mod != orig){ resetContent(orig); }
setTimeout(watchContent,1000)
}
function resetContent(html) {
$("body").append( html );
}
function getContent() {
return $("body").html();
}
With jQuery events if you want the event to apply to new elements you would use the .live method, however jQuery 1.3 doesn't support blur, focus, mouseenter, mouseleave, change, or submit events as live events, and it's change that you will want to use. (change, submit, and blur/focus are on the roadmap for jQuery 1.4)
As an alternative you could use the liveQuery plugin.
Related
EDIT: The Issue has been solved, as it turns out, the Select2 library had a custom command for this typa thing:
$("#element").on("change", function (e) { ... }
// Defined as "change"
I'm using a dropdown menu library called Select2 3.2. In short, the code takes a bunch of select and option tags, and generates a cool drop down search list.
However, after the site is rendered; when I click 'view source', all my select and option tags are still there, but when I right click the fancy new generated menus themselves and select "inspect element" (using google chrome), the html is TOTALLY different.
I think that this is causing the problem, all this new code is rendered from the custom library's JS, and after my jQuery event commands.
Specifically, here is my command:
$(document.body).on('click', '.select2-result-label', function() {
var name = $(this).text();
var post_to = '/myurl/';
$.post(post_to, { dat: dat},
function(response) {
...
}, 'json'
)
I believe the on() method takes care of this kinda stuff but apparently not, any help would be appreciated!
RELEVANT EDIT:
Here is a blurb from another Stack Overflow post:
The view page source page shows you the exact text that
was returned by the server.
Inspect element actually shows you the fully rendered DOM tree.
Knowing that, maybe solving this will be easier.
Here is a JS Fiddle related:
http://jsfiddle.net/JpvDt/47/
Try to make the alert "worked" appear when you click on an "x" in the multi bar.
Right now my code has it to register the class which contains the x's.
$(document.body).on("click", ".select2-search-choice-close", alert("worked"));
Scenario 1:
Your problem is may be you bind on method for whole DOM which is really BAD. So always try to bind that to the closest div (closest parent element) which your controls are exist.
About Event performance from Jquery API says like below.
Attaching many delegated event handlers near the top of the document
tree can degrade performance. Each time the event occurs, jQuery must
compare all selectors of all attached events of that type to every
element in the path from the event target up to the top of the
document. For best performance, attach delegated events at a document
location as close as possible to the target elements. Avoid excessive
use of document or document.body for delegated events on large
documents.
Scenario 2:
Call your on event like below (with off event).
$(#yourElement).off('click').on('click', '.select2-result-label', function() {
var name = $(this).text();
var post_to = '/myurl/';
$.post(post_to, { dat: dat},
function(response) {
...
}, 'json'
)
I hope this will help to you.
As it turns out, the Select2 library had a custom command for future changes to the toolbar.
Read more here: http://ivaynberg.github.com/select2/#programmatic
It's vital to note that many standardized jQuery calls won't work with Select2, you must use their custom set-up.
$("#element").on("change", function (e) { ... }
// Defined as "change"
Just replace $(document.body) by $(document)
http://blog.jeremymartin.name/2008/02/building-your-first-jquery-plugin-that.html
Based on this tutorial, I created my first plugin and made some modifications.
But, the plugin doesn't work for dynamically generated content when I load new content on the site.
I have no idea how to go about making it live. The events are already using .on but the building of the pluggin doesn't work.
Here is the jsFiddle: http://jsfiddle.net/bT4dH/13/
I know I could call the plugin everytime I add content dynamically, but as that gets messy very quickly, I would prefer to avoid it, and integrate it directly into the plugin.
I was starting to try this:
$(document).on('DOMNodeInserted', function (e) {
if (e.target.classname === 'JS_postShrinker') {
$(e.target).shrinker(options);
}
});
But it doesn't work
UPDATE
Please ignore the DOMNodeInserted, I was just trying it. How do people in general make plugins live? I have the same problem with:
http://code.google.com/p/jquery-watermark/
http://unwrongest.com/projects/elastic/
And many more...
You can simply make it live by using .on() in a bit different way, with delegation. The documentation explains it in detail.
$(closeParent).on(event, selectorForElement, handler);
All you have to do is to choose a parent that you surely know will be part of the DOM when you attach the handler. In the worst case, you can choose body.
Then you attach the handler on this element, and specify the selector for the child elements (that can be inserted into the DOM at any time). The handler will run whenever the event is fired on any of the child elements matching the selector. This method makes use of event bubbling in a very clever way.
EDIT: Of course this will only work for event handling. If you need to initialize your elements when they are added to the DOM (resizing, decorating, etc.), you better call the plugin every time this happens. This is how most plugins work. The DOMNodeInserted event is not cross-browser and deprecated, like all Mutation events, so you should not use it.
There is an extra parameter (selector) to delegate the event on it:
$(document).on('DOMNodeInserted',"." + opts.clickZoneClass, function (e) {
if (e.target.classname === 'JS_postShrinker') {
$(e.target).shrinker(options);
}
});
jquery attaches a click method on even things that aren't typically clickable like a DIV. this can be great because some things respond to that. How can i "click" on any old regular DIV using plain old javascript without Jquery?
what i am trying to do is trigger clicking on the area where the user can post in Jquery. I'm using a chrome extension that can run some javascript on a hotkey. I wrote a jquery version
var x = $('div[guidedhelpid="sharebox"]'); x.click();
which works fine, other than it seems that the jquery library only loads about 1/4 of the time. not sure why, so i figured i'd try to make it in plain JS. As for the handler, googles own code is intercepting and processing the clicks fine, and it works in the Jquery version. so i just want to effectively do the same thing.
does Jquery internally go up or down the DOM until it finds the first think clickable?
update
in light of it, i was looking in the wrong direction, and really just needed to find the right element to focus on (in JQUERY).
If you just want to bind one function to the element, you could use
var element = document.getElementById("el"); //grab the element
element.onclick = function() { //asign a function
//code
}
but if you need to attach more than one event, you should use addEventListener (eveything except IE) and attachEvent (IE)
if(element.addEventListener) {
element.addEventListener("click", function() {});
} else {
element.attachEvent("onclick", function() {})
}
The click() function is built in JavaScript, not jQuery.
HTMLElementObject.click()
Source.
var d = document.getElementById("test");
d.onclick = function(){alert('hi');};
var divElement = document.getElementById('section');
divElement.addEventListener('click', function () {
alert('div clicked');
},false);
I use tables to control the page layout. The "td" are clickable, so I write my "onclick = whatever()" in the td tag and not in the div tag.
Could I create a function or custom event in a javascript file called "justDidStuff" and then make .live() watch for that being triggered in another jQuery file?
I know this sounds really complicated, but I can't think of another way to do this.
I have new content coming in from the javascript file which is the only infinite scroller known to work for Tumblr.
I have a bunch of styling happening on the layout of the incoming posts (http://syndex.me) which i'm obviously going to make with jQuery. Hence i'm in a situation where I
A) have to use .live() (posts are dynamically loaded) and
B) can't trigger the changes in a straightforward manner
In a previous question related to this DOMNodeInserted was reluctantly suggested. This just listens for when something has been changed, but it slows down pages such as this and has been depreciated.
EDIT
http://marckremers.com/syndex/js/jquery.infinitescrollfortumblr.js
Is the javascript file (NB it's a monster)
http://marckremers.com/syndex/js/jquery.syndex.js
Is my Styling and Site behaviour jQuery file.
You can use bind and trigger.
var justDidStuff = function(){
//do some stuff
}
$('something').bind('justDidStuff',justDidStuff); // binds to all elements,
// now and in the future.
//call it:
$('something').trigger('justDidStuff');
I think you want to use trigger() and bind
Something like this:
jQuery("body").bind("myEvent", function( data ){ alert("triggered"); } );
and in your function you can notify the page
jQuery("body").trigger("myEvent", { "foo", "bar" });
OK I have solved the problem. It's so easy i can't believe it. You live and learn. All I had to do was place jquery code inline within the javascript file by doing this:
jQuery(function ($) {//doStuff in a javascript file as normal, OMG}
This is actually a bigger question because I know there are several ways to solve this problem but I will try to sum it up.
What I try to do: I am using this jQuery plugin to upload files via Flash http://www.uploadify.com/. However, the element #fileInput that I supposed to bind this function to is a live element which is generated after the page loaded: $('#fileInput').uploadify(). The reason #fileInput is a live element is because I use FancyBox to popup a DIV and this FancyBox basically just "cloned" the inner html of the DIV.
What happened: When I clicked "BROWSE" to upload a file, there is no progress bar for upload. The reason is because the Uploadify could not bind to live elements.
Questions:
1. I tried to replace bind() with live() in uploadify code but that did not work because bind() allows to pass [data]. The LiveQuery plugin http://docs.jquery.com/Plugins/livequery does not have the same syntax as bind() either. Is there anything similar to bind but works for live elements?
If I don't try to replace bind() function and keep uploadify code the same. Does anyone know how to change code in FancyBox so that it WILL NOT make a clone to generate live elements? I know this is a hard question too.
Note: FancyBox site seems dead --> http://www.visual-blast.com/javascript/fancybox-jquery-image-zooming-plugin/
Thank you very much!
You might consider changing the FancyBox code to support calling a callback function after it clones the HTML. Then, put the uploadify() call in the callback function.
You could overload the live method, making it support data as the second parameter:
jQuery.fn.live = (function(_live){
return function( type, data, fn ) {
var _fn;
if ( jQuery.isFunction(fn) ) {
_fn = function(e) {
e.data = data;
return fn.call( this, e );
};
}
return _live.call( this, type, _fn || fn || data );
};
})(jQuery.fn.live);
Replacing all instances of bind(...) with live(...) should now work.
Note: you'll have to put the overloaded method above everything else.
From my experience , the only way I have found to do this is by using livequery
It has a similar syntax, and in your case to bind uploadify on a live element, you would use
$('#fileInput').livequery(function(){
$(this).uploadify();
})
Livequery accepts functions without events, and executes them everytime there is a change in the DOM
How is the element generated? If its fetched from the server using jQuery you can use a more hackish way of fixing it, simply put jQuery runs eval() on any script tags it runs into so you could just put:
<script type='text/javascript'>
$(function(){
$('#fileInput').uploadify();
});
</script>
In the fetched html and it'll bind it on load instead of trying to watch over it live. Bonus points, if you fetch the html again it'll be unbound.