This is going to be the first part of a blog post series about javascript widgets.
First type I’m going to cover is Popup Widget. Sometimes it’s called Popin Widget because there is no actually new window that pops up, instead the content is shown IN-side a current page. The idea is quite simple: you provide some html/js snippet to other sites. They put it into relevant place, and you have some functionality of your site running there.
I’m going to explain how exactly it works, what should be done to achieve this, and what common mistakes i see once and again.
At the end of the blog post you will get a link to complete javascript library, grab it, play with it, and use it for fun or profit.
Content.
Ok, less talk, more work. If you don’t have a time and strong will to read my thoughts about the approach, scroll to the last part 15. Getting things together.
1. Layout.
The main idea is very simple. Let’s call a site that have your widget - “target”.
You add one or more divs to the end of target document, and they hold an iframe. Ifame content comes from your site. Once user clicks some button you show a div and bring relevant iframe content. Once user click some “close” link, you hide this div together with iframe. Actually it’s likely to remove iframe completely, I will talk about this later.
2. Cross-browser support.
Well, there is nothing more to say about it. Your code should work with all grade-A browsers, meaning FF, Safari, IE7/8 and Opera.
3. Global namespace.
Since we’re going to put our javascript into 3rd party website, we should not spam javascript namespace with our own variables and functions. That’s why I personally dislike Google approach with setting global variables like
google_ad_client = "12345";
4. Loading javascript.
It’s good idea to have static javascript that can be cached, or even loaded from Amazon S3. If you think you have to generate javascript dynamically, most probably you’re doing smth wrong and have to review your architecture.
There are 2 different ways to load external javascript: syncronous, and asyncronous (which sometimes called WEDJE ‐ Widget Enabled DOM Javascript Embedding).
5. UI problem with WEDJE.
WEDJE approach is the right one for most cases because your javascript doesn’t slow down the target site. But since we have to bind some button click event with our code, there is a chance that user will click this button before our js code is loaded in a asyncronous way. And that’s not good. That’s why this approach is not applicable here, at least it’s not applicable without modifications.
6. Never slow down target site.
Since WEDJE approach is not applicable here, we have to go with syncronous way of loading assets. Once you include javascript into a web page, browser stops loading everything else until it loads and runs this javascript.
It means that if your site is down and doesn’t respond to requests, target site will be frozen until the browser figures this out and times out. In other words, if your site is down - you hurt the target site.
It might be tempting to put your javascript on some cloud storage solution, like Amazon S3 together with all your other assets.
But there is a problem with it. See, S3 doesn’t support HTTPS protocol. And if someone will want to use your widget on secure site it will work, but with nasty “secure/insecure content” message.
Not nice.
So please allow HTTP and HTTPS access to your widget, it’s really annoying to find useful widget and not use because of lack of support for HTTPS (Feedburner, i’m looking at you).
Update: see Dubek’s comment below about S3 and HTTPS.
7. Using of js frameworks.
Short answer is: no.
Long answer is: never ever even try.
Since we’re writing a widget, we are doing something that adds a value to a target site.
Target site worked without our widget before and will keep working without it in a future. That’s why we should be modest here. Modest as in NOT bringing 100K of framework to use 3.5 functions from it.
We have no choice - need to implement these functions by ourselves.
Here is the short list of functions we need:
- get element by id
- show element
- hide element
- remove element
Right, DOM has it, but who will write document.getElementById
serveral times?
It takes time to write and takes bytes to load :-)
8. Random div ids.
To avoid problems with similar ids on a page, I’d suggest to generarte random
ids for the elements we’re going to add to the page. Check out rnd(...)
function in the example code.
9. Passing parameters to the script.
As i mentioned above, I think it’s a good idea to avoid spamming the javascript namespace.
So, to pass parameters to the script we need to add them into script URL, and than parse from the script itself, e.g.:
.../mywidget.js?key1=value1&key2=value2
Once script is loaded, it finds itself in a DOM tree, parses parameters and
passes them as-is to the iframe URL defined in opts.iframe_base_url
.
See “detecting protocol and parameters” section of the code for more detalis.
10. Loading, please wait…
Some of the widgets we see on internet doesn’t provide a visual feedback to users about what’s going on.
While iframe is being loaded users see only dark backgorund, when browser starts loading the iframe users see some white background.
That’s not good.
We need to provide some visual feedback like “Loading, please wait…” until
the iframe is completely loaded. That’s is done by binding to onload
event
of the iframe and switching the iframe’s and “loading…” div’s “display”
styles.
Please pay attention to opts.close_image
and opts.loading_image
parameters
at the beginning of the script.
11. Pop up the popup.
There are serveral approaches here.
-
user put a link/button in any place he likes, and passes it’s DOM id to the script to allow us binding to its click-event;
-
we create a link/button in a place that user includes the script.
The first one is a quite rare approach because it requires more coding on a
user side. But you can still use it If you’re a writing a widget for your own
site. In such a case you could pass parameter to the javascript as mentioned in
“Passing parameters to the script.”, parse it in jasvascript and
call bind(...)
function:
bind("my_parsed_elelemt_id", "click", function(){show_widget(); return false});
The second one is the one we’re going to implement and use.
We create fancy image that will serve as a link to show the popup and define it
in opts.button_image
, don’t forget to avoid defining protocol there.
12. HTML/JS snippet.
You should share with your users a snippet. Here it is:
<script type='text/javascript'>
document.write(unescape("%3Cscript src='" + ("https:" == document.location.protocol ? "https" : "http") + "://assets.astrails.com/popup-assests/astrails-widget.js?q=wow' type='text/javascript'%3E%3C/script%3E"));
</script>
The snippet will actually embed a button and bind all the events.
Pay attention that we pass q=wow parameter to the script, your server-side part of a widget will get this parameter. You can pass anything you want in those parameters.
13. Passing referrer.
Since we open server-side part of a widget in a iframe, sever-side script will
not obtain HTTP_REFERRER
value.
We need to pass it manually in request URL. Take a look at “detecting protocol and parameters” section of the code for more details.
14. YUI compressor
To finally distribute your code use YUI Compressor, it could reduce a downloadable code size.
15. Getting things together.
-
Open astrails-widget.js, and change values of hash “opts” to point to your URLs and adjust iframe sizes.
-
Read “6. Never slow down target site.” if you haven’t already. If you will take only one thing from this article, make it this one.
-
Compress the script with YUI compressor.
-
Upload compressed script to the location defined in opts.js_url.
-
Copy-paste a snippet from “12. HTML/JS snippet.”, add parameters you need on the server side to the javascript URL.
-
Write the server part refered by
opts.iframe_base_url
. -
Give this snippet to your users.
-
Enjoy.
16. Example
Click the button below to see it in action.
In a next part i will try cover so called Embedded Widgets.