Troubleshooting (Script Authors): Difference between revisions

From GreaseSpot Wiki
Jump to navigationJump to search
(Update for 4.0)
 
(2 intermediate revisions by 2 users not shown)
Line 1: Line 1:
The article [[Avoid Common Pitfalls in Greasemonkey]] covers some of the most common problems people come across when writing [[user script]]s.
If your problem is not listed, try [[Getting Help]].


If your problem is not listed, please ask on the [[mailing list]].
__TOC__


__TOC__
== Variables change before a GM_xmlhttpRequest or setTimeout callback runs ==
 
Problem example:
 
<pre class='sample-bad'>
for (var i = document.links.length - 1; i >= 0; --i) {
  var link = document.links[i];
 
  GM.xmlHttpRequest({
    method: "GET",
    url: "http://example.com/lookup?url=" + link.href,
    onload: function(result) {
      link.href = result.responseText;
    }
  });
}</pre>


== Changes don't take effect when editing a script ==
The request is asynchronous, meaning the rest of the code doesn't wait for it to complete. The <code>for</code> keeps running as the request loads. When the request for the first link on the page completes and the <code>onload</code> callback function runs, the <code>link</code> variable might point to a different link altogether, typically the last one (since the <code>for</code> loop completes much quicker than the HTTP requests).


