Read/Load files from ZIP in JavaScript
At work we do a lot of JavaScript applications that have little to no HTML files (beside the index), everything is generated by JavaScript and we have tons of .js files that load at runtime and to reduce the size we have to minify them and that is really hard to debug and watch in the browser if something goes wrong. So I've made this JavaScript class that comes to help. What can you do is Zip up all your assets (js, images, css) and use ZipLoader class to read the zip and unpack your resources whenever you need them. It's small (10KB), easy to use and quite fast considering the extraction is made by JavaScript.
1 2 3 4 5 6 7 8 9 10 | // loads and caches the zip file var loader = new ZipLoader('files.zip'); // creates a style node in the document header and appends the style loader.LoadCSS('files.zip://style.css'); // creates a script node in the document header and appends the script loader.loadScript('files.zip://jquery.js'); // returns the file content var someFileYouNeed = loader.load("files.zip://myFile.txt"); // returns the base64 encoded image usable as img source $("#logo").attr('src', loader.loadImage('files.zip://images/logo.png')); |
The level of compression using zip surpasses the js and css minification in all the ways possible. For example, My current application has 79 files (js, and few css) and they all sum up to 924KB in size. Zipping all those 96 files using Ultra compression level gives me 1 file of 126 KB => 1 server request. That's something.
The best performance is made Opera (strangely), then Firefox, Crome, Safari and last IE (no surprise here, I was expecting it before I even started).
It's a V 1.0 that still needs some work and it doesn't work in IE because that stupid browser overrides the mime type and at first null character in the reading of the zip, the content ends. I will fix this eventually I will also include this as a jClass library soon.
Update: Fixed it so it works in IE as well. There is a performance issue still. Will fix that too.
Till then, HERE are the sources and a demo.
The zip in the demo is made using 7Zip with Ultra Compression level.
Happy codding.
Parse XML in JavaScript with jQuery
Yes, you can do it with XMLDOM and all the other ways out there, but why not use the power of jQuery ?
Like so:
1 2 3 4 5 6 7 | <root> <items> <item name="first" id="1">Content 1</item> <item name="second" id="2">Content 2</item> </items> <other atribute="true" /> </root> |
1 2 3 4 | var xml = '<root ......'; var obj = $(xml); // and now you can use jquery selectors to get what you want $("item[name=second]", obj).attr('id'); // 2 |
JavaScript Object-Oriented Programming (OOP) – jClass
I just finished working on a JavaScript 'framework' that will allow you to write highly object-oriented code in your browser.
Using jClass you can easily define namespaces, create and extend class, define and implement interfaces, define public/private/static methods, override and overload them, have getters and setters, and so on.
The syntax for writing code using jClass looks something like this
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | include("some.other.files"); namespace("my.namespace") ({ MyClass : jClass.extends(BaseClass).implements(SomeInterf, SomeOtherInterf) ({ constructor : function(){ .... }, private : { .... }, public : { .... }, static : { .... } }), OtherClass : jClass({ ...... }) }) |
I'm also working on some useful libraries that you can use with jClass.
Usage examples, documentation and downloads are all available on Google Code right HERE
Check if user visited certain websites
Today I found a website called http://www.stayinvisible.com/ that uses a really clever technique to peak in your browser history. They can't see everything of course but they can see whatever they are interested in and that is a list of web-proxy websites.
So how are they doing it ?
First, they have a list of websites they are interested in, like i said, a list of web-proxies.
1 2 3 4 5 6 7 | var sites = { "hidemyass.com": ["http://www.hidemyass.com", "http://forum.hidemyass.com"], "freeproxy.ca": ["http://www.freeproxy.ca"], "proxy4free.com": ["http://www.proxy4free.com"], .... .... } |
Second, they create a temporary IFRAME where they write a simple 2 lines CSS that does the magic
1 2 | a { color: #000; display: none} a: visited { color: #F00; display: inline } |
... and in the body they append all the links from the
The browser renders the links, and all the sites that appear in your history will use the "a:visited" CSS class. The others use the normal "a" class that has a display:none property and will be hidden.
What's left to do is iterate all the links from the frame and check if they are visible or not to know which of them are in your history and which of them aren't. Pretty simple eh ?
So here's the class:
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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | var bHistory = function(){ var sites = { "hidemyass.com": ["http://www.hidemyass.com", "http://forum.hidemyass.com"], "freeproxy.ca": ["http://www.freeproxy.ca"], "proxy.org": ["http://www.proxy.org", "http://www.proxy.org/cgi_proxies.shtml", "http://www.proxy.org/forum/index.html"] }; var visited = {}; function getStyle(el, scopeDoc,styleProp) { if (el.currentStyle) var y = el.currentStyle[styleProp]; else if (window.getComputedStyle) var y = scopeDoc.defaultView.getComputedStyle(el,null).getPropertyValue(styleProp); return y; } function remove( el ) { el.parentNode.removeChild( el ); } function createIframe() { var iframe = document.createElement("iframe"); iframe.style.position = "absolute"; iframe.style.visibility = "hidden"; document.body.appendChild(iframe); if(iframe.contentDocument) iframe.doc = iframe.contentDocument; else if(iframe.contentWindow) iframe.doc = iframe.contentWindow.document; iframe.doc.open(); iframe.doc.write('<style>'); iframe.doc.write("a{color: #000000; display:none;}"); iframe.doc.write("a:visited {color: #FF0000; display:inline;}"); iframe.doc.write('</style>'); iframe.doc.close(); return iframe; } var iframe = createIframe(); function embedLinkInIframe( href, text ) { var a = iframe.doc.createElement("a"); a.href = href; a.innerHTML = site; iframe.doc.body.appendChild( a ); } for( var site in sites ) { var urls = sites[site]; for( var i=0; i<urls .length; i++ ) { embedLinkInIframe( urls[i], site ); if( urls[i].match(/www\./) ){ var sansWWW = urls[i].replace(/www\./, ""); embedLinkInIframe( sansWWW, site ); } else { var httpLen = urls[i].indexOf("//") + 2; var withWWW = urls[i].substring(0, httpLen ) + "www." + urls[i].substring( httpLen ); embedLinkInIframe( withWWW, site ); } } } var links = iframe.doc.body.childNodes; for( var i=0; i<links.length; i++) { var displayValue = getStyle(links[i], iframe.doc, "display"); var didVisit = displayValue != "none"; if( didVisit ){ visited[ links[i].innerHTML ] = true; } } remove( iframe ); var usedSites = []; for( var site in visited ){ usedSites.push( site ); } return usedSites; } |
To use it:
1 2 | var visited = new bHistory(); alert(visited); // an array with visited websites from the defined list |
All credits go to the smart man who did this. Cheers!
Open and Save files to Desktop without going to Server
Few days ago I was working on a jQuery based tool to QA the JavaScript functionality of a website and I was in need of a method to save and load my scripts to Desktop.
In most cases this require a server script where you send the content and it will serve it to download and same for loading it. But a colleague suggested a better solution: to use the FileReference class.
First step was to create a simple flash with the required functionality and send/retrieve data with ExternalInterface. Failed miserably. Why ? Because it seems Flash will not allow you to open a File Dialog from script only. You literally have to click a button from the movie interface to be able to do that. If you knew that good for you, I didn't.
So, I've created another flash movie, where you pass the open and save image and callback and it will insert the flash with the specified images in place and look just like any other buttons.
Here's a small demonstration (other buttons beside open and save are just for show):
So what do you need to set it up ?
First, you have to include the FileDialogs.js in your document (or just paste the code inside it into your own script).
Second, you need your JavaScript callbacks.
1 2 3 4 5 6 7 | function openCallback(input) { document.getElementById('text').value = input; } function saveCallback() { return document.getElementById('text').value; } |
openCallback() will be called once the user will select a file from the desktop and pass it's content as a parameter
saveCallback() will be called when the user clicks save, before the dialog to choose a file name opens, and it must return the content you want to save to disk
Third, you must setup the whole thing.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | // call this function on the onload event so the placeHolder element gets created function onLoad() { // Create a config object var config = new FileDialogsConfig(); // width of the entire flash movie (buttons width + padding) config.width = 45; // height of the movie config.height = 16; // padding between buttons config.padding = 5; // open dialog button image and javascript callback function config.open.image = "open.png"; config.open.handler = "openCallback"; // save dialog button image and javascript callback function config.save.image = "save.png"; config.save.handler = "saveCallback"; // create the movie inside an element with the given id and configuration new FileDialogs("placeHolder", config); } |
Note: Handler callbacks in the config must be declared as String and not reference. IE will freak out and I don't want to fix it.
You can have only one button (open or save) if you chose so. Just don't set the other one.
That's about it. The placeHolder can be any container element. The script will set it's style size based on the configuration, the movie will have transparent background so don't worry about that, and it will set it's float property to left so you can add other stuff after it. But all those things are easy to configure if you mess a bit with the FileDialogs.js file.
Cheers!
