diff --git a/modules/backend/assets/js/october-min.js b/modules/backend/assets/js/october-min.js index 5b1bf868d..2217eb381 100644 --- a/modules/backend/assets/js/october-min.js +++ b/modules/backend/assets/js/october-min.js @@ -1258,8 +1258,9 @@ this.shown=false this.listen()} Autocomplete.prototype={constructor:Autocomplete,select:function(){var val=this.$menu.find('.active').attr('data-value') this.$element.val(this.updater(val)).change() -return this.hide()},updater:function(item){return item},show:function(){var pos=$.extend({},this.$element.position(),{height:this.$element[0].offsetHeight}) -this.$menu.insertAfter(this.$element).css({top:pos.top+pos.height,left:pos.left}).show() +return this.hide()},updater:function(item){return item},show:function(){var pos=$.extend({},this.$element.position(),{height:this.$element[0].offsetHeight}),cssOptions={top:pos.top+pos.height,left:pos.left} +if(this.options.matchWidth){cssOptions.width=this.$element[0].offsetWidth} +this.$menu.insertAfter(this.$element).css(cssOptions).show() this.shown=true return this},hide:function(){this.$menu.hide() this.shown=false @@ -1293,9 +1294,9 @@ return this},next:function(event){var active=this.$menu.find('.active').removeCl if(!next.length){next=$(this.$menu.find('li')[0])} next.addClass('active')},prev:function(event){var active=this.$menu.find('.active').removeClass('active'),prev=active.prev() if(!prev.length){prev=this.$menu.find('li').last()} -prev.addClass('active')},listen:function(){this.$element.on('focus',$.proxy(this.focus,this)).on('blur',$.proxy(this.blur,this)).on('keypress',$.proxy(this.keypress,this)).on('keyup',$.proxy(this.keyup,this)) -if(this.eventSupported('keydown')){this.$element.on('keydown',$.proxy(this.keydown,this))} -this.$menu.on('click',$.proxy(this.click,this)).on('mouseenter','li',$.proxy(this.mouseenter,this)).on('mouseleave','li',$.proxy(this.mouseleave,this))},eventSupported:function(eventName){var isSupported=eventName in this.$element +prev.addClass('active')},listen:function(){this.$element.on('focus.autocomplete',$.proxy(this.focus,this)).on('blur.autocomplete',$.proxy(this.blur,this)).on('keypress.autocomplete',$.proxy(this.keypress,this)).on('keyup.autocomplete',$.proxy(this.keyup,this)) +if(this.eventSupported('keydown')){this.$element.on('keydown.autocomplete',$.proxy(this.keydown,this))} +this.$menu.on('click.autocomplete',$.proxy(this.click,this)).on('mouseenter.autocomplete','li',$.proxy(this.mouseenter,this)).on('mouseleave.autocomplete','li',$.proxy(this.mouseleave,this))},eventSupported:function(eventName){var isSupported=eventName in this.$element if(!isSupported){this.$element.setAttribute(eventName,'return;') isSupported=typeof this.$element[eventName]==='function'} return isSupported},move:function(e){if(!this.shown)return @@ -1325,7 +1326,13 @@ this.select() this.$element.focus()},mouseenter:function(e){this.mousedover=true this.$menu.find('.active').removeClass('active') $(e.currentTarget).addClass('active')},mouseleave:function(e){this.mousedover=false -if(!this.focused&&this.shown)this.hide()}} +if(!this.focused&&this.shown)this.hide()},destroy:function(){this.hide() +this.$element.removeData('autocomplete') +this.$menu.remove() +this.$element.off('.autocomplete') +this.$menu.off('.autocomplete') +this.$element=null +this.$menu=null}} var old=$.fn.autocomplete $.fn.autocomplete=function(option){return this.each(function(){var $this=$(this),data=$this.data('autocomplete'),options=typeof option=='object'&&option if(!data)$this.data('autocomplete',(data=new Autocomplete(this,options))) diff --git a/modules/backend/assets/js/october.autocomplete.js b/modules/backend/assets/js/october.autocomplete.js index 870c5d006..ff9bd3f74 100644 --- a/modules/backend/assets/js/october.autocomplete.js +++ b/modules/backend/assets/js/october.autocomplete.js @@ -53,14 +53,19 @@ show: function () { var pos = $.extend({}, this.$element.position(), { height: this.$element[0].offsetHeight - }) + }), + cssOptions = { + top: pos.top + pos.height + , left: pos.left + } + + if (this.options.matchWidth) { + cssOptions.width = this.$element[0].offsetWidth + } this.$menu .insertAfter(this.$element) - .css({ - top: pos.top + pos.height - , left: pos.left - }) + .css(cssOptions) .show() this.shown = true @@ -194,19 +199,19 @@ listen: function () { this.$element - .on('focus', $.proxy(this.focus, this)) - .on('blur', $.proxy(this.blur, this)) - .on('keypress', $.proxy(this.keypress, this)) - .on('keyup', $.proxy(this.keyup, this)) + .on('focus.autocomplete', $.proxy(this.focus, this)) + .on('blur.autocomplete', $.proxy(this.blur, this)) + .on('keypress.autocomplete', $.proxy(this.keypress, this)) + .on('keyup.autocomplete', $.proxy(this.keyup, this)) if (this.eventSupported('keydown')) { - this.$element.on('keydown', $.proxy(this.keydown, this)) + this.$element.on('keydown.autocomplete', $.proxy(this.keydown, this)) } this.$menu - .on('click', $.proxy(this.click, this)) - .on('mouseenter', 'li', $.proxy(this.mouseenter, this)) - .on('mouseleave', 'li', $.proxy(this.mouseleave, this)) + .on('click.autocomplete', $.proxy(this.click, this)) + .on('mouseenter.autocomplete', 'li', $.proxy(this.mouseenter, this)) + .on('mouseleave.autocomplete', 'li', $.proxy(this.mouseleave, this)) }, eventSupported: function(eventName) { @@ -305,8 +310,20 @@ mouseleave: function (e) { this.mousedover = false if (!this.focused && this.shown) this.hide() - } + }, + destroy: function() { + this.hide() + + this.$element.removeData('autocomplete') + this.$menu.remove() + + this.$element.off('.autocomplete') + this.$menu.off('.autocomplete') + + this.$element = null + this.$menu = null + } } diff --git a/modules/system/assets/ui/js/inspector.editor.autocomplete.js b/modules/system/assets/ui/js/inspector.editor.autocomplete.js new file mode 100644 index 000000000..0fb2d3e3e --- /dev/null +++ b/modules/system/assets/ui/js/inspector.editor.autocomplete.js @@ -0,0 +1,146 @@ +/* + * Inspector autocomplete editor class. + * + * Depends on october.autocomplete.js + */ ++function ($) { "use strict"; + + var Base = $.oc.inspector.propertyEditors.string, + BaseProto = Base.prototype + + var AutocompleteEditor = function(inspector, propertyDefinition, containerCell, group) { + Base.call(this, inspector, propertyDefinition, containerCell, group) + } + + AutocompleteEditor.prototype = Object.create(BaseProto) + AutocompleteEditor.prototype.constructor = Base + + AutocompleteEditor.prototype.dispose = function() { + this.removeAutocomplete() + + BaseProto.dispose.call(this) + } + + AutocompleteEditor.prototype.build = function() { + var container = document.createElement('div'), + editor = document.createElement('input'), + placeholder = this.propertyDefinition.placeholder !== undefined ? this.propertyDefinition.placeholder : '', + value = this.inspector.getPropertyValue(this.propertyDefinition.property) + + editor.setAttribute('type', 'text') + editor.setAttribute('class', 'string-editor') + editor.setAttribute('placeholder', placeholder) + + container.setAttribute('class', 'autocomplete-container') + + if (value === undefined) { + value = this.propertyDefinition.default + } + + if (value === undefined) { + value = '' + } + + editor.value = value + + $.oc.foundation.element.addClass(this.containerCell, 'text autocomplete') + + container.appendChild(editor) + this.containerCell.appendChild(container) + + if (this.propertyDefinition.items !== undefined) { + this.buildAutoComplete(this.propertyDefinition.items) + } + else { + this.loadDynamicItems() + } + } + + AutocompleteEditor.prototype.buildAutoComplete = function(items) { + var input = this.getInput() + + if (items === undefined) { + items = [] + } + + $(input).autocomplete({ + source: this.prepareItems(items), + matchWidth: true + }) + } + + AutocompleteEditor.prototype.removeAutocomplete = function() { + var input = this.getInput() + + $(input).autocomplete('destroy') + } + + AutocompleteEditor.prototype.prepareItems = function(items) { + var result = {} + + if ($.isArray(items)) { + for (var i = 0, len = items.length; i < len; i++) { + result[items[i]] = items[i] + } + } + else { + result = items + } + + return result + } + + AutocompleteEditor.prototype.supportsExternalParameterEditor = function() { + return false + } + + AutocompleteEditor.prototype.getContainer = function() { + return this.getInput().parentNode + } + + // + // Dynamic items + // + + AutocompleteEditor.prototype.showLoadingIndicator = function() { + $(this.getContainer()).loadIndicator() + } + + AutocompleteEditor.prototype.hideLoadingIndicator = function() { + var $container = $(this.getContainer()) + + $container.loadIndicator('hide') + $container.loadIndicator('destroy') + + $container.removeClass('loading-indicator-container') + } + + AutocompleteEditor.prototype.loadDynamicItems = function() { + var container = this.getContainer(), + data = this.inspector.getValues(), + $form = $(container).closest('form') + + $.oc.foundation.element.addClass(container, 'loading-indicator-container size-small') + this.showLoadingIndicator() + + $form.request('onInspectableGetOptions', { + data: data, + }) + .done(this.proxy(this.itemsRequestDone)) + .always(this.proxy(this.hideLoadingIndicator)) + } + + AutocompleteEditor.prototype.itemsRequestDone = function(data, currentValue, initialization) { + var loadedItems = {} + + if (data.options) { + for (var i = data.options.length-1; i >= 0; i--) { + loadedItems[data.options[i].value] = data.options[i].title + } + } + + this.buildAutoComplete(loadedItems) + } + + $.oc.inspector.propertyEditors.autocomplete = AutocompleteEditor +}(window.jQuery); \ No newline at end of file diff --git a/modules/system/assets/ui/js/inspector.editor.dropdown.js b/modules/system/assets/ui/js/inspector.editor.dropdown.js index 1b9d06392..6a2bf5337 100644 --- a/modules/system/assets/ui/js/inspector.editor.dropdown.js +++ b/modules/system/assets/ui/js/inspector.editor.dropdown.js @@ -293,6 +293,7 @@ DropdownEditor.prototype.hideLoadingIndicator = function() { if (!Modernizr.touch) { this.indicatorContainer.loadIndicator('hide') + this.indicatorContainer.loadIndicator('destroy') } } diff --git a/modules/system/assets/ui/js/inspector.editor.set.js b/modules/system/assets/ui/js/inspector.editor.set.js index f0ea29cdd..8ee495ec6 100644 --- a/modules/system/assets/ui/js/inspector.editor.set.js +++ b/modules/system/assets/ui/js/inspector.editor.set.js @@ -145,7 +145,10 @@ } SetEditor.prototype.hideLoadingIndicator = function() { - $(this.getLink()).loadIndicator('hide') + var $link = $(this.getLink()) + + $link.loadIndicator('hide') + $link.loadIndicator('destroy') } SetEditor.prototype.loadDynamicItems = function() { diff --git a/modules/system/assets/ui/js/inspector.editor.string.js b/modules/system/assets/ui/js/inspector.editor.string.js index 2568bfc26..58a93849d 100644 --- a/modules/system/assets/ui/js/inspector.editor.string.js +++ b/modules/system/assets/ui/js/inspector.editor.string.js @@ -80,5 +80,9 @@ this.inspector.setPropertyValue(this.propertyDefinition.property, value) } + StringEditor.prototype.onExternalPropertyEditorHidden = function() { + this.focus() + } + $.oc.inspector.propertyEditors.string = StringEditor }(window.jQuery); \ No newline at end of file