Search code examples
jquerycssbootstrap-modalgreasemonkeytampermonkey

Make bootstrap modal work with another website using greasemonkey/tampermonkey (eg SO)


I'm just trying to add a couple of buttons, which when clicked a bootstrap dialogbox/modal should pop up. Something like this demo: http://jsbin.com/wiruhepere/1/edit?html,css,js,output

However when applying this using greasemonkey/tampermonkey on a real website, let's say stackoverflow: It's not working at all !!

I'm suspecting some script/css conflict maybe but I don't have the knowledge to track that down :<

What I'm looking for is:

  1. Make the modal appear when clicking on the "Delete" button
  2. When clicking on "OK" to confirm, grab/intercept that answer to do some other stuffs...

Please bear in mind I'm a beginner in this, so if soemthing isn't clear enough, feel free to ask :-)

Updated GM code based on wOxxOm comments:

// ==UserScript==
// @name        Bootstrap Test
// @namespace   http://tampermonkey.net/
// @description Why the hell the modal isnt working :<
// @author      Enissay
// @include     http://stackoverflow.com/*
// @include     https://stackoverflow.com/*
// @resource    jqueryJS https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js
// @resource    bootstrapJS https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js
// @resource    buttonCSS https://raw.githubusercontent.com/necolas/css3-github-buttons/master/gh-buttons.css
// @resource    bootstrapCSS https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css
// @resource    githubButtonIconSet https://raw.githubusercontent.com/necolas/css3-github-buttons/master/gh-icons.png
// @grant       GM_addStyle
// @grant       GM_getResourceText
// @grant       GM_getResourceURL
// ==/UserScript==

(function() {
    //--- Inject scripts & css including myCode/Func
    $("head").append("<script>" + GM_getResourceText("jqueryJS") + "</script>");
    $("head").append("<script>" + GM_getResourceText("bootstrapJS") + "</script>");
    $("head").append("<style>" + GM_getResourceText("bootstrapCSS") + "</style>");

    var githubButtonIconSet = GM_getResourceURL ("githubButtonIconSet");
    var buttonCSS = GM_getResourceText("buttonCSS");
    buttonCSS = buttonCSS.replace (/gh-icons\.png/g, githubButtonIconSet);
    $("head").append("<style>" + GM_getResourceText(buttonCSS) + "</style>");

    $("body").append("<script>("+myFunc+")();</script>");
})();

function myFunc () {
(function() {
    'use strict';
    var deleteButtonHtml = `
<div class="button-group">
    <button type="button" class="btn btn-primary btn-lg" data-toggle="modal" data-target="#myModal">
        Launch demo modal
    </button>

    <a href="#" class="button icon edit">Edit</a>
    <a href="#" class="button icon remove danger">Delete</a>
</div>
`;
    var modalHtml = `
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
        <h4 class="modal-title" id="myModalLabel">Modal title</h4>
      </div>
      <div class="modal-body">
        ...
      </div>
      <div class="modal-footer">

        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
        <button type="button" class="btn btn-primary">Save changes</button>
      </div>
    </div>
  </div>
</div>
`;

    //--- Add nodes to page
    $("body").prepend(deleteButtonHtml);
    $("body").prepend(modalHtml);

    //--- Attach event to button
    $(".button-group").find(".remove").click(function(evt){
        //debugger;
        $('#myModal').modal({
            keyboard: true
        });
    });
})();
}

Initial GM code bellow:

// ==UserScript==
// @name        Bootstrap Test
// @namespace   http://tampermonkey.net/
// @description Why the hell the modal isnt working :<
// @author      Enissay
// @include     http://stackoverflow.com/*
// @require     https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js
// @require     https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js
// @resource    buttonCSS https://raw.githubusercontent.com/necolas/css3-github-buttons/master/gh-buttons.css
// @resource    bootstrapCSS https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css
// @resource    githubButtonIconSet https://raw.githubusercontent.com/necolas/css3-github-buttons/master/gh-icons.png
// @grant       GM_addStyle
// @grant       GM_getResourceText
// @grant       GM_getResourceURL
// ==/UserScript==

