diff --git a/modules/system/assets/ui/js/popup.js b/modules/system/assets/ui/js/popup.js index 72087b6c7..610834212 100644 --- a/modules/system/assets/ui/js/popup.js +++ b/modules/system/assets/ui/js/popup.js @@ -9,11 +9,13 @@ +function ($) { "use strict"; + var Base = $.oc.foundation.base, + BaseProto = Base.prototype + // POPUP CLASS DEFINITION // ============================ var Popup = function(element, options) { - var self = this this.options = options this.$el = $(element) this.$container = null @@ -28,45 +30,16 @@ this.$dialog = this.$container.find('.modal-dialog:first') this.$modal = this.$container.modal({ show: false, backdrop: false, keyboard: this.options.keyboard }) - /* - * Duplicate the popup reference on the .control-popup container - */ - this.$container.data('oc.popup', this) - - /* - * Hook in to BS Modal events - */ - this.$modal.on('hide.bs.modal', function(){ - self.triggerEvent('hide.oc.popup') - self.isOpen = false - self.setBackdrop(false) - }) - - this.$modal.on('hidden.bs.modal', function(){ - self.triggerEvent('hidden.oc.popup') - self.$container.remove() - self.$el.data('oc.popup', null) - $(document.body).removeClass('modal-open') - }) - - this.$modal.on('show.bs.modal', function(){ - self.isOpen = true - self.setBackdrop(true) - $(document.body).addClass('modal-open') - }) - - this.$modal.on('shown.bs.modal', function(){ - self.triggerEvent('shown.oc.popup') - }) - - this.$modal.on('close.oc.popup', function(){ - self.hide() - return false - }) + $.oc.foundation.controlUtils.markDisposable(element) + Base.call(this) + this.initEvents() this.init() } + Popup.prototype = Object.create(BaseProto) + Popup.prototype.constructor = Popup + Popup.DEFAULTS = { ajax: null, handler: null, @@ -84,16 +57,16 @@ /* * Do not allow the same popup to open twice */ - if (self.isOpen) - return + if (self.isOpen) return /* * Show loading panel */ this.setBackdrop(true) - if (!this.options.content) + if (!this.options.content) { this.setLoading(true) + } /* * October AJAX @@ -120,7 +93,6 @@ }) } - /* * Regular AJAX */ @@ -136,7 +108,6 @@ }) } - /* * Specified content */ @@ -150,6 +121,70 @@ } } + Popup.prototype.initEvents = function(){ + var self = this + + /* + * Duplicate the popup reference on the .control-popup container + */ + this.$container.data('oc.popup', this) + + /* + * Hook in to BS Modal events + */ + this.$modal.on('hide.bs.modal', function(){ + self.triggerEvent('hide.oc.popup') + self.isOpen = false + self.setBackdrop(false) + }) + + this.$modal.on('hidden.bs.modal', function(){ + self.triggerEvent('hidden.oc.popup') + self.$container.remove() + $(document.body).removeClass('modal-open') + self.dispose() + }) + + this.$modal.on('show.bs.modal', function(){ + self.isOpen = true + self.setBackdrop(true) + $(document.body).addClass('modal-open') + }) + + this.$modal.on('shown.bs.modal', function(){ + self.triggerEvent('shown.oc.popup') + }) + + this.$modal.on('close.oc.popup', function(){ + self.hide() + return false + }) + } + + Popup.prototype.dispose = function() { + this.$modal.off('hide.bs.modal') + this.$modal.off('hidden.bs.modal') + this.$modal.off('show.bs.modal') + this.$modal.off('shown.bs.modal') + this.$modal.off('close.oc.popup') + + this.$el.off('dispose-control', this.proxy(this.dispose)) + this.$el.removeData('oc.popup') + this.$container.removeData('oc.popup') + + this.$container = null + this.$content = null + this.$dialog = null + this.$modal = null + this.$el = null + + // In some cases options could contain callbacks, + // so it's better to clean them up too. + this.options = null + + BaseProto.dispose.call(this) + } + Popup.prototype.createPopupContainer = function() { var modal = $('
').prop({ @@ -223,6 +258,16 @@ } } + Popup.prototype.setShake = function() { + var self = this + + this.$content.addClass('popup-shaking') + + setTimeout(function() { + self.$content.removeClass('popup-shaking') + }, 1000) + } + Popup.prototype.hideLoading = function(val) { this.setLoading(false) @@ -233,15 +278,17 @@ } Popup.prototype.triggerEvent = function(eventName, params) { - if (!params) + if (!params) { params = [this.$el, this.$modal] + } var eventObject = jQuery.Event(eventName, { relatedTarget: this.$container.get(0) }) this.$el.trigger(eventObject, params) - if (this.firstDiv) + if (this.firstDiv) { this.firstDiv.trigger(eventObject, params) + } } Popup.prototype.reload = function() { @@ -277,10 +324,12 @@ * you should call .hide() once finished */ Popup.prototype.visible = function(val) { - if (val) + if (val) { this.$modal.addClass('in') - else + } + else { this.$modal.removeClass('in') + } this.setBackdrop(val) } @@ -360,7 +409,7 @@ }) .on('ajaxFail', '[data-popup-load-indicator]', function(event, context) { if ($(this).data('request') != context.handler) return - $(this).closest('.control-popup').addClass('in').popup('setLoading', false) + $(this).closest('.control-popup').addClass('in').popup('setLoading', false).popup('setShake') }) .on('ajaxDone', '[data-popup-load-indicator]', function(event, context) { if ($(this).data('request') != context.handler) return diff --git a/modules/system/assets/ui/less/popup.less b/modules/system/assets/ui/less/popup.less index bd18c7411..7a7f4ed1c 100644 --- a/modules/system/assets/ui/less/popup.less +++ b/modules/system/assets/ui/less/popup.less @@ -29,6 +29,13 @@ background: @color-popup-content-bg; } +.modal-content.popup-shaking { + .animation(popup-shake 0.82s cubic-bezier(.36,.07,.19,.97) both); + .transform(translate3d(0, 0, 0)); + .backface-visibility(hidden); + .perspective(1000px); +} + .modal-header { background: @color-popup-header-bg; color: @color-popup-header-text; @@ -168,3 +175,27 @@ .mac body.modal-open { margin-right: 0; } + +// Popup animations +// ------------------------- + +@-moz-keyframes popup-shake { + 10%, 90% { -moz-transform: translate3d(-1px, 0, 0); } + 20%, 80% { -moz-transform: translate3d(2px, 0, 0); } + 30%, 50%, 70% { -moz-transform: translate3d(-4px, 0, 0); } + 40%, 60% { -moz-transform: translate3d(4px, 0, 0); } +} + +@-webkit-keyframes popup-shake { + 10%, 90% { -webkit-transform: translate3d(-1px, 0, 0); } + 20%, 80% { -webkit-transform: translate3d(2px, 0, 0); } + 30%, 50%, 70% { -webkit-transform: translate3d(-4px, 0, 0); } + 40%, 60% { -webkit-transform: translate3d(4px, 0, 0); } +} + +@keyframes popup-shake { + 10%, 90% { transform: translate3d(-1px, 0, 0); } + 20%, 80% { transform: translate3d(2px, 0, 0); } + 30%, 50%, 70% { transform: translate3d(-4px, 0, 0); } + 40%, 60% { transform: translate3d(4px, 0, 0); } +} diff --git a/modules/system/assets/ui/storm-min.js b/modules/system/assets/ui/storm-min.js index 85c01bc73..213c808c5 100644 --- a/modules/system/assets/ui/storm-min.js +++ b/modules/system/assets/ui/storm-min.js @@ -3393,8 +3393,8 @@ $.fn.ocPopover.Constructor=Popover $.fn.ocPopover.noConflict=function(){$.fn.ocPopover=old return this} $(document).on('click','[data-control=popover]',function(e){$(this).ocPopover() -return false;})}(window.jQuery);+function($){"use strict";var Popup=function(element,options){var self=this -this.options=options +return false;})}(window.jQuery);+function($){"use strict";var Base=$.oc.foundation.base,BaseProto=Base.prototype +var Popup=function(element,options){this.options=options this.$el=$(element) this.$container=null this.$modal=null @@ -3406,28 +3406,17 @@ this.$container=this.createPopupContainer() this.$content=this.$container.find('.modal-content:first') this.$dialog=this.$container.find('.modal-dialog:first') this.$modal=this.$container.modal({show:false,backdrop:false,keyboard:this.options.keyboard}) -this.$container.data('oc.popup',this) -this.$modal.on('hide.bs.modal',function(){self.triggerEvent('hide.oc.popup') -self.isOpen=false -self.setBackdrop(false)}) -this.$modal.on('hidden.bs.modal',function(){self.triggerEvent('hidden.oc.popup') -self.$container.remove() -self.$el.data('oc.popup',null) -$(document.body).removeClass('modal-open')}) -this.$modal.on('show.bs.modal',function(){self.isOpen=true -self.setBackdrop(true) -$(document.body).addClass('modal-open')}) -this.$modal.on('shown.bs.modal',function(){self.triggerEvent('shown.oc.popup')}) -this.$modal.on('close.oc.popup',function(){self.hide() -return false}) +$.oc.foundation.controlUtils.markDisposable(element) +Base.call(this) +this.initEvents() this.init()} +Popup.prototype=Object.create(BaseProto) +Popup.prototype.constructor=Popup Popup.DEFAULTS={ajax:null,handler:null,keyboard:true,extraData:{},content:null,size:null,adaptiveHeight:false,zIndex:null} Popup.prototype.init=function(){var self=this -if(self.isOpen) -return +if(self.isOpen)return this.setBackdrop(true) -if(!this.options.content) -this.setLoading(true) +if(!this.options.content){this.setLoading(true)} if(this.options.handler){this.$el.request(this.options.handler,{data:paramToObj('data-extra-data',this.options.extraData),success:function(data,textStatus,jqXHR){this.success(data,textStatus,jqXHR).done(function(){self.setContent(data.result) $(window).trigger('ajaxUpdateComplete',[this,data,textStatus,jqXHR]) self.triggerEvent('popupComplete') @@ -3437,6 +3426,36 @@ self.triggerEvent('error.oc.popup')})}})} else if(this.options.ajax){$.ajax({url:this.options.ajax,data:paramToObj('data-extra-data',this.options.extraData),success:function(data){self.setContent(data)},cache:false})} else if(this.options.content){var content=typeof this.options.content=='function'?this.options.content.call(this.$el[0],this):this.options.content this.setContent(content)}} +Popup.prototype.initEvents=function(){var self=this +this.$container.data('oc.popup',this) +this.$modal.on('hide.bs.modal',function(){self.triggerEvent('hide.oc.popup') +self.isOpen=false +self.setBackdrop(false)}) +this.$modal.on('hidden.bs.modal',function(){self.triggerEvent('hidden.oc.popup') +self.$container.remove() +$(document.body).removeClass('modal-open') +self.dispose()}) +this.$modal.on('show.bs.modal',function(){self.isOpen=true +self.setBackdrop(true) +$(document.body).addClass('modal-open')}) +this.$modal.on('shown.bs.modal',function(){self.triggerEvent('shown.oc.popup')}) +this.$modal.on('close.oc.popup',function(){self.hide() +return false})} +Popup.prototype.dispose=function(){this.$modal.off('hide.bs.modal') +this.$modal.off('hidden.bs.modal') +this.$modal.off('show.bs.modal') +this.$modal.off('shown.bs.modal') +this.$modal.off('close.oc.popup') +this.$el.off('dispose-control',this.proxy(this.dispose)) +this.$el.removeData('oc.popup') +this.$container.removeData('oc.popup') +this.$container=null +this.$content=null +this.$dialog=null +this.$modal=null +this.$el=null +this.options=null +BaseProto.dispose.call(this)} Popup.prototype.createPopupContainer=function(){var modal=$('').prop({class:'control-popup modal fade',role:'dialog',tabindex:-1}),modalDialog=$('').addClass('modal-dialog'),modalContent=$('').addClass('modal-content') if(this.options.size) @@ -3467,16 +3486,17 @@ Popup.prototype.setLoading=function(val){if(!this.$backdrop) return;var self=this if(val){setTimeout(function(){self.$backdrop.addClass('loading');},100)} else{this.$backdrop.removeClass('loading');}} +Popup.prototype.setShake=function(){var self=this +this.$content.addClass('popup-shaking') +setTimeout(function(){self.$content.removeClass('popup-shaking')},1000)} Popup.prototype.hideLoading=function(val){this.setLoading(false) var self=this setTimeout(function(){self.setBackdrop(false)},250) setTimeout(function(){self.hide()},500)} -Popup.prototype.triggerEvent=function(eventName,params){if(!params) -params=[this.$el,this.$modal] +Popup.prototype.triggerEvent=function(eventName,params){if(!params){params=[this.$el,this.$modal]} var eventObject=jQuery.Event(eventName,{relatedTarget:this.$container.get(0)}) this.$el.trigger(eventObject,params) -if(this.firstDiv) -this.firstDiv.trigger(eventObject,params)} +if(this.firstDiv){this.firstDiv.trigger(eventObject,params)}} Popup.prototype.reload=function(){this.init()} Popup.prototype.show=function(){this.$modal.modal('show') this.$modal.on('click.dismiss.popup','[data-dismiss="popup"]',$.proxy(this.hide,this)) @@ -3488,10 +3508,8 @@ this.triggerEvent('hide.oc.popup') if(this.allowHide) this.$modal.modal('hide') this.$dialog.css('transform','')} -Popup.prototype.visible=function(val){if(val) -this.$modal.addClass('in') -else -this.$modal.removeClass('in') +Popup.prototype.visible=function(val){if(val){this.$modal.addClass('in')} +else{this.$modal.removeClass('in')} this.setBackdrop(val)} Popup.prototype.toggle=function(){this.triggerEvent('popupToggle',[this.$modal]) this.triggerEvent('toggle.oc.popup',[this.$modal]) @@ -3516,7 +3534,7 @@ catch(e){throw new Error('Error parsing the '+name+' attribute value. '+e)}} $(document).on('click.oc.popup','[data-control="popup"]',function(event){event.preventDefault() $(this).popup()});$(document).on('ajaxPromise','[data-popup-load-indicator]',function(event,context){if($(this).data('request')!=context.handler)return $(this).closest('.control-popup').removeClass('in').popup('setLoading',true)}).on('ajaxFail','[data-popup-load-indicator]',function(event,context){if($(this).data('request')!=context.handler)return -$(this).closest('.control-popup').addClass('in').popup('setLoading',false)}).on('ajaxDone','[data-popup-load-indicator]',function(event,context){if($(this).data('request')!=context.handler)return +$(this).closest('.control-popup').addClass('in').popup('setLoading',false).popup('setShake')}).on('ajaxDone','[data-popup-load-indicator]',function(event,context){if($(this).data('request')!=context.handler)return $(this).closest('.control-popup').popup('hideLoading')})}(window.jQuery);+function($){"use strict";var ChartUtils=function(){} ChartUtils.prototype.defaultValueColor='#b8b8b8';ChartUtils.prototype.getColor=function(index){var colors=['#95b753','#cc3300','#e5a91a','#3366ff','#ff0f00','#ff6600','#ff9e01','#fcd202','#f8ff01','#b0de09','#04d215','#0d8ecf','#0d52d1','#2a0cd0','#8a0ccf','#cd0d74','#754deb','#dddddd','#999999','#333333','#000000','#57032a','#ca9726','#990000','#4b0c25'],colorIndex=index%(colors.length-1);return colors[colorIndex];} diff --git a/modules/system/assets/ui/storm.css b/modules/system/assets/ui/storm.css index 4e8bb854e..12498129a 100644 --- a/modules/system/assets/ui/storm.css +++ b/modules/system/assets/ui/storm.css @@ -2810,6 +2810,7 @@ ul.autocomplete.dropdown-menu.inspector-autocomplete li a{padding:5px 12px;white @media (min-width:992px){.modal-lg{width:900px} } .modal-content{-webkit-box-shadow:0 27px 24px 0 rgba(0,0,0,0.2),0 40px 77px 0 rgba(0,0,0,0.22);box-shadow:0 27px 24px 0 rgba(0,0,0,0.2),0 40px 77px 0 rgba(0,0,0,0.22);-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;border:none;background:#f9f9f9} +.modal-content.popup-shaking{-webkit-animation:popup-shake 0.82s cubic-bezier(0.36,0.07000000000000001,0.19,0.97) both;animation:popup-shake 0.82s cubic-bezier(0.36,0.07000000000000001,0.19,0.97) both;-webkit-transform:translate3d(0,0,0);-ms-transform:translate3d(0,0,0);transform:translate3d(0,0,0);-webkit-backface-visibility:hidden;-moz-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;-moz-perspective:1000px;perspective:1000px} .modal-header{background:transparent;color:#2a3e51;text-shadow:0 1px 0 rgba(255,255,255,0.35);border-top-right-radius:3px;border-top-left-radius:3px;padding:20px 20px;border:none} .modal-header h4{font-weight:normal;font-size:18px} .modal-footer{background:transparent;border:none;margin-top:0;padding:0 20px 20px 20px} @@ -2836,6 +2837,21 @@ ul.autocomplete.dropdown-menu.inspector-autocomplete li a{padding:5px 12px;white .popup-backdrop .popup-loading-indicator:after{content:' ';display:block;background-size:50px 50px;background-repeat:no-repeat;background-position:50% 50%;background-image:url('images/loader-transparent.svg');-webkit-animation:spin 1s linear infinite;animation:spin 1s linear infinite;width:50px;height:50px;margin:25px 0 0 25px} .popup-backdrop.loading .popup-loading-indicator{opacity:1;filter:alpha(opacity=100);-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)} .mac body.modal-open{margin-right:0} +@-moz-keyframes popup-shake{10%,90%{-moz-transform:translate3d(-1px,0,0)} +20%,80%{-moz-transform:translate3d(2px,0,0)} +30%,50%,70%{-moz-transform:translate3d(-4px,0,0)} +40%,60%{-moz-transform:translate3d(4px,0,0)} +} +@-webkit-keyframes popup-shake{10%,90%{-webkit-transform:translate3d(-1px,0,0)} +20%,80%{-webkit-transform:translate3d(2px,0,0)} +30%,50%,70%{-webkit-transform:translate3d(-4px,0,0)} +40%,60%{-webkit-transform:translate3d(4px,0,0)} +} +@keyframes popup-shake{10%,90%{transform:translate3d(-1px,0,0)} +20%,80%{transform:translate3d(2px,0,0)} +30%,50%,70%{transform:translate3d(-4px,0,0)} +40%,60%{transform:translate3d(4px,0,0)} +} .pika-single{display:block;position:relative;width:240px;padding:8px;color:#333;background:#fff} .pika-single.is-hidden{display:none} .pika-single.is-bound{position:absolute;box-shadow:0 5px 15px -5px rgba(0,0,0,0.5)}