Search code examples
javascriptjqueryuserscriptstampermonkey

unwrap() removes link in jsFiddle test, but not in Tampermonkey script?


I tried remove a link on a div, and it works using unwrap(), see it on jsfiddle

Now, I want implement a userscript to remove the link on a website (example on jsfiddle), but it's not working.

I'm using Tampermonkey. Here's my userscript:

// ==UserScript==
// @name           Remove Link
// @include        http://jsfiddle.net/dv3Fm/2/embedded/result/
// ==/UserScript==

function addJQuery(callback) {
  var script = document.createElement("script");
  script.setAttribute("src", "http://code.jquery.com/jquery-1.9.1.js");
  script.addEventListener('load', function() {
    var script = document.createElement("script");
    script.textContent = "(" + callback.toString() + ")();";
    document.body.appendChild(script);
  }, false);
  document.body.appendChild(script);
}

// the guts of this userscript
function main() {
 $('.spoiler a > .smallfont').unwrap();
}

// load jQuery and execute the main function
addJQuery(main);

Here's the HTML:

<div class="spoiler">
    <!--I want remove link only -->
    <a href="http://www.domain.com" target="_blank">
        <div class="smallfont" id="bbcode_div"/>        
        </div>
    </a>  

</div>

<!--I want result such as : -->
 <div class="spoiler">
        <div class="smallfont" id="bbcode_div"/>        
        </div> 
</div>

What is my userscript doing wrong? How can I remove the link using unwrap jQuery in a userscript?


Solution

  • There are two problems with that script:

    1. It's including the wrong page.
    2. It's injecting jQuery which conflicts with the page's own jQuery.

    (1) jsFiddle loads the payload page in iframes. For a fiddle of:

    http://jsfiddle.net/dv3Fm/2/
    

    The content iframe is (current scheme):

    http://fiddle.jshell.net/dv3Fm/2/show/light/
    

    So, your script must include the iframe for the content it wants to change.


    (2) That target page already has jQuery, so using addJQuery() like that will bust either the page's jQuery or the script's jQuery, depending on the timing.

    As a general rule, never use script injection (create a <script> tag), if you can help it!
    Fortunately, Tampermonkey, and Greasemonkey provide a far-superior option in the form of the @require directive.

    With that (and the @grant directive), your script can avoid all conflicts with the page's script (and can even run, in Greasemonkey, if the page's JS is completely blocked).

    Given all that, your script would become:

    // ==UserScript==
    // @name     Remove Link
    // @include  http://fiddle.jshell.net/dv3Fm/2/show/light/
    // @require  http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js
    // @grant    GM_addStyle
    // ==/UserScript==
    /*- The @grant directive is needed to work around a design change
        introduced in GM 1.0.   It restores the sandbox.
    */
    
    $('.spoiler a > .smallfont').unwrap();
    


    If you want your script to also be able to work in browsers that don't support the @require directive, without losing the advantages in browsers that do, use the second technique shown in this answer.

    But I recommend just sticking with Tampermonkey and Greasemonkey (which are almost completely code compatible).