Multiple jQuery.noConflict() instances - javascript

I am working with several jQuery scripts that include a MenuFader (http://css-tricks.com/examples/MenuFader/), twitter feed, and timestamp. Additionally I have a couple Mootools scripts that include the Barackslideshow (http://devthought.com/wp-content/moogets/BarackSlideshow/demo.html). And finally I have a scrolling ticker with tooltips taken from the twitter homepage.
I originally had a conflict with the Jquery MenuFader and Mootools BarackSlideshow, but easily fixed this issue with the jQuery.noconflict(); and replaced all corresponding $ with jQuery.
Unfortunately, after I added the scrolling ticker from Twitter, the Mootools BarackSlideshow and the Jquery MenuFader no longer work.
I tried to implement jQuery.noconflict(); then $.noconflict(); then var j = jQuery.noconflict(); and replacing the $ as I did previously, but I cannot get the scripts to play nicely.
Any help is greatly appreciated...I have been working on this all day. I am pretty new with javascript, but have managed to get through most problems with a little persistence. Please take a look at the script below:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.0/jquery.min.js" type="text/javascript"></script>
<script src="http://a2.twimg.com/a/1274914417/javascripts/fronts.js" type="text/javascript"></script>
<script type="text/javascript">
//<![CDATA[
$( function () {
setTimeout(function() { $(".twtr-widget").append($("<div></div>").attr("class", "twtr-fade")); }, 0);
(function() {
var tabIndex = $("[tabindex]:last").attr("tabIndex");
var setTabIndex = function() {
$(this).attr("tabindex", ++tabIndex);
}
$(".footer-nav a").each(setTabIndex);
$(".language-select a").each(setTabIndex);
})();
$("#signup_submit").scribe({
event_name: "signup_submit_click",
experiment: "ab_signup_button",
bucket: "sign_up"
}, "www_ab_tests");
$('#signin_menu').isSigninMenu();
new FrontPage().init();
});
//]]>

noConflict is simply and only about changing the name the jQuery library is available under.
This is an attempt to play nicer with other frameworks that may also want to use the name $, but that's all it does. It does not solve any other kind of general conflict with other frameworks. For example when one framework clones, changes or removes an element with jQuery's internal ID markers, weird undebuggable errors may ensure. It is still a really bad idea to use more than one framework on a single page, when they're as wide-ranging and intrusive as jQuery. (Especially jQuery 1.3, which was super-promiscuous about what elements it touched.)
Similarly, two high-level plugins that operate on the same elements are very likely to have unwanted behavioural interactions. Say one plugin binds a behaviour to an element, but then the other plugin deletes that element to replace it with a progressive-enhanced version. Or one plugin tries to read the offsetWidth of an element that no longer has a visible width because another plugin has called hide() on its parent.
Scripts and plugins may pretend to be fully encapsulated behaviours that you can throw around without understanding how they work, but they really aren't. If you bind two scripts (that have not been deliberately designed to work together) to the same elements they are likely to interfere or fail. Try to keep elements that will be affected by different plugins apart from each other to reduce this potential.

Related

js: Using some custom jQuery

I have a bit unusual case in my project. The jQuery is loaded under a namespace, like
var grp = {
"jQuery": jQuery.noConflict(true)
};
So in my custom scripts I am doing:
(function($){...}(grp.jQuery);
The question I have is how to handle external jQuery plugins. E.g. I want to add autocomplete plugin, which depends on jQuery, and starts with
$(document).ready(function() { ....
And it looks like the only option to include them in source code like
<script type="text/javascript" src="/static/autocomplete_light/django_admin.js"></script>
would be to edit them all, which is not practical...
You have two options:
Move jQuery to where the plugins expect to find it (i.e. to a global)
Edit all the plugins to tell them where jQuery actually is
You could try writing a preprocessor that edits all the plugins for you at build time (this would probably be more work and more error prone than is worthwhile).
Assuming you are not using the $ variable name anywhere else,
maybe you can append it to the window on startup so it'll be available.
Something like:
(function(jQuery) {
window.$ = jQuery;
}(grp.jQuery))

Apply jquery mobile only a portion of page?

I have a sample page which we have design very well. Now, we need to use jquery mobile only a portion of our page. The problem is that, when I add jquery mobile it is messing all my UI stuff. Is there is a way to apply jquery mobile only a portion of page?
There are several ways of achieving this, and you can find them in my other ARTICLE, or find it HERE. Search for chapter called: Methods of markup enhancement prevention.
And here's a short description with examples. There are several solutions and you will need to pick right one:
Methods of markup enhancement prevention:
This can be done in few ways, sometimes you will need to combine them to achieve a desired result.
Method 1:
It can do it by adding this attribute:
data-enhance="false"
to the header, content, footer container.
This also needs to be turned in the app loading phase:
$(document).one("mobileinit", function () {
$.mobile.ignoreContentEnabled=true;
});
Initialize it before jquery-mobile.js is initialized (look at the example below).
More about this can be found here:
http://jquerymobile.com/test/docs/pages/page-scripting.html
Example: http://jsfiddle.net/Gajotres/UZwpj/
To recreate a page again use this:
$('#index').live('pagebeforeshow', function (event) {
$.mobile.ignoreContentEnabled = false;
$(this).attr('data-enhance','true');
$(this).trigger("pagecreate")
});
Method 2:
Second option is to do it manually with this line:
data-role="none"
Example: http://jsfiddle.net/Gajotres/LqDke/
Method 3:
Certain HTML elements can be prevented from markup enhancement:
$(document).bind('mobileinit',function(){
$.mobile.page.prototype.options.keepNative = "select, input";
});
Example: http://jsfiddle.net/Gajotres/jjETe/

jQuery plugin conflicting with other basic show/hide functions

I bought (didn't code myself due to lack of education blah, blah, blah) a jQuery image slider/navigation plug in. it works fine, and I have adjusted the images and CSS fittingly.
Problem is that when the slider is working properly, I cannot use a show/hide onClick event such as $('#someId').toggle();.
Using trial and error I have found that commenting a few lines of js on the html page allows the show/hide functions to work, but then the slider is broken,.
The js that I comment out comes after the slider images(plug-in).
The JS code in questin is:
<script type="text/javascript">
var $jx = jQuery.noConflict();
$jx('.slidedeck').slidedeck();
</script>
When comment it out with html, then I can use onclick="$('#someId').toggle();" without a problem. But again, then the slider plugin is very broken and splattered all over the page.
As it is noticeable, and stated, I know nearly nothing.
Can anyone help me understand when this is happening?
Thanks
/Brian
try change:
<script type="text/javascript">
var $jx = jQuery.noConflict();
$jx('.slidedeck').slidedeck();
</script>
to:
<script type="text/javascript">
$('.slidedeck').slidedeck();
</script>
http://api.jquery.com/jQuery.noConflict/
you have to use $jx or jQuery
ex: onclick="jQuery('#someId').toggle();"
The dollar sign is an alias for the jQuery method. Because there are other JavaScript libraries that may use the dollar sign as well, jQuery offers the noConflict method which basically renames the jQuery method to the variable that you set it to. (This way, it won't conflict with those other libraries.)
So, after the noConflict is called, all of your jQuery calls will need to replace the dollar sign with that variable. So in your example, just do this:
onclick="$jx('#someid').toggle();"

Is it possible to create element on the fly with jQuery Mobile?

I have an app built using jQuery (and using various jQuery-UI tools).
For some reason, i have to port it to smartphones/tablet computer, and decided to use jQuery Mobile for that (in order to minimize the number of changes).
In my vanilla app, I created some elements of the page on the fly, depending of user interactions.
For example a slider could be created like that (p is an object with a bunch of params):
function createSlider(p){
return $("<div/>",{
"id":p.id,
"class":p.divClass,
}).slider({
"orientation": p.align,
"min":p.constraint.min,
"max":p.constraint.max,
"step":p.step,
"value":p.curVal,
"animate":"normal"
/*and some event handling here, but it doesn't matter*/
});
}
And it will produce a nice looking slider. Now it looks like:
function createSlider(p){
return $("<range/>",{
"id":p.id,
"class":p.divClass,
"min":p.constraint.min,
"max":p.constraint.max,
"step":p.step,
"value":p.curVal,
});
}
But as it's created on the fly, all the stuff done by jQuery Mobile on the page load isn't done on it.
Is there a way to force that initialization without writing the slider in the html?
Thanks.
EDIT: I found in the doc that it could be achieved using container.trigger("create");
However this does not work yet.
EDIT2: Ok create was the solution.
According to the documentation (see edit in the question), using trigger("create") on the containing element works.
And to make that work, you also need to remember that range is an input type and not a tag...
Working solution:
function createSlider(){
return $("<input/>",{
"type":"range",
"id":"sl",
"min":0,
"max":15,
"step":1,
"value":1,
});
}
function appendSlider(){
$("#yourdiv").append(createSlider()).trigger("create");
}
As a sidenote, the documentation for jQuery mobile lacks a search option.
Try calling .page() on the container the content is being added to. Alternatively, adding .page() to the content you're returning may also work.

Recommended method to locate the current script?

I am writing a script that needs to add DOM elements to the page, at the place where the script is located (widget-like approach).
What is the best way to do this?
Here are the techniques I am considering:
Include an element with an id="Locator" right above the script. Issues:
I don't like the extra markup
If I reuse the widget in the page, several elements will have the same "Locator" id. I was thinking about adding a line in the script to remove the id once used, but still...
Add an id to the script. Issues:
even though it seems to work, the id attribute is not valid for the script element
same issue as above, several elements will have the same id if I reuse the script in the page.
Use getElementsByTagName("script") and pick the last element. This has worked for me so far, it just seems a little heavy and I am not sure if it is reliable (thinking about deferred scripts)
document.write: not elegant, but seems to do the job.
[Edit] Based on the reply from idealmachine, I am thinking about one more option:
Include in the script tag an attribute, for example goal="tabify".
Use getElementsByTagName("script") to get all the scripts.
Loop through the scripts and check the goal="tabify" attribute to find my script.
Remove the goal attribute in case there's another widget in the page.
[Edit] Another idea, also inspired by the replies so far:
Use getElementsByTagName("script") to get all the scripts.
Loop through the scripts and check innerHTML to find my script.
At the end of the script, remove the script tag in case there's another widget in the page.
Out of the box : document.currentScript (not supported by IE)
I've worked for OnlyWire which provides, as their main service, a widget to put on your site.
We use the var scripts = document.getElementsByTagName("script"); var thisScript = scripts[scripts.length - 1]; trick and it seems to work pretty well. Then we use thisScript.parentNode.insertBefore(ga, thisScript); to insert whatever we want before it, in the DOM tree.
I'm not sure I understand why you consider this a "heavy" solution... it doesn't involve iteration, it's a pure cross-browser solution which integrates perfectly.
This works with multiple copies of same code on page as well as with dynamically inserted code:
<script type="text/javascript" class="to-run">
(function(self){
if (self == window) {
var script = document.querySelector('script.to-run');
script.className = '';
Function(script.innerHTML).call(script);
} else {
// Do real stuff here. self refers to current script element.
console.log(1, self);
}
})(this);
</script>
Either document.write or picking the last script element will work for synchronously loaded scripts in the majority of web pages. However, there are some options I can think of that you did not consider to allow for async loading:
Adding a div with class="Locator" before the script. HTML classes has the advantage that duplicates are not invalid. Of course, to handle the multiple widget case, you will want to change the element's class name when done adding the HTML elements so you do not add them twice. (Note that it is also possible for an element to be a member of multiple classes; it is a space-separated list.)
Checking the src of each script element can ensure that tracking code (e.g. Google Analytics legacy tracking code) and other scripts loaded at the very end of the page will not prevent your script from working properly when async loading is used. Again, to handle the multiple widget case, you may need to remove the script elements when done with them (i.e. when the desired code has been added to the page).
One final comment I will make (although you may already be aware of this) is that when coding a widget, you need to declare all your variables using var and enclose all your code within: (JSLint can help check this)
(function(){
...
})();
This has been called a "self-executing function" and will ensure that variables used in your script do not interfere with the rest of the Web page.
Whether you drop a <script> tag in or a <div class="mywidget">, you're adding something to the markup. Personally, I prefer the latter as the script itself is only added once. Too many scripts in the page body can slow down the page load time.
But if you need to add the script tag where the widget is going to be, I don't see what's wrong with using document.write() to place a div.
I just found another method that seems to answer my question:
How to access parent Iframe from javascript
Embedding the script in an iframe allows to locate it anytime, as the script always keeps a reference to its own window.
I vote this the best approach, as it'll always work no matter how many times you add the script to the page (think widget). You're welcome to comment.
What pushed me to consider iframes in the first place was an experiment I did to build a Google gadget.
In many cases this work well (hud.js is the name of the scipt):
var jsscript = document.getElementsByTagName("script");
for (var i = 0; i < jsscript.length; i++) {
var pattern = /hud.js/i;
if ( pattern.test( jsscript[i].getAttribute("src") ) )
{
var parser = document.createElement('a');
parser.href = jsscript[i].getAttribute("src");
host = parser.host;
}
}
Also you can add individual script's name inside them.
either inside some js-script
dataset['my_prefix_name'] = 'someScriptName'
or inside HTML - in the <script> tag
data-my_prefix_name='someScriptName'
and next search appropriate one by looping over document.scripts array:
... function(){
for (var i = 0, n = document.scripts.length; i < n; i++) {
var prefix = document.scripts[i].dataset['my_prefix_name']
if (prefix == 'whatYouNeed')
return prefix
}
}
I haven't had access to internet explorer since forever, but this should work pretty much everywhere:
<script src="script.js"
data-count="30"
data-headline="My headline"
onload="uniqueFunctionName(this)"
defer
></script>
and inside script.js:
window.uniqueFunctionName = function (currentScript) {
var dataset = currentScript.dataset
console.log(dataset['count'])
console.log(dataset['headline'])
}

Categories

Resources