As things stand, if you want to use Drupal with the prototype library, you have a problem, in that both jQuery and Prototype use the $() function.
On the jQuery site, there is a workaround using (see http://docs.jquery.com/Using_jQuery_with_Other_Libraries ).
However: the recommended method doesn't work with jQuery 1.0.4:
var $j = jQuery.noConflict(); // Use jQuery via $j(...) $j(document).ready(function(){ $j("div").hide(); });
because the noConflict() function isn't supported in 1.0.4
What I did
In each of the files listed below, I did two things:
1. Added the following at the top:
var $jq = jQuery;
2. Change ever instance of $(...) to $jq(...)
Then, my prototype and jQuery got on fine.
List of files changed:
autocomplete.js
collapse.js
drupal.js
progress.js
tableselect.js
textarea.js
upload.js
update.js
As of jQuery 1.1.x, the first line in the files will have to read:
var $jq = jQuery.noConflict();
My _feature request_ is... is there any way that in core, we could adopt a $jq or $drupal_jq override of the jQuery $() function? That way, Drupal will be compatible with Prototype and other libraries off the shelf!
Victor Kane
http://awebfactory.com.ar
Comment | File | Size | Author |
---|---|---|---|
#90 | drupal6.jquery-fixes-d6.patch | 28.01 KB | sun |
#79 | jquery_noconflict.patch | 22.43 KB | quicksketch |
#74 | jquery_noconflict.patch | 17.62 KB | kkaefer |
#65 | js_test_module.zip.txt | 30.47 KB | mfer |
#64 | jquery_noconflict-125030-64.patch | 18.33 KB | mfer |
Comments
Comment #1
xhochy CreditAttribution: xhochy commentedI think too, that it is really necessary to remove the use of the $()-function and write into the development handbooks, that developers shouldn't use the $()-function because there can be conflicts with other JavaScript-Libraries, but as long as this problem is not solved, I created my own version of Prototype where the $()-function is renamed to $ID(), so I can be used with Drupal 5 without having any problems. I made a compressed version too, which is available at my Weblog.
Comment #2
John Resig CreditAttribution: John Resig commentedThere's a lot confusion on this point, and I'd like to point out a more-ideal solution. The Drupal core, and any Drupal plugins, should use the native jQuery() function. Defining it to any other namespace (like $jq) will only cause any/all Drupal/jQuery code to become Drupal-specific; which is, generally, a poor solution.
Once the Drupal core is using jQuery() exclusively, the decision to use $() would then be left to the user; the same person who should be choosing to use Prototype or Mootools (or any other $-using library).
Additionally, any module that uses Prototype, or Mootools (or any library that explicitly overwrites Drupal/jQuery's $() function) should be re-written to use a copy of Prototype or Mootools that isn't so destructive (like the one posted by xhochy). In this respect, the JavaScript code of Drupal modules should be treated just like any other PHP module code (like completely overwriting, and breaking, a native Drupal function).
Finally, it is then left to the user, if they should chose to use Prototype, to simply call jQuery.noConflict() - allowing them to use Prototype's native $() function. While, at the same time, regular Drupal users, who wish to use jQuery's $() function, don't have to jump through any additional hoops in order to get started. But that's ok, because with this solution these two groups of users will still be able to happily co-exist.
Comment #3
victorkane CreditAttribution: victorkane commentedExcellent points!
We should work along those lines.
The only little detail is that jQuery.noConflict() is not available in the older version of jQuery that currently comes with Drupal core (5.1).
Hopefully this will change in the future.
Comment #4
xhochy CreditAttribution: xhochy commentedI found ca. 190 occurences of the $()-function in Drupal HEAD with the following command
find -name "*" -exec grep -Hn "\$(" "{}" ";"
Sadly not all occurences found by find are really $()-function-calls, some belong to a regular expression or are part of a binary file, I think that I will try to write a simple(4-10 lines) replacement script, that I would run on each of the file without those regular expressions. The other files(which cause conflict through regular expressions) have to be edited manually, but I think that shouldn't be a lot of work.
Comment #5
xhochy CreditAttribution: xhochy commentedI think most important now is to add to a handbook(I don't know where it belongs) that core implementation should only use jquery() and not $() in future to give the user the choice of the javascript library he wants.
Comment #6
xhochy CreditAttribution: xhochy commentedOk here's my script(sry but it's in ruby but should be simple to understand) for the replacing of $() with jquery and the patch for Drupal so that $() isn't anymore used. The next step should be a upgrade to jquery 1.1.x.
Comment #7
xhochy CreditAttribution: xhochy commentedBecause only one file per comment can be uploaded here's the ruby script.
Comment #8
pwolanin CreditAttribution: pwolanin commentedcan you post the patch as a unified diff?
Comment #9
xhochy CreditAttribution: xhochy commentedThe "jquery_15.patch" should be an unified patch, or do you want the patch for prototype?
Comment #10
pwolanin CreditAttribution: pwolanin commentedPerhaps I wasn't clear- "jquery_15.patch" does not seem to have been made in the unified diff format.
Please run diff as "diff -up" when making a patch: http://drupal.org/patch/create
Comment #11
xhochy CreditAttribution: xhochy commentedok, I made a new after the Drupal instructions, here is it.
Comment #12
psychopath_mind CreditAttribution: psychopath_mind commentedAnd before it...
If i need to upgrade my Drupal 5.1 for a newer version... I will lose this replacements right? has someone know about what this will be solved on the future by the development core team? or a link about what the develompents pretend to solve this on future version?
On her last path, what is the version of JQuery?
Can you take me the source of replacement script?
Thanks!
Comment #13
chx CreditAttribution: chx commentedComment #14
AmrMostafa CreditAttribution: AmrMostafa commentedPatch updated for HEAD.
Comment #15
Steven CreditAttribution: Steven commentedRather than bloating the code and hampering readability by peppering the code with 'jQuery', a closure could be used to alias jQuery to $ locally instead to keep the best of both worlds.
Comment #16
infojunkie@Steven: I'm trying to use a script made with scriptaculous and prototype on Drupal 5.3, but I'm a JavaScript n00b. Can you please explain further how the closure approach would be implemented? TIA.
Comment #17
catchMarking as needs work per #15.
kratib: http://docs.jquery.com/Using_jQuery_with_Other_Libraries
Comment #18
infojunkie@catch: Thanks. I read that page, but IINM that still means every occurrence of $(*) in Drupal core (and modules) must be replaced with either a closure or a new jQuery variable. Which is what the original thread is all about, right? Does the closure approach save some search-and-replace?
Comment #19
Steven CreditAttribution: Steven commentedYou just wrap the entire .js file in:
as has been proposed elsewhere.
Comment #20
infojunkieThat seems to work perfectly, with much less editing indeed. Note that in misc/drupal.js, one has to insert the
after the line
Thanks for a great tip!
Comment #21
kourge CreditAttribution: kourge commentedI wrapped the scoping anonymous function around all JS files in core and rolled this patch. All JS files are wrapped except for jQuery itself (obvious) and jQuery form (it already does the wrapping). This approach should be much cleaner (and saner) than replacing every instance of
$
withjQuery
. I've roughly tested this; the installer, drag-and-drop functionality, and sticky table headers are all working correctly.Comment #22
kourge CreditAttribution: kourge commentedComment #23
dvessel CreditAttribution: dvessel commentedA lot's happened since the patch. Needs a re-roll.
Comment #24
dvessel CreditAttribution: dvessel commentedNot sure this is the exact same. All js files wrapped except jquery.js & jquery.form.js.
Comment #25
dvessel CreditAttribution: dvessel commentedremoved space in
function ($)
.Comment #26
dvessel CreditAttribution: dvessel commentedTime is running short.. Wait for Drupal 7?
Comment #27
kourge CreditAttribution: kourge commentedIt's not like this patch (gasp!) adds new strings, changes the database schema, ports Drupal to Java, or anything big like that. Why are patches like these always so heartbreaking? :(
Comment #28
quicksketchAfter applying #25, I added prototype.js (1.6) to drupal_add_js() so it gets loaded along with jquery.js. The result unfortunately was not optimal. Prototype immediately throws an error when the page loads and drag and drop throws an error on every drop. This patch missed all the places where we have inline javascript added to the page (in book, poll and user) which will no longer be able to use the $ function without wrapping in a special clause. (See http://docs.jquery.com/Using_jQuery_with_Other_Libraries if you haven't).
I updated the patch to fix book, poll, and user, but generally I don't think this can get into Drupal 6. For any module that has already been ported to Drupal 6, it will need to be wrapped in
(function($) { });
to make it compatible with another library. That previously wasn't a requirement since other libraries weren't even pretending to be supported. It's something that would definitely be added to the Upgrading 5.x modules to 6.x page and an API change.Comment #29
quicksketchComment #30
webchickSounds like this represents an API change, which makes it a clear 7.x feature. Sorry, kourge/dvessel. :(
Comment #31
dvessel CreditAttribution: dvessel commentedDoh, forgot about the inline scripts. So 7 it is. No worries from me webchick, thought it was going to be a small enough change.
Comment #32
kourge CreditAttribution: kourge commentedSo does that mean the handbook page on converting 5.x modules to 6.x needs to be updated so that module authors wrap their JavaScript in a scoping function?
Also, I sort of doubt that inline functions need to be wrapped again. I think it may have something to do with the
for...in
loop construct; I'll investigate more on this.Comment #33
starbow CreditAttribution: starbow commentedsubscribing
Comment #34
webchickkourge: No, there's no need to update that document because this patch is an API change and thus won't be applied until 7.x. But it /will/ need to be documented in the updating 6.x to 7.x handbook page. :)
Comment #35
Matt V. CreditAttribution: Matt V. commentedsubscribing
Comment #36
mfer CreditAttribution: mfer commentedsubscribing.
Comment #37
catchhttp://drupal.org/node/170418 was duplicate.
Comment #38
kkaefer CreditAttribution: kkaefer commentedRerolled the patch. We definitely need this in D7. I added a call to
jQuery.noConflict
which removes jQuery from the$
variable. That means that all contrib module JS also has to wrap its code into(function($) { ... })(jQuery);
to continue functioning.Comment #39
kourge CreditAttribution: kourge commentedGood move. This'll be a good enough motivation for maintainers. Breakage is the last thing maintainers want to happen on their modules.
Comment #40
Wim LeersSubscribing.
Comment #41
Wim LeersHierarchical Select is now doing this: http://drupal.org/node/231576#comment-828004.
It's a super easy change, so I think there's no valid reason at all to prevent this patch from going in.
Comment #42
quicksketchI agree, after John Resig chided us a little bit (rightly so) about Drupal's lack of wrapping the Drupal core code in these compatibility wrappers I did feel a little poorly about shooting this down for D6. Anyway, this definitely does need to happen with Drupal 7.
@kkaefer: Is there a good reason for adding this to jquery.js instead of drupal.js?
I agree with the decision to essentially "force" contrib modules to use the wrappers also.
Comment #43
roman25 CreditAttribution: roman25 commentednot sure if this is rellevant to this post, but there is a problem with for and while loops in javascript in the latest version... very easily reproducable,
Comment #44
kkaefer CreditAttribution: kkaefer commentedIt's completely unrelated. If you think you found a valid bug, please post an issue at http://drupal.org/node/add/project_issue/drupal.
Comment #45
lilou CreditAttribution: lilou commentedPatch no longer applied :
Comment #46
mfer CreditAttribution: mfer commentedAt the very least this is because there is a new version of jQuery present in core.
Should Drupal.behaviors be wrapped in ;(function($) { ... })(jQuery);???
Comment #47
kkaefer CreditAttribution: kkaefer commentedUpdated patch; also adds some semicolons where they were missing.
Comment #48
kkaefer CreditAttribution: kkaefer commentedComment #49
mfer CreditAttribution: mfer commentedI'm still wondering if the Drupal.behaviors should be wrapped with ;(function($) { ... })(jQuery);
If we follow the jQuery way of wrapping it looks like Drupal.behaviors would be wrapped with ;(function() { ... })();
Can someone a little more familiar with jQuery clear this up for me?
Comment #50
kkaefer CreditAttribution: kkaefer commentedWhy shouldn't they be wrapped in that new scope? Behaviors can use $ as well.
Comment #51
mfer CreditAttribution: mfer commentedAfter I posted that I started thinking the same thing. I'll test this later this week (most likely Friday)
Comment #52
webchickJust a note to say that I'm hugely in support of this patch. We allow pluggable caching systems, pluggable image handling libraries, and even pluggable *password hashing algorithms*. It's a little silly that we don't allow pluggable JS libraries as well.
Comment #53
Susurrus CreditAttribution: Susurrus commentedIn regards to pluggable libraries #251578: More flexible js/css ordering and an alter operation is another step in that direction having a
JS_LIBRARY_WEIGHT
.Comment #54
mfer CreditAttribution: mfer commentedThe patch no longer applies. Specifically simpletest.js. Can someone re-roll the patch and I'll test it.
Comment #55
dvessel CreditAttribution: dvessel commentedre-rolled
Comment #56
mfer CreditAttribution: mfer commentedApplies cleanly. Tested in FF3 and Safari on mac and found no issues. I'll keep testing more later.
Comment #57
mfer CreditAttribution: mfer commentedTested in FF3, Opera 9.5b, IE6, IE7, and Chrome on PC. Did a brief review of the patch and it looks good. Marking RTBC.
On a side note: Opera is still having trouble with file uploads via the upload module both before and after the patch. This is an ongoing issue.
Comment #58
webchickAwesome. Thanks for your hard work, folks!
This is a big enough change that I feel like I should get Dries's two cents before committing. So in the meantime, if someone wants to write up a blurb that can be copy/pasted into the upgrade docs, that would be lovely. ;)
Comment #59
chx CreditAttribution: chx commentedWe define an anonymous function with a single parameter. This parameter is $. So it's now
function ($) { original JS code}
. Now, we call this function. If it would be assigned to a variable then we would dowhatever(jquery);
so that inside the function,$ = jquery
. But with anonymous functions, we do not have and do not need a name, so we can just write.
Comment #60
mfer CreditAttribution: mfer commentedAny status on this issue? Anything we can do to help it along?
Comment #61
RobLoachOh, this is cool!
Comment #62
webchickActually, could we have someone re-run the same tests as quicksketch did back in #28 and make sure a mootools/prototype script gets added to a page correctly? Seems like that hasn't been done since January, and this patch has changed a few times since then.
Comment #63
webchickOh, and karma points to anyone who does this and posts back with some source code and clear instructions on how to reproduce that it's working for non-JS folks (like me :D).
Comment #64
mfer CreditAttribution: mfer commentedUpdated to follow a moving head.
Comment #65
mfer CreditAttribution: mfer commentedThe attached file is a zip file (remove the .txt extension). It contains a basic module that adds prototype.js to every page.
To test with this enabled the console in firebug for a test site, enable this module, go to a page (like /admin/build/block), and test the JavaScript based functionality. If there is an issue firebug will start through errors. This is a basic way to see if anything is wrong.
Sadly, on /admin/build/block I got errors. This was the first page I tested. This still needs some work.
Comment #66
mfer CreditAttribution: mfer commentedI found part of the issue, I think. According to the jQuery documentation on using noConflict jQuery.noCOnflict() needs to be called after jQuery and the other library have been loaded. If you do a drupal_add_js('/path/to/prototype.js') call jquery.js, drupal.js (containing the noConflict call), and then prototype.js will be loaded. The issue may have to do with ordering.
But, I tried manually reordering the including of the files and still found problems. Another problem is autocomplete when nothing is returned.
Comment #67
mfer CreditAttribution: mfer commentedNow that #315798: JavaScript Patch #2: Weight is in we should have an easier time adding another library and positioning it where we need to make this work. I'm going to revisit this issue after #315801: JavaScript Patch #3: JS Alter Operation gets in.
To quote the jQuery.noConflict() documentation:
When we go to add another Library it can be added with a weight of JS_LIBRARY since jQuery is added with a weight of JS_LIBRARY - 2 and drupal.js, which contains a jQuery.noConflict call (in the patches here) has a weight of JS_LIBRARY - 1.
Comment #68
webchickAwesome. Looking greatly forward to seeing this fixed.
Comment #69
webchickhook_js_alter() is in now. Still looking forward to seeing this fixed. ;)
Comment #70
XanoI like chx's explanation in #59, but I still don't understand the technical part behind this change. I have a fair knowledge of JS (good enough for regular stuff), but there will be lots of people with less knowledge who will understand even less of this than I do. I am hoping somebody can shed some more light on this change at "Converting 6.x modules to 7.x".
Comment #71
Wim Leers@Xano: It's really *that* simple. It's exactly as chx demonstrated. Just "wrap" your code that way and it'll be able to co-exist with any JS library, while you can continue to use the shorthand
$
notation. I've been doing the same in Hierarchical Select for quite some time for example: hierarchical_select.js. It's just the old code, with one line added at the top of the file and one at the end of the file. That simple :)Comment #72
XanoIt's not that I don't know how to use it, it's that I don't get how it works :)
Comment #73
kkaefer CreditAttribution: kkaefer commented@Xano: It wraps the code in a function. That function has a parameter called $, so in that function, $ is what the caller of that function passed into that function. That function is then called right away with jQuery as the first parameter, which subsequently is mapped to $, just inside that function.
Comment #74
kkaefer CreditAttribution: kkaefer commentedRecreated patch (there were too many conflicts due to attach/detach for behaviors). I also added a function to $ that indicates when people use $ without wrapping their code.
Patch also adds semicolons where they are missing.
Comment #75
kkaefer CreditAttribution: kkaefer commentedComment #76
kkaefer CreditAttribution: kkaefer commentedWhen testing, please make sure that you clear your browser cache to prevent old JS files from interfering. If you don't, you might get alert messages telling you to wrap your code.
Comment #77
webchick#62/#63 still applies for testing this patch.
Thanks for the re-roll, kkaefer! I'd really like to see this get in.
Comment #78
XanoThanks a lot :)
Comment #79
quicksketchThis looks absolutely great. I found one more call to $() in an inline function in install.php. I tested (not that it should make a difference):
- Upload and Book (ahah.js and progress.js)
- Install (timezone.js and batch.js)
- Node form (collapse.js, teaser.js, textarea.js)
- Powered by Drupal block (drupal.js)
- Menu page (tabledrag.js and tableheader.js)
As long as I didn't screw up my one change in install.php, this looks RTBC to me.
Comment #80
sunComment #81
chx CreditAttribution: chx commentedLet's go with this.
Comment #82
webchickSo someone tried to add Prototype to their Drupal 7 site? Can someone please explain how I can do this so I can verify that it's working?
Comment #83
XanoYou simply include the prototype JS file and use it just like you would do in any other situation :)
Comment #84
Matt V. CreditAttribution: Matt V. commentedHere's what I did to test the patch...
I downloaded prototype-1.6.0.2.js and added it to the Garland theme, by adding the following line to garland.info:
I cleared the cache and confirmed that prototype-1.6.0.2.js was loading by viewing the source of a page.
I noticed two trouble spots. When I went to node/add/page, the collapsible fieldsets were no longer clickable. Also, on admin/build/block, the draggable cross was gone and the weight fields showed.
I then applied the patch, which applied cleanly. To confirm the fix, I went back to node/add/page; the fieldsets were clickable again. When I went to admin/build/block, the blocks were draggable and the weight fields were hidden again.
I'd be glad to check other issues, if anyone can point me to other trouble spots.
Comment #85
kkaefer CreditAttribution: kkaefer commented@webchick: When I tested the patch, I downloaded the module from #65 and visited all pages I could think of that use JS. All of them worked fine (i.e. they didn't show the alert box, so it's quite obvious when something goes wrong).
Comment #86
webchickExcellent. Thanks, everyone! I'm very happy to announce that this is now fixed! :)
Please update the docs!
Comment #87
XanoDone.
Great job everyone!
Comment #88
quicksketchFantastic! Great job guys!
Comment #89
sunThis patch actually contained some fixes that made me worry about the state of Drupal 6.
Attached patch ports some coding-style niceties and fixes of this patch back to Drupal 6.
Especially (but not only) the last hunk for Drupal.behaviors.copyFieldValue() makes me wonder whether the existing code in D6 shouldn't lead to a syntax error.
Comment #90
sun2nd try. Displayed in preview.
Comment #91
Pasqualle@sun as I see it is not a backport patch, and not related to the original problem. Then why not create a new issue?
Comment #92
webchickI think this was meant to be a reply to a different issue... I remember committing a similar patch a few months back, but I can't seem to find which issue it was. At any rate, restoring original properties.
Comment #94
doompal CreditAttribution: doompal commentedI know it's a long time ago, but was there a rationale for breaking jQuery for the sake of Prototype? What does Prototype do to justify this?
Comment #95
Maedi CreditAttribution: Maedi commentedI would also like to voice my concern over this change.
Drupal should work out of the box when it comes to writing in jQuery (or another library). Most tutorials are written with the '$' function in mind. Currently any mainstream code snippets wont work instantly with Drupal 7.
The accepted wrapper function and 'jQuery()' solutions lead to needlessly convoluted code. I think many beginner to mid-level Drupal developers will stumble upon the "$ is not a function" error caused by this change, and be genuinely confused. The majority of Drupal developers use jQuery and this majority is being given an avoidable error.
If there's someone else out there who feels the same way, then let me know and I'll start a separate issue.
Comment #96
sunPlease open a new issue for discussing that and link to it in here.
In case you didn't notice, this change was committed 3 years ago.
Thanks.
Comment #97
Maedi CreditAttribution: Maedi commentedThanks sun. I've created a new issue here:
#1407256: Wrap inline JS in a self-executing closure
Yeah I'd noticed that this is an old issue though still something I'd like to see changed.
Comment #98
justindodge CreditAttribution: justindodge commentedHey guys, if you still want to use the $ in D7, I've created a contributed module that allows you to do so.
It can be found here:
http://drupal.org/project/jquery_dollar
I know this particular issue is old and dead, but since the "Converting 6.x modules to 7.x" documentation points to this issue, I thought it would be worth mentioning here.