Content Scope Runner: Difference between revisions

From GreaseSpot Wiki
Jump to navigationJump to search
m (Reverted edits by Tobu (Talk) to last revision by Phyzome)
(restore the original version, with comments, fixed, and the example @require line to it)
Line 1: Line 1:
An extension of the [[Content Script Injection]] technique, this snippet automatically runs the ''entire'' user script in the content scope.
An extension of the [[Content Script Injection]] technique, this snippet automatically runs the ''entire'' user script in the content scope.


<pre class="sample">if(typeof __PAGE_SCOPE_RUN__ == 'undefined') {
<pre class="sample">if ('undefined' == typeof __PAGE_SCOPE_RUN__) {
  (function page_scope_runner() {
  (function page_scope_runner() {
      var script = document.createElement('script');
    // If we're _not_ already running in the page, grab the full source
      script.setAttribute("type", "application/javascript");
    // of this script.
      script.textContent = "(function() { var __PAGE_SCOPE_RUN__ = 'yes'; (" + page_scope_runner.caller.toString() + ")(); })();";
    var my_src = "(" + page_scope_runner.caller.toString() + ")();";
      document.documentElement.appendChild(script);
 
      document.documentElement.removeChild(script);
    // Create a script node holding this script, plus a marker that lets us
  })();
    // know we are running in the page scope (not the Greasemonkey sandbox).
  return;
    // Note that we are intentionally *not* scope-wrapping here.
    var script = document.createElement('script');
    script.setAttribute("type", "application/javascript");
    script.setAttribute("src",
        "data:,"+escape("const __PAGE_SCOPE_RUN__ = true;\n" + my_src));
 
    // Insert the script node into the page, so it will run, and immediately
    // remove it to clean up. Use setTimeout to force execution "outside" of
    // the user script scope completely.
    setTimeout(function() {
          document.body.appendChild(script);
          document.body.removeChild(script);
        }, 0);
  })();
 
  // Stop running, because we know Greasemonkey actually runs us in
  // an anonymous wrapper.
  return;
}</pre>
}</pre>


Line 17: Line 34:


* This code must not be wrapped in a function, or the <code>return</code> will fail to work. It may be wrapped in a conditional.
* This code must not be wrapped in a function, or the <code>return</code> will fail to work. It may be wrapped in a conditional.
* Any code before the block will be run twice: Once in GreaseMonkey context, once in page context.
* Any code before (and including) this block will be run twice: Once in GreaseMonkey context, once in page context.
* Any code after the block will only be run once, in the page context.
* Any code after this block will only be run once, in the page context.


== Explanation ==
== Explanation ==


The code block first checks to see if it is being run inside the page by looking for a marker it knows about. If the marker is not present, the block creates and injects a script element that starts by setting the aforementioned marker variable and finishes by executing the text of the userscript. Finally, the block calls <code>return</code>, ending execution.
The code block first checks to see if it is being run inside the page by looking for a marker it knows about.
If the marker is not present, the block creates and injects a script element that starts by setting the aforementioned marker variable and finishes by executing the text of the user script.
Finally, the block calls <code>return</code>, ending execution.


<!-- This still needs work.
== @require ==
== @require ==


If used as the first [[Metadata Block#.40require|@require]]d script, this snippet will continue to run and work perfectly.
Since it must run before the rest of the script, this snipped functions best as the first [[Metadata Block#.40require|@require]].
Try it by adding this line as the first @require in the [[Metadata Block]]:
Try it by adding this line as the first @require in the [[Metadata Block]]:


  <nowiki>// @require http://userscripts.org/scripts/source/68059.user.js</nowiki>
  <nowiki>// @require http://userscripts.org/scripts/source/68059.user.js</nowiki>
-->


[[Category:Coding Tips:Interacting With The Page]]
[[Category:Coding Tips:Interacting With The Page]]
[[Category:@require Library]]
[[Category:@require Library]]

Revision as of 16:10, 8 August 2010

An extension of the Content Script Injection technique, this snippet automatically runs the entire user script in the content scope.

if ('undefined' == typeof __PAGE_SCOPE_RUN__) {
  (function page_scope_runner() {
    // If we're _not_ already running in the page, grab the full source
    // of this script.
    var my_src = "(" + page_scope_runner.caller.toString() + ")();";

    // Create a script node holding this script, plus a marker that lets us
    // know we are running in the page scope (not the Greasemonkey sandbox).
    // Note that we are intentionally *not* scope-wrapping here.
    var script = document.createElement('script');
    script.setAttribute("type", "application/javascript");
    script.setAttribute("src",
        "data:,"+escape("const __PAGE_SCOPE_RUN__ = true;\n" + my_src));

    // Insert the script node into the page, so it will run, and immediately
    // remove it to clean up.  Use setTimeout to force execution "outside" of
    // the user script scope completely.
    setTimeout(function() {
          document.body.appendChild(script);
          document.body.removeChild(script);
        }, 0);
  })();

  // Stop running, because we know Greasemonkey actually runs us in
  // an anonymous wrapper.
  return;
}

As soon as execution reaches this code, the entire script will be injected into the page and re-run. Thus you need not worry about any of the security restrictions from XPCNativeWrappers in the Greasemonkey sandbox. You also will, of course, not have access to any of the APIs.

Tips

  • This code must not be wrapped in a function, or the return will fail to work. It may be wrapped in a conditional.
  • Any code before (and including) this block will be run twice: Once in GreaseMonkey context, once in page context.
  • Any code after this block will only be run once, in the page context.

Explanation

The code block first checks to see if it is being run inside the page by looking for a marker it knows about. If the marker is not present, the block creates and injects a script element that starts by setting the aforementioned marker variable and finishes by executing the text of the user script. Finally, the block calls return, ending execution.

@require

Since it must run before the rest of the script, this snipped functions best as the first @require. Try it by adding this line as the first @require in the Metadata Block:

// @require http://userscripts.org/scripts/source/68059.user.js