Created
February 28, 2016 08:58
-
-
Save niittymaa/220e16e296a45cb655ba to your computer and use it in GitHub Desktop.
Combine all page scripts or styles
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Combine page scripts and styles. | |
* | |
* Usage: | |
* 1. Copy/Paste and execute this script in the browser console | |
* 2. Call combineScripts() or combineStyles() | |
* | |
* Press ESC to hide textarea. | |
* | |
* P.S. Use http://refresh-sf.com/ to create min.js and min.css | |
*/ | |
/** | |
* Add this script as bookmark and execute it on any site just by clicking on bookmark | |
* | |
* javascript:!function(){return"undefined"==typeof jQuery?void alert("no jQuery"):void jQuery.get("https://gist.githubusercontent.com/moldcraft/5b81392ec202a18fc801/raw/combine.js",function(code){eval(code),confirm("Combine Scripts?")?combineScripts():combineStyles()}).fail(function(){alert("Error")})}(); | |
*/ | |
if (false) { | |
(function(){ | |
if (typeof jQuery == 'undefined') { | |
alert('no jQuery'); | |
return; | |
} | |
jQuery.get( | |
'https://gist.githubusercontent.com/moldcraft/5b81392ec202a18fc801/raw/combine.js', | |
function(code){ | |
eval(code); | |
if (confirm('Combine Scripts?')) { | |
combineScripts(); | |
} else { | |
combineStyles(); | |
} | |
} | |
).fail(function() { | |
alert('Error'); | |
}); | |
})(); | |
} | |
(function(){ | |
var AssetsCombiner = function(){}; | |
AssetsCombiner.prototype = { | |
pending: [], | |
contents: [], | |
currentlyDownloadedAssetUrl: false, | |
combine: function (urls) { | |
if (this.currentlyDownloadedAssetUrl) { | |
console.warn('Download in progress. Try again later'); | |
return; | |
} | |
this.pending = urls; | |
this.contents = []; | |
this.confirm(); | |
}, | |
isInline: function(link) { | |
return /^data:/.test(link); | |
}, | |
downloadNext: function () { | |
if (!this.pending.length) { | |
this.displayResult(); | |
return; | |
} | |
this.currentlyDownloadedAssetUrl = this.pending.shift(); | |
var isInline = this.isInline(this.currentlyDownloadedAssetUrl); | |
if (isInline) { | |
console.log('Inline', this.currentlyDownloadedAssetUrl.length) | |
} else { | |
console.log('Downloading', this.currentlyDownloadedAssetUrl); | |
} | |
jQuery.ajax({ | |
url: isInline ? 'data:text/plain,~' : this.currentlyDownloadedAssetUrl, | |
processData: false, | |
dataType: 'text' | |
}) | |
.done(function(contents){ | |
this.contents.push( | |
"/*\n"+ (isInline ? 'inline' : 'url: '+ this.currentlyDownloadedAssetUrl) +"\n*/\n"+ | |
(isInline | |
? decodeURIComponent(escape(atob(this.currentlyDownloadedAssetUrl.split(';base64,').pop()))) | |
: this.filterAssetContents(contents, this.currentlyDownloadedAssetUrl) | |
) +"\n\n" | |
); | |
this.currentlyDownloadedAssetUrl = false; | |
this.downloadNext(); | |
}.bind(this)) | |
.fail(function(jqXHR, textStatus, errorThrown){ | |
this.contents.push( | |
"/*\nurl: "+ this.currentlyDownloadedAssetUrl +"\nDownload Failed\n*/\n\n" | |
); | |
this.currentlyDownloadedAssetUrl = false; | |
this.downloadNext(); | |
}.bind(this)); | |
}, | |
// overwrite this method to change asset contents | |
filterAssetContents: function(contents, assetUrl) { | |
return contents; | |
}, | |
displayResult: function () { | |
jQuery('<textarea></textarea>') | |
.val(this.contents.join('')) | |
.css({ | |
position: 'fixed', | |
top: '0', | |
left: '0', | |
width: '100%', | |
height: '100%', | |
'z-index': '9999999', | |
resize: 'both', | |
'box-sizing': 'border-box' | |
}) | |
.on('keydown', function(e){ | |
if (e.keyCode == 27) { // esc | |
jQuery(this).remove(); | |
} | |
}) | |
.prependTo( jQuery(document.body) ); | |
// free memory | |
this.contents = []; | |
}, | |
confirm: function(callback) { | |
var that = this; | |
var $el = jQuery( | |
'<table><tbody><tr>'+ | |
'<td style="width:50%;">'+ | |
'<form onsubmit="return false;" style="overflow:scroll;max-height:100%;"></form>'+ | |
'</td>'+ | |
'<td><textarea resize="both" placeholder="Inline Preview" style="width:100%;height:100%;"></textarea></td>'+ | |
'</tr></tbody></table>' | |
) | |
.css({ | |
position: 'fixed', | |
top: '0', | |
left: '0', | |
width: '100%', | |
height: '100%', | |
'z-index': '9999999', | |
'background': '#fff' | |
}) | |
.each(function(){ | |
var $form = jQuery(this).find('form:first'), | |
hasInline = false; | |
jQuery.each(that.pending, function(i, url){ | |
var isInline = that.isInline(url); | |
if (isInline) { | |
hasInline = true; | |
} | |
$form.append( | |
'<p>'+ | |
'<input type="checkbox" name="'+ i +'" '+ (isInline ? 'data-is-inline' : '') +' checked /> '+ | |
(isInline | |
? '<a href="#" onclick="return false;" data-i="'+ i +'">inline '+ url.length +'</a>' | |
: (url +' <a href="'+ jQuery('<div/>').html(url).text() +'" target="_blank">»</a>') | |
)+ | |
'</p>' | |
); | |
}); | |
if (hasInline) { | |
$form | |
.append( | |
'<p>'+ | |
'<a href="#" onclick="return false;" data-check-all-inline>Check</a>'+ | |
' / '+ | |
'<a href="#" onclick="return false;" data-uncheck-all-inline>Uncheck</a>'+ | |
' all Inline'+ | |
'</p>' | |
) | |
.on('click', 'a[data-check-all-inline]', function(){ | |
$form.find('input[type="checkbox"][data-is-inline]').prop('checked', true); | |
}) | |
.on('click', 'a[data-uncheck-all-inline]', function(){ | |
$form.find('input[type="checkbox"][data-is-inline]').prop('checked', false); | |
}); | |
} | |
$form.append('<p><button>Combine</button></p>'); | |
}) | |
.on('keydown', function(e){ | |
if (e.keyCode == 27) { // esc | |
jQuery(this).remove(); | |
} | |
}) | |
.on('click', 'a[data-i]', function(){ | |
var url = that.pending[ parseInt( jQuery(this).attr('data-i') ) ]; | |
$el.find('textarea:first').val( | |
that.isInline(url) ? decodeURIComponent(escape(atob(url.split(';base64,').pop()))) : url | |
); | |
}) | |
.on('submit', 'form', function(){ | |
var pending = []; | |
jQuery.each(jQuery(this).serializeArray(), function(i, o){ | |
pending.push( | |
that.pending[ parseInt(o.name) ] | |
); | |
}); | |
that.pending = pending; | |
$el.remove(); | |
that.downloadNext(); | |
}) | |
.prependTo( jQuery(document.body) ); | |
} | |
}; | |
/** | |
* Source: http://javascript.ru/tutorial/object/inheritance#nasledovanie-na-klassah-funkciya-extend | |
*/ | |
function extend(Child, Parent) { | |
var F = function() { }; | |
F.prototype = Parent.prototype; | |
Child.prototype = new F(); | |
Child.prototype.constructor = Child; | |
Child.superclass = Parent.prototype; | |
} | |
// Scripts | |
{ | |
{ | |
var ScriptsCombiner = function(){}; | |
extend(ScriptsCombiner, AssetsCombiner); | |
ScriptsCombiner.prototype.filterAssetContents = function(contents, assetUrl) { | |
return contents +';'; // prevent error if some script forget to add ; at end | |
}; | |
} | |
var scriptsCombiner = new ScriptsCombiner(); | |
window.combineScripts = function(urls) { | |
if (typeof urls == 'undefined') { | |
urls = []; | |
jQuery('script').each(function(){ | |
if (jQuery(this).attr('src')) { | |
urls.push( | |
jQuery(this).attr('src') | |
); | |
} else if (!jQuery(this).attr('type') || jQuery(this).attr('type') == 'text/javascript') { | |
urls.push( | |
'data:text/javascript;base64,' + btoa(unescape(encodeURIComponent(jQuery(this).html()))) | |
); | |
} | |
}); | |
} | |
scriptsCombiner.combine(urls); | |
}; | |
} | |
// Styles | |
{ | |
{ | |
var StylesCombiner = function(){}; | |
extend(StylesCombiner, AssetsCombiner); | |
StylesCombiner.prototype.filterAssetContents = function(contents, assetUrl) { | |
/** | |
* Extract dir url 'http://site.com/assets' from 'http://site.com/assets/style.css' | |
*/ | |
var assetDirUrl = assetUrl.replace(/\/[^\/]*\/?$/, ''); | |
/** | |
* To prevent https warning bar in browser, when the site is using https but in css are http links | |
* Replace 'http://' and 'https://' prefix with '//' (this will work on both) | |
*/ | |
assetDirUrl = assetDirUrl.replace(/^https?:\/\/(.+)/, '//$1'); | |
/** | |
* Replace relative 'url(img/bg.png)' with full 'url(http://site.com/assets/img/bg.png)' | |
* | |
* Do not touch if url starts with: | |
* - 'https://' | |
* - 'http://' | |
* - '/' (also matches '//') | |
* - '#' (for css property: "behavior: url(#behaveBinObject)") | |
* - 'data:' | |
*/ | |
return contents.replace(/url\s*\((?!\s*[\'"]?(?:\/|data\:|\#|(?:https?:)?\/\/))\s*([\'"])?/g, 'url($1'+ assetDirUrl +'/'); | |
}; | |
} | |
var stylesCombiner = new StylesCombiner(); | |
window.combineStyles = function(urls) { | |
if (typeof urls == 'undefined') { | |
urls = []; | |
jQuery('link[rel="stylesheet"][href],style[type="text/css"]').each(function(){ | |
if (jQuery(this).attr('href')) { | |
urls.push( | |
jQuery(this).attr('href') | |
); | |
} else { | |
urls.push( | |
'data:text/css;base64,' + btoa(unescape(encodeURIComponent(jQuery(this).html()))) | |
); | |
} | |
}); | |
} | |
stylesCombiner.combine(urls); | |
}; | |
} | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment