Popup will now shake when an error occurs

Improve memory management / garbage collection
This commit is contained in:
Samuel Georges 2016-08-26 20:01:04 +10:00
parent 58ed3e12d2
commit 89e390edcc
4 changed files with 189 additions and 75 deletions

View File

@ -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 = $('<div />').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

View File

@ -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); }
}

View File

@ -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=$('<div />').prop({class:'control-popup modal fade',role:'dialog',tabindex:-1}),modalDialog=$('<div />').addClass('modal-dialog'),modalContent=$('<div />').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];}

View File

@ -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)}