JS Minification: Compressing the code - javascript

A online tool, such as JSCompress, will reduce code size up to 80%. It's easy to notice that the result, compressed code, removes space. Beyond the removal of EOL and ' ' characters, is there any other trickery needed to minify a js file?
Example compressed:
function glow(e){$("#"+e).fadeIn(700,function(){$(this).fadeOut(700)})}function startLevel(){ptrn=[],pos=0,setLevel(lvl),$("#mg-lvl").fadeOut("slow",function(){$("#mg-contain").prop("onclick",null).off("click"),$("#mg-contain").css("cursor","default"),$(this).text("Level "+lvl+": "+ptrn.length+" blink(s)."),$(this).fadeIn("slow"),showLevel(0)})}function setLevel(e){ptrn.push(Math.floor(3*Math.random()+1)),0==e||setLevel(--e)}function showLevel(e){$("#b"+ptrn[e]+"c").fadeOut(speed,function(){$("#ball_"+ptrn[e]).fadeOut(speed,function(){$("#b"+ptrn[e]+"c").fadeIn(speed),$(this).fadeIn(speed,function(){e+1<ptrn.length&&showLevel(++e,speed)})})}),e+1==ptrn.length&&setTimeout(bindKeys(1),ptrn.length*speed+15)}function bindKeys(e){for(var e=1;e<4;e++)bind(e)}function bind(e){$("#ball_"+e).on("click",function(){$("#b"+e+"c").fadeOut(speed,function(){$("#ball_"+e).fadeOut(speed,function(){$("#ball_"+e).fadeIn(speed),$("#b"+e+"c").fadeIn(speed),referee(e)&&unbind()})})})}function referee(e){if(pos<ptrn.length&&(e===ptrn[pos]?$("#mg-score").text(parseInt($("#mg-score").text())+1):end()),++pos==ptrn.length)return++lvl,speed-=40,!0}function unbind(){for(var e=1;e<4;e++)$("#ball_"+e).off();startLevel()}function nestedFade(e,n,t){e[n]&&$(e[n]).fadeOut("fast",function(){t[n]&&($(e),t[n]),nestedFade(e,++n,t)})}function end(){for(var e=[],n=[],t=1;t<4;t++)e.push("#b"+t+"c"),e.push("#ball_"+t),n.push(null);e.push("#mg-contain"),n.push('.fadeOut("slow")'),e.push("#mg-obj"),n.push(".fadeOut('slow')"),e.push("#bg-ball-container"),n.push(".toggle()"),nestedFade(e,0,n)}var ptrn=[],pos=0,lvl=1,speed=400,b1=setInterval(function(){glow("ball_1b",700)}),b2=setInterval(function(){glow("ball_2b",700)}),b3=setInterval(function(){glow("ball_3b",700)});
Example uncompressed:
var ptrn = [];
var pos = 0;
var lvl = 1;
var speed = 400;
/* make balls glow */
function glow(id)
{
$('#'+id).fadeIn(700, function(){$(this).fadeOut(700);})
}
var b1 = setInterval(function(){ glow('ball_1b',700) ,1500});
var b2 = setInterval(function(){ glow('ball_2b',700) ,1500});
var b3 = setInterval(function(){ glow('ball_3b',700) ,1500});
/* end */
function startLevel()
{
ptrn = [];
pos = 0;
/* set pattern for the level */
setLevel(lvl);
/* display prompt for level */
$('#mg-lvl').fadeOut("slow", function(){
$('#mg-contain').prop('onclick',null).off('click');
$('#mg-contain').css('cursor','default');
$(this).text("Level " + lvl + ": " + ptrn.length + " blink(s).");
$(this).fadeIn('slow');
/* play back the pattern for user to play */
showLevel(0); //TODO: use promise and deferred pattern to pull this out of fade function.
});
}
function setLevel(lvl)
{
ptrn.push(Math.floor((Math.random() * 3) + 1));
(lvl == 0 ) ? null : setLevel(--lvl);
}
function showLevel(i)
{
/* blink the balls */
$('#b'+ptrn[i]+'c').fadeOut(speed, function(){
$('#ball_'+ptrn[i]).fadeOut(speed, function(){
$('#b'+ptrn[i]+'c').fadeIn(speed);
$(this).fadeIn(speed, function(){
if(i+1<ptrn.length)
showLevel(++i,speed);
});
});
});
if( (i+1) == ptrn.length)
setTimeout( bindKeys(1), ptrn.length*speed+15) //after the pattern is revealed bind the clicker
}
function bindKeys(i)
{
for(var i=1;i<4;i++)
bind(i);
}
function bind(i)
{
$('#ball_'+i).on('click', function() {
$('#b'+i+'c').fadeOut(speed, function() {
$('#ball_'+i).fadeOut(speed, function() {
$('#ball_'+i).fadeIn(speed);
$('#b'+i+'c').fadeIn(speed);
if(referee(i))
unbind();
});
});
});
}
function referee(val)
{
if(pos < ptrn.length){
( val === ptrn[pos] ) ? $('#mg-score').text(parseInt($('#mg-score').text())+1) : end();
}
if(++pos == ptrn.length)
{
++lvl;
speed-=40;
return true;
}
}
function unbind()
{
for(var i=1;i<4;i++)
$( "#ball_"+i).off();
startLevel();
}
function nestedFade(id,i,func)
{
(!id[i]) ? 0 : $(id[i]).fadeOut('fast',function(){ if(func[i])
{$(id)+func[i];};nestedFade(id,++i,func);})
}
function end()
{
var id = [];
var func = [];
for(var i=1;i<4;i++){
id.push('#b'+i+'c');
id.push('#ball_'+i);
func.push(null)
}
id.push('#mg-contain');
func.push('.fadeOut("slow")');
id.push('#mg-obj');
func.push(".fadeOut('slow')");
id.push('#bg-ball-container');
func.push(".toggle()");
nestedFade(id,0,func);
}
Saves 32% on file size...and if that is the case, is it a fair assumption then that writing less is doing more for the end user?

