Archive for the ‘JavaScript’ Category

Google Chrome Extension and Loading/Embeding the Flash Files

Monday, September 24th, 2012

If you are Google Chrome Extension developer, then you may have used the “chrome-extension://” protocol to refer to the locally stored files under the extension (could be images, JS, html, etc).

However, I have been trying to use the “.swf” files in the page, and it had kept failing. For some reason, you can’t use the embed tag source with file protocol like “chrome-extension://”. Now this might be some security check at Adobe Flash plug-in or it could be a bug in the Chrome. As a workaround, I have shared the resources on a website, and using them from the extension.

FYI, I have been using this in the Basecamp Extension product to show the animated and active graphs which are developed in the Falsh. I know there are other, may be even better, workarounds available in the JavaScript only, but I started with the flash, and its code is complex enough to stop me from porting this to another language until I have lot of free time.

So, back to the problem, with increased security policies from the Google with Chrome Extensions, I have to look back into this because now youc an’t load the remote resoruces from the “http” only remote (though you can access remote resources over the https).

Fortunatley, the new version of the Chrome on Windows allow accessing the flash files in the extension folder (or may be it was a Adobe Flash fix). But this works on the Windows only, and other Google Chrome version for platforms like Mac OS-X or Linux still have this issue.

After, doing some research, I was able to make all this work and thought to share with you too.

The trick is that though you can’t seem to load the local (placed in extension bundle) swf files using the embed tags, this work well if you add the flash file using the iFrame tag. This solves one problem, but what if you also have to pass the data (as used the FlashVars). The asnwer is simple, and that’s you can pass all these variables using query string parameter.

So, here is my fix for all this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Get the full path of the locally stored graph file
graphUrl = chrome.extension.getURL ("FusionCharts/" + graphFile);
 
// Setup the width and height
graphWidth = 500;
graphHeight = 300;
 
// So far only the Windows Chrome seems to load the local flash/swf files correctly
// For all others, we need to use the iFrame to load the local swf file
if (!(window.navigator.userAgent && window.navigator.userAgent.indexOf("(Windows") > 0) )
{
	// Add the flash varaibles/defaults
	graphUrl += "?chartWidth="+graphWidth+"&chartHeight="+graphHeight;
	graphUrl += "&debugMode=0&DOMId=bceTimeChart&registerWithJS=0&scaleMode=noScale&lang=EN";
 
	// Make an IFRAME and set this flash object as its source
	iFrameHtml = "<iframe src='"+graphUrl+"' style='border:none; width:100%; height:"+graphHeight+"px'>"
	$('#bceGraphDiv').html(iFrameHtml);
}
else
{
	// Render the flash file using the EMBED tag
	// Better use swfobject for rendering:
	// http://code.google.com/p/swfobject/
}

The solution is not very elegant, but at least it works

Content Security Policy and Remote Scripts

Saturday, September 15th, 2012

Google Chrome is targeting toward more secure web, and one of the major step in this is by also enforcing Content Security Policy at the Chrome Extensions level. This is enabled in all the manifest version 2 Extension, and the manifest version 1 is slowly being phased out (you get warning about it being deprecated soon when installing it).

This new policy applies two of the following main limitations on the content scripts:
- Inline JavaScript will not be executed
- Only local script and and object resources are loaded

For more details on this, please check:
http://developer.chrome.com/trunk/contentSecurityPolicy.html

I was working on upgrading my Dynamic Language Tools extension, and though applying first rule of using the Inline scripts was comparatively easy (for tips and pitfalls on this, please check JavaScript eval function and Content Security Policy). But I found the other policy “Only local script and and object resources are loaded” was quite limiting and confusing. I was using the Google AJAX APIs in my extension, and since these are just the JavaScript files, I can download them and integrate most of them directly in the extension, but then this would mean that I will have to update my extension with every update of Google API. This is something which I hate most.

I was using the following code in my extension background page:

1
2
3
4
5
6
7
8
9
10
11
12
13
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
 
<script type="text/javascript">
// Load the Necessary APIs
googleElementsLoaded = false;
googleLanguageLoaded = false;
 
// Load the necessary Google APIs
google.load("language", "1", { "callback" : function() {googleLanguageLoaded = true}});
 
// Load Google Transliteration package
google.load("elements", "1", {packages: ["keyboard", "transliteration"], callback: function() {googleElementsLoaded = true}});
</script>

And as I was afraid, when I run the extension after upgrading the manifest to version 2, it throw the following error:

Refused to load the script ‘http://www.google.com/jsapi’ because it violates the following Content Security Policy directive: “script-src ‘self’”.

After doing some research, I found that it’s possible to load remote scripts too (phew!), but with two conditions:
- It must be served on the HTTPS.
- You need to explicitly add this relaxation in the manifest file.

Both of the steps were quite easy for me. For the first, I simply changed the script source from “http://www.google.com/jsapi” to “https://www.google.com/jsapi”, and then added the following line in the manifest file:

1
"content_security_policy": "script-src 'self' https://www.google.com; object-src 'self'",

Which simply means that I’m allowing it to load the scripts from extension local folder, and from www.google.com. Simply reload the extension after doing these changes and you are good to go.

JavaScript eval function and Content Security Policy

Thursday, August 23rd, 2012

I have been getting warnings for my two of the Basecampe Extensions for the manifest version 1, and need to upgrade those to version 2. However, when working on this upgrade, I found that upgrade was not as simple, as I thought at first.

