Creating Google Chrome Extensions – II

Here we are again, let’s continue from where I get stuck on my previous post. I have started creating a google chrome extension, and I was stuck, because the Javascript code being executed on a separated context.

Once I realized which was the problem I started googling around, until I found a script able to execute a given javascript code in page’s context.

Basically, the works by injecting the given javascript code in dom’s page, at the document head section:

<script type="text/javascript">Your code</script></head>

This way it gets executed in the page’s context, instead of the extension’s one. You just have to call injectScript, passing the code to be executed as parameter, and optionally you can even send function arguments, if the given code is a function.

At the begining, I had some problems, because as I said previously, my extension was being injected at the “document_start”. That means, even before the head tag is defined. This was causing a javascript error (undefined head), but I really needed to put the script at the begining, in order to save a copy of window.console object before it was overriden by Magento.

After some attempts, I was able to inject it as soon as the head is defined, just by creating a timer interval, and prepending some lines at the begining of voodooattack’s function. This is how it looks like (I’ll put just the new lines of the injectScript function for the shake of simplicity):

//Wait 1 milisecond because the document's head might be not defined yet, so we cannot append our script
var theDeveloperWorldIsYours = setInterval(function(){ injectScript(restoreConsole)}, 1);
function injectScript(source){
    //Cannot execute this script until head has been defined
    if (document.head === null) {
        return;
    } else {
        clearInterval(theDeveloperWorldIsYours);
    }
...
}

The function execution is prevented until the document.head is defined, where I firstly remove the timer, and that’s it.

After this modifications, I got a quick and dirty solution:

//Function that stores the window.console in a variable to restore if after magento script has remove id
var restoreConsole = function(){
        //Function that checks if console.log has been removed and restores it
        var checkRestore = function(){
                //Once magento removes the console, this method is defined, so he have to restore the old console
                if (typeof window.console.log.argumentNames != 'undefined') {
                        window.console = __consola;
                        if (__retry-- == 0) {
                                console.log("Console restored by TheDeveloperWorldIsYours!");
                                clearInterval(a);
                        }
                }
        }
        __retry = 10;   //Retry several times, as magento is removing console on a loop, and it might take some time
        __consola = window.console;
        a = setInterval(checkRestore, 1);
        //After 1 second, clearInterval
        setTimeout(function(){clearInterval(a);},1000);
}
//On browsing sometimes you have to wait
injectScript(restoreConsole);
//Wait 1 milisecond because the <head> document isn't defined yet, so we cannot append our script
var theDeveloperWorldIsYours  = setInterval(function(){ injectScript(restoreConsole)}, 1);

I was saving console’s object on a global variable, and I then I was waiting until the original window.console is overriden by magento. I noticed that the method argumentNames is undefined on the original code, but not after it’s been replaced, so I used it as flag.

Once the flag is set, I have to replace the object with the original one several times, as I noticed that only one wasn’t enough, because magento’s overriding loop might be still in execution.

I also added a timer removal after one second, in order to prevent infinite timers execution on all other pages.

This code kinda works, but it has several drawbacks, apart from the obvious overuse of timers.
The main problem was that I noticed that it wasn’t working every time. It works once you load a magento page or if you refresh the window. However, once you are browsing around, it seems that the magento code is cached, and therefore it’s being executed right before the extension could inject the code in the document’s head. This broke my code, because I wouldn’t be able to save a original copy of window.console on time.

I was wondering if I could pass window.console object as function argument from the extension’s context, as it wasn’t being overriden by magento, but then I found a solution even better, just by coincidence.

I was having a look at stackoverflow (I’m sorry but I don’t remember exactly which page was), and I saw an alternative way of getting a working window.console object. It sees that you can get it from an iframe, so I just had to dynamically create an iframe, append it to the page and retrieve window.console object from it. This is the final version of the code:

/**
 *  restoreConsole
 *  This code is supposed to be injected into the dom document at the very begining of the page load.
 *  Check for attempts to unset the console.log, and restore it back if needed.
 *  The execution will stop once the page has been loaded.
 *
 *  @author Javier Carrascal <javilumbrales[at]gmail[dot]com>
 *  @return void
 */
var restoreConsole = function() {
    __theDeveloperWorldIsYours = setInterval(function() {
        //Anonymous function that checks if console.log has been removed
        //By default, console.log.name should return "log", otherwhise, something has removed it and we have to restore it
        if (typeof window.console.log.name !== 'log' && document.head !== null) {
            //We can restore the original window.console by creating an iframe and appending it to the document
            var i = document.createElement('iframe');
            i.style.display = 'none';
            //We append it to the head so we don't miss console.log messages sent before the body.
            document.head.appendChild(i);
            window.console = i.contentWindow.console;
            console.log('Console restored by TheDeveloperWorldIsYours!');
            //We are done here
            clearInterval(__theDeveloperWorldIsYours);
        }

    }, 1);
    //Stop the execution of the code after page has been loaded.
    window.onload = function() { clearInterval(__theDeveloperWorldIsYours);};
}