The same way you can 'minify' a file to reduce its size, you can also 'uglify' a file, which takes your code and shortens things like variable names to the same end: reduce file size by reducing the number of characters in it (not just removing line breaks and space characters).
While it will reduce loadtime for a user, it's not a great practice to write minified/uglified-style code off the bat. That's why in almost any professional build/deploy process, you take your clear, descriptive code and then run your build processes to reduce the size of your files and eventually deploy versions that your end user will have a quicker time loading. You can always write your regular code, then run a compression process like the one you described, save it into a "public" folder and upload that for users to have access to, rather than your fleshed out code.

All a minifier will do is remove white space, which like you said, is ' ' and EOL characters. I believe you may be thinking of file compression tools such as a .zip file with the way your question is worded. Such file types (.zip) will find common strings in your file, and put references to the original string rather than having it written out 10 times. Meaning if the string "I like cake" shows up 4 times in your file, it will have "I like cake" in one location, and the other three locations will reference that first location, shortening the length of the file and therefore decreasing its size.
Well the main reason JS, CSS and HTML get's minified is to decrease the size of the files transmitted from server to client when a client requests a webpage. This decrease in size will allow for a faster load time. So technically writing less is more for a webpages load time, but realistically the effect of you as a developer consciously writing shorter code to minimize file size will either a.) Be to minimal a change to actually make a difference or b.) lead to loss of functionality or bugs due to the focus being on cutting down code length, not code quality.

Related

How can I get automatically numbered headings in confluence?