The biggest problem for me was the new Content Security Policy of Chrome Extension, and to make my application compliant with this, I have to do a lot of code changes here and there in the extensions.

Most of them was simple, though tedious, to integrate. However, I was stuck on one issue and that’s new security policy doesn’t allow the javascript “eval” function. I have been using this in past for evaluating the JSON, checking dynamic global variables and executing dynamic code from the server.

While, I can understand that it’s pretty dangerous and vulnerable to attacks, I have to use it one way or the other. Fortunately, there are some workarounds available. For example, one of the most widely use of the eval by me is to evaluate if a particular event has occurred or something is loaded:

1
eval(" result = " + customJavascriptCode)

If you don’t want to use the eval (or are blocked by some security policy like I was), then one simple workaround for this is by help of javascript Anonymous functions like:

1
var result = ( new Function( 'return ' + customJavascriptCode) )();

Now, I think this is as unsecure as the eval function, and in fact, this gets blocked by Chrome Extension. So the better workaround is to instead of passing the string to evaluate or make anonymous functions, simply pass the anonymous functions and then let the evaluation script simply execute them. So here is another round of changes which actually work in Chrome extension too:

1
2
3
4
5
6
// Instead of passing the string to evaluate, pass anonymous function evaluate 
var result = getResult( function() { return javaScriptVariableToCheck };)
 
// The target function can then execute that function to generate, process and return the 
// results.
function getResult(func) {return func(); }

In worst case, if you only get the JavaScript as a string (may be from some third party) and still want to evaluate the results, the one (though bad in terms of security) is to pass create send this JavaScript as string to a HTTP server which simply echo it back, and then you can use that server file in the Script src tag. The following thread discuss this option in bit more detail:
http://stackoverflow.com/questions/7127652/alternatives-for-javascript-eval

One the side note, if you have been using the eval to evaluate JSON in past (like me), the I found that there is a better workaround for this, and that’s most of the latest browser, including Chrome 3.0+ support JSON object which helps you easily achieve this goal. Here is a sample of this which works fine in Chrome:

1
JSON.parse("{ \"firstName\": \"John\", \"lastName\": \"Smith\" }")

HTML Nested Elements & OnMouseOut Event

Sunday, August 19th, 2012

If you are trying to track the mouse-out event, for example to hide the sub menu when user leave that area, then there are good chances there are good chances that you may stuck into a problem, where the parent element mouse-out event fires, when you move the cursor to the child.

Here is a quick demo of this:

You will notice that as soon as you move the mouse over to the child DIV, the mouse out event of the parent is fired. This is problem in most of the cases, where you want to detect the true mouse out (where the mouse is still over main Div or any of its child Div areas).

There are two possible solutions for this. First is that if you are using the JQuery, then you are good. There is already a special event in JQuery called mouseleave which does exactly what you want. All you have to do is to bind to this event instead of HTML element onmouseout event, and you are good.

However, if you are not using the JQuery, and for some reason don’t want to use it just for this fix. Then there is simple JavaScript only fix for this too (somewhat same rule is used by JQuery too). Here is the JavaScript for such mouse leave event:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
 
// JQuery style getElementByID wrapper
$ = function(id) {
    return document.getElementById(id);
}
 
// Our generic code to handle the on mouse event
isMouseLeave = function(event, parent) {
    // Get the reference to the event object
    if (!event) var e = window.event;
 
    // Get the target parent (extra code for cross browser compatability)
    e = event.toElement || event.relatedTarget;
 
    // Now keep traversing all the parents of the current target object to detect if the 
    // object on which the mouse is being moved is child of the main parent element we are looking 
    // for or not
    while (e && e.nodeName && e.nodeName != 'BODY') {
        // if this is a child element, ignore this on mouse out event
        if (e == parent) return false;
 
        // check the next parent
        e = e.parentNode;
    };
 
    // If we are here, then this is actually the mouse out leave event, so do what you want to do
    return true;
}
 
// Generic event binder
bindMouseOut = function(object, handler) {
    object.onmouseout = function(event) {
 
        // Call handler if this is mouse leave even
        if (isMouseLeave(event, object))
            handler();
    };
}

And you can bind this mouse leave function with any HTML element using the following simple script:

1
2
3
4
5
 
bindMouseOut ($('outerDiv'), function(){
       showMsg('messageLog', 'Out Div Mouse Out');
})

You can view this in action on Jfiddle:

JQuery magic revealed.

JQuery SlideToggle and Stop Methods

Monday, July 30th, 2012

I was working on a new slider animation for my home page, for Jack Sparrow’s Compass product, and I was stuck on one basic problem; that’s I wanted to give the info popup DIV slide-in effect similar to that of Google App Store i.e. slide in from bottom to top.

Instead of trying different options of JQuery, I preferred searching on the web, and the first link I found answered my question well (Google, you rock):
Configure jQuery’s slideToggle() to slide up from the bottom

However, I was having another issue and that’s as I quickly applied mouse over and out on the parent DIV, I was able to make these animation queued, and it was showing animation several time even when the mouse goes outside the parent DIV area. The fix however was simple and that is to call JQuery stop() method for the object on which animation is running.

Here is the code snippets which worked well for me:

1
2
3
4
5
6
$(document).ready(function() {
	$("#jackCompassWrapper").hover(
		  function() { $(this).children('#jackCompassInfo').stop().slideToggle(500); },
		  function() { $(this).children('#jackCompassInfo').stop().slideToggle(500);  }
	 );
 });

JQuery Rocks!