From 48feffd60a3f3c3a248744a6f761ac65b90a8262 Mon Sep 17 00:00:00 2001 From: alekseybobkov Date: Thu, 29 Oct 2015 22:01:29 -0700 Subject: [PATCH 01/19] Added live update mode for Inspector. --- .../assets/ui/js/inspector.editor.base.js | 6 ++- .../assets/ui/js/inspector.editor.object.js | 4 +- .../ui/js/inspector.editor.stringlist.js | 1 - .../js/inspector.externalparametereditor.js | 8 +-- .../system/assets/ui/js/inspector.surface.js | 40 +++++++++++++-- .../assets/ui/js/inspector.wrapper.base.js | 26 ++++++++-- .../ui/js/inspector.wrapper.container.js | 20 ++++++++ modules/system/assets/ui/storm-min.js | 49 +++++++++++++------ 8 files changed, 123 insertions(+), 31 deletions(-) diff --git a/modules/system/assets/ui/js/inspector.editor.base.js b/modules/system/assets/ui/js/inspector.editor.base.js index 915ed0d7f..46d1030b6 100644 --- a/modules/system/assets/ui/js/inspector.editor.base.js +++ b/modules/system/assets/ui/js/inspector.editor.base.js @@ -127,7 +127,7 @@ return this.inspector.getPropertyValue(this.propertyDefinition.property) } - BaseEditor.prototype.validate = function() { + BaseEditor.prototype.validate = function(silentMode) { var value = this.getValueToValidate() if (value === undefined) { @@ -136,7 +136,9 @@ var validationResult = this.validationSet.validate(value) if (validationResult !== null) { - $.oc.flashMsg({text: validationResult, 'class': 'error', 'interval': 5}) + if (!silentMode) { + $.oc.flashMsg({text: validationResult, 'class': 'error', 'interval': 5}) + } return false } diff --git a/modules/system/assets/ui/js/inspector.editor.object.js b/modules/system/assets/ui/js/inspector.editor.object.js index 31ffe2c3c..ea9349c26 100644 --- a/modules/system/assets/ui/js/inspector.editor.object.js +++ b/modules/system/assets/ui/js/inspector.editor.object.js @@ -120,7 +120,7 @@ return this.getValueOrRemove(result) } - ObjectEditor.prototype.validate = function() { + ObjectEditor.prototype.validate = function(silentMode) { var values = values = this.childInspector.getValues() if (this.cleanUpValue(values) === $.oc.inspector.removedProperty) { @@ -130,7 +130,7 @@ return true } - return this.childInspector.validate() + return this.childInspector.validate(silentMode) } // diff --git a/modules/system/assets/ui/js/inspector.editor.stringlist.js b/modules/system/assets/ui/js/inspector.editor.stringlist.js index ee03a74ac..2779e750c 100644 --- a/modules/system/assets/ui/js/inspector.editor.stringlist.js +++ b/modules/system/assets/ui/js/inspector.editor.stringlist.js @@ -88,7 +88,6 @@ } this.inspector.setPropertyValue(this.propertyDefinition.property, resultValue) -// TODO: validate here } $.oc.inspector.propertyEditors.stringList = StringListEditor diff --git a/modules/system/assets/ui/js/inspector.externalparametereditor.js b/modules/system/assets/ui/js/inspector.externalparametereditor.js index 95f1acdc2..d373a9dcb 100644 --- a/modules/system/assets/ui/js/inspector.externalparametereditor.js +++ b/modules/system/assets/ui/js/inspector.externalparametereditor.js @@ -241,12 +241,14 @@ this.getInput().focus() } - ExternalParameterEditor.prototype.validate = function() { + ExternalParameterEditor.prototype.validate = function(silentMode) { var value = $.trim(this.getValue()) if (value.length === 0) { - $.oc.flashMsg({text: 'Please enter the external parameter name.', 'class': 'error', 'interval': 5}) - this.focus() + if (!silentMode) { + $.oc.flashMsg({text: 'Please enter the external parameter name.', 'class': 'error', 'interval': 5}) + this.focus() + } return false } diff --git a/modules/system/assets/ui/js/inspector.surface.js b/modules/system/assets/ui/js/inspector.surface.js index 4c6d78e75..c6d5b24d3 100644 --- a/modules/system/assets/ui/js/inspector.surface.js +++ b/modules/system/assets/ui/js/inspector.surface.js @@ -797,7 +797,33 @@ return result } - Surface.prototype.validate = function() { + Surface.prototype.getValidValues = function() { + var allValues = this.getValues(), + result = {} + + for (var property in allValues) { + var editor = this.findPropertyEditor(property) + + if (!editor) { + throw new Error('Cannot find editor for property ' + property) + } + + var externalEditor = this.findExternalParameterEditor(property) + if (externalEditor && externalEditor.isEditorVisible() && !externalEditor.validate(true)) { + continue + } + + if (!editor.validate(true)) { + continue + } + + result[property] = allValues[property] + } + + return result + } + + Surface.prototype.validate = function(silentMode) { this.getGroupManager().unmarkInvalidGroups(this.getRootTable()) for (var i = 0, len = this.editors.length; i < len; i++) { @@ -805,8 +831,10 @@ externalEditor = this.findExternalParameterEditor(editor.propertyDefinition.property) if (externalEditor && externalEditor.isEditorVisible()) { - if (!externalEditor.validate()) { - editor.markInvalid() + if (!externalEditor.validate(silentMode)) { + if (!silentMode) { + editor.markInvalid() + } return false } else { @@ -814,8 +842,10 @@ } } - if (!editor.validate()) { - editor.markInvalid() + if (!editor.validate(silentMode)) { + if (!silentMode) { + editor.markInvalid() + } return false } } diff --git a/modules/system/assets/ui/js/inspector.wrapper.base.js b/modules/system/assets/ui/js/inspector.wrapper.base.js index d3d020062..5d3c6acc1 100644 --- a/modules/system/assets/ui/js/inspector.wrapper.base.js +++ b/modules/system/assets/ui/js/inspector.wrapper.base.js @@ -23,6 +23,7 @@ this.options = $.extend({}, BaseWrapper.DEFAULTS, typeof options == 'object' && options) this.switched = false + this.configuration = null Base.call(this) @@ -63,6 +64,7 @@ this.$element = null this.title = null this.description = null + this.configuration = null BaseProto.dispose.call(this) } @@ -194,9 +196,21 @@ return values } - BaseWrapper.prototype.applyValues = function() { + BaseWrapper.prototype.applyValues = function(liveUpdateMode) { var $valuesField = this.getElementValuesInput(), - values = this.surface.getValues() + values = liveUpdateMode ? + this.surface.getValidValues() : + this.surface.getValues() + + if (liveUpdateMode) { + // In the live update mode, when only valid values are applied, + // we don't want to change all other values (invalid properties), + // so we merge existing values with the valid values. + + var existingValues = this.loadValues(this.configuration) + + values = $.extend(existingValues, values) + } if ($valuesField.length > 0) { $valuesField.val(JSON.stringify(values)) @@ -214,7 +228,12 @@ } if (this.surface.hasChanges()) { - this.$element.trigger('change') + if (!liveUpdateMode) { + this.$element.trigger('change') + } + else { + this.$element.trigger('livechange') + } } } @@ -284,6 +303,7 @@ this.title = configuration.title this.description = configuration.description + this.configuration = configuration this.createSurfaceAndUi(configuration.properties, values) } diff --git a/modules/system/assets/ui/js/inspector.wrapper.container.js b/modules/system/assets/ui/js/inspector.wrapper.container.js index 8ed49dfbb..5031e2aee 100644 --- a/modules/system/assets/ui/js/inspector.wrapper.container.js +++ b/modules/system/assets/ui/js/inspector.wrapper.container.js @@ -41,12 +41,20 @@ this.buildUi() this.initSurface(this.surfaceContainer, properties, values) + + if (this.isLiveUpdateEnabled()) { + this.surface.options.onChange = this.proxy(this.onLiveUpdate) + } } InspectorContainer.prototype.adoptSurface = function() { this.buildUi() this.surface.moveToContainer(this.surfaceContainer) + + if (this.isLiveUpdateEnabled()) { + this.surface.options.onChange = this.proxy(this.onLiveUpdate) + } } InspectorContainer.prototype.buildUi = function() { @@ -155,6 +163,10 @@ return this.options.container.data('inspector-scrollable') !== undefined } + InspectorContainer.prototype.isLiveUpdateEnabled = function() { + return this.options.container.data('inspector-live-update') !== undefined + } + InspectorContainer.prototype.getLayout = function() { return this.options.container.get(0).querySelector('div.layout') } @@ -181,6 +193,10 @@ $layout.off('dispose-control', this.proxy(this.dispose)) $layout.off('click', 'span.close', this.proxy(this.onClose)) $layout.off('click', 'span.detach', this.proxy(this.onDetach)) + + if (this.surface !== null && this.surface.options.onChange === this.proxy(this.onLiveUpdate)) { + this.surface.options.onChange = null + } } InspectorContainer.prototype.removeControls = function() { @@ -222,6 +238,10 @@ this.dispose() } + InspectorContainer.prototype.onLiveUpdate = function() { + this.applyValues(true) + } + InspectorContainer.prototype.onDetach = function() { $.oc.inspector.manager.switchToPopup(this) } diff --git a/modules/system/assets/ui/storm-min.js b/modules/system/assets/ui/storm-min.js index 3387a36d1..32268461d 100644 --- a/modules/system/assets/ui/storm-min.js +++ b/modules/system/assets/ui/storm-min.js @@ -3567,12 +3567,20 @@ else{value=externalParameterEditor.getValue() value='{{ '+value+' }}'} result[property.property]=value} return result} -Surface.prototype.validate=function(){this.getGroupManager().unmarkInvalidGroups(this.getRootTable()) +Surface.prototype.getValidValues=function(){var allValues=this.getValues(),result={} +for(var property in allValues){var editor=this.findPropertyEditor(property) +if(!editor){throw new Error('Cannot find editor for property '+property)} +var externalEditor=this.findExternalParameterEditor(property) +if(externalEditor&&externalEditor.isEditorVisible()&&!externalEditor.validate(true)){continue} +if(!editor.validate(true)){continue} +result[property]=allValues[property]} +return result} +Surface.prototype.validate=function(silentMode){this.getGroupManager().unmarkInvalidGroups(this.getRootTable()) for(var i=0,len=this.editors.length;i0){$valuesField.val(JSON.stringify(values))} else{for(var property in values){var value=values[property] if($.isArray(value)||$.isPlainObject(value)){throw new Error('Inspector data-property-xxx attributes do not support complex values. Property: '+property)} this.$element.attr('data-property-'+property,value)}} -if(this.surface.hasChanges()){this.$element.trigger('change')}} +if(this.surface.hasChanges()){if(!liveUpdateMode){this.$element.trigger('change')} +else{this.$element.trigger('livechange')}}} BaseWrapper.prototype.loadConfiguration=function(){var configString=this.$element.data('inspector-config'),result={properties:{},title:null,description:null} result.title=this.$element.data('inspector-title') result.description=this.$element.data('inspector-description') @@ -3709,6 +3722,7 @@ try{return $.parseJSON(configuration)}catch(err){throw new Error('Error parsing BaseWrapper.prototype.configurationLoaded=function(configuration){var values=this.loadValues(configuration.properties) this.title=configuration.title this.description=configuration.description +this.configuration=configuration this.createSurfaceAndUi(configuration.properties,values)} BaseWrapper.prototype.onConfigurartionRequestDone=function(data,result){result.properties=this.parseConfiguration(data.configuration.properties) if(data.configuration.title!==undefined){result.title=data.configuration.title} @@ -3815,9 +3829,11 @@ this.removeControls() this.surfaceContainer=null BaseProto.dispose.call(this)} InspectorContainer.prototype.createSurfaceAndUi=function(properties,values){this.buildUi() -this.initSurface(this.surfaceContainer,properties,values)} +this.initSurface(this.surfaceContainer,properties,values) +if(this.isLiveUpdateEnabled()){this.surface.options.onChange=this.proxy(this.onLiveUpdate)}} InspectorContainer.prototype.adoptSurface=function(){this.buildUi() -this.surface.moveToContainer(this.surfaceContainer)} +this.surface.moveToContainer(this.surfaceContainer) +if(this.isLiveUpdateEnabled()){this.surface.options.onChange=this.proxy(this.onLiveUpdate)}} InspectorContainer.prototype.buildUi=function(){var scrollable=this.isScrollable(),head=this.buildHead(),layoutElements=this.buildLayout() layoutElements.headContainer.appendChild(head) if(scrollable){var scrollpad=this.buildScrollpad() @@ -3862,6 +3878,7 @@ InspectorContainer.prototype.validateAndApply=function(){if(!this.surface.valida this.applyValues() return true} InspectorContainer.prototype.isScrollable=function(){return this.options.container.data('inspector-scrollable')!==undefined} +InspectorContainer.prototype.isLiveUpdateEnabled=function(){return this.options.container.data('inspector-live-update')!==undefined} InspectorContainer.prototype.getLayout=function(){return this.options.container.get(0).querySelector('div.layout')} InspectorContainer.prototype.registerLayoutHandlers=function(layout){var $layout=$(layout) $layout.one('dispose-control',this.proxy(this.dispose)) @@ -3874,7 +3891,8 @@ this.options.container.off('apply.oc.inspector',this.proxy(this.onApplyValues)) this.options.container.off('beforeContainerHide.oc.inspector',this.proxy(this.onBeforeHide)) $layout.off('dispose-control',this.proxy(this.dispose)) $layout.off('click','span.close',this.proxy(this.onClose)) -$layout.off('click','span.detach',this.proxy(this.onDetach))} +$layout.off('click','span.detach',this.proxy(this.onDetach)) +if(this.surface!==null&&this.surface.options.onChange===this.proxy(this.onLiveUpdate)){this.surface.options.onChange=null}} InspectorContainer.prototype.removeControls=function(){if(this.isScrollable()){this.options.container.find('.control-scrollpad').scrollpad('dispose')} var layout=this.getLayout() layout.parentNode.removeChild(layout)} @@ -3888,6 +3906,7 @@ if(!this.triggerHiding()){ev.preventDefault() return false} this.surface.dispose() this.dispose()} +InspectorContainer.prototype.onLiveUpdate=function(){this.applyValues(true)} InspectorContainer.prototype.onDetach=function(){$.oc.inspector.manager.switchToPopup(this)} $.oc.inspector.wrappers.container=InspectorContainer}(window.jQuery);+function($){"use strict";var GroupManager=function(controlId){this.controlId=controlId this.rootGroup=null @@ -4039,10 +4058,10 @@ BaseEditor.prototype.throwError=function(errorMessage){throw new Error(errorMess BaseEditor.prototype.initValidation=function(){this.validationSet=new $.oc.inspector.validationSet(this.propertyDefinition,this.propertyDefinition.property)} BaseEditor.prototype.disposeValidation=function(){this.validationSet.dispose()} BaseEditor.prototype.getValueToValidate=function(){return this.inspector.getPropertyValue(this.propertyDefinition.property)} -BaseEditor.prototype.validate=function(){var value=this.getValueToValidate() +BaseEditor.prototype.validate=function(silentMode){var value=this.getValueToValidate() if(value===undefined){value=this.getUndefinedValue()} var validationResult=this.validationSet.validate(value) -if(validationResult!==null){$.oc.flashMsg({text:validationResult,'class':'error','interval':5}) +if(validationResult!==null){if(!silentMode){$.oc.flashMsg({text:validationResult,'class':'error','interval':5})} return false} return true} BaseEditor.prototype.markInvalid=function(){$.oc.foundation.element.addClass(this.containerRow,'invalid') @@ -4681,9 +4700,9 @@ ObjectEditor.prototype.getUndefinedValue=function(){var result={} for(var i=0,len=this.propertyDefinition.properties.length;i Date: Fri, 30 Oct 2015 23:01:35 -0700 Subject: [PATCH 02/19] Minor style fix in the fancy layout tabs. Improved live update mode in Inspector. --- modules/backend/assets/css/october.css | 2 +- modules/backend/assets/less/layout/fancylayout.less | 2 +- modules/system/assets/ui/js/inspector.wrapper.base.js | 6 +++++- modules/system/assets/ui/storm-min.js | 2 +- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/modules/backend/assets/css/october.css b/modules/backend/assets/css/october.css index 96eeff815..3661b3254 100644 --- a/modules/backend/assets/css/october.css +++ b/modules/backend/assets/css/october.css @@ -782,7 +782,7 @@ html.csstransitions body.outer.preload .outer-form-container{-webkit-transform:s .fancy-layout .control-tabs.master-tabs > div > div.tabs-container > ul.nav-tabs > li.active a > span.title,.fancy-layout.control-tabs.master-tabs > div > div.tabs-container > ul.nav-tabs > li.active a > span.title{background-color:#e67e22;z-index:105} .fancy-layout .control-tabs.master-tabs > div > div.tabs-container > ul.nav-tabs > li.active a > span.title:before,.fancy-layout.control-tabs.master-tabs > div > div.tabs-container > ul.nav-tabs > li.active a > span.title:before{background-position:left -40px;z-index:107} .fancy-layout .control-tabs.master-tabs > div > div.tabs-container > ul.nav-tabs > li.active a > span.title:after,.fancy-layout.control-tabs.master-tabs > div > div.tabs-container > ul.nav-tabs > li.active a > span.title:after{background-position:-80px -40px;z-index:107} -.fancy-layout .control-tabs.master-tabs > div > div.tabs-container > ul.nav-tabs > li[data-modified] span.tab-close i,.fancy-layout.control-tabs.master-tabs > div > div.tabs-container > ul.nav-tabs > li[data-modified] span.tab-close i{top:4px;font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0} +.fancy-layout .control-tabs.master-tabs > div > div.tabs-container > ul.nav-tabs > li[data-modified] span.tab-close i,.fancy-layout.control-tabs.master-tabs > div > div.tabs-container > ul.nav-tabs > li[data-modified] span.tab-close i{top:3px;font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0} .fancy-layout .control-tabs.master-tabs > div > div.tabs-container > ul.nav-tabs > li[data-modified] span.tab-close i:before,.fancy-layout.control-tabs.master-tabs > div > div.tabs-container > ul.nav-tabs > li[data-modified] span.tab-close i:before{font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f111";font-size:9px} .fancy-layout .control-tabs.master-tabs > div > div.tabs-container > ul.nav-tabs > li:first-child,.fancy-layout.control-tabs.master-tabs > div > div.tabs-container > ul.nav-tabs > li:first-child{margin-left:0} .fancy-layout .control-tabs.master-tabs[data-closable] > div > div.tabs-container > ul.nav-tabs > li a > span.title,.fancy-layout.control-tabs.master-tabs[data-closable] > div > div.tabs-container > ul.nav-tabs > li a > span.title{padding-right:10px} diff --git a/modules/backend/assets/less/layout/fancylayout.less b/modules/backend/assets/less/layout/fancylayout.less index 8c4d5c4bb..630751d82 100644 --- a/modules/backend/assets/less/layout/fancylayout.less +++ b/modules/backend/assets/less/layout/fancylayout.less @@ -146,7 +146,7 @@ &[data-modified] { span.tab-close i { - top: 4px; + top: 3px; .hide-text(); &:before { diff --git a/modules/system/assets/ui/js/inspector.wrapper.base.js b/modules/system/assets/ui/js/inspector.wrapper.base.js index 5d3c6acc1..4330ae0b9 100644 --- a/modules/system/assets/ui/js/inspector.wrapper.base.js +++ b/modules/system/assets/ui/js/inspector.wrapper.base.js @@ -227,7 +227,11 @@ } } - if (this.surface.hasChanges()) { + // In the live update mode the livechange event is triggered + // regardless of whether Surface properties match or don't match + // the original properties of the inspectable element. Without it + // there could be undesirable side effects. + if (this.surface.hasChanges() || liveUpdateMode) { if (!liveUpdateMode) { this.$element.trigger('change') } diff --git a/modules/system/assets/ui/storm-min.js b/modules/system/assets/ui/storm-min.js index 32268461d..bef8c986a 100644 --- a/modules/system/assets/ui/storm-min.js +++ b/modules/system/assets/ui/storm-min.js @@ -3702,7 +3702,7 @@ if($valuesField.length>0){$valuesField.val(JSON.stringify(values))} else{for(var property in values){var value=values[property] if($.isArray(value)||$.isPlainObject(value)){throw new Error('Inspector data-property-xxx attributes do not support complex values. Property: '+property)} this.$element.attr('data-property-'+property,value)}} -if(this.surface.hasChanges()){if(!liveUpdateMode){this.$element.trigger('change')} +if(this.surface.hasChanges()||liveUpdateMode){if(!liveUpdateMode){this.$element.trigger('change')} else{this.$element.trigger('livechange')}}} BaseWrapper.prototype.loadConfiguration=function(){var configString=this.$element.data('inspector-config'),result={properties:{},title:null,description:null} result.title=this.$element.data('inspector-title') From 2d849b264019b21710eb4fa5027bda838d2fb4ba Mon Sep 17 00:00:00 2001 From: alekseybobkov Date: Tue, 3 Nov 2015 22:02:10 -0800 Subject: [PATCH 03/19] Implemented Inspector ignoreIfEmpty and ignoreIfDefault properties. Minor refactoring of Inspector. --- .../ui/js/inspector.editor.autocomplete.js | 29 +++++- .../assets/ui/js/inspector.editor.base.js | 12 +++ .../assets/ui/js/inspector.editor.dropdown.js | 34 ++++++- .../assets/ui/js/inspector.editor.object.js | 11 +-- .../assets/ui/js/inspector.editor.set.js | 22 ++--- .../system/assets/ui/js/inspector.surface.js | 59 ++++++++++-- .../assets/ui/js/inspector.wrapper.base.js | 64 +++++++++++-- .../ui/js/inspector.wrapper.container.js | 2 + .../assets/ui/js/inspector.wrapper.popup.js | 2 + modules/system/assets/ui/storm-min.js | 89 ++++++++++++++----- 10 files changed, 266 insertions(+), 58 deletions(-) diff --git a/modules/system/assets/ui/js/inspector.editor.autocomplete.js b/modules/system/assets/ui/js/inspector.editor.autocomplete.js index 4f79a1b6a..c80524cce 100644 --- a/modules/system/assets/ui/js/inspector.editor.autocomplete.js +++ b/modules/system/assets/ui/js/inspector.editor.autocomplete.js @@ -139,6 +139,10 @@ $.oc.foundation.element.addClass(container, 'loading-indicator-container size-small') this.showLoadingIndicator() + if (this.triggerGetItems(data) === false) { + return + } + data['inspectorProperty'] = this.propertyDefinition.property data['inspectorClassName'] = this.inspector.options.inspectorClass @@ -149,13 +153,36 @@ .always(this.proxy(this.hideLoadingIndicator)) } - AutocompleteEditor.prototype.itemsRequestDone = function(data, currentValue, initialization) { + AutocompleteEditor.prototype.triggerGetItems = function(values) { + var $inspectable = this.getInspectableElement() + if (!$inspectable) { + return true + } + + var itemsEvent = $.Event('autocompleteitems.oc.inspector') + + $inspectable.trigger(itemsEvent, [{ + values: values, + callback: this.proxy(this.itemsRequestDone), + property: this.inspector.getPropertyPath(this.propertyDefinition.property) + }]) + + if (itemsEvent.isDefaultPrevented()) { + return false + } + + return true + } + + AutocompleteEditor.prototype.itemsRequestDone = function(data) { if (this.isDisposed()) { // Handle the case when the asynchronous request finishes after // the editor is disposed return } + this.hideLoadingIndicator() + var loadedItems = {} if (data.options) { diff --git a/modules/system/assets/ui/js/inspector.editor.base.js b/modules/system/assets/ui/js/inspector.editor.base.js index 46d1030b6..5bdf6dfbe 100644 --- a/modules/system/assets/ui/js/inspector.editor.base.js +++ b/modules/system/assets/ui/js/inspector.editor.base.js @@ -111,6 +111,18 @@ throw new Error(errorMessage + ' Property: ' + this.propertyDefinition.property) } + BaseEditor.prototype.getInspectableElement = function() { + return this.getRootSurface().getInspectableElement() + } + + BaseEditor.prototype.isEmptyValue = function(value) { + return value === undefined + || value === null + || $.isEmptyObject(value) + || (typeof value == 'string' && $.trim(value).length === 0) + || (Object.prototype.toString.call(value) === '[object Array]' && value.length === 0) + } + // // Validation // diff --git a/modules/system/assets/ui/js/inspector.editor.dropdown.js b/modules/system/assets/ui/js/inspector.editor.dropdown.js index 2e97fdbc3..02fd3eec7 100644 --- a/modules/system/assets/ui/js/inspector.editor.dropdown.js +++ b/modules/system/assets/ui/js/inspector.editor.dropdown.js @@ -247,6 +247,11 @@ currentValue = this.propertyDefinition.default } + var callback = function dropdownOptionsRequestDoneClosure(data) { + self.hideLoadingIndicator() + self.optionsRequestDone(data, currentValue, true) + } + if (this.propertyDefinition.depends) { this.saveDependencyValues() } @@ -256,15 +261,38 @@ this.showLoadingIndicator() + if (this.triggerGetOptions(data, callback) === false) { + return + } + $form.request('onInspectableGetOptions', { data: data, - }).done(function dropdownOptionsRequestDoneClosure(data) { - self.optionsRequestDone(data, currentValue, true) - }).always( + }).done(callback).always( this.proxy(this.hideLoadingIndicator) ) } + DropdownEditor.prototype.triggerGetOptions = function(values, callback) { + var $inspectable = this.getInspectableElement() + if (!$inspectable) { + return true + } + + var optionsEvent = $.Event('dropdownoptions.oc.inspector') + + $inspectable.trigger(optionsEvent, [{ + values: values, + callback: callback, + property: this.inspector.getPropertyPath(this.propertyDefinition.property) + }]) + + if (optionsEvent.isDefaultPrevented()) { + return false + } + + return true + } + DropdownEditor.prototype.saveDependencyValues = function() { this.prevDependencyValues = this.getDependencyValues() } diff --git a/modules/system/assets/ui/js/inspector.editor.object.js b/modules/system/assets/ui/js/inspector.editor.object.js index ea9349c26..d88c28118 100644 --- a/modules/system/assets/ui/js/inspector.editor.object.js +++ b/modules/system/assets/ui/js/inspector.editor.object.js @@ -49,7 +49,8 @@ this.inspector.getInspectorUniqueId() + '-' + this.propertyDefinition.property, options, this.inspector, - this.group) + this.group, + this.propertyDefinition.property) this.inspector.mergeChildSurface(this.childInspector, currentRow) } @@ -70,14 +71,6 @@ return this.getValueOrRemove(value) } - ObjectEditor.prototype.isEmptyValue = function(value) { - return value === undefined - || value === null - || $.isEmptyObject(value) - || (typeof value == 'string' && $.trim(value).length === 0) - || (Object.prototype.toString.call(value) === '[object Array]' && value.length === 0) - } - ObjectEditor.prototype.getValueOrRemove = function(value) { if (this.propertyDefinition.ignoreIfPropertyEmpty === undefined) { return value diff --git a/modules/system/assets/ui/js/inspector.editor.set.js b/modules/system/assets/ui/js/inspector.editor.set.js index b63e3f416..3bffc4d7c 100644 --- a/modules/system/assets/ui/js/inspector.editor.set.js +++ b/modules/system/assets/ui/js/inspector.editor.set.js @@ -318,19 +318,21 @@ currentValue = [] } - if (isChecked) { - if (currentValue.indexOf(checkboxValue) === -1) { - currentValue.push(checkboxValue) - } - } - else { - var index = currentValue.indexOf(checkboxValue) - if (index !== -1) { - currentValue.splice(index, 1) + var resultValue = [] + for (var itemValue in this.propertyDefinition.items) { + if (itemValue !== checkboxValue) { + if (currentValue.indexOf(itemValue) !== -1) { + resultValue.push(itemValue) + } + } + else { + if (isChecked) { + resultValue.push(itemValue) + } } } - this.inspector.setPropertyValue(this.propertyDefinition.property, this.cleanUpValue(currentValue)) + this.inspector.setPropertyValue(this.propertyDefinition.property, this.cleanUpValue(resultValue)) this.setLinkText(this.getLink()) } diff --git a/modules/system/assets/ui/js/inspector.surface.js b/modules/system/assets/ui/js/inspector.surface.js index c6d5b24d3..25cd1cf6e 100644 --- a/modules/system/assets/ui/js/inspector.surface.js +++ b/modules/system/assets/ui/js/inspector.surface.js @@ -35,7 +35,7 @@ * not associated with an element. Inspector uses the ID for storing configuration * related to an element in the document DOM. */ - var Surface = function(containerElement, properties, values, inspectorUniqueId, options, parentSurface, group) { + var Surface = function(containerElement, properties, values, inspectorUniqueId, options, parentSurface, group, propertyName) { if (inspectorUniqueId === undefined) { throw new Error('Inspector surface unique ID should be defined.') } @@ -50,6 +50,7 @@ this.idCounter = 1 this.popupCounter = 0 this.parentSurface = parentSurface + this.propertyName = propertyName this.editors = [] this.externalParameterEditors = [] @@ -91,6 +92,7 @@ this.options.onChange = null this.options.onPopupDisplayed = null this.options.onPopupHidden = null + this.options.onGetInspectableElement = null this.parentSurface = null this.groupManager = null this.group = null @@ -482,8 +484,6 @@ var editor = new $.oc.inspector.propertyEditors[type](this, property, cell, group) if (editor.isGroupedEditor()) { -// property.groupedControl = true - $.oc.foundation.element.addClass(dataTable, 'has-groups') $.oc.foundation.element.addClass(row, 'control-group') @@ -642,6 +642,31 @@ } } + Surface.prototype.getInspectableElement = function() { + if (this.options.onGetInspectableElement !== null) { + return this.options.onGetInspectableElement() + } + } + + Surface.prototype.getPropertyPath = function(propertyName) { + var result = [], + current = this + + result.push(propertyName) + + while (current) { + if (current.propertyName) { + result.push(current.propertyName) + } + + current = current.parentSurface + } + + result.reverse() + + return result.join('.') + } + // // Nested surfaces support // @@ -785,6 +810,22 @@ if (value === $.oc.inspector.removedProperty) { continue } + + if (property.ignoreIfEmpty !== undefined && (property.ignoreIfEmpty === true || property.ignoreIfEmpty === "true") && editor) { + if (editor.isEmptyValue(value)) { + continue + } + } + + if (property.ignoreIfDefault !== undefined && (property.ignoreIfDefault === true || property.ignoreIfDefault === "true") && editor) { + if (property.default === undefined) { + throw new Error('The ignoreIfDefault feature cannot be used without the default property value.') + } + + if (this.comparePropertyValues(value, property.default)) { + continue + } + } } else { value = externalParameterEditor.getValue() @@ -810,10 +851,12 @@ var externalEditor = this.findExternalParameterEditor(property) if (externalEditor && externalEditor.isEditorVisible() && !externalEditor.validate(true)) { + result[property] = $.oc.inspector.invalidProperty continue } if (!editor.validate(true)) { + result[property] = $.oc.inspector.invalidProperty continue } @@ -853,8 +896,10 @@ return true } - Surface.prototype.hasChanges = function() { - return !this.comparePropertyValues(this.originalValues, this.values) + Surface.prototype.hasChanges = function(originalValues) { + var values = originalValues !== undefined ? originalValues : this.originalValues + + return !this.comparePropertyValues(values, this.values) } // EVENT HANDLERS @@ -876,7 +921,8 @@ enableExternalParameterEditor: false, onChange: null, onPopupDisplayed: null, - onPopupHidden: null + onPopupHidden: null, + onGetInspectableElement: null } // REGISTRATION @@ -884,4 +930,5 @@ $.oc.inspector.surface = Surface $.oc.inspector.removedProperty = {removed: true} + $.oc.inspector.invalidProperty = {invalid: true} }(window.jQuery); \ No newline at end of file diff --git a/modules/system/assets/ui/js/inspector.wrapper.base.js b/modules/system/assets/ui/js/inspector.wrapper.base.js index 4330ae0b9..06cbf884e 100644 --- a/modules/system/assets/ui/js/inspector.wrapper.base.js +++ b/modules/system/assets/ui/js/inspector.wrapper.base.js @@ -60,6 +60,10 @@ this.$element.trigger('hidden.oc.inspector') } + if (this.surface !== null && this.surface.options.onGetInspectableElement === this.proxy(this.onGetInspectableElement)) { + this.surface.options.onGetInspectableElement = null + } + this.surface = null this.$element = null this.title = null @@ -118,6 +122,7 @@ var options = this.$element.data() || {} options.enableExternalParameterEditor = this.isExternalParametersEditorEnabled() + options.onGetInspectableElement = this.proxy(this.onGetInspectableElement) this.surface = new $.oc.inspector.surface( containerElement, @@ -127,6 +132,10 @@ options) } + BaseWrapper.prototype.isLiveUpdateEnabled = function() { + return false + } + // // Wrapper API // @@ -140,7 +149,7 @@ } BaseWrapper.prototype.adoptSurface = function() { - + this.surface.options.onGetInspectableElement = this.proxy(this.onGetInspectableElement) } BaseWrapper.prototype.cleanupAfterSwitch = function() { @@ -204,12 +213,30 @@ if (liveUpdateMode) { // In the live update mode, when only valid values are applied, - // we don't want to change all other values (invalid properties), - // so we merge existing values with the valid values. + // we don't want to change all other values (invalid properties). var existingValues = this.loadValues(this.configuration) - values = $.extend(existingValues, values) + for (var property in values) { + if (values[property] !== $.oc.inspector.invalidProperty) { + existingValues[property] = values[property] + } + } + + // Properties that use settings like ignoreIfPropertyEmpty could + // be removed from the list returned by getValidValues(). Removed + // properties should be removed from the result list. + + var filteredValues = {} + + for (var property in existingValues) { + if (values.hasOwnProperty(property)) { + filteredValues[property] = existingValues[property] + } + } + + + values = filteredValues } if ($valuesField.length > 0) { @@ -231,12 +258,29 @@ // regardless of whether Surface properties match or don't match // the original properties of the inspectable element. Without it // there could be undesirable side effects. - if (this.surface.hasChanges() || liveUpdateMode) { - if (!liveUpdateMode) { - this.$element.trigger('change') + + if (liveUpdateMode) { + this.$element.trigger('livechange') + } + else { + var hasChanges = false + + if (this.isLiveUpdateEnabled()) { + var currentValues = this.loadValues(this.configuration) + + // If the Inspector setup supports the live update mode, + // evaluate changes as a difference between the current element + // properties and internal properties stored in the Surface. + // If there is no differences, the properties have already + // been applied with a preceding live update. + hasChanges = this.surface.hasChanges(currentValues) } else { - this.$element.trigger('livechange') + hasChanges = this.surface.hasChanges() + } + + if (hasChanges) { + this.$element.trigger('change') } } } @@ -357,6 +401,10 @@ return true } + BaseWrapper.prototype.onGetInspectableElement = function() { + return this.$element + } + BaseWrapper.DEFAULTS = { containerSupported: false } diff --git a/modules/system/assets/ui/js/inspector.wrapper.container.js b/modules/system/assets/ui/js/inspector.wrapper.container.js index 5031e2aee..46724a94f 100644 --- a/modules/system/assets/ui/js/inspector.wrapper.container.js +++ b/modules/system/assets/ui/js/inspector.wrapper.container.js @@ -55,6 +55,8 @@ if (this.isLiveUpdateEnabled()) { this.surface.options.onChange = this.proxy(this.onLiveUpdate) } + + BaseProto.adoptSurface.call(this) } InspectorContainer.prototype.buildUi = function() { diff --git a/modules/system/assets/ui/js/inspector.wrapper.popup.js b/modules/system/assets/ui/js/inspector.wrapper.popup.js index a8b3da0c0..09d85799f 100644 --- a/modules/system/assets/ui/js/inspector.wrapper.popup.js +++ b/modules/system/assets/ui/js/inspector.wrapper.popup.js @@ -45,6 +45,8 @@ this.repositionPopover() this.registerPopupHandlers() + + BaseProto.adoptSurface.call(this) } InspectorPopup.prototype.cleanupAfterSwitch = function() { diff --git a/modules/system/assets/ui/storm-min.js b/modules/system/assets/ui/storm-min.js index bef8c986a..d76799cc5 100644 --- a/modules/system/assets/ui/storm-min.js +++ b/modules/system/assets/ui/storm-min.js @@ -3332,7 +3332,7 @@ $.oc={} if($.oc.inspector===undefined) $.oc.inspector={} var Base=$.oc.foundation.base,BaseProto=Base.prototype -var Surface=function(containerElement,properties,values,inspectorUniqueId,options,parentSurface,group){if(inspectorUniqueId===undefined){throw new Error('Inspector surface unique ID should be defined.')} +var Surface=function(containerElement,properties,values,inspectorUniqueId,options,parentSurface,group,propertyName){if(inspectorUniqueId===undefined){throw new Error('Inspector surface unique ID should be defined.')} this.options=$.extend({},Surface.DEFAULTS,typeof options=='object'&&options) this.rawProperties=properties this.parsedProperties=$.oc.inspector.engine.processPropertyGroups(properties) @@ -3343,6 +3343,7 @@ this.originalValues=$.extend(true,{},this.values) this.idCounter=1 this.popupCounter=0 this.parentSurface=parentSurface +this.propertyName=propertyName this.editors=[] this.externalParameterEditors=[] this.tableContainer=null @@ -3370,6 +3371,7 @@ this.originalValues=null this.options.onChange=null this.options.onPopupDisplayed=null this.options.onPopupHidden=null +this.options.onGetInspectableElement=null this.parentSurface=null this.groupManager=null this.group=null @@ -3527,6 +3529,13 @@ this.popupCounter++} Surface.prototype.popupHidden=function(){this.popupCounter-- if(this.popupCounter<0){this.popupCounter=0} if(this.popupCounter===0&&this.options.onPopupHidden!==null){this.options.onPopupHidden()}} +Surface.prototype.getInspectableElement=function(){if(this.options.onGetInspectableElement!==null){return this.options.onGetInspectableElement()}} +Surface.prototype.getPropertyPath=function(propertyName){var result=[],current=this +result.push(propertyName) +while(current){if(current.propertyName){result.push(current.propertyName)} +current=current.parentSurface} +result.reverse() +return result.join('.')} Surface.prototype.mergeChildSurface=function(surface,mergeAfterRow){var rows=surface.tableContainer.querySelectorAll('table.inspector-fields > tbody > tr') surface.tableContainer=this.getRootSurface().tableContainer for(var i=rows.length-1;i>=0;i--){var row=rows[i] @@ -3562,7 +3571,10 @@ if(!externalParameterEditor||!externalParameterEditor.isEditorVisible()){value=t if(value===undefined){var editor=this.findPropertyEditor(property.property) if(editor){value=editor.getUndefinedValue()} else{value=property.default}} -if(value===$.oc.inspector.removedProperty){continue}} +if(value===$.oc.inspector.removedProperty){continue} +if(property.ignoreIfEmpty!==undefined&&(property.ignoreIfEmpty===true||property.ignoreIfEmpty==="true")&&editor){if(editor.isEmptyValue(value)){continue}} +if(property.ignoreIfDefault!==undefined&&(property.ignoreIfDefault===true||property.ignoreIfDefault==="true")&&editor){if(property.default===undefined){throw new Error('The ignoreIfDefault feature cannot be used without the default property value.')} +if(this.comparePropertyValues(value,property.default)){continue}}} else{value=externalParameterEditor.getValue() value='{{ '+value+' }}'} result[property.property]=value} @@ -3571,8 +3583,10 @@ Surface.prototype.getValidValues=function(){var allValues=this.getValues(),resul for(var property in allValues){var editor=this.findPropertyEditor(property) if(!editor){throw new Error('Cannot find editor for property '+property)} var externalEditor=this.findExternalParameterEditor(property) -if(externalEditor&&externalEditor.isEditorVisible()&&!externalEditor.validate(true)){continue} -if(!editor.validate(true)){continue} +if(externalEditor&&externalEditor.isEditorVisible()&&!externalEditor.validate(true)){result[property]=$.oc.inspector.invalidProperty +continue} +if(!editor.validate(true)){result[property]=$.oc.inspector.invalidProperty +continue} result[property]=allValues[property]} return result} Surface.prototype.validate=function(silentMode){this.getGroupManager().unmarkInvalidGroups(this.getRootTable()) @@ -3583,14 +3597,16 @@ else{continue}} if(!editor.validate(silentMode)){if(!silentMode){editor.markInvalid()} return false}} return true} -Surface.prototype.hasChanges=function(){return!this.comparePropertyValues(this.originalValues,this.values)} +Surface.prototype.hasChanges=function(originalValues){var values=originalValues!==undefined?originalValues:this.originalValues +return!this.comparePropertyValues(values,this.values)} Surface.prototype.onGroupClick=function(ev){var row=ev.currentTarget this.toggleGroup(row) $.oc.foundation.event.stop(ev) return false} -Surface.DEFAULTS={enableExternalParameterEditor:false,onChange:null,onPopupDisplayed:null,onPopupHidden:null} +Surface.DEFAULTS={enableExternalParameterEditor:false,onChange:null,onPopupDisplayed:null,onPopupHidden:null,onGetInspectableElement:null} $.oc.inspector.surface=Surface -$.oc.inspector.removedProperty={removed:true}}(window.jQuery);+function($){"use strict";var Base=$.oc.foundation.base,BaseProto=Base.prototype +$.oc.inspector.removedProperty={removed:true} +$.oc.inspector.invalidProperty={invalid:true}}(window.jQuery);+function($){"use strict";var Base=$.oc.foundation.base,BaseProto=Base.prototype var InspectorManager=function(){Base.call(this) this.init()} InspectorManager.prototype=Object.create(BaseProto) @@ -3664,6 +3680,7 @@ BaseWrapper.prototype.constructor=Base BaseWrapper.prototype.dispose=function(){if(!this.switched){this.$element.removeClass('inspector-open') this.setInspectorVisibleFlag(false) this.$element.trigger('hidden.oc.inspector')} +if(this.surface!==null&&this.surface.options.onGetInspectableElement===this.proxy(this.onGetInspectableElement)){this.surface.options.onGetInspectableElement=null} this.surface=null this.$element=null this.title=null @@ -3681,10 +3698,12 @@ return code} BaseWrapper.prototype.isExternalParametersEditorEnabled=function(){return this.$element.closest('[data-inspector-external-parameters]').length>0} BaseWrapper.prototype.initSurface=function(containerElement,properties,values){var options=this.$element.data()||{} options.enableExternalParameterEditor=this.isExternalParametersEditorEnabled() +options.onGetInspectableElement=this.proxy(this.onGetInspectableElement) this.surface=new $.oc.inspector.surface(containerElement,properties,values,$.oc.inspector.helpers.generateElementUniqueId(this.$element.get(0)),options)} +BaseWrapper.prototype.isLiveUpdateEnabled=function(){return false} BaseWrapper.prototype.createSurfaceAndUi=function(properties,values){} BaseWrapper.prototype.setInspectorVisibleFlag=function(value){this.$element.data('oc.inspectorVisible',value)} -BaseWrapper.prototype.adoptSurface=function(){} +BaseWrapper.prototype.adoptSurface=function(){this.surface.options.onGetInspectableElement=this.proxy(this.onGetInspectableElement)} BaseWrapper.prototype.cleanupAfterSwitch=function(){this.switched=true this.dispose()} BaseWrapper.prototype.loadValues=function(configuration){var $valuesField=this.getElementValuesInput() @@ -3697,13 +3716,20 @@ values[normalizedPropertyName]=attribute.value}} return values} BaseWrapper.prototype.applyValues=function(liveUpdateMode){var $valuesField=this.getElementValuesInput(),values=liveUpdateMode?this.surface.getValidValues():this.surface.getValues() if(liveUpdateMode){var existingValues=this.loadValues(this.configuration) -values=$.extend(existingValues,values)} +for(var property in values){if(values[property]!==$.oc.inspector.invalidProperty){existingValues[property]=values[property]}} +var filteredValues={} +for(var property in existingValues){if(values.hasOwnProperty(property)){filteredValues[property]=existingValues[property]}} +values=filteredValues} if($valuesField.length>0){$valuesField.val(JSON.stringify(values))} else{for(var property in values){var value=values[property] if($.isArray(value)||$.isPlainObject(value)){throw new Error('Inspector data-property-xxx attributes do not support complex values. Property: '+property)} this.$element.attr('data-property-'+property,value)}} -if(this.surface.hasChanges()||liveUpdateMode){if(!liveUpdateMode){this.$element.trigger('change')} -else{this.$element.trigger('livechange')}}} +if(liveUpdateMode){this.$element.trigger('livechange')} +else{var hasChanges=false +if(this.isLiveUpdateEnabled()){var currentValues=this.loadValues(this.configuration) +hasChanges=this.surface.hasChanges(currentValues)} +else{hasChanges=this.surface.hasChanges()} +if(hasChanges){this.$element.trigger('change')}}} BaseWrapper.prototype.loadConfiguration=function(){var configString=this.$element.data('inspector-config'),result={properties:{},title:null,description:null} result.title=this.$element.data('inspector-title') result.description=this.$element.data('inspector-description') @@ -3737,6 +3763,7 @@ BaseWrapper.prototype.triggerHiding=function(){var hidingEvent=$.Event('hiding.o this.$element.trigger(hidingEvent,[{values:values}]) if(hidingEvent.isDefaultPrevented()){return false} return true} +BaseWrapper.prototype.onGetInspectableElement=function(){return this.$element} BaseWrapper.DEFAULTS={containerSupported:false} $.oc.inspector.wrappers.base=BaseWrapper}(window.jQuery);+function($){"use strict";var Base=$.oc.inspector.wrappers.base,BaseProto=Base.prototype var InspectorPopup=function($element,surface,options){this.$popoverContainer=null @@ -3756,7 +3783,8 @@ this.registerPopupHandlers()} InspectorPopup.prototype.adoptSurface=function(){this.showPopover() this.surface.moveToContainer(this.$popoverContainer.find('[data-surface-container]').get(0)) this.repositionPopover() -this.registerPopupHandlers()} +this.registerPopupHandlers() +BaseProto.adoptSurface.call(this)} InspectorPopup.prototype.cleanupAfterSwitch=function(){this.cleaningUp=true this.switched=true this.forceClose()} @@ -3833,7 +3861,8 @@ this.initSurface(this.surfaceContainer,properties,values) if(this.isLiveUpdateEnabled()){this.surface.options.onChange=this.proxy(this.onLiveUpdate)}} InspectorContainer.prototype.adoptSurface=function(){this.buildUi() this.surface.moveToContainer(this.surfaceContainer) -if(this.isLiveUpdateEnabled()){this.surface.options.onChange=this.proxy(this.onLiveUpdate)}} +if(this.isLiveUpdateEnabled()){this.surface.options.onChange=this.proxy(this.onLiveUpdate)} +BaseProto.adoptSurface.call(this)} InspectorContainer.prototype.buildUi=function(){var scrollable=this.isScrollable(),head=this.buildHead(),layoutElements=this.buildLayout() layoutElements.headContainer.appendChild(head) if(scrollable){var scrollpad=this.buildScrollpad() @@ -4055,6 +4084,8 @@ BaseEditor.prototype.updateDisplayedValue=function(value){} BaseEditor.prototype.getPropertyName=function(){return this.propertyDefinition.property} BaseEditor.prototype.getUndefinedValue=function(){return this.propertyDefinition.default===undefined?undefined:this.propertyDefinition.default} BaseEditor.prototype.throwError=function(errorMessage){throw new Error(errorMessage+' Property: '+this.propertyDefinition.property)} +BaseEditor.prototype.getInspectableElement=function(){return this.getRootSurface().getInspectableElement()} +BaseEditor.prototype.isEmptyValue=function(value){return value===undefined||value===null||$.isEmptyObject(value)||(typeof value=='string'&&$.trim(value).length===0)||(Object.prototype.toString.call(value)==='[object Array]'&&value.length===0)} BaseEditor.prototype.initValidation=function(){this.validationSet=new $.oc.inspector.validationSet(this.propertyDefinition,this.propertyDefinition.property)} BaseEditor.prototype.disposeValidation=function(){this.validationSet.dispose()} BaseEditor.prototype.getValueToValidate=function(){return this.inspector.getPropertyValue(this.propertyDefinition.property)} @@ -4205,11 +4236,20 @@ if(value===undefined){value=this.propertyDefinition.default} select.value=value} DropdownEditor.prototype.loadDynamicOptions=function(initialization){var currentValue=this.inspector.getPropertyValue(this.propertyDefinition.property),data=this.inspector.getValues(),self=this,$form=$(this.getSelect()).closest('form') if(currentValue===undefined){currentValue=this.propertyDefinition.default} +var callback=function dropdownOptionsRequestDoneClosure(data){self.hideLoadingIndicator() +self.optionsRequestDone(data,currentValue,true)} if(this.propertyDefinition.depends){this.saveDependencyValues()} data['inspectorProperty']=this.propertyDefinition.property data['inspectorClassName']=this.inspector.options.inspectorClass this.showLoadingIndicator() -$form.request('onInspectableGetOptions',{data:data,}).done(function dropdownOptionsRequestDoneClosure(data){self.optionsRequestDone(data,currentValue,true)}).always(this.proxy(this.hideLoadingIndicator))} +if(this.triggerGetOptions(data,callback)===false){return} +$form.request('onInspectableGetOptions',{data:data,}).done(callback).always(this.proxy(this.hideLoadingIndicator))} +DropdownEditor.prototype.triggerGetOptions=function(values,callback){var $inspectable=this.getInspectableElement() +if(!$inspectable){return true} +var optionsEvent=$.Event('dropdownoptions.oc.inspector') +$inspectable.trigger(optionsEvent,[{values:values,callback:callback,property:this.inspector.getPropertyPath(this.propertyDefinition.property)}]) +if(optionsEvent.isDefaultPrevented()){return false} +return true} DropdownEditor.prototype.saveDependencyValues=function(){this.prevDependencyValues=this.getDependencyValues()} DropdownEditor.prototype.getDependencyValues=function(){var result='' for(var i=0,len=this.propertyDefinition.depends.length;i-1} SetEditor.prototype.setPropertyValue=function(checkboxValue,isChecked){var currentValue=this.getNormalizedValue() if(currentValue===undefined){currentValue=this.propertyDefinition.default} if(!currentValue){currentValue=[]} -if(isChecked){if(currentValue.indexOf(checkboxValue)===-1){currentValue.push(checkboxValue)}} -else{var index=currentValue.indexOf(checkboxValue) -if(index!==-1){currentValue.splice(index,1)}} -this.inspector.setPropertyValue(this.propertyDefinition.property,this.cleanUpValue(currentValue)) +var resultValue=[] +for(var itemValue in this.propertyDefinition.items){if(itemValue!==checkboxValue){if(currentValue.indexOf(itemValue)!==-1){resultValue.push(itemValue)}} +else{if(isChecked){resultValue.push(itemValue)}}} +this.inspector.setPropertyValue(this.propertyDefinition.property,this.cleanUpValue(resultValue)) this.setLinkText(this.getLink())} SetEditor.prototype.generateSequencedId=function(){return this.inspector.generateSequencedId()} SetEditor.prototype.disposeEditors=function(){for(var i=0,len=this.editors.length;i=0;i--){loadedItems[data.options[i].value]=data.options[i].title}} this.buildAutoComplete(loadedItems)} From d34bb2bd864edaf126034eb72edb17e4a8408228 Mon Sep 17 00:00:00 2001 From: alekseybobkov Date: Mon, 9 Nov 2015 21:59:19 -0800 Subject: [PATCH 04/19] Minor changes in the Inspector API. --- modules/system/assets/ui/js/inspector.manager.js | 3 +++ modules/system/assets/ui/js/inspector.wrapper.base.js | 2 +- modules/system/assets/ui/storm-min.js | 6 ++++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/modules/system/assets/ui/js/inspector.manager.js b/modules/system/assets/ui/js/inspector.manager.js index ce2c4e732..73ad394bd 100644 --- a/modules/system/assets/ui/js/inspector.manager.js +++ b/modules/system/assets/ui/js/inspector.manager.js @@ -170,6 +170,9 @@ if (this.createInspector($element) === false) { return false } + + ev.stopPropagation() + return false } $.oc.inspector.manager = new InspectorManager() diff --git a/modules/system/assets/ui/js/inspector.wrapper.base.js b/modules/system/assets/ui/js/inspector.wrapper.base.js index 06cbf884e..d865bd8a9 100644 --- a/modules/system/assets/ui/js/inspector.wrapper.base.js +++ b/modules/system/assets/ui/js/inspector.wrapper.base.js @@ -97,7 +97,7 @@ // BaseWrapper.prototype.getElementValuesInput = function() { - return this.$element.find('input[data-inspector-values]') + return this.$element.find('> input[data-inspector-values]') } BaseWrapper.prototype.normalizePropertyCode = function(code, configuration) { diff --git a/modules/system/assets/ui/storm-min.js b/modules/system/assets/ui/storm-min.js index d76799cc5..ad96a0a97 100644 --- a/modules/system/assets/ui/storm-min.js +++ b/modules/system/assets/ui/storm-min.js @@ -3654,7 +3654,9 @@ $container.trigger(allowedEvent) if(allowedEvent.isDefaultPrevented()){return false} return true} InspectorManager.prototype.onInspectableClicked=function(ev){var $element=$(ev.currentTarget) -if(this.createInspector($element)===false){return false}} +if(this.createInspector($element)===false){return false} +ev.stopPropagation() +return false} $.oc.inspector.manager=new InspectorManager() $.fn.inspector=function(){return this.each(function(){$.oc.inspector.manager.createInspector(this)})}}(window.jQuery);+function($){"use strict";if($.oc.inspector===undefined) $.oc.inspector={} @@ -3690,7 +3692,7 @@ BaseProto.dispose.call(this)} BaseWrapper.prototype.init=function(){if(!this.surface){this.loadConfiguration()} else{this.adoptSurface()} this.$element.addClass('inspector-open')} -BaseWrapper.prototype.getElementValuesInput=function(){return this.$element.find('input[data-inspector-values]')} +BaseWrapper.prototype.getElementValuesInput=function(){return this.$element.find('> input[data-inspector-values]')} BaseWrapper.prototype.normalizePropertyCode=function(code,configuration){var lowerCaseCode=code.toLowerCase() for(var index in configuration){var propertyInfo=configuration[index] if(propertyInfo.property.toLowerCase()==lowerCaseCode){return propertyInfo.property}} From 5cb873862abe148ce6d25105e1cecd06dc12d162 Mon Sep 17 00:00:00 2001 From: alekseybobkov Date: Wed, 11 Nov 2015 13:03:18 -0800 Subject: [PATCH 05/19] Minor changes in the Inspector API --- modules/system/assets/ui/js/inspector.wrapper.base.js | 2 +- modules/system/assets/ui/storm-min.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/system/assets/ui/js/inspector.wrapper.base.js b/modules/system/assets/ui/js/inspector.wrapper.base.js index d865bd8a9..b3136cdeb 100644 --- a/modules/system/assets/ui/js/inspector.wrapper.base.js +++ b/modules/system/assets/ui/js/inspector.wrapper.base.js @@ -307,7 +307,7 @@ return } - var $configurationField = this.$element.find('input[data-inspector-config]') + var $configurationField = this.$element.find('> input[data-inspector-config]') if ($configurationField.length > 0) { result.properties = this.parseConfiguration($configurationField.val()) diff --git a/modules/system/assets/ui/storm-min.js b/modules/system/assets/ui/storm-min.js index ad96a0a97..b60367cbe 100644 --- a/modules/system/assets/ui/storm-min.js +++ b/modules/system/assets/ui/storm-min.js @@ -3738,7 +3738,7 @@ result.description=this.$element.data('inspector-description') if(configString!==undefined){result.properties=this.parseConfiguration(configString) this.configurationLoaded(result) return} -var $configurationField=this.$element.find('input[data-inspector-config]') +var $configurationField=this.$element.find('> input[data-inspector-config]') if($configurationField.length>0){result.properties=this.parseConfiguration($configurationField.val()) this.configurationLoaded(result) return} From 3217bf03d82479c03f6376acf3a9ac8e9a4fa73b Mon Sep 17 00:00:00 2001 From: alekseybobkov Date: Wed, 11 Nov 2015 20:18:38 -0800 Subject: [PATCH 06/19] Minor fix in the flyout implementation --- modules/backend/assets/js/october-min.js | 2 +- modules/backend/assets/js/october.flyout.js | 2 ++ modules/backend/assets/js/october.sidepaneltab.js | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/backend/assets/js/october-min.js b/modules/backend/assets/js/october-min.js index 9d04aa730..cf8fa6de7 100644 --- a/modules/backend/assets/js/october-min.js +++ b/modules/backend/assets/js/october-min.js @@ -1186,7 +1186,7 @@ $.fn.sidePanelTab=function(option){return this.each(function(){var $this=$(this) var data=$this.data('oc.sidePanelTab') var options=$.extend({},SidePanelTab.DEFAULTS,$this.data(),typeof option=='object'&&option) if(!data)$this.data('oc.sidePanelTab',(data=new SidePanelTab(this,options))) -if(typeof option=='string')data[option].call($this)})} +if(typeof option=='string')data[option].call(data)})} $.fn.sidePanelTab.Constructor=SidePanelTab $.fn.sidePanelTab.noConflict=function(){$.fn.sidePanelTab=old return this} diff --git a/modules/backend/assets/js/october.flyout.js b/modules/backend/assets/js/october.flyout.js index 22f2e4d1c..251bd71d8 100644 --- a/modules/backend/assets/js/october.flyout.js +++ b/modules/backend/assets/js/october.flyout.js @@ -38,6 +38,8 @@ var $cells = this.$el.find('> .layout-cell'), $flyout = this.$el.find('> .flyout') + $('[data-control=layout-sidepanel]').sidePanelTab('hideSidePanel') + this.removeOverlay() for (var i = 0; i < $cells.length; i++) { diff --git a/modules/backend/assets/js/october.sidepaneltab.js b/modules/backend/assets/js/october.sidepaneltab.js index da3bc442e..0d317fb16 100644 --- a/modules/backend/assets/js/october.sidepaneltab.js +++ b/modules/backend/assets/js/october.sidepaneltab.js @@ -198,7 +198,7 @@ var data = $this.data('oc.sidePanelTab') var options = $.extend({}, SidePanelTab.DEFAULTS, $this.data(), typeof option == 'object' && option) if (!data) $this.data('oc.sidePanelTab', (data = new SidePanelTab(this, options))) - if (typeof option == 'string') data[option].call($this) + if (typeof option == 'string') data[option].call(data) }) } From f8cd8e72a195b8cc46a4929dc2d9c462b111de5f Mon Sep 17 00:00:00 2001 From: alekseybobkov Date: Thu, 12 Nov 2015 21:56:56 -0800 Subject: [PATCH 07/19] Minor improvement in the Inspector --- .../assets/ui/js/inspector.editor.base.js | 2 +- .../assets/ui/js/inspector.editor.checkbox.js | 8 +++++ .../assets/ui/js/inspector.editor.dropdown.js | 34 +++++++++++++++++-- .../ui/js/inspector.editor.stringlist.js | 2 ++ .../assets/ui/js/inspector.editor.text.js | 12 +++++++ .../system/assets/ui/js/inspector.engine.js | 11 ++++++ .../system/assets/ui/js/inspector.surface.js | 4 +-- modules/system/assets/ui/less/inspector.less | 6 ++++ modules/system/assets/ui/storm-min.js | 33 ++++++++++++++---- modules/system/assets/ui/storm.css | 1 + 10 files changed, 101 insertions(+), 12 deletions(-) diff --git a/modules/system/assets/ui/js/inspector.editor.base.js b/modules/system/assets/ui/js/inspector.editor.base.js index 5bdf6dfbe..c0f0cd9f0 100644 --- a/modules/system/assets/ui/js/inspector.editor.base.js +++ b/modules/system/assets/ui/js/inspector.editor.base.js @@ -118,7 +118,7 @@ BaseEditor.prototype.isEmptyValue = function(value) { return value === undefined || value === null - || $.isEmptyObject(value) + || (typeof value == 'object' && $.isEmptyObject(value) ) || (typeof value == 'string' && $.trim(value).length === 0) || (Object.prototype.toString.call(value) === '[object Array]' && value.length === 0) } diff --git a/modules/system/assets/ui/js/inspector.editor.checkbox.js b/modules/system/assets/ui/js/inspector.editor.checkbox.js index b842e7045..fa924c551 100644 --- a/modules/system/assets/ui/js/inspector.editor.checkbox.js +++ b/modules/system/assets/ui/js/inspector.editor.checkbox.js @@ -78,6 +78,14 @@ this.getInput().checked = this.normalizeCheckedValue(value) } + CheckboxEditor.prototype.isEmptyValue = function(value) { + if (value === 0 || value === '0' || value === 'false') { + return true + } + + return BaseProto.isEmptyValue.call(this, value) + } + CheckboxEditor.prototype.registerHandlers = function() { var input = this.getInput() diff --git a/modules/system/assets/ui/js/inspector.editor.dropdown.js b/modules/system/assets/ui/js/inspector.editor.dropdown.js index 02fd3eec7..776ec0408 100644 --- a/modules/system/assets/ui/js/inspector.editor.dropdown.js +++ b/modules/system/assets/ui/js/inspector.editor.dropdown.js @@ -135,6 +135,24 @@ return false } + DropdownEditor.prototype.normalizeValue = function(value) { + if (!this.propertyDefinition.booleanValues) { + return value + } + + var str = String(value) + + if (str.length === 0) { + return '' + } + + if (str === 'true') { + return true + } + + return false + } + // // Event handlers // @@ -148,7 +166,7 @@ DropdownEditor.prototype.onSelectionChange = function() { var select = this.getSelect() - this.inspector.setPropertyValue(this.propertyDefinition.property, select.value, this.initialization) + this.inspector.setPropertyValue(this.propertyDefinition.property, this.normalizeValue(select.value), this.initialization) } DropdownEditor.prototype.onInspectorPropertyChanged = function(property, value) { @@ -191,12 +209,24 @@ var select = this.getSelect() if (select) { - return select.value + return this.normalizeValue(select.value) } return undefined } + DropdownEditor.prototype.isEmptyValue = function(value) { + if (this.propertyDefinition.booleanValues) { + if (value === '') { + return true + } + + return false + } + + return BaseProto.isEmptyValue.call(this, value) + } + // // Disposing // diff --git a/modules/system/assets/ui/js/inspector.editor.stringlist.js b/modules/system/assets/ui/js/inspector.editor.stringlist.js index 2779e750c..2dd009201 100644 --- a/modules/system/assets/ui/js/inspector.editor.stringlist.js +++ b/modules/system/assets/ui/js/inspector.editor.stringlist.js @@ -65,6 +65,8 @@ } $textarea.focus() + + this.configureComment(popup) } StringListEditor.prototype.handleSubmit = function($form) { diff --git a/modules/system/assets/ui/js/inspector.editor.text.js b/modules/system/assets/ui/js/inspector.editor.text.js index 28dc74026..9a6a6d6b8 100644 --- a/modules/system/assets/ui/js/inspector.editor.text.js +++ b/modules/system/assets/ui/js/inspector.editor.text.js @@ -46,6 +46,7 @@ \