jsfiddle / togetherjs

A service for your website that makes it surprisingly easy to collaborate in real-time.
https://togetherjs.com
Mozilla Public License 2.0
7.01k stars 849 forks source link

Conflict with Prototype.js: TypeError: Object has no method 'match' #851

Open ianb opened 11 years ago

ianb commented 11 years ago

Some older versions of Prototype.js (maybe before 1.6) include an implementation of document.getElementsByClassName. This method doesn't match the standard version, and overwrites the standard version. jQuery sometimes calls that method, and when it does it invokes it differently than Prototype.js expects, leading to an error.

Not sure how we can resolve. The code is deep in both jQuery and kind of deep in prototype.js. We could try to just destroy Prototype.js's version, which may sometimes work (but could also break the app). Or try to detect the problem and patch in a version of the function that works for everyone.

AlanBell commented 11 years ago

if document.getElementsByClassName isn't being used for anything else specific to the prototype.js implementation of it then doing delete document.getElementsByClassName to remove that implementation and return to the browser native function (assuming a modern browser that implements it)

ianb commented 11 years ago

If anyone wants to try to fix this, they'd need to detect that prototype.js is being used and causing this problem, and then figure out a way to implement this prototype.js function (implementation) and the standard function together.

Mostly it seems that if you are calling document.getElementsByClassName(baseElement, className) then you are doing it the prototype.js way, but if typeof baseElement == "string" then it's a call intended for the standard getElementsByClassName function. Getting access to the original requires a silly thing like:

var patched = document.getElementsByClassName;
delete document.getElementsByClassName;
var standard = document.getElementsByClassName;
if (standard && patched && standard !== patched) {
  document.getElementsByClassName = function (element, className) {
    if (typeof element == "string") {
      return standard.call(document, element);
    }
    return patched.apply(document, arguments);
  };
}

But I'd also want a specific prototype.js test in here, as such cruel treatment of a DOM API is only called for when absolutely necessary.

jdalton commented 11 years ago

Old Prototype.js user here ;) The documentation for Prototype's version of document.getElementsByClassName is here. The call signature is document.getElementsByClassName(className[, element]).

Newer versions of Prototype.js don't pave document.getElementsByClassName if it exists, I had to go back to Prototype 1.5 for a version that paves without checking for its existence.

It shouldn't conflict with jQuery's use as Sizzle does a feature test for a working document.getElementsByClassName for their usage scenario though they could enhance it further with an rnative check.

ianb commented 11 years ago

It looks like jQuery 1.10.11 improves the check for getElementsByClassName since 1.8.3 (which we are using). So updating jQuery should probably fix this.

jdalton commented 11 years ago

Also related, Sizzle just updated their edge to use the rnative check for document.getElementsByClassName too :D