Currently it is not possible in confluence to have the headings of the document structure numbered automatically. I am aware that there are (paid) 3rd party plugins available.
How can I achieve continuous numbered headings?
TL;DR
Create a bookmark for the following javascript and click it in edit mode in confluence to renumber your headings.
javascript:(function()%7Bfunction%20addIndex()%20%7Bvar%20indices%20%3D%20%5B%5D%3BjQuery(%22.ak-editor-content-area%20.ProseMirror%22).find(%22h1%2Ch2%2Ch3%2Ch4%2Ch5%2Ch6%22).each(function(i%2Ce)%20%7Bvar%20hIndex%20%3D%20parseInt(this.nodeName.substring(1))%20-%201%3Bif%20(indices.length%20-%201%20%3E%20hIndex)%20%7Bindices%3D%20indices.slice(0%2C%20hIndex%20%2B%201%20)%3B%7Dif%20(indices%5BhIndex%5D%20%3D%3D%20undefined)%20%7Bindices%5BhIndex%5D%20%3D%200%3B%7Dindices%5BhIndex%5D%2B%2B%3BjQuery(this).html(indices.join(%22.%22)%2B%22.%20%22%20%2B%20removeNo(jQuery(this).html()))%3B%7D)%3B%7Dfunction%20removeNo(str)%20%7Blet%20newstr%20%3D%20str.trim()%3Bnewstr%20%3D%20newstr.replace(%2F%5B%5Cu00A0%5Cu1680%E2%80%8B%5Cu180e%5Cu2000-%5Cu2009%5Cu200a%E2%80%8B%5Cu200b%E2%80%8B%5Cu202f%5Cu205f%E2%80%8B%5Cu3000%5D%2Fg%2C'%20')%3Bif(IsNumeric(newstr.substring(0%2Cnewstr.indexOf('%20'))))%7Breturn%20newstr.substring(newstr.indexOf('%20')%2B1).trim()%3B%7Dreturn%20newstr%3B%7Dfunction%20IsNumeric(num)%20%7Bnum%20%3D%20num.split('.').join(%22%22)%3Breturn%20(num%20%3E%3D0%20%7C%7C%20num%20%3C%200)%3B%7DaddIndex()%7D)()
Result
How to use
After changes to the structure have been made, clicking the bookmarked javascript renumbers the document.
Limitations are that it only provides n.n.n. numbering, but for many cases that's sufficient. The script can also be customized as required.
Background, explanation and disclosure
I tried this TaperMonkey script that apparently resulted from this post, but it didn't work as is. So I took its source code and stripped it of the integration code, old version compatibility and made some minor adjustments to get this:
function addIndex() {
var indices = [];
jQuery(".ak-editor-content-area .ProseMirror").find("h1,h2,h3,h4,h5,h6").each(function(i,e) {
var hIndex = parseInt(this.nodeName.substring(1)) - 1;
if (indices.length - 1 > hIndex) {
indices= indices.slice(0, hIndex + 1 );
}
if (indices[hIndex] == undefined) {
indices[hIndex] = 0;
}
indices[hIndex]++;
jQuery(this).html(indices.join(".")+". " + removeNo(jQuery(this).html()));
});
}
function removeNo(str) {
let newstr = str.trim();
newstr = newstr.replace(/[\u00A0\u1680​\u180e\u2000-\u2009\u200a​\u200b​\u202f\u205f​\u3000]/g,' ');
if(IsNumeric(newstr.substring(0,newstr.indexOf(' ')))){
return newstr.substring(newstr.indexOf(' ')+1).trim();
}
return newstr;
}
function IsNumeric(num) {
num = num.split('.').join("");
return (num >=0 || num < 0);
}
addIndex();
(I'm not a JavaScript developer, I'm sure it can be written nicer/better)
Then I used bookmarklet to convert it into the javascript bookmark at the top, which can be clicked to trigger the functionality.

How to select and delete every clipping masks in an Illustrator document using javascript?

I'm making extend scripts for Adobe Illustrator CS6 (javascript) and I need to delete every clipping masks of a document.
I already have a solution but it's not fast enough in big documents.
Here is my code:
var releaseClippingMasks = function(document) {
var pathItems = document.pathItems;
log('Looking for clipping masks among ' + pathItems.length + ' elements');
var n = 0;
for(var p = pathItems.length - 1; p >= 0; p--) {
if(p / 1000 == Math.round(p / 1000)) {
log(p + ' remaining');
}
if(pathItems[p].clipping) { // accessing to the element [p] of pathItems takes a lot of time
pathItems[p].remove();
n++;
}
}
log(n + ' deleted masks');
}
There are not so many clipping masks in my documents, but a lot of pathItems (100000+), so iterating takes a very long time.
Does anyone know a better way to select every clipping masks in a document by javascript?
Any help would be very appreciated.
The fastest way to select all clipping mask and delete it:
// Select->Objects->Clipping Mask
app.executeMenuCommand("Clipping Masks menu item");
// Edit->Clear
app.executeMenuCommand("clear");

