Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #11423 (new enhancement)

Opened 1 year ago

Last modified 1 year ago

[PATCH][TEST] Prototype.exec() (Equiv to jQuery.globalEval())

Reported by: jdalton Assigned to: tobie
Priority: normal Milestone: 2.x
Component: Prototype Version: edge
Severity: normal Keywords:
Cc: Tobie

Description

Prototype has lacked the ability to properly execute code in the global space.
The use of eval has its limitations.

  • Its scope is assigned from the closure it was called.
  • Its not executed synchronously in Safari
  • It doesn't handle CDATA comments or legacy <!-- comments correctly
  • It angers the eval() trolls, seriously they can be sooo mean!

To avoid this use Prototype.exec(code);

  • The code accepts a string or any object with a toString() method.
  • It doesn't use eval()
  • It doesn't require a browser sniff.
  • It works with CDATA comments and legacy <!-- comments
  • It takes a broadsword to eval() trolls
  • 1 ups the jQuery implimentation by fixing a bug in firefox 2.0.0.2 on Mac

Attachments

exec_test_patch.diff (1.0 kB) - added by jdalton on 03/25/08 18:20:47.
unit tests
exec_patch.diff (1.6 kB) - added by jdalton on 03/29/08 08:34:53.
addition of the exec() method to Prototype object
exe_closure_love_patch.diff (1.3 kB) - added by jdalton on 04/04/08 20:29:55.
Better: Optimizes Prototype.exec() by using a closure and clone node.

Change History

03/25/08 18:20:47 changed by jdalton

  • attachment exec_test_patch.diff added.

unit tests

03/25/08 19:03:00 changed by Tobie

I don't buy the argument about not using eval to avoid trolls.

03/25/08 19:06:18 changed by jdalton

Also Prototype.exec() is synchronous in Safari :)

03/25/08 19:10:35 changed by jdalton

If used within the ajax methods it will close several trac tickets.

03/25/08 20:08:50 changed by kangax

How about some closure love to speed things up?

exec: (function() {
  var head = $$('head').first() || $(document.documentElement),
      script = new Element('script', { type:'text/javascript'}),
      scriptId = '__prototype_exec_script';
  
  return function(code) {
    if ((code += '').blank()) return;
    if (document.body) {
      try {
         //appendChild(), not insert(), must be used to trigger error
         script.appendChild( document.createTextNode(code) );
      } catch (e) { script.text = code }
      head.insert(script);
    }
    else {
      //firefox 2.0.0.2/camino 1.0.4 don't execute inserted scripts synchronously when dom not loaded
      document.write('<script id="'+ scriptId +'" type="text/javascript">'+ code +'<\/script>');
      script = $(scriptId);
    }
    script.remove();
    script.text = '';
  }
})()

03/25/08 23:42:13 changed by staaky

You can avoid calling $$('head') upfront, same goes for creating the script node and string when needed. I like the idea +1

exec: function(code) {
  if ((code += '').blank()) return;
  var script;

  if (document.body) {
    script = new Element('script', { type:'text/javascript' });
    try {
      script.appendChild(document.createTextNode(code));
    } catch (e) { script.text = code; }
    ($$('head').first() || $(document.documentElement)).insert(script);
  }
  else {
    var scriptId = '__prototype_exec_script';
    document.write('<script id="'+ scriptId +'" type="text/javascript">'+ code +'<\/script>');
    script = $(scriptId);
  }
  script.remove();
  script.text = '';
},

03/26/08 00:06:09 changed by staaky

Oh wait, I didn't notice the love, that's just fine.

03/27/08 19:33:43 changed by jdalton

We need to ensure some kind of error feedback as the tests here show: http://dev.rubyonrails.org/ticket/9685

03/29/08 08:34:53 changed by jdalton

  • attachment exec_patch.diff added.

addition of the exec() method to Prototype object

03/29/08 08:36:04 changed by jdalton

  • cc set to Tobie.

now with 100% less document.body :)

04/04/08 20:29:55 changed by jdalton

  • attachment exe_closure_love_patch.diff added.

Better: Optimizes Prototype.exec() by using a closure and clone node.

04/05/08 20:35:48 changed by jdalton

Use Prototype.exec() in combo with this patch: #11453

04/14/08 02:32:59 changed by jdalton

Also fixes #8112, #8595