/* Note: This script is invoked by the following code embedded in the body of the HTML document:
*/ /******************************************************************************************************************/ /*! * Kachingle utility function. * (C) Copyright 2011 Kachingle Inc. * All Rights Reserved * Proprietary * */ /* Function pair to protect jQuery from host sites that have created their own document.getElementsByClassName (back before browsers had a native implementation), and now that browsers *do* have their own, these sites break jQuery! Bracket any call to jQuery that searches for a class, with these. Probably should bracket the jQuery loading as well, since it calls gEBCN at load time. In the particular site where I was debugging this, that was neither needed nor helpful; bracketing my jQuery call was sufficient. But that was probably just lucky timing - the host page probably messed with gEBCN *after* jQuery was loaded, but *before* my call was executed, so the former worked and the latter didn't. Other sites may not be so lucky. */ var kachingle_host_substitute_gEBCN = { remove: function(){ // In case a substitute was created, remember it. this.sub = document.getElementsByClassName; // Native one can't be deleted, but substitute can be, exposing the native one. if (document.getElementsByClassName) try { delete document.getElementsByClassName; } catch (e) {}; // mysteriously bombs in FF 3.6 // If the native one (or lack of one) was *not* overridden, then remember that fact. if (this.sub === document.getElementsByClassName) this.sub = null; }, restore: function(){ // Host page depends on its weird implementation, so give it back. if (this.sub) document.getElementsByClassName = this.sub; } }; // So use it right away, as a precaution: kachingle_host_substitute_gEBCN.remove(); // INCLUDE JQUERY v.1.4 -- DO NOT EDIT!!!!! /* jQuery code was here, in line. For purposes of code sample, removed that for the sake of readability of this file. */ // END JQUERY CODE kachingle_host_substitute_gEBCN.restore(); /*! * * Kachingle Medallion Controller, rev. B * (C) Copyright 2009, 2010, 2011 Kachingle Inc. * All Rights Reserved * Proprietary * with the exception of BrowserDetect, * based on BrowserDetect by Peter-Paul Koch, http://www.quirksmode.org/ * */ /* In the NEW medallion code snippet, the in-line Javascript checks (window.kachingle_loaded) and will only load this file in the first place if that flag doesn't exist yet. It's declared and set true at the very end, so this file will only be loaded ONCE, and the following check is unnecessary. But OLD medallions also must be supported, and in that case, the snippet contains no check, so this file could be loaded multiple times. So check the flag again here to make sure that at least the code is EXECUTED only once. */ if (!window.kachingle_loaded) { /* The jQuery calls need to be wrapped entirely into a closure (anonymous, self-executing function with jQuery passed in as the argument), followed by the call to jQuery.noConflict(true), to completely prevent all other interactions with other Javascript, either that uses another version of jQuery or that uses other JS libraries. Include the browser detection stuff in that function as well, just to make these variables local. */ (function($) { /* If kachingle.com or .net, prepare to communicate with the content of the iframe */ if (document.domain.length >= 13) { // *might be* kachingle.com or .net var main_domain = document.domain.slice(-13); // Last 13 chars if (main_domain == "kachingle.com" || main_domain == "kachingle.net") // Change domain to that part only, so we can receive messages from inside the // medallion. (In the form of the variable message_from_kachingle_iframe.) document.domain = main_domain; } // BROWSER DETECTION var BrowserDetect = { init: function () { this.browser = this.searchString(this.dataBrowser) || "An unknown browser"; this.version = this.searchVersion(navigator.userAgent) || this.searchVersion(navigator.appVersion) || "an unknown version"; this.OS = this.searchString(this.dataOS) || "an unknown OS"; }, searchString: function (data) { for (var i=0;i'); // We'll style it and load it later. kachinglex_ids[site] = kachinglex_id; } // Style-specific properties var iFrameHeight = styles[style_name].iFrameHeight; var iFrameWidth = styles[style_name].iFrameWidth; if (styles[style_name].isClickableOnly) { $(this).css({backgroundColor: normal_color}); iframe.css({backgroundColor: "transparent"}); }; $(this).css({ height: iFrameHeight, width: iFrameWidth }); iframe.css({ height: iFrameHeight, width: iFrameWidth }); iframe.attr({allowTransparency:'true'}); // For IE < 8 // In mobile (and now in clickable bar medallion, too), no mouseover possible, so need clickable medallion. // But iframes aren't clickable, so create a clickable div to lie above. // (Note this makes the container itself clickable, too, since we can just let the event propagate up.) // (HOWEVER, in the end it worked better to just capture the clicks from the clicker itself.) var clicker = $('
'); clicker.css({ // superimpose over iframe, same dimensions and position, but shave off the top row of pixesls // to avoid subtle webkit problem with clickable bar medallion - cursor in chrome interpreted // as top of window at load time, bar would come up in hover_color instead of normal_color. height: (parseInt(iFrameHeight) - 1) + "px", width: iFrameWidth, position: 'absolute', top: 1, left: 0, zIndex: 1, // prevent host page from overriding these default values! backgroundColor: 'transparent', backgroundImage: 'none', margin: 0, padding: 0, border: 'none', boxShadow: '0 0 0', webkitBoxShadow: '0 0 0', mozBoxShadow: '0 0 0' }); $(this).append(clicker); // Display the iframe only *after* it finishes loading. iframe.one('load', function(){ // (For old medallions, show the div; for new medallions, show the iframe.) var container = $(this).parent(); if (container.is('#kMedallionContainer')) container.css({display: 'block'}); else $(this).css({display: 'block'}); medallion_iframes_loading = medallion_iframes_loading.not(this); if (medallion_iframes_loading.length == 0) // then that means all the render requests have been queued to the browser, // so we can, first, briefly give control back to the browser to render them: setTimeout( // and second, come back to JS and do the overlay initialization: all_the_rest_of_it, 10); }); // Load it! iframe.attr('src', medallion_url); medallion_iframes_loading = medallion_iframes_loading.add(iframe); }); // all_medallion_containers.each() /* End of $(document).ready(), i.e., the statement above is the last thing executed when this function is called; all the rest of it is nested inside function all_the_rest_of_it() -- to be executed only after all the medallions have had a chance to be rendered. */ /********************************************************************************/ /* */ /* Create invisible overlays: set of iframes, one for each site id */ /* */ /********************************************************************************/ function all_the_rest_of_it() { // Create just ONE container, containing ALL the iframes // Dimensions -- must be same for all medallion states -- do all fiddling in this section var overlay_iframe_h = styles['overlay'].iFrameHeight; var overlay_iframe_w = styles['overlay'].iFrameWidth; var overlay_container_h = parseInt(overlay_iframe_h); // Make these integers instead of strings, so we can calculate on them. var overlay_container_w = parseInt(overlay_iframe_w); // Create a single overlay container var overlay_container = $('
'); // Set its properties overlay_container.css({ //height: overlay_container_h + 'px', // Nah, instead just let it collapse down to the iframe (or 0 when no iframe visible) width: overlay_container_w + 'px', // position: FIXED_IS_SUPPORTED ? 'fixed' : 'absolute', position: 'absolute', zIndex: 0x7fffffff // greatest integer CSS seems to understand - why screw around? }); var overlay_url = path + '/medallion.php?style=overlay&site='; // unlike medallion_url, add the site on the fly, at time of use // Style the multiple overlay iframes, and stick them in the // single overlay container. (Only one will be visible at a time.) for (var site in overlay_iframes) { var overlay_iframe = overlay_iframes[site]; overlay_iframe.css({ height: overlay_iframe_h, width: overlay_iframe_w, display: 'none' }); overlay_iframe.attr({ allowTransparency: 'true', scrolling: 'no', frameborder: '0', src: overlay_url + site // Load the overlay iframe with content + '&x=' + kachinglex_ids[site] + widget_return_to }); // Add iframe to the container overlay_container.append(overlay_iframe); } // Load a close button as a clickable image over the iframe, since clicking anything inside the // iframe won't be detectable. var close_clicker = $(""); close_clicker.css({ position: 'absolute', top: '0px', right: '0px', zIndex: 1, // on top of the iframes display: 'none', // appear and disappear along with the iframes cursor: 'pointer', padding: 0, margin: 0, border: 0 }); overlay_container.append(close_clicker); // Put the container into the DOM $('body').append(overlay_container); // for communicating between different events var pageX_at_hide, pageY_at_hide, current_overlay_iframe; // undefined at first // Install the event handlers declared below:... // These in desktop only. Interfering with click behavior in mobile? These events are also generated by tap. if (platform == "desktop or unknown") { // TO SIMULATE MOBILE ON THE DESKTOP, TEMPORARILY COMMENT OUT THIS WHOLE THING (and one more, below) all_medallion_containers.each(function(){ var c = $(this); // container if (styles[c.data("style_name")].isClickableOnly) { // on mouseover, indicate clickability; don't open overlay c.find("div").css({cursor: 'pointer'}); // mouseenter/leave could slightly more simply be detected on c, but use c.find("div") (the clicker) instead // to exclude the top row of pixels, otherwise subtle webkit bug causes pg to load with hover_color instead // of normal_color. c.find("div").mouseenter(function(){ c.css({backgroundColor: hover_color}); }); c.find("div").mouseleave(function(){ c.css({backgroundColor: normal_color}); }); // if this is a KX medallion and has a news_msg_txt... if (c.parent().find("span").length > 0) // ...then move the text container from in front of the medallion container, to behind the click target c.parent().find("div").last().detach().insertBefore(c.find("div")); } else c.mouseenter(show_overlay); // on mouseover, open overlay }); overlay_container.mouseleave(hide_overlay); } // Attaching click handler to the container (with event bubbling up from the clicker itself) worked almost everywhere, but not in // the Android default browser! So attach to the clicker itself instead. //all_medallion_containers.click(show_overlay); all_medallion_containers.find('div').click(show_overlay); // The following would not be needed if using document-click, which would catch this event on its way up (see below). Unfortunately // the document.click doesn't work in iPhone, so you do need this. Strangely, though: in Safari, you couldn't **generate** a click on // document, but the click on close_clicker would still bubble up and trigger that handler, which was clearly active, so this handler // wasn't needed. In contrast, in Opera Mini on iPhone, it couldn't detect *either* event until this handler also installed, so // apparently document click handler was not even active for propagated events. Meanwhile, Android seems to be able to handle both // the X-click and the click-outside, using only the document (or window, not sure which) click handler, both in Android default and // in Opera Mini. (Hmm, click-outside was working in Opera Mini? Not anymore.) close_clicker.click(hide_overlay); /* overlay_container.mouseleave(function(mouse_evt) { alert('mouse Leave triggered, x & y = ' + mouse_evt.pageX + ', ' + mouse_evt.pageY); hide_overlay(mouse_evt); }); */ /* End of all_the_rest_of_it(), i.e., the statement above is the last thing executed when the function is called; what follows are nested functions executed only after mouse events. */ /********************************/ /* */ /* Event Handlers */ /* */ /********************************/ // Three ways to hide overlay: 1) On mouseleave, which can be bound just once, above. 2) When ESC pressed, but this has to // be done differently. Has to go on document, which is a likely target of other scripts as well, so to make sure it's there // when needed, we bind it on mouseenter (inside show_overlay()) and unbind it on mouse out (inside hide_overlay()). // 3) On mousemove. Normally wouldn't want to do that. But if mouse is already outside the overlay area by the time the // overlay opens, you won't ever get a mouseleave event and so this is the only way to detect it. This can happen because // mouse can move very fast over the medallion. (Or from the user POV, the medallion pops open and you can't figure out how to // close it, unless you hit upon moving the mouse back over it again.) So, just get a single mousemove event. It won't occur // at all if the mouse remains inside the medallion (because the iframe eats it), so if it does occur, either the mouse just // left (and generated a mouseleave event at the same time), or was outside the boundaries already and then moved. So hide the // overlay. Event will also be bound to document so handle binding and unbinding same as for ESC. // (This **MAY** no longer be needed, thanks to subsequent performance improvements, but it's not hurting anything.) // Popup the overlay when medallion moused over or clicked. function show_overlay(mouse_evt) { // Mouse position when entered. Note: relative to **document** (not window) var mouseX = mouse_evt.pageX; var mouseY = mouse_evt.pageY; // alert('at last mouseleave, pageX = ' + pageX_at_hide + ', pageY = ' + pageY_at_hide + // '\n at mousenter, pageX = ' + mouseX + ', pageY = ' + mouseY); // If cursor location exactly the same as when overlay previously hidden, then user // moused directly off of overlay and onto medallion, so suppress opening of new overlay. if (typeof pageX_at_hide != 'undefined' && mouseX == pageX_at_hide && typeof pageY_at_hide != 'undefined' && mouseY == pageY_at_hide) return; // Get window position relative to document var jQwin = $(window); var windowLeft = jQwin.scrollLeft(); var windowTop = jQwin.scrollTop(); // alert('windowLeft = ' + windowLeft + '\nwindowTop = ' + windowTop + // '\nwindow width - 240 = ' + (jQwin.width()-240) + '\nwindow height - 240 = ' + (jQwin.height()-240)); var cornerX, cornerY; // calculate these by two different algorithms: if (browser == "Opera Mini") // Use a much simpler positioning algorithm! For vertical, window height & offset and mouse position seem to fail; don't use. { var container_offset = $(mouse_evt.target).offset(); // position of the medallion cornerX = container_offset.left; // overlay flush with medallion left cornerY = container_offset.top - overlay_container_h / 2; // overlay centered over medallion top } else { // Center the (left half of the) overlay over the cursor by positioning upper left corner above and left // (coords still relative to document) cornerX = mouseX - overlay_container_w / 4; cornerY = mouseY - overlay_container_h / 2; // Account for overlapping the window edges: set limits, relative to **window** (not document) var max_allowed_x = jQwin.width() - overlay_container_w; var max_allowed_y = jQwin.height() - overlay_container_h; var min_allowed_x = 0; var min_allowed_y = 0; // Corner coordinates (make limits relative to document, not window -- overlay now scrolls along with medallion) /* // Corner coordinates relative to window or to document, as appropriate if (FIXED_IS_SUPPORTED) { // Use position relative to window instead of to document cornerX -= windowLeft; cornerY -= windowTop; } else { // (Quirks mode) Make limits relative to document instead of to window */ max_allowed_x += windowLeft; max_allowed_y += windowTop; min_allowed_x = windowLeft; // To accomodate KX 3.0.0 (where element has a marginTop), subtract this amount from windowTop // in order to get the overlay all the way up to the top of the window. It doesn't work otherwise. min_allowed_y = windowTop - (parseInt($("html").css("marginTop")) || 0); // || 0 protects from NaN /* } */ if (cornerX > max_allowed_x) cornerX = max_allowed_x; if (cornerY > max_allowed_y) cornerY = max_allowed_y; if (cornerX < min_allowed_x) cornerX = min_allowed_x; if (cornerY < min_allowed_y) cornerY = min_allowed_y; // alert('x= ' + cornerX + ', y= ' + cornerY); } // position the overlay at the computed location overlay_container.css({top: cornerY, left: cornerX}); /* // Revert coords to be relative to document again, for later comparison with mouse. (This goes with the code // below that tests the mouse location inside the mousemove handler. If that's not needed, neither is this.) if (FIXED_IS_SUPPORTED) { cornerX += windowLeft; cornerY += windowTop; } */ // Remove any load handlers left over from *previous* mouseovers; we will want to trigger *only* on the newly opened one. // (Note, can't do this on mouseleave because overlay reloading might not be finished yet.) if (typeof current_overlay_iframe != 'undefined') { // (will be undefined on the very *first* mouseover) current_overlay_iframe.unbind('load'); // Also make *sure* the previouse iframe gets closed, before overwriting this variable and forgetting // which iframe that was. This should not be necessary, because it should be impossible to mouse over // and open a medallion while an overlay is already open. But in Opera for Windows only, somehow the // identity of the open iframe was being forgotten, leaving it uncloseable. It must be that by moving // the mouse fast enough, you could trigger one to open before the previous one had closed. Close it now. current_overlay_iframe.css({display: 'none'}); } //alert("event = " + mouse_evt.type + "; target position = " + $(mouse_evt.target).css('position') + // "; target = " + mouse_evt.target + "; parent = " + $(mouse_evt.target).parent() + ", " + $(mouse_evt.target).parent().css('position')); // Get the site for this particular medallion and find its particular overlay iframe. (Used to use "this" to get // the container; however, once this handler was added in additional places -- on the container for mousing over, // but now on the "clicker" (covering transparent div) itself for clicking -- "this" is no longer always the // container. So use mouse_evt.target, which should always be the clicker.) // (Note this exception: weirdly in IE when the mouse is over text in the iframe, that part of the iframe // actually pokes through the clicker and becomes the target of the mouseover! [This is also why the medallion // isn't clickable in IE when hovering over the text!] Luckily the iframe and the clicker both have the same // parent; so the data can still live on the container, and use mouse_evt.target.parent to find it.) //current_overlay_iframe = overlay_iframes[$(this).data('site')]; current_overlay_iframe = overlay_iframes[$(mouse_evt.target).parent().data('site')]; // Add an onload trigger to this iframe, to go reload all the medallions as well as the other overlay iframes, on subsequent // overlay loads. Must be removed when closing the overlay so that *only* the currently active overlay has a trigger. current_overlay_iframe.bind('load', function() { //alert("message_from_kachingle_iframe = " + message_from_kachingle_iframe); if (message_from_kachingle_iframe) { // This message can only be received if we're on a kachingle domain. If true, the iframe is telling us // that start/stop kachingling was pressed, and therefore we don't have to do all that work. // No need to reload overlays at all. Medallions only have to be reloaded if linked to *this* overlay. message_from_kachingle_iframe = false; // Which site to reload? for (var site in overlay_iframes) if (overlay_iframes[site].attr('src') == $(this).attr('src')) var current_site = site; all_medallion_containers.each(function() { // "this" = a medallion container if ($(this).data('site') == current_site) $(this).find('iframe').attr('src', $(this).find('iframe').data('medallion_url')); }); } else { // Normal case. We don't know if this was a logout or a start/stop kachingling. // Logout requires reloading *everything*. for (var site in overlay_iframes) { // "this" = the overlay iframe that triggered the load overlay_iframes[site].not(this).attr({src: overlay_url + site + '&x=' + kachinglex_ids[site]}); } all_medallion_iframes.each(function() { $(this).attr('src', $(this).data('medallion_url')); // Here, "this" = the **medallion** iframe. }); } }); // Finally, display the overlay. current_overlay_iframe.css({display: 'block'}); //if (mouse_evt.type == "click") // Show the X to close only if overlay was clicked to open in the first place. // whoops, this test was not registering on iPhone! So clicker didn't get displayed. So can't use it. Fix later. :-( // if ((platform == "supported mobile") // Show the X to close only on mobile platforms (no mouseout possible) // I don't actually knows the container here. Would need to store the flag in the overlays object // || styles[container.data("style_name")].isClickableOnly) // clickable bar, too close_clicker.css({display: 'block'}); // Now that bar medallion is clickable, show this always, not just on mobile // Now that clickability added, in addition to closing on clicking the X, also close on clicking the document anywhere // outside the overlay. In fact, the easy way will be to just close on clicking the document **anywhere**, since clicks // inside the overlay iframe will be ignored. And that means that we can use this **instead** of making the button itself // clickable; a click on the button will just bubble up to the document and be handled at that level, too! // Note: must stop propagation first, otherwise the very click that caused the overlay to open, will also cause it to close! // NOTE: BINDING THIS TO DOCUMENT DIDN'T WORK ON IPHONE/IPAD. (CLICKING X WORKED; CLICKING OUTSIDE DID NOT. THAT MEANS THAT // THE HANDLER WORKED AS INTENDED BUT NO CLICK EVENT EVER FIRED ON DOCUMENT. IT NEEDS TO BE A "CLICKABLE" ELEMENT.) // TRIED WINDOW AS AN ALTERNATIVE -- STILL NEEDS TO BE TESTED! That worked just as well in most browsers, but not in IE; // IE required document. So use **both** for now. (Get rid of window if it doesn't help on iPhone.) // (Apple docs say click will only work on "clickable" elements; and that an element can be made clickable with onclick="". // But haven't I already done that with 'bind()'? That must not work, it has to actually be inline HTML onclick=""? // Or at least use the onclick *property* as opposed to addEventListener(), which is probably what bind() uses? // (Oh, I think I know why... it's not that it has to be inline, it's just that it has to be the actual onclick property; // bind() probably uses addEventListener/attachEvent, which is not the same. So I bet I could clean this up if wanted to...) mouse_evt.stopPropagation(); $(window).bind('click.kaching', hide_overlay); //documentClickToClose); //hide_overlay); $(document).bind('click.kaching', hide_overlay); //documentClickToClose); //hide_overlay); /* function documentClickToClose(new_mouse_evt){ // On Opera Mobile (but not Mini?), tap seems to generate multiple clicks. (Or stopPropagation isn't working, but that doesn't // seem to be the case.) Apparently also on Android default browser. So for those two, only hide overlay if new event is more // than 0.2 sec after the old event (mouse_evt from closure). //if (!(browser == "Opera Mobile" || browser == "Opera Mini not iOS" || OS == "Android") || if (browser != "Android default" || new_mouse_evt.timeStamp - mouse_evt.timeStamp > 200) hide_overlay(new_mouse_evt); } */ // ONCE THIS GETS ALL STABILIZED, THIS COMMENT COULD USE SOME REVISION! // (Note, once the overlay is visible, the user can either mouse out, handled in the hide_overlay() handler, below; // or, by a green-purple switch or logout, they can trigger the reloading of all medallions and (other) overlays, // handled here. Importantly, in the latter case, they can trigger it and then immediately mouse out before the reload is // finished, so the load event and the mouseleave event can occur in *either* order. That's why the reload handler // can't be unbound inside the mouseleave handler, as commented above.) if (platform == "desktop or unknown") { // TO SIMULATE MOBILE ON THE DESKTOP, TEMPORARILY COMMENT OUT THIS WHOLE THING (and one more, above) // These in desktop only. Interfering with click behavior in mobile? Mousemove event is also generated on tap. // Add a keydown handler and a mousemove handler each time we bring up an overlay. $(document).bind('keydown.kaching', function(key_evt) { // alert('key ' + key_evt.which + ' triggered, x & y = ' + key_evt.pageX + ', ' + key_evt.pageY); if (key_evt.which == 27) hide_overlay(key_evt); // Note, disappearance of overlay from under the cursor generates a mouseleave event }); // TEMPORARILY COMMENT OUT THE FOLLOWING ENTIRE FUNCTION, TO SIMULATE MOBILE (along with two other items above) $(document).bind('mousemove.kaching', function(move_evt) { // $(document).unbind('mousemove.kaching'); // Only fire once // alert('mouse Move triggered, x & y = ' + move_evt.pageX + ', ' + move_evt.pageY + ', and unbound'); // Mainly, need to hide the overlay. But need to be careful of a few things... // Mouse move can actually be triggered and the medallion hidden before the browser ever has a chance // to render it. So set timeout on the hiding in order to give control briefly back to the browser for // rendering, allowing the medallion to appear before we make it go away again. // Also note, only mouse moves OUTSIDE the medallion should cause it to close, not mouse moves INSIDE. // But: // In most browsers it works like this: Mousemove events internal to the medallion are never generated, // because they go to a different document (the one inside the iframe). Therefore, if you get here, the // mouse is outside the medallion, so you can go ahead and close. If it was inside and then moused out, // this event is generated on the way out, and a mouseleave event will be generated along with it. But if // it was outside to start with (because it moved away before the medallion was loaded and displayed), // then there will be no mouseleave event, so this mousemove is needed in order to close. // HOWEVER, in Opera for PC only (apparently): Internal mouse moves can trigger this event, so you have to // test the mouse location to see if it's inside or outside before hiding the overlay. var evtx = move_evt.pageX; // mouse location, relative to document var evty = move_evt.pageY; if (evtx < cornerX || evtx > cornerX + overlay_container_w || evty < cornerY || evty > cornerY + overlay_container_h) { // mouse move OUTSIDE overlay $(document).unbind('mousemove.kaching'); // only fire once (outside) // alert('OUTSIDE, x & y = ' + move_evt.pageX + ', ' + move_evt.pageY + ': closing overlay'); setTimeout(function() { hide_overlay(move_evt); }, 50); } // else mouse move was INSIDE overlay: ignore // else { // alert('INSIDE, x & y = ' + move_evt.pageX + ', ' + move_evt.pageY + ': ignoring'); // } }); } } // show_overlay function hide_overlay(mouse_evt) { // Record the mouse coordinates for later comparison at next mouseover pageX_at_hide = mouse_evt.pageX; pageY_at_hide = mouse_evt.pageY; // alert('inside hide_overlay(), about to close'); current_overlay_iframe.css({display: 'none'}); close_clicker.css({display: 'none'}); // remove the keydown and mousemove handlers because otherwise adding new ones on each call to show_overlay() (which we have to do) // would result in a whole stack of them. Namespacing makes sure not to remove anybody else's handler that might be there. $(document).unbind('keydown.kaching'); $(document).unbind('mousemove.kaching'); $(window).unbind('click.kaching'); $(document).unbind('click.kaching'); } } // all_the_rest_of_it() }); // $(document).ready(function(){... })(jQuery); // (function($){... jQuery.noConflict(true); var kachingle_loaded = true; // Multi medallions per page: only load this file once! var message_from_kachingle_iframe = false; // For communication with iframe. Must be global. if (!window.kexecutecount) var kexecutecount = 0; kexecutecount++; // For testing. Counts how many times *executed*. Can leave in since affects nothing. } // if (!window.kachingle_loaded) if (!window.kloadcount) var kloadcount = 0; kloadcount++; // For testing. Counts how many times *loaded*. Can leave in since affects nothing.