You may be editing your original copy of the script, not the installed copy.
One solution is to pass those values that you want unchanged into a function surrounding the request, as arguments. Then they will be in a different scope, and will no longer be changed from the outside.
Once you create and install a script, you need to follow [[FAQ#How_do_I_edit_a_script_I.27m_working_on.3F|these steps]] to make sure you're editing the installed, active copy.


// ==UserScript==
Solution example with named function:
// @name Ask.fm Auto Like by Gabriiel Santos
<pre class='sample-good'>
// @namespace                  http://userscripts.org/scripts/show/999999
function do_it(link_inside) {
// @version 2.0
  GM_xmlhttpRequest({
// @copyright         http://ask.fm/GabriielSantos1
    method: "GET",
// @description         Auto Like Ask.fm
    url: "http://example.com/lookup?url=" + link_inside.href,
// @author (http://userscripts.org/users/476758)
    onload: function(result) {
// @include http://ask.fm/*
      link_inside.href = result.responseText;
// @icon http://s3.amazonaws.com/uso_ss/icon/138450/large.gif?1342345458
    }
// Like Automatico Para Ask.FM
  });
// Version numero 2
// DON'T COPY THIS SOURCE CODE!!! THIS CODE HAVE A COPYRIGHT.
// NO COPIAR este código fuente! El presente Código tienen derechos de autor.
// mentenovinho@live.com
// ==/UserScript==
// ==Profile==
body = document.body;
if(body != null) {
div = document.createElement("div");
div.setAttribute('id','like1');
div.style.position = "fixed";
div.style.display = "block";
div.style.width = "125px";
div.style.opacity= 1.00;
div.style.bottom = "+105px";
div.style.left = "+6px";
div.style.backgroundColor = "#ff00ae";
div.style.border = "1px solid #555";
div.style.padding = "2px";
div.innerHTML = "<div style='background-color: #00a2ff; color: #FFFFFF; border: 1px solid #00a2ff;'><center><a style='color: #000000;' <a href='https://www.facebook.com/Gabriiel Santoos' target='_blank' title='Agregame  para agradecerme :)'> Mi Facebook </a></div>"
div2 = document.createElement("div");
div2.setAttribute('id','spoiler');
div2.style.position = "fixed";
        div2.style.width = "125px";
div2.style.opacity= 0.90;
div2.style.bottom = "+65px";
div2.style.left = "+6px";
div2.style.backgroundColor = "#ff00ae";
div2.style.border = "1px solid #555";
div2.style.padding = "2px";
div2.innerHTML = "<div style='background-color: #00a2ff; color: #FFFFFF; border: 1px solid #00a2ff;'><a style='color: #FFFFFF;' onclick='spoiler()' title='Click Para Ocultar'>&laquo;</a> &#8226; <a href='http://ask.fm/GabriielSantos1' title='Preguntame :)' style='color: #FFFFFF;' onclick='alert(\'Thanks for install this script\');'>Preguntame & Regalame</a></div> "
body.appendChild(div);
body.appendChild(div2);
unsafeWindow.spoiler = function() {
var i;
for(i=1;i<=20;i++) {
var x=document.getElementById('like'+i);
if (x.style.display=="none") {
x.style.display="block";
div2.innerHTML = "<a onclick='spoiler()' title='Mostrar :) Mi Ask JeffFernando'>&laquo;</a> &#8226; <a href='http://ask.fm/GabriielSantos1' title='Gabriiel Santos'>Preguntame!</a>"
}
else {
x.style.display="none";
div2.innerHTML = "<a onclick='spoiler()' title='Click Para Mostrar'> Mostrar Auto Like &raquo;</a>"
}
}
};
}
}
 
for (var i = document.links.length - 1; i >= 0; --i) {
  var link = document.links[i];
  do_it(link);
}
</pre>


// ==============
Solution example with anonymous function:
// ==Like All==
body = document.body;
if(body != null) {
div = document.createElement("div");
div.setAttribute('id','like2');
div.style.position = "fixed";
div.style.display = "block";
div.style.width = "125px";
div.style.opacity= 0.90;
div.style.bottom = "+42px";
div.style.left = "+6px";
div.style.backgroundColor = "#eceff5";
div.style.border = "1px solid #94a3c4";
div.style.padding = "2px";
div.innerHTML = "<img src='https://lh4.googleusercontent.com/-D1HYuLwPnNQ/TxPK6cm_THI/AAAAAAAAAIE/ynATGaxGbv0/s16/Facebook%252520Like%252520Small.jpg' width='16' height='14' align='absmiddle' />&nbsp;&nbsp;<a onclick='OtomatisLike()'>Me Gusta Todo!</a>"
body.appendChild(div);
unsafeWindow.OtomatisLike = function() {
document.getElementsByClassName("submit-button-more")[0].click();
document.getElementsByClassName("like hintable")[0].click();
document.getElementsByClassName("like hintable")[0].click();
document.getElementsByClassName("like hintable")[0].click();
document.getElementsByClassName("like hintable")[0].click();
document.getElementsByClassName("like hintable")[0].click();
document.getElementsByClassName("like hintable")[0].click();
document.getElementsByClassName("like hintable")[0].click();
document.getElementsByClassName("like hintable")[0].click();
document.getElementsByClassName("like hintable")[0].click();
document.getElementsByClassName("like hintable")[0].click();
document.getElementsByClassName("like hintable")[0].click();
document.getElementsByClassName("like hintable")[0].click();
document.getElementsByClassName("like hintable")[0].click();
document.getElementsByClassName("like hintable")[0].click();
document.getElementsByClassName("like hintable")[0].click();
document.getElementsByClassName("like hintable")[0].click();
document.getElementsByClassName("like hintable")[0].click();
document.getElementsByClassName("like hintable")[0].click();
document.getElementsByClassName("like hintable")[0].click();
document.getElementsByClassName("like hintable")[0].click();
document.getElementsByClassName("like hintable")[0].click();
document.getElementsByClassName("like hintable")[0].click();
document.getElementsByClassName("like hintable")[0].click();
document.getElementsByClassName("like hintable")[0].click();
document.getElementsByClassName("like hintable")[0].click();


buttons = document.getElementsByTagName("button");
<pre class='sample-good'>
for(i = 0; i < buttons.length; i++) {
for (var i = document.links.length - 1; i >= 0; --i) {
myClass = buttons[i].getAttribute("class");
  var link = document.links[i];
if(myClass != null && myClass.indexOf("like") >= 0)
 
if(buttons[i].getAttribute("name") == "likern false;")
  (function (link_inside) {
buttons[i].click();
    GM_xmlhttpRequest({
}
      method: "GET",
      url: "http://example.com/lookup?url=" + link_inside.href,
};
      onload: function(result) {
        link_inside.href = result.responseText;
      }
    }); 
  })(link);
}
}
</pre>
Solution example with iteration in the "onload" function. Note that this processes each element one by one.
<pre class='sample-good'>
(function getNext(i) {
  var link = document.links[i];
  GM_xmlhttpRequest({
    method: "GET",
    url: "http://example.com/lookup?url=" + link.href,
    onload: function(result) {
      link.href = result.responseText;
      if (--i >= 0) {
        getNext(i);
      }
    }
  });
})(document.links.length - 1);
</pre>


== Form POST data ==
== Form POST data ==


When using [[GM_xmlhttpRequest]] to POST form data, remember to add the '''Content-Type''' parameter:
When using [[GM.xmlHttpRequest]] to POST form data, remember to add the '''Content-Type''' parameter:


<pre class='sample-good'>
<pre class='sample-good'>
Line 146: Line 95:


== Character set ==
== Character set ==
Various issues can arise when working in the wrong character set. In general, writers are advised to use the standard utf-8 format, which isn't supported in the latest version of Windows Notepad. Other workarounds include using JavaScript to parse characters which would otherwise be invalid in other formats, from integer values.
Various issues can arise when working in the wrong character set. In general, writers are advised to use the standard utf-8 format, which isn't supported in the latest version of Windows Notepad. Other workarounds include using JavaScript to parse characters which would otherwise be invalid in other formats, from integer values.


Line 153: Line 103:
</pre>
</pre>


<!-- 4.0 + files = fail
== Installing from /tmp ==
== Installing from /tmp ==
If you try to install a user script located in the /tmp directory, Greasemonkey will not bring up the install dialog, and the Install button at the top of the page will not do anything.  To solve this, simply move the .user.js file to another directory, such as your home directory.
If you try to install a user script located in the /tmp directory, Greasemonkey will not bring up the install dialog, and the Install button at the top of the page will not do anything.  To solve this, simply move the .user.js file to another directory, such as your home directory.
 
-->
== See Also ==
 
* [http://greaseblog.blogspot.com/2005/12/troubleshooting-064.html Troubleshooting Greasemonkey 0.6.4]

Latest revision as of 16:20, 3 November 2017

If your problem is not listed, try Getting Help.

Variables change before a GM_xmlhttpRequest or setTimeout callback runs

Problem example:

for (var i = document.links.length - 1; i >= 0; --i) {
  var link = document.links[i];
  
  GM.xmlHttpRequest({
    method: "GET",
    url: "http://example.com/lookup?url=" + link.href,
    onload: function(result) {
      link.href = result.responseText;
    }
  });
}

The request is asynchronous, meaning the rest of the code doesn't wait for it to complete. The for keeps running as the request loads. When the request for the first link on the page completes and the onload callback function runs, the link variable might point to a different link altogether, typically the last one (since the for loop completes much quicker than the HTTP requests).

One solution is to pass those values that you want unchanged into a function surrounding the request, as arguments. Then they will be in a different scope, and will no longer be changed from the outside.

Solution example with named function:

function do_it(link_inside) {
  GM_xmlhttpRequest({
    method: "GET",
    url: "http://example.com/lookup?url=" + link_inside.href,
    onload: function(result) {
      link_inside.href = result.responseText;
    }
  });
}
  
for (var i = document.links.length - 1; i >= 0; --i) {
  var link = document.links[i];
  do_it(link);
}

Solution example with anonymous function:

for (var i = document.links.length - 1; i >= 0; --i) {
  var link = document.links[i];
  
  (function (link_inside) {
    GM_xmlhttpRequest({
      method: "GET",
      url: "http://example.com/lookup?url=" + link_inside.href,
      onload: function(result) {
        link_inside.href = result.responseText;
      }
    });  
  })(link);
}

Solution example with iteration in the "onload" function. Note that this processes each element one by one.

(function getNext(i) {
  var link = document.links[i];
  GM_xmlhttpRequest({
    method: "GET",
    url: "http://example.com/lookup?url=" + link.href,
    onload: function(result) {
      link.href = result.responseText;
      if (--i >= 0) {
        getNext(i);
      }
    }
  });
})(document.links.length - 1);

Form POST data

When using GM.xmlHttpRequest to POST form data, remember to add the Content-Type parameter:

GM_xmlhttpRequest({
  method: "POST",
  url: myurl,
  headers: {
    "Content-Type": "application/x-www-form-urlencoded"
  },
  data: mydata,
  onload: function(res) { /* Some code */ }
});

Character set

Various issues can arise when working in the wrong character set. In general, writers are advised to use the standard utf-8 format, which isn't supported in the latest version of Windows Notepad. Other workarounds include using JavaScript to parse characters which would otherwise be invalid in other formats, from integer values.

var values = [72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33];
alert(String.fromCharCode.apply(String, values));