Tuesday, January 12, 2016

Running Javascript in Firefox and Google Chrome

Suppose I want to run the printHelloWorldError function from this code in Firefox or Google Chrome. There are several ways to do it.

This code will add a div tag to the body tag of the page with the message 'Hello World'.

var err=function(e){
  var s=e.description;
  if(!s){
    s=String(e);
  }
  var d=DocumentFunction().createElement("div");
  d.id="print_err";
  d.innerHTML=s;
  d.style.color="red";
  DocumentFunction().body.appendChild(d);
};
var DocumentFunction;
var printHelloWorldError=function(){
  DocumentFunction = function() {
    return document;
  };
  err('HelloWorld');
};

Option 1 - From Firefox/Google Chrome Console

Edit the code above to add a line with this at the end: 'printHelloWorldError();' (don't include the single quotes).  Right click any page, Inspect (the element), Find the Console.  Paste the modified code in the console and hit Enter.  You should see the words 'Hello World' at the bottom of the page.

Option 2 - From the Firefox/Google Chrome Browser

Edit the code above to add a line with this at the beginning: 'javascript:' and this at the end 'printHelloWorldError();'.  Add it to Notepadd++.  Highlight the code and either drag it onto the Firefox address bar or right above the Google Chrome tab.

Option 3 - From the Firefox/Google Chrome Bookmark

If you drag and drop the edited code (with 'javascript:' at the beginning and 'printHelloWorldError();' at the end) into the Firefox address bar from Notepad++, it will reformat the Notepadd++ code into a single line like this:

javascript:var err=function(e){  var s=e.description;  if(!s){    s=String(e);  }  var d=DocumentFunction().createElement("div");  d.id="print_err";  d.innerHTML=s;  d.style.color="red";  DocumentFunction().body.appendChild(d);};var DocumentFunction;var printHelloWorldError=function(){  DocumentFunction = function() {    return document;  };  err('Hello World');};printHelloWorldError();

You can right click the Firefox Brower, show the Bookmark Toolbar, create a New Bookmark with the name 'Print Error' and for the location enter the above code.  Then, anytime you hit this bookmark, the code will execute.

In Google Chrome, Add a new bookmark by using 'Bookmark this page' from the hamburger menu.  Then, edit the bookmark and change the url to the code above (condensed one liner code with javascript: to indicate to run javascript code and printHelloWorldError(); to actually call the function).

Option 4a - From a Right Click Menu added through a Firefox Extension

Create an install.rdf file.

For other options like hompageURL, optionsURL, aboutURL, iconURL (ie em:iconURL="chrome://mypackage/content/myicon.png") which use the chrome.manifest file, see developer.mozilla.org

<?xml version="1.0"?>
<RDF:RDF xmlns:em="http://www.mozilla.org/2004/em-rdf#"
         xmlns:NC="http://home.netscape.com/NC-rdf#"
         xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#">

  <RDF:Description RDF:about="urn:mozilla:install-manifest"
                   em:id="scottizu@gmail.com"
                   em:version="0.1"
                   em:name="Print Error"
                   em:unpack="true"
                   em:description="Prints an error on the page."
                   em:creator="scottizu">
    <em:targetApplication RDF:resource="rdf:#$RI.6J3"/>
  </RDF:Description>
    <RDF:Description RDF:about="rdf:#$RI.6J3"
                   em:id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}"
                   em:minVersion="1.5"
                   em:maxVersion="*.*" />
</RDF:RDF>


Note: The ID needs to either be an e-mail address or a GUID.  See link above for more details.

Create a chrome.manifest file.

content mypackage mycontent/ contentaccessible=yes
overlay chrome://browser/content/browser.xul chrome://mypackage/content/rightClickMenuForFirefox.xul

Create a folder called mycontent.  In it, create a file called rightClickMenuForFirefox.xul

<?xml version="1.0"?>
<overlay id="myoverlay"
    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
  
    <script type="application/x-javascript" src="chrome://mypackage/content/printError.js"/>
    
    // This is for the right click menu.
    <popup id="contentAreaContextMenu">
        <menuitem id="printError" label="Print Error" insertafter="context-stop" oncommand="printHelloWorldErrorForRightClick();"/>
    </popup>
</overlay>


Modify the printError.js file to add a method printHelloWorldErrorForRightClick.  The challenge in the right click menu for Firefox and Chrome is getting access to the document for the page.  This is why there is a function named DocumentFunction whose job is to return the document for the page.  This way, we can see the change on the web page we are looking at.


