Skip to content

Commit

Permalink
Adds support for minifying framework assets (#3240)
Browse files Browse the repository at this point in the history
Fixes #2753. Credit to @jimcottrell
  • Loading branch information
jimcottrell authored and Luke Towers committed Jul 5, 2018
1 parent 7eaa4d9 commit e4bfb3a
Show file tree
Hide file tree
Showing 6 changed files with 452 additions and 1 deletion.
3 changes: 3 additions & 0 deletions ServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,9 @@ protected function registerAssetBundles()
$combiner->registerBundle('~/modules/system/assets/less/styles.less');
$combiner->registerBundle('~/modules/system/assets/ui/storm.less');
$combiner->registerBundle('~/modules/system/assets/ui/storm.js');
$combiner->registerBundle('~/modules/system/assets/js/framework.js');
$combiner->registerBundle('~/modules/system/assets/js/framework.combined.js');
$combiner->registerBundle('~/modules/system/assets/css/framework.extras.css');
});
}

Expand Down
96 changes: 96 additions & 0 deletions assets/css/framework.extras-min.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
body.oc-loading,body.oc-loading *{cursor:wait !important}
.stripe-loading-indicator{height:5px;background:transparent;position:fixed;top:0;left:0;width:100%;overflow:hidden;z-index:2000}
.stripe-loading-indicator .stripe,.stripe-loading-indicator .stripe-loaded{height:5px;display:block;background:#0090c0;position:absolute;-webkit-box-shadow:inset 0 1px 1px -1px #FFF,inset 0 -1px 1px -1px #FFF;box-shadow:inset 0 1px 1px -1px #FFF,inset 0 -1px 1px -1px #FFF}
.stripe-loading-indicator .stripe{width:100%;-webkit-animation:oc-infinite-loader 60s linear;animation:oc-infinite-loader 60s linear}
.stripe-loading-indicator .stripe-loaded{width:0;opacity:0;filter:alpha(opacity=0)}
.stripe-loading-indicator.loaded{opacity:0;filter:alpha(opacity=0);-webkit-transition:opacity 0.4s linear;transition:opacity 0.4s linear;-webkit-transition-delay:0.3s;transition-delay:0.3s}
.stripe-loading-indicator.loaded .stripe-loaded{opacity:1;filter:alpha(opacity=100);-webkit-transition:width 0.3s linear;transition:width 0.3s linear;width:100% !important}
.stripe-loading-indicator.hide{display:none}
body > p.flash-message{position:fixed;width:500px;left:50%;top:13px;margin-left:-250px;color:#ffffff;font-size:14px;padding:10px 30px 10px 15px;z-index:10300;word-wrap:break-word;text-shadow:0 -1px 0px rgba(0,0,0,0.15);text-align:center;-webkit-box-shadow:0 1px 6px rgba(0,0,0,0.12),0 1px 4px rgba(0,0,0,0.24);box-shadow:0 1px 6px rgba(0,0,0,0.12),0 1px 4px rgba(0,0,0,0.24);-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
body > p.flash-message.fade{opacity:0;filter:alpha(opacity=0);-webkit-transition:all 0.5s,width 0s;transition:all 0.5s,width 0s;-webkit-transform:scale(0.9);-ms-transform:scale(0.9);transform:scale(0.9)}
body > p.flash-message.fade.in{opacity:1;filter:alpha(opacity=100);-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}
body > p.flash-message.success{background:#8da85e}
body > p.flash-message.error{background:#cc3300}
body > p.flash-message.warning{background:#f0ad4e}
body > p.flash-message.info{background:#5fb6f5}
body > p.flash-message button.close{float:none;position:absolute;right:10px;top:8px;color:white;font-size:21px;line-height:1;font-weight:bold;opacity:0.2;filter:alpha(opacity=20);padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none;outline:none}
body > p.flash-message button.close:hover,body > p.flash-message button.close:focus{color:white;text-decoration:none;cursor:pointer;opacity:0.5;filter:alpha(opacity=50)}
@media (max-width:768px){body > p.flash-message{left:10px;right:10px;top:10px;margin-left:0;width:auto}
}
[data-request][data-request-validate] [data-validate-for]:not(.visible),[data-request][data-request-validate] [data-validate-error]:not(.visible){display:none}
a.oc-loading:after,button.oc-loading:after,span.oc-loading:after{content:'';display:inline-block;vertical-align:middle;margin-left:.4em;height:1em;width:1em;animation:oc-rotate-loader 0.8s infinite linear;border:.2em solid currentColor;border-right-color:transparent;border-radius:50%;opacity:0.5;filter:alpha(opacity=50)}
@-moz-keyframes oc-rotate-loader{0%{-moz-transform:rotate(0deg)}
100%{-moz-transform:rotate(360deg)}
}
@-webkit-keyframes oc-rotate-loader{0%{-webkit-transform:rotate(0deg)}
100%{-webkit-transform:rotate(360deg)}
}
@-o-keyframes oc-rotate-loader{0%{-o-transform:rotate(0deg)}
100%{-o-transform:rotate(360deg)}
}
@-ms-keyframes oc-rotate-loader{0%{-ms-transform:rotate(0deg)}
100%{-ms-transform:rotate(360deg)}
}
@keyframes oc-rotate-loader{0%{transform:rotate(0deg)}
100%{transform:rotate(360deg)}
}
@-moz-keyframes oc-infinite-loader{0%{width:0}
10%{width:42%}
20%{width:63%}
30%{width:78.75%}
40%{width:88.59375%}
50%{width:94.130859375%}
60%{width:97.07244873046875%}
70%{width:98.58920574188232%}
80%{width:99.35943391174078%}
90%{width:99.74755670045852%}
100%{width:99.9423761471391%}
}
@-webkit-keyframes oc-infinite-loader{0%{width:0}
10%{width:42%}
20%{width:63%}
30%{width:78.75%}
40%{width:88.59375%}
50%{width:94.130859375%}
60%{width:97.07244873046875%}
70%{width:98.58920574188232%}
80%{width:99.35943391174078%}
90%{width:99.74755670045852%}
100%{width:99.9423761471391%}
}
@-o-keyframes oc-infinite-loader{0%{width:0}
10%{width:42%}
20%{width:63%}
30%{width:78.75%}
40%{width:88.59375%}
50%{width:94.130859375%}
60%{width:97.07244873046875%}
70%{width:98.58920574188232%}
80%{width:99.35943391174078%}
90%{width:99.74755670045852%}
100%{width:99.9423761471391%}
}
@-ms-keyframes oc-infinite-loader{0%{width:0}
10%{width:42%}
20%{width:63%}
30%{width:78.75%}
40%{width:88.59375%}
50%{width:94.130859375%}
60%{width:97.07244873046875%}
70%{width:98.58920574188232%}
80%{width:99.35943391174078%}
90%{width:99.74755670045852%}
100%{width:99.9423761471391%}
}
@keyframes oc-infinite-loader{0%{width:0}
10%{width:42%}
20%{width:63%}
30%{width:78.75%}
40%{width:88.59375%}
50%{width:94.130859375%}
60%{width:97.07244873046875%}
70%{width:98.58920574188232%}
80%{width:99.35943391174078%}
90%{width:99.74755670045852%}
100%{width:99.9423761471391%}
}
143 changes: 143 additions & 0 deletions assets/js/framework-min.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@

if(window.jQuery===undefined){throw new Error('The jQuery library is not loaded. The OctoberCMS framework cannot be initialized.');}
if(window.jQuery.request!==undefined){throw new Error('The OctoberCMS framework is already loaded.');}
+function($){"use strict";var Request=function(element,handler,options){var $el=this.$el=$(element);this.options=options||{};if(handler===undefined){throw new Error('The request handler name is not specified.')}
if(!handler.match(/^(?:\w+\:{2})?on*/)){throw new Error('Invalid handler name. The correct handler name format is: "onEvent".')}
var $form=options.form?$(options.form):$el.closest('form'),$triggerEl=!!$form.length?$form:$el,context={handler:handler,options:options}
$el.trigger('ajaxSetup',[context])
var _event=jQuery.Event('oc.beforeRequest')
$triggerEl.trigger(_event,context)
if(_event.isDefaultPrevented())return
var loading=options.loading!==undefined?options.loading:null,isRedirect=options.redirect!==undefined&&options.redirect.length,useFlash=options.flash!==undefined,useFiles=options.files!==undefined
if(useFiles&&typeof FormData==='undefined'){console.warn('This browser does not support file uploads via FormData')
useFiles=false}
if($.type(loading)=='string'){loading=$(loading)}
var requestHeaders={'X-OCTOBER-REQUEST-HANDLER':handler,'X-OCTOBER-REQUEST-PARTIALS':this.extractPartials(options.update)}
if(useFlash){requestHeaders['X-OCTOBER-REQUEST-FLASH']=1}
var requestData,inputName,data={}
$.each($el.parents('[data-request-data]').toArray().reverse(),function extendRequest(){$.extend(data,paramToObj('data-request-data',$(this).data('request-data')))})
if($el.is(':input')&&!$form.length){inputName=$el.attr('name')
if(inputName!==undefined&&options.data[inputName]===undefined){options.data[inputName]=$el.val()}}
if(options.data!==undefined&&!$.isEmptyObject(options.data)){$.extend(data,options.data)}
if(useFiles){requestData=new FormData($form.length?$form.get(0):null)
if($el.is(':file')&&inputName){$.each($el.prop('files'),function(){requestData.append(inputName,this)})
delete data[inputName]}
$.each(data,function(key){requestData.append(key,this)})}
else{requestData=[$form.serialize(),$.param(data)].filter(Boolean).join('&')}
var requestOptions={url:window.location.href,crossDomain:false,context:context,headers:requestHeaders,success:function(data,textStatus,jqXHR){if(this.options.beforeUpdate.apply(this,[data,textStatus,jqXHR])===false)return
if(options.evalBeforeUpdate&&eval('(function($el, context, data, textStatus, jqXHR) {'+options.evalBeforeUpdate+'}.call($el.get(0), $el, context, data, textStatus, jqXHR))')===false)return
var _event=jQuery.Event('ajaxBeforeUpdate')
$triggerEl.trigger(_event,[context,data,textStatus,jqXHR])
if(_event.isDefaultPrevented())return
if(useFlash&&data['X_OCTOBER_FLASH_MESSAGES']){$.each(data['X_OCTOBER_FLASH_MESSAGES'],function(type,message){requestOptions.handleFlashMessage(message,type)})}
var updatePromise=requestOptions.handleUpdateResponse(data,textStatus,jqXHR)
updatePromise.done(function(){$triggerEl.trigger('ajaxSuccess',[context,data,textStatus,jqXHR])
options.evalSuccess&&eval('(function($el, context, data, textStatus, jqXHR) {'+options.evalSuccess+'}.call($el.get(0), $el, context, data, textStatus, jqXHR))')})
return updatePromise},error:function(jqXHR,textStatus,errorThrown){var errorMsg,updatePromise=$.Deferred()
if((window.ocUnloading!==undefined&&window.ocUnloading)||errorThrown=='abort')
return
isRedirect=false
options.redirect=null
if(jqXHR.status==406&&jqXHR.responseJSON){errorMsg=jqXHR.responseJSON['X_OCTOBER_ERROR_MESSAGE']
updatePromise=requestOptions.handleUpdateResponse(jqXHR.responseJSON,textStatus,jqXHR)}
else{errorMsg=jqXHR.responseText?jqXHR.responseText:jqXHR.statusText
updatePromise.resolve()}
updatePromise.done(function(){$el.data('error-message',errorMsg)
var _event=jQuery.Event('ajaxError')
$triggerEl.trigger(_event,[context,errorMsg,textStatus,jqXHR])
if(_event.isDefaultPrevented())return
if(options.evalError&&eval('(function($el, context, errorMsg, textStatus, jqXHR) {'+options.evalError+'}.call($el.get(0), $el, context, errorMsg, textStatus, jqXHR))')===false)
return
requestOptions.handleErrorMessage(errorMsg)})
return updatePromise},complete:function(data,textStatus,jqXHR){$triggerEl.trigger('ajaxComplete',[context,data,textStatus,jqXHR])
options.evalComplete&&eval('(function($el, context, data, textStatus, jqXHR) {'+options.evalComplete+'}.call($el.get(0), $el, context, data, textStatus, jqXHR))')},handleConfirmMessage:function(message){var _event=jQuery.Event('ajaxConfirmMessage')
_event.promise=$.Deferred()
if($(window).triggerHandler(_event,[message])!==undefined){_event.promise.done(function(){options.confirm=null
new Request(element,handler,options)})
return false}
if(_event.isDefaultPrevented())return
if(message)return confirm(message)},handleErrorMessage:function(message){var _event=jQuery.Event('ajaxErrorMessage')
$(window).trigger(_event,[message])
if(_event.isDefaultPrevented())return
if(message)alert(message)},handleValidationMessage:function(message,fields){$triggerEl.trigger('ajaxValidation',[context,message,fields])
var isFirstInvalidField=true
$.each(fields,function focusErrorField(fieldName,fieldMessages){fieldName=fieldName.replace(/\.(\w+)/g,'[$1]')
var fieldElement=$form.find('[name="'+fieldName+'"], [name="'+fieldName+'[]"], [name$="['+fieldName+']"], [name$="['+fieldName+'][]"]').filter(':enabled').first()
if(fieldElement.length>0){var _event=jQuery.Event('ajaxInvalidField')
$(window).trigger(_event,[fieldElement.get(0),fieldName,fieldMessages,isFirstInvalidField])
if(isFirstInvalidField){if(!_event.isDefaultPrevented())fieldElement.focus()
isFirstInvalidField=false}}})},handleFlashMessage:function(message,type){},handleRedirectResponse:function(url){window.location.href=url},handleUpdateResponse:function(data,textStatus,jqXHR){var updatePromise=$.Deferred().done(function(){for(var partial in data){var selector=(options.update[partial])?options.update[partial]:partial
if($.type(selector)=='string'&&selector.charAt(0)=='@'){$(selector.substring(1)).append(data[partial]).trigger('ajaxUpdate',[context,data,textStatus,jqXHR])}
else if($.type(selector)=='string'&&selector.charAt(0)=='^'){$(selector.substring(1)).prepend(data[partial]).trigger('ajaxUpdate',[context,data,textStatus,jqXHR])}
else{$(selector).trigger('ajaxBeforeReplace')
$(selector).html(data[partial]).trigger('ajaxUpdate',[context,data,textStatus,jqXHR])}}
setTimeout(function(){$(window).trigger('ajaxUpdateComplete',[context,data,textStatus,jqXHR]).trigger('resize')},0)})
if(data['X_OCTOBER_REDIRECT']){options.redirect=data['X_OCTOBER_REDIRECT']
isRedirect=true}
if(isRedirect){requestOptions.handleRedirectResponse(options.redirect)}
if(data['X_OCTOBER_ERROR_FIELDS']){requestOptions.handleValidationMessage(data['X_OCTOBER_ERROR_MESSAGE'],data['X_OCTOBER_ERROR_FIELDS'])}
if(data['X_OCTOBER_ASSETS']){assetManager.load(data['X_OCTOBER_ASSETS'],$.proxy(updatePromise.resolve,updatePromise))}
else{updatePromise.resolve()}
return updatePromise}}
if(useFiles){requestOptions.processData=requestOptions.contentType=false}
context.success=requestOptions.success
context.error=requestOptions.error
context.complete=requestOptions.complete
requestOptions=$.extend(requestOptions,options)
requestOptions.data=requestData
if(options.confirm&&!requestOptions.handleConfirmMessage(options.confirm)){return}
if(loading)loading.show()
$(window).trigger('ajaxBeforeSend',[context])
$el.trigger('ajaxPromise',[context])
return $.ajax(requestOptions).fail(function(jqXHR,textStatus,errorThrown){if(!isRedirect){$el.trigger('ajaxFail',[context,textStatus,jqXHR])}
if(loading)loading.hide()}).done(function(data,textStatus,jqXHR){if(!isRedirect){$el.trigger('ajaxDone',[context,data,textStatus,jqXHR])}
if(loading)loading.hide()}).always(function(dataOrXhr,textStatus,xhrOrError){$el.trigger('ajaxAlways',[context,dataOrXhr,textStatus,xhrOrError])})}
Request.DEFAULTS={update:{},type:'POST',beforeUpdate:function(data,textStatus,jqXHR){},evalBeforeUpdate:null,evalSuccess:null,evalError:null,evalComplete:null}
Request.prototype.extractPartials=function(update){var result=[]
for(var partial in update)
result.push(partial)
return result.join('&')}
var old=$.fn.request
$.fn.request=function(handler,option){var args=arguments
var $this=$(this).first()
var data={evalBeforeUpdate:$this.data('request-before-update'),evalSuccess:$this.data('request-success'),evalError:$this.data('request-error'),evalComplete:$this.data('request-complete'),confirm:$this.data('request-confirm'),redirect:$this.data('request-redirect'),loading:$this.data('request-loading'),flash:$this.data('request-flash'),files:$this.data('request-files'),form:$this.data('request-form'),update:paramToObj('data-request-update',$this.data('request-update')),data:paramToObj('data-request-data',$this.data('request-data'))}
if(!handler)handler=$this.data('request')
var options=$.extend(true,{},Request.DEFAULTS,data,typeof option=='object'&&option)
return new Request($this,handler,options)}
$.fn.request.Constructor=Request
$.request=function(handler,option){return $(document).request(handler,option)}
$.fn.request.noConflict=function(){$.fn.request=old
return this}
function paramToObj(name,value){if(value===undefined)value=''
if(typeof value=='object')return value
try{return JSON.parse(JSON.stringify(eval("({"+value+"})")))}
catch(e){throw new Error('Error parsing the '+name+' attribute value. '+e)}}
$(document).on('change','select[data-request], input[type=radio][data-request], input[type=checkbox][data-request], input[type=file][data-request]',function documentOnChange(){$(this).request()})
$(document).on('click','a[data-request], button[data-request], input[type=button][data-request], input[type=submit][data-request]',function documentOnClick(e){e.preventDefault()
$(this).request()
if($(this).is('[type=submit]'))
return false})
$(document).on('keydown','input[type=text][data-request], input[type=submit][data-request], input[type=password][data-request]',function documentOnKeydown(e){if(e.keyCode==13){if(this.dataTrackInputTimer!==undefined)
window.clearTimeout(this.dataTrackInputTimer)
$(this).request()
return false}})
$(document).on('input','input[data-request][data-track-input]',function documentOnKeyup(e){var
$el=$(this),lastValue=$el.data('oc.lastvalue')
if(!$el.is('[type=email],[type=number],[type=password],[type=search],[type=text]'))
return
if(lastValue!==undefined&&lastValue==this.value)
return
$el.data('oc.lastvalue',this.value)
if(this.dataTrackInputTimer!==undefined)
window.clearTimeout(this.dataTrackInputTimer)
var interval=$(this).data('track-input')
if(!interval)
interval=300
var self=this
this.dataTrackInputTimer=window.setTimeout(function(){$(self).request()},interval)})
$(document).on('submit','[data-request]',function documentOnSubmit(){$(this).request()
return false})
$(window).on('beforeunload',function documentOnBeforeUnload(){window.ocUnloading=true})
$(document).ready(function triggerRenderOnReady(){$(document).trigger('render')})
$(window).on('ajaxUpdateComplete',function triggerRenderOnAjaxUpdateComplete(){$(document).trigger('render')})
$.fn.render=function(callback){$(document).on('render',callback)}}(window.jQuery);
Loading

0 comments on commit e4bfb3a

Please sign in to comment.