Incrementing Number Inside String

For a client's requirement, I have set out several images as follows:
img/img1.jpg
img/img2.jpg
img/img3.jpg
...
img/img4.jpg.
Now, I need to make the function that loads images dynamic. At the moment, the current solution is as follows:
// Grab the last image path
var lastImagePath = $("lastImage").attr("src");
// Increment the value.
var nextImagePath = "img/img" + (+lastImagePath.replace("img/img").replace(".jpg") + 1) + ".jpg";
// So on.
I was wondering if there's a cleaner way to increment the number?
Slightly cleaner:
var nextImagePath = lastImagePath.replace(/\d+/, function (n) { return ++n; });
This uses the version of replace that accepts a regular expression and a function.

Replace Picture Source (Error Handling)

Hi I have a script wich changes the source of an image ie webpics/1.jpg to webpics/2.jpg on click of an image. One problem i am having though is that the script will still work for one more image after there is images, so if i have 11 images i can press next 11 times and will get an empty image, what i would like is for the script to run a error check and stay on the current image if the next on doesn't exist. Here is the script:
$("#prev, #next").click(function() {
var currentNumber = parseInt($("#image1").attr("src").split('gallery/')[1]); // get the
number
var newNumber = ($(this).attr("id")=="next")?currentNumber+1:currentNumber-1;
var testImage = new Image();
testImage.onload=function() {
var img = $("#image1");
img.attr("src",this.src);
img.css("visibility","visible");
}
testImage.onerror=function() {
$("#image1").css("visibility","hidden");
}
testImage.src="http://www.yogahealth.net.au/gallery/"+newNumber+".jpg";
return false;
});
Do you know how many images exist? If so, just test if the new number would exceed the total count (if newNumber ...) and do nothing (i.e. skip the part where you change the testImage.src.
For example, you need to have the total count in the variable totalImages, then you could do:
$("#prev, #next").click(function() {
var currentNumber = parseInt($("#image1").attr("src").split('gallery/')[1]); // get the number
var newNumber = ($(this).attr("id")=="next")?currentNumber+1:currentNumber-1;
var totalImages = // get the number of total images here
if ((newNumber > totalImages) || (newNumber <= 0)) {
return false; // just do nothing
}
// here comes the rest of your code
});
Note that I also added the possibility that your number becomes less than 0 or 0, depending on whether you have an image named 0. If yes, you can change the <= to <, otherwise it won't show the 0 image.
In order to get this number into your Javascript code, you could either render the code using PHP and insert it into your script with <?php echo $total; ?> or you extract it from another element from the HTML page, as you did with the currentNumber.

Best way to build HTML from json

I'm trying to build a POC to migrate a heavy JSF application to a stateless ajax/restful application .
In the proccess i can't decide what is the best way of presenting the JSON data returned to the screen , i can see 2 major approaches one is to have templates and use something like prototype's toHTML() with them and the other is to build the objects in javascript and then use appendchild .
the first one is much more easy to understand for a new person who has to maintain the code as the templates are very clear and easier to maintain (allso the skills needed to change the html in templates are lower) but from what i understand the appendchild method is better in regards to browser speed .
what is the preferable way to handle this and am i missing other points of comparison between the two ?
append child is this a good compromise between the two ?
are there any other ways to do this ?
P.S : to be clear i'm talking about client side manipulations only
Setting html directly with innerHTML is the fastest way cross-browser. It has some bugs, however, that you should keep in mind (tables, forms, etc.).
var html = [];
for (...) {
html.push( PARTIAL_HTML );
}
element.innerHTML = html.join("");
UPDATE: The best way may be to test it for yourself:
function test( name, fn, n, next ) {
var n = n || 100; // default number of runs
var start, end, elapsed;
setTimeout(function() {
start = Number(new Date());
for ( ; n--; ) {
fn()
}
end = Number(new Date());
elapsed = end - start;
// LOG THE RESULT
// can be: $("#debug").html(name + ": " + elapsed + " ms");
console.log(name + ": " + elapsed + " ms"));
next && next();
}, 0);
}
test("dom", function() {
// ...
});
test("innerHTML", function() {
// ...
});

Categories