var err=function(e){
  var s=e.description;
  if(!s){
    s=String(e);
  }
  var d=DocumentFunction().createElement("div");
  d.id="print_err";
  d.innerHTML=s;
  d.style.color="red";
  DocumentFunction().body.appendChild(d);
};
var DocumentFunction;
var printHelloWorldError=function(){
  DocumentFunction = function() {
    return document;
  };
  err('Hello World');
};
var printHelloWorldErrorForRightClick=function(){
  DocumentFunction = function() {
    return gContextMenu.target.ownerDocument;
  };
  err('Hello World (RC)');
};

Here is the file structure.

- install.rdf
- chrome.manifest
- mycontent
   - rightClickMenuForFirefox.xul
   - printError.js

Highlight, install.rdf, chrome.manifest, mycontent, right click, send to, Compressed (zipped) folder.  Rename the new file as RightClickMenuForFirefox.xpi.  Go to Firefox 'about:config', 'I'll be careful, I promise', search for xpinstall.signatures.required, set to false so the new extension won't need signing.  Go to Firefox address bar and type 'about:addons', click Extensions and drag the file RightClickMenuForFirefox.xpi on this page.  Firefox will install this unsigned Extension, restart.  From there, you should be able to right click any page and select 'Print Error'.

There are many other things that you can do with the Firefox Extension such as adding an icon, adding a skin, etc.

You can also configure menus as well as menu items.  Just add something like this with appropriate closing menu and menupopup closing tags.

 <menu id="mymenu" label="Error Menu" insertafter="context-stop">            
            <menupopup>
                                   
                    <menu id="Error Sub Menu" label="Print Error Menu">
                        <menupopup>
                            <menuitem id="printError1" label="Print Error 1" oncommand="printHelloWorldErrorForRightClick();"/>
                            <menuitem id="printError2" label="Print Error 2" oncommand="printHelloWorldErrorForRightClick2();"/>

Option 4b - From a Right Click Menu added through a Google Chrome Extension

In the mycontent folder, create a file called manifest.json

Note: I debated whether to store this in the same directory as install.rdf, but the Chrome packager uses a folder, which in this case will be mycontent, so that the .crx file created will be at the same level as install.rdf.  This is unfortunate and the only difference is that the scripts value would be mycontent/rightClickMenuForGoogleChrome.js instead of rightClickMenuForGoogleChrome.js and execute script command would have to have mycontent/printError.js instead of printError.js if the manifest.json was up one level.

{
  "manifest_version": 2,
  "name""Print Error",
  "description""Prints an error on the page.",
  "version""0.1",
  "minimum_chrome_version""38",
  "permissions": [
    "contextMenus"
    "tabs",
    "http://*/*", 
    "https://*/*" ],

  "background": {
    "scripts": [
      "rightClickMenuForGoogleChrome.js"
    ]
  }
}


Create a file rightClickMenuForGoogleChrome.js

printErrorMenu = function(info, tab){
  chrome.tabs.executeScript(tab.id, {file:"printError.js"}, function() {
    chrome.tabs.executeScript(tab.id, {code:"printHelloWorldError();"});
  });
};

chrome.contextMenus.create({
  id: 'printError',
  title: "Print Error",
  contexts:["all"],
  onclick: printErrorMenu
});

Here is the file structure.
- mycontent
   - rightClickMenuForGoogleChrome.js
   - printError.js
   - manifest.json

Go to Google Chrome, in address bar type 'chrome://extensions', select Developer mode, Load unpacked extension, select the mycontent folder.

You can also package with the Pack extension (Developer mode must be checked).  Browse to mycontent folder as extension root directory (leave private key field empty).  This will create a .crx file and .pem file.  The .pem file is a private key file but is not needed if the field was left empty.  Later, you can drag and drop this .crx file directly onto the 'chrome://extensions' page.

You can also add other menu options to run more code.  Just make sure the appropriate onclick methods are defined.

chrome.contextMenus.create({
  id: 'parentMenu',
  title: "Error Menu",
  contexts:["all"]
});
chrome.contextMenus.create({
  id: 'printError1',
  parentId: 'parentMenu',
  title: "Print Error 1",
  contexts:["all"],
  onclick: printErrorMenu
});
chrome.contextMenus.create({
  id: 'printError2',
  parentId: 'parentMenu',
  title: "Print Error 2",
  contexts:["all"],
  onclick: printErrorMenu2
});

No comments:

Post a Comment