This is IMO a much better approach which actually works well. It might probably be improved, of course, but at least its working fine for my purposes. For instance now I’m able to use Google Analytics Debugger extension on any magento page and check what’s being push at the page load, and I’m finally able to use console.log anywhere and at any time .

If you have any questions/suggestions/improvements, they are more than welcomed.

Special thanks for voodooattack’s blog, because without its script, I wouldn’t have been able to get it working.

Find attached the full code of the extension, just in case you want to give it a try, or just have a look.

Creating Google Chrome Extensions – I

This is the story of how I wanted to restore the console.log on the sites that prevent you to use it by overriding the object on the page load. I’ll tell my experience and meanwhile, I’ll show you how to create your own google chrome extensions.

Some applications tend to disable/remove the console.log, usually to hide the debugging messages and/or avoid problems with older versions of IE. For instance, Magento has a script code that erases all the window.console code. This can be very annoying when you have to debug some javascript code, as you cannot print anything on the console. Your options are reduced to either use the built-in Javascript debugger, by putting a break point on the code, or go back to the old times of the well-known alerts. Both options are not so bad, but I am a bit stubborn, and I want to be able to use my loved console.log anywhere and at any time, so I had to fix this. Please, note that I just could remove the offending code from the magento javascript file, but that would be too easy and uninteresting at all, not to mention that I rather leave it disabled at least for the production environment, and I didn’t want to make a environment-dependent code.

I thought that maybe I would be able to install some browser extension that would do all the job for me just by pressing one button, but after a depth research I was unable to find it. It seemed like nobody had the same problem, or nobody cares about it.

I was wondering how to make my own workaround. My idea was to save a copy of the window.console object into a variable just before the evil code was executed. Then, I just would need to restore the saved copy in window.console, and hopefully I would get the console working.

I remembered that I’ve used once a Firefox extension called Greasemonkey that allows to inject Javascript code on the pages, so I gave it a try. Unluckily, after some failed attempts I realized that all the scripts are executed after the page loaded event, wich didn’t serve for my purposes.

After googling for a while, I come up to the conclusion that the only way to do what to do that was to create my own browser extension. I had never tried something like that before, so I decided to try it. After having a look at Chrome documentation, I started developing my first version. It’s ridiculously easy to create a Google Chrome Extension, you just need a manifest.json (specifying a few settings), and a javascript file (depending on your needs, of course, you might need more stuff).

This is how my manifest.json looks:

{
 "name": "Enable Console.log - The Developers World Is Yours",
 "description": "This extensions automatically restores the console object, if any javascript code attempts to remove it.",
 "manifest_version": 2,
 "version": "1.0",
 "content_scripts": [
 {
 "matches": ["http://*/*"],
 "js": ["enable.js"],
 "run_at": "document_start"
 }
 ]
}

