Gary Andrew
Gary Andrew

Reputation: 23

My Code works the in Firefox console but not in Tampermonkey? (not a timing issue)

I am trying to write a Tampermonkey userscript that uses a <canvas> to combine pictures into a single image and then auto downloads it.

My script code:

// ==UserScript==
// @name         Picture Download
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  Picture Download
// @author       Oray
// @match        https://www.example.com/*
// @require      https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js
// @grant        unsafeWindow
// ==/UserScript==
(function(){
  function GM_wait(){
    if(typeof unsafeWindow.jQuery == 'undefined'){
      window.setTimeout(GM_wait,100);
    }else{
      unsafeWindow.jQuery(function() { letsJQuery(unsafeWindow.jQuery); });
  }}
  GM_wait();

  function letsJQuery($){
$('html[lang] > body').prepend('<canvas id="cve"></canvas>');
      var img1 = new Image();
      var img2 = new Image();
      var combined = new Image();
      var nloaded = 0;
      var combinedx;
      var filename;
      var e;
      function checkload(event){
        nloaded++;
        if (nloaded < 2){
          return;
        }
        var canvas = document.getElementById('cve');
        var context = canvas.getContext('2d');
        canvas.width = img1.width;
        canvas.height = img1.height + img2.height;
        context.drawImage(img1, 0, 0);
        context.drawImage(img2, img1.width / 2 - img2.width / 2 , img1.height);
        combinedx = canvas.toDataURL('data/gif');
        filename = 'myimage.png';
        var lnk = document.createElement('a');
        lnk.download = filename;
        lnk.href = combinedx;
          e = document.createEvent("MouseEvents");
          e.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false,false, 0, null);
          lnk.dispatchEvent(e);
      }
      img1.onload = checkload;
      img1.crossOrigin = "Anonymous";
      img1.src ="https://images-na.ssl-images-amazon.com/images/I/81pNr82OTgL._SX679_.jpg";
      img2.onload = checkload;
      img2.crossOrigin = "Anonymous";
      img2.src = "https://images-na.ssl-images-amazon.com/images/I/31W%2BDml7GsL.jpg";
  }
})();


...works in the console but doesn't as a Tampermonkey script.

Why?




Editor's note: By the original title, this would be a very common problem due to AJAX timing (example). But this question covers a different, rarer cause with the same base symptom.

Upvotes: 2

Views: 1213

Answers (1)

Brock Adams
Brock Adams

Reputation: 93473

If you check the browser console (Ctrl+Shift+J), you should see errors like:

Uncaught TypeError: Failed to execute 'initMouseEvent' on 'MouseEvent': parameter 4 is not of type 'Window'.

Or:

TypeError: Argument 4 of MouseEvent.initMouseEvent does not implement interface Window.


That's because window has the wrong context inside your userscript in this line:

e.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false,false, 0, null);

If you had used unsafeWindow it would work in the script (but not in the console).

If you use e.initMouseEvent("click", true, true); it will work in both.

BUT, initMouseEvent is deprecated, best to use the MouseEvent() constructor; see the code below.

Also:

  1. That (function(){ has been superfluous clutter for years. Userscripts are wrapped by default and fire after jQuery's ready, by default, on all major script engines.
  2. Likewise, the letsJQuery rigmarole is completely unnecessary.
  3. After calls like canvas = document.getElementById('cve');, you need to make sure the variable is defined before using it. See the code below.


So, here is the working userscript with those adjustments:

// ==UserScript==
// @name        Picture Download
// @match       *://YOUR_SERVER.COM/YOUR_PATH/*
// @require     https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js
// @grant       GM_addStyle
// @grant       GM.getValue
// ==/UserScript==
//- The @grant directives are needed to restore the proper sandbox.
/* global $ */

//$('html[lang] > body').prepend ('<canvas id="cve"></canvas>');
$('html > body').prepend ('<canvas id="cve"></canvas>');
var img1 = new Image ();
var img2 = new Image ();
var combined = new Image ();
var nloaded = 0;
var combinedx;
var filename;
var e;

img1.onload = checkload;
img1.crossOrigin = "Anonymous";
img1.src = "https://images-na.ssl-images-amazon.com/images/I/81pNr82OTgL._SX679_.jpg";
img2.onload = checkload;
img2.crossOrigin = "Anonymous";
img2.src = "https://images-na.ssl-images-amazon.com/images/I/31W%2BDml7GsL.jpg";

function checkload (event) {
    nloaded++;
    if (nloaded < 2) {
        return;
    }
    var canvas = document.getElementById ('cve');
    if (!canvas) {
        console.warn ("No canvas.");
        return;
    }
    var context = canvas.getContext ('2d');
    canvas.width = img1.width;
    canvas.height = img1.height + img2.height;
    context.drawImage (img1, 0, 0);
    context.drawImage (img2, img1.width / 2 - img2.width / 2, img1.height);
    combinedx = canvas.toDataURL ('data/gif');
    filename = 'myimage.png';
    var lnk = document.createElement ('a');
    lnk.download = filename;
    lnk.href = combinedx;

    e = new MouseEvent ("click");
    lnk.dispatchEvent (e);
}

Upvotes: 3

Related Questions