Skip to content

Instantly share code, notes, and snippets.

@niittymaa
Created February 28, 2016 08:58
Show Gist options
  • Save niittymaa/220e16e296a45cb655ba to your computer and use it in GitHub Desktop.
Save niittymaa/220e16e296a45cb655ba to your computer and use it in GitHub Desktop.
Combine all page scripts or styles
/**
* 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">&raquo;</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