(function() {
    'use strict';

    var deleteButtonHtml = `
<div class="button-group">
    <button type="button" class="btn btn-primary btn-lg" data-toggle="modal" data-target="#myModal">
        Launch demo modal
    </button>

    <a href="#" class="button icon edit">Edit</a>
    <a href="#" class="button icon remove danger">Delete</a>
</div>
`;
    var modalHtml = `
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
        <h4 class="modal-title" id="myModalLabel">Modal title</h4>
      </div>
      <div class="modal-body">
        ...
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
        <button type="button" class="btn btn-primary">Save changes</button>
      </div>
    </div>
  </div>
</div>
`;
    //--- Add nodes to page
    $("body").prepend(deleteButtonHtml);
    $("body").prepend(modalHtml);

    //--- Attach event to button
    $(".button-group").find(".remove").click(function(evt){
        $('#myModal').modal({
            keyboard: false
        });
    });


    //--- Style our newly added elements using CSS.
    GM_addStyle (GM_getResourceText ("bootstrapCSS"));
    var githubButtonIconSet = GM_getResourceURL ("githubButtonIconSet");
    var buttonCSS = GM_getResourceText("buttonCSS");
    buttonCSS = buttonCSS.replace (/gh-icons\.png/g, githubButtonIconSet);
    GM_addStyle(buttonCSS);
})();

Solution

  • There's so many things wrong with the script, let me list them:

    • Manually appending javascript to DOM - for requiring other javascript resources, use @require such as:

      // @require     https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js
      
    • Mistaking string and a variable - bellow, you're using getResourceText but giving it a CSS string, not resource name:

      var buttonCSS = GM_getResourceText("buttonCSS");
      buttonCSS = buttonCSS.replace (/gh-icons\.png/g, githubButtonIconSet);
      // Button CSS does not contain name of resource, but actual CSS
      $("head").append("<style>" + GM_getResourceText(buttonCSS) + "</style>");
      
    • Unnecesary closures - this doesn't cause any errors, but why would you wrap whole function body in self invoking closure? This is crazy:

      // WARNING: Crazy code, do not use!
      function myFunc() {
          (function() {
      
          })()
      }
      
    • Executing function by appending it to HTML - while not exactly an error in general, people just normally do this to call myFunction:

      // Call my function
      myFunction();
      

      Not sure why did you do this instead:

      $("body").append("<script>("+myFunction+")();</script>");
      

      This also cannot work, because greasemonkey variable scope is hidden from global scope. So it is impossible to call myFunction from HTML. This means in your case it just cannot work.

    I fixed most of the problems for you, but you still need to figure out how to resolve CSS conflicts for the dialog on stackoverflow, that problem is out of scope of answer to your question.

    The script below works on http://blank.org:

    // ==UserScript==
    // @name        Bootstrap Test
    // @namespace   http://tampermonkey.net/
    // @description Why the hell the modal isnt working :<
    // @author      Enissay, Tomas Zato (http://stackoverflow.com/users/607407/tom%c3%a1%c5%a1-zato)
    // @include     /https?:\/\/stackoverflow\.com\/*/
    // @include     http://blank.org/*
    // @require     https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js
    // @require     https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js
    // @resource    buttonCSS https://raw.githubusercontent.com/necolas/css3-github-buttons/master/gh-buttons.css
    // @resource    bootstrapCSS https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css
    // @resource    githubButtonIconSet https://raw.githubusercontent.com/necolas/css3-github-buttons/master/gh-icons.png
    // @grant       GM_addStyle
    // @grant       GM_getResourceText
    // @grant       GM_getResourceURL
    // ==/UserScript==
    console.log("Start");
    
    document.head.appendChild(cssElement(GM_getResourceURL ("githubButtonIconSet")));
    document.head.appendChild(cssElement(GM_getResourceURL ("buttonCSS")));
    document.head.appendChild(cssElement(GM_getResourceURL ("bootstrapCSS")));
    
    function cssElement(url) {
      var link = document.createElement("link");
      link.href = url;
      link.rel="stylesheet";
      link.type="text/css";
      return link;
    }
    
    function myFunc () {
        'use strict';
        var deleteButtonHtml = `
    <div class="button-group">
        <button type="button" class="btn btn-primary btn-lg" data-toggle="modal" data-target="#myModal">
            Launch demo modal
        </button>
    
        <a href="#" class="button icon edit">Edit</a>
        <a href="#" class="button icon remove danger">Delete</a>
    </div>
    `;
        var modalHtml = `
    <!-- Modal -->
    <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
      <div class="modal-dialog" role="document">
        <div class="modal-content">
          <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
            <h4 class="modal-title" id="myModalLabel">Modal title</h4>
          </div>
          <div class="modal-body">
            ...
          </div>
          <div class="modal-footer">
    
            <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
            <button type="button" class="btn btn-primary">Save changes</button>
          </div>
        </div>
      </div>
    </div>
    `;
    
        //--- Add nodes to page
        $("body").prepend(deleteButtonHtml);
        $("body").prepend(modalHtml);
        //--- Attach event to button
        // NOT NECESSARY, bootsrap creates event listeners automatically
        /*$(".button-group").find("button").click(function(evt){
            console.log("Click.", $('#myModal'));
            $('#myModal').modal("show");
        });   */
    }
    myFunc();