Javascript: Allow compatibility with other libraries.

victorkane - March 5, 2007 - 21:21
Project:Drupal
Version:7.x-dev
Component:javascript
Category:feature request
Priority:normal
Assigned:Unassigned
Status:patch (code needs review)
Description

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

#1

xhochy - March 18, 2007 - 18:15

I 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.

AttachmentSize
prototype.js_.txt69.74 KB

#2

John Resig - March 18, 2007 - 20:14

There'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.

#3

victorkane - March 26, 2007 - 15:17

Excellent 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.

#4

xhochy - April 5, 2007 - 07:50

I 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.

#5

xhochy - April 5, 2007 - 08:09

I 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.

#6

xhochy - April 5, 2007 - 08:28

Ok 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.

AttachmentSize
jquery_15.patch25.04 KB

#7

xhochy - April 5, 2007 - 08:31

Because only one file per comment can be uploaded here's the ruby script.

AttachmentSize
replace_dollar_function.rb_.txt131 bytes

#8

pwolanin - April 15, 2007 - 22:06

can you post the patch as a unified diff?

#9

xhochy - April 16, 2007 - 15:06

The "jquery_15.patch" should be an unified patch, or do you want the patch for prototype?

#10

pwolanin - April 16, 2007 - 15:55

Perhaps 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

#11

xhochy - April 17, 2007 - 19:45

ok, I made a new after the Drupal instructions, here is it.

AttachmentSize
jquery_16.patch44.95 KB

#12

psychopath_mind - April 24, 2007 - 05:47
Status:active» active (needs more info)

And 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!

#13

chx - November 27, 2007 - 12:18
Project:jQuery» Drupal
Version:» 6.x-dev
Component:Code» javascript
Status:active (needs more info)» patch (code needs work)

#14

alienbrain - November 27, 2007 - 14:26
Title:override $() in Drupal's invocation of jQuery in order to allow compatibility with prototype» Javascript: Allow compatibility with other libraries.
Status:patch (code needs work)» patch (code needs review)

Patch updated for HEAD.

AttachmentSize
jquery_noconflict.patch102.14 KB

#15

Steven - November 29, 2007 - 03:50

Rather 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.

#16

kratib - November 30, 2007 - 17:28

@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.

#17

catch - December 1, 2007 - 12:03
Status:patch (code needs review)» patch (code needs work)

Marking as needs work per #15.

kratib: http://docs.jquery.com/Using_jQuery_with_Other_Libraries

#18

kratib - December 1, 2007 - 12:31

@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?

#19

Steven - December 2, 2007 - 01:01

You just wrap the entire .js file in:

(function ($) {
...
})(jQuery);

as has been proposed elsewhere.

#20

kratib - December 2, 2007 - 22:02

That seems to work perfectly, with much less editing indeed. Note that in misc/drupal.js, one has to insert the

(function ($) {

after the line
var Drupal = Drupal || {};

Thanks for a great tip!

#21

kourge - January 29, 2008 - 06:47

I 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 $ with jQuery. I've roughly tested this; the installer, drag-and-drop functionality, and sticky table headers are all working correctly.

AttachmentSize
js.patch13.9 KB

#22

kourge - January 29, 2008 - 06:54
Status:patch (code needs work)» patch (code needs review)

#23

dvessel - January 29, 2008 - 21:31
Status:patch (code needs review)» patch (code needs work)

A lot's happened since the patch. Needs a re-roll.

#24

dvessel - January 29, 2008 - 21:54
Status:patch (code needs work)» patch (code needs review)

Not sure this is the exact same. All js files wrapped except jquery.js & jquery.form.js.

AttachmentSize
jquery_compatible.patch13.3 KB

#25

dvessel - January 29, 2008 - 22:06

removed space in function ($).

AttachmentSize
jquery_compatible_b.patch13.28 KB

#26

dvessel - January 30, 2008 - 23:44

Time is running short.. Wait for Drupal 7?

#27

kourge - January 31, 2008 - 03:54

It'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? :(

#28

quicksketch - January 31, 2008 - 06:16

After 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.

AttachmentSize
jquery_compatible_patch.patch14.14 KB

#29

quicksketch - January 31, 2008 - 06:17
Status:patch (code needs review)» patch (code needs work)

#30

webchick - January 31, 2008 - 06:20
Version:6.x-dev» 7.x-dev

Sounds like this represents an API change, which makes it a clear 7.x feature. Sorry, kourge/dvessel. :(

#31

dvessel - January 31, 2008 - 18:04

Doh, forgot about the inline scripts. So 7 it is. No worries from me webchick, thought it was going to be a small enough change.

#32

kourge - February 1, 2008 - 00:38

So 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.

#33

starbow - February 1, 2008 - 20:42

subscribing

#34

webchick - February 1, 2008 - 21:10

kourge: 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. :)

#35

Matt V. - February 2, 2008 - 07:11

subscribing

#36

mfer - February 13, 2008 - 18:04

subscribing.

#37

catch - February 14, 2008 - 10:05

#38

kkaefer - March 7, 2008 - 19:34
Status:patch (code needs work)» patch (code needs review)

Rerolled 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.

AttachmentSize
jquery-compatibility.patch73.65 KB

#39

kourge - March 8, 2008 - 02:51

Good move. This'll be a good enough motivation for maintainers. Breakage is the last thing maintainers want to happen on their modules.

#40

Wim Leers - March 8, 2008 - 11:01

Subscribing.

#41

Wim Leers - May 1, 2008 - 12:15

Hierarchical 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.

#42

quicksketch - May 1, 2008 - 15:02

I 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?

+// Allow other JavaScript libraries to use $.
+jQuery.noConflict();

I agree with the decision to essentially "force" contrib modules to use the wrappers also.

#43

roman25 - July 22, 2008 - 02:55

not 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,

#44

kkaefer - July 22, 2008 - 08:13

It's completely unrelated. If you think you found a valid bug, please post an issue at http://drupal.org/node/add/project_issue/drupal.

 
 

Drupal is a registered trademark of Dries Buytaert.