Basically, the first lines are just standard fields, and the interesting part is focused on the last three lines:
“matches”: [“http://*/*”]: Means that my extension should be executed at any page.
“js”: [“enable.js”]: This is the source file of the Javascript code that will be executed.
“run_at”: “document_start”: This line specifies WHEN should the script be executed. In my case, I want it to be executed at the very begining, so I’ve set the option “document_start”.

More information regarding the options of this settings can be found at google documentation page.

With the manifest.json done, I could focus on the interesting part, my own extension. I started doing some tests and the expectations were good. I was able to print debug messages in the console from my extension, which means that it was being executed before the page javascript code. This should be enough for me to save in memory a copy of the window.console object and then I just have to wait some time and restore it, if needed.

This is the code I had so far on my “enable.js” file:

var __working_console = window.console;
//Each second, try to put a console.log message
var count = 5;
var test = setInterval(function(){
console.log("Console is still working!");
//Stop it after a while
if (count == 0) {
window.console = __working_console; //Try to restart the console, just in case (IT DOESN'T WORK)
clearInterval(test);
} else {
count = count -1;
}
}, 1000);

I was on my way doing the script, when I realized that I have a big problem: My script was being executed on a different context. It seems that from a Chrome Extension script, you are able to retrieve data from the page, but your code isn’t actually being executed likely a common script loaded on he header’s page (or anywhere else). This means that, even though I was able to save a copy of a working version of window.console object, I was unable to restore it in the page context. Because the window object where the Chrome extension is executed, is different from the window object of the page, so no matters what I do, that I won’t be able to change anything.

Very bad news, but did not give up, and I did well, because although I didn’t know yet, I was very close to find the solution. Do you want to know how I did it, eventually? Do not miss the second part!

A Third-Party Integration in JavaScript

Nowadays, almost any third party application has some kind of backend API where you can interact, or an external JavaScript library that you can load and use, depending on the service.
However, sometimes you have to deal with a third-party integration in javascript, and very limited applications, with a lack of APIs support, and/or documentation.

For instance, a few weeks ago I had to integrate a new shipping method in the checkout process of an eshop. Basically, the user had to go to the carrier website, and select a pick up place. There wasn’t any API where I could retrieve the available places, so the user actually had to interact to the external website.
The available options for the integration were:

  • Redirect the user to the carrier’s page when he selects the specific carrier, and pass a callback URL. Then, once user selects the pick up place, the carrier’s page would redirect back the user, passing all the selected data by GET.
  • Open an iframe when the user selects the carrier as shipping method, passing a callback URL. Then, when the user has chosen the place, the carrier’s page would redirect the parent window to the given callback.

Neither of them were desirable at all, as the first one would require the user to temporarily leave the eshop, and the second one would require to refresh or move to another page, and we have a one-step checkout process.

After discarding the first option, I was wondering how could I retrieve the user’s data from the carrier’s page without refreshing the page, because on the shipping method step, the user had almost finished fulfilling the checkout form, and we needed to preserve all his data.
Firstly, I thought of performing an ajax petition to save the user’s data on session before opening the iframe, and then retrieve them on the page refresh. I didn’t like it at all, though it would probably work, so I discarded it. I had a look at the carrier’s page to see how did they perform the callback redirection. This is the interesting part:

if(parent!=null){
		parent.location=url;
	}else{
		location.href=url;
}

Basically, if the parent window is defined, its location is changed, otherwise, the current window is changed.

Although I don’t like the iframes, I thought that if i put the carrier’s iframe inside another iframe, then, its parent would be my iframe and not the main page, so the checkout page wouldn’t be refreshed and I just would need to retrieve the data.
It seemed a very hackie but “acceptable” solution, so it worth trying. Unfortunately, I realized that chrome and firefox (I didn’t bother to try IE) wouldn’t like it. It seems that it’s not allowed/safe that an iframe attempts to change it’s parent’s location, if it’s an iframe as well. After some research I figured out that I had to think of another way.

I tried to find an alternative way, such as trying to capture iframe’s calls to its parent with javascript, or triggering an event before the window.location was modified, but I had no luck. Eventually, I found that there is an event triggered when the url hash changes (ie: mypage.com/ => mypage.com/#whatever). Maybe I could send the current url as callback concatenated with the character “#”, so when the iframe attempts to change the parent location, it would actually be changing the hash and I would be able to capture the data avoiding refreshing the page.
It seemed a good idea, taking into account the circunstances, so I tried it, but unluckily, as the callback URL is provided by GET, the “#” was being interpreted as hash of the carrier’s url, and the callback variable wasn’t actually containing the “#” character, so the redirection didn’t work as I expected. I mean, the iframe was like this:

<iframe src="carrierspage.com/blablabla?callbackurl=http://mysite.com/checkoutpage#" height="240" width="320"></iframe>

I wanted that the value of callbackurl (on the carrier’s page) was something like “http://mysite.com/checkoutpage#”
But it was actually “http://mysite.com/checkoutpage”, because the “#” was being interpreted as part of the carrier’s page.

After some unsuccessful attempts, I tried url-encoding the character “#”:

<iframe src="carrierspage.com/blablabla?callbackurl=http://mysite.com/checkoutpage%23" height="240" width="320"></iframe>

Voila! It worked smoothly, when the user picked up a place, all the data was being added to the hash of the checkout page, and I just needed to parse the data by JavaScript.

I created a function that would be triggered on the event window.onhashchange, performing the parsing of the url’s hash, clearing the URL, and more uninteresting stuff that is out of the scope of this post.

It was almost finished. I was proud of my -hackie but working- achievement, but then I tested it on IE7. Everything seemed to work, but the onhaschange event.
After some research I discovered that this event is not supported on IE7. Many people suggest an acceptable approach, which consist in constantly checking the location with a timer interval. It’s not so beautiful, but well, it’s IE7.

Finally, I ended up combining both solutions: If the browser is IE7, set the timerinterval and wait for changes on the URL, otherwise wait until the onhaschange event is triggered.

That’s it, I hope it can help you if sometime you get stuck in a similar situation.

Please, remember that any suggestions/improvements/alternatives are more than welcomed.

JavaScript Validation with JsLint

Here I’ll explain how to integrate javascript validation with JsLint in VIM. If you usually have to write some JavaScript code, either using a framework, or just “pure” js code, you should probably use a JS Validator.
Before I started usin JsLint, I used to write the code, save the file, go to the browser, clean the cache (not always but usually), go to an specific page, and eventually test if my code was working.

Sometimes, if have to write just a few lines, I usually do it directly on the firebug or Chrome console, and once I had verified that it works, I copy the code an put it wherever it’s needed on my app.
However, if it’s something bigger, it becomes unhandleable to work on the console, and I rather type the code on the JS files, for the shake of readability.

When I’m coding in PHP, I have a shortcut to directly check syntax errors, which actually helps me a lot. It doesn’t guarantee that the code would work, but at least I know there aren’t syntax errors. One day I was wondering if there is something similar for JavaScript, and after some research, eventually I found it.

It seems that there are several ways to validate JS code, however after trying some of them, I’ve finally choosen JsLint, a static code analyzer for JavaScript source code.

I usually write code using VIM, and debug in NetBeans, so I was looking for some plugin or script that I can easily integrate with VIM. There are many tutorials on the web, however most of them didn’t work as I expected, so I had to combine some of them until I achieved a satisfactory solution.

Okay, enough speech, let’s do it!
I’m using Ubuntu 12 and theese are the steps I followed in order to get it working:
1. You need a command line JS interpreter, and the easiest to install is rhino:

sudo apt-get install rhino

After the installation, you should be able to enter the interpreter just by typing js on your terminal:

Javascript Interpreter

2. You need JsLint and a plugin to integrate it on your favourite IDE (VIM in my case).
Luckly, there is already a JsLint VIM plugin that includes all together, you just have to download the files and put them under the folder ~/.vim/ftplugin. You can find additional help and installation instructions on the link.
Depending on your .vimrc config, you might need to add the following line to enable filetype plugins: filetype plugin on (only if you don’t have it already).

3. After installing the plugin, the validator should be already working:

Javascript Validator

Note that the “wrong” lines are highlighted, and you will see an error description at the bottom once you put the cursor on the line. Each time you save a file with JS extension, the validation will be performed.

4. Now, you have a JS validator integrated on your editor. However, you’ll probably notice that almos every single line will be highlighted, because depending on the JsLint settings, it can be too strict, but you can customize it. In order to do that, create a new file on your home location: ~/.jslintrc and put your custom config. This is the one I’m using:

/*jslint browser: true, regexp: true, nomen: true, sloppy: true*/
/*global jQuery, $, $$ */
/*global _gaq, FB, twttr */
/* vim: set ft=javascript: */

Taken from the JSLint documentation, here is a little explanation of the customizable settings:

anon       true, if the space may be omitted in anonymous function declarations
bitwise    true, if bitwise operators should be allowed
browser    true, if the standard browser globals should be predefined
cap        true, if upper case HTML should be allowed
'continue' true, if the continuation statement should be tolerated
css        true, if CSS workarounds should be tolerated
debug      true, if debugger statements should be allowed
devel      true, if logging should be allowed (console, alert, etc.)
eqeq       true, if == should be allowed
es5        true, if ES5 syntax should be allowed
evil       true, if eval should be allowed
forin      true, if for in statements need not filter
fragment   true, if HTML fragments should be allowed
indent     the indentation factor
maxerr     the maximum number of errors to allow
maxlen     the maximum length of a source line
newcap     true, if constructor names capitalization is ignored
node       true, if Node.js globals should be predefined
nomen      true, if names may have dangling _
on         true, if HTML event handlers should be allowed
passfail   true, if the scan should stop on first error
plusplus   true, if increment/decrement should be allowed
properties true, if all property names must be declared with /*properties*/
regexp     true, if the . should be allowed in regexp literals
rhino      true, if the Rhino environment globals should be predefined
undef      true, if variables can be declared out of order
unparam    true, if unused parameters should be tolerated
sloppy     true, if the 'use strict'; pragma is optional
sub        true, if all forms of subscript notation are tolerated
vars       true, if multiple var statements per function should be allowed
white      true, if sloppy whitespace is tolerated
widget     true  if the Yahoo Widgets globals should be predefined
windows    true, if MS Windows-specific globals should be predefined

Basically, I’ve enabled browser global variables, set the “use strict” as optional, and I set some additional global variables for the external libs that are usually loaded on the pages.
You might disable several validations such as white spaces, multiple var statements and so on, but I think it’s better to get used to this way of coding, as it makes you improve the readability and the quality of the code that you write.

That’s it, now I’m looking for a way to validate JS code inside HTML files, but I haven’t found a solution yet. Do you have any ideas/suggestions?