diff options
Diffstat (limited to 'apps/user_ldap/js/wizard/wizardTabGeneric.js')
-rw-r--r-- | apps/user_ldap/js/wizard/wizardTabGeneric.js | 547 |
1 files changed, 547 insertions, 0 deletions
diff --git a/apps/user_ldap/js/wizard/wizardTabGeneric.js b/apps/user_ldap/js/wizard/wizardTabGeneric.js new file mode 100644 index 00000000000..524d2a048a1 --- /dev/null +++ b/apps/user_ldap/js/wizard/wizardTabGeneric.js @@ -0,0 +1,547 @@ + +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + +(function() { + + /** + * @classdesc An abstract tab view + * @abstract + */ + var WizardTabGeneric = OCA.LDAP.Wizard.WizardObject.subClass({ + isActive: false, + + /** + * @property {string} - class that identifies a multiselect-plugin + * control. + */ + multiSelectPluginClass: 'multiSelectPlugin', + + /** @inheritdoc */ + init: function(tabIndex, tabID) { + this.tabIndex = tabIndex; + this.tabID = tabID; + this.spinner = $('.ldapSpinner').first().clone().removeClass('hidden'); + _.bindAll(this, '_toggleRawFilterMode', '_toggleRawFilterModeConfirmation'); + }, + + /** + * sets the configuration items that are managed by that view. + * + * The parameter contains key-value pairs the key being the + * configuration keys and the value being its setter method. + * + * @param {object} managedItems + */ + setManagedItems: function(managedItems) { + this.managedItems = managedItems; + this._enableAutoSave(); + }, + + /** + * Sets the config model. The concrete view likely wants to subscribe + * to events as well. + * + * @param {OCA.LDAP.Wizard.ConfigModel} configModel + */ + setModel: function(configModel) { + this.configModel = configModel; + this.parsedFilterMode = this.configModel.FILTER_MODE_ASSISTED; + this.configModel.on('detectionStarted', this.onDetectionStarted, this); + this.configModel.on('detectionCompleted', this.onDetectionCompleted, this); + this.configModel.on('serverError', this.onServerError, this); + this.configModel.on('setCompleted', this.onItemSaved, this); + this.configModel.on('configUpdated', this.onConfigLoaded, this); + }, + + /** + * the method can be used to display a different error/information + * message than provided by the ownCloud server response. The concrete + * Tab View may optionally implement it. Returning an empty string will + * avoid any notification. + * + * @param {string} message + * @param {string} key + * @returns {string} + */ + overrideErrorMessage: function(message, key) { + return message; + }, + + /** + * this is called by the main view, if the tab is being switched to. + * The concrete tab view can implement this if necessary. + */ + onActivate: function() { }, + + /** + * updates the tab when the model loaded a configuration and notified + * this view. + * + * @param {WizardTabGeneric} view - this instance + * @param {Object} configuration + */ + onConfigLoaded: function(view, configuration) { + for(var key in view.managedItems){ + if(!_.isUndefined(configuration[key])) { + var value = configuration[key]; + var methodName = view.managedItems[key].setMethod; + if(!_.isUndefined(view[methodName])) { + view[methodName](value); + } + } + } + }, + + /** + * reacts on a set action on the model and updates the tab with the + * valid value. + * + * @param {WizardTabGeneric} view + * @param {Object} result + */ + onItemSaved: function(view, result) { + if(!_.isUndefined(view.managedItems[result.key])) { + var methodName = view.managedItems[result.key].setMethod; + view[methodName](result.value); + if(!result.isSuccess) { + OC.Notification.showTemporary(t('user_ldap', 'Saving failed. Please make sure the database is in Operation. Reload before continuing.')); + console.warn(result.errorMessage); + } + } + }, + + /** + * displays server error messages. + * + * @param view + * @param payload + */ + onServerError: function(view, payload) { + if ( !_.isUndefined(view.managedItems[payload.relatedKey])) { + var message = view.overrideErrorMessage(payload.message, payload.relatedKey); + if(message) { + OC.Notification.showTemporary(message); + } + } + }, + + /** + * disables affected, managed fields if a detector is running against them + * + * @param {WizardTabGeneric} view + * @param {string} key + */ + onDetectionStarted: function(view, key) { + if(!_.isUndefined(view.managedItems[key])) { + view.disableElement(view.managedItems[key].$element); + if(!_.isUndefined(view.managedItems[key].$relatedElements)){ + view.disableElement(view.managedItems[key].$relatedElements); + } + view.attachSpinner(view.managedItems[key].$element.attr('id')); + } + }, + + /** + * enables affected, managed fields after a detector was run against them + * + * @param {WizardTabGeneric} view + * @param {string} key + */ + onDetectionCompleted: function(view, key) { + if(!_.isUndefined(view.managedItems[key])) { + view.enableElement(view.managedItems[key].$element); + if(!_.isUndefined(view.managedItems[key].$relatedElements)){ + view.enableElement(view.managedItems[key].$relatedElements); + } + view.removeSpinner(view.managedItems[key].$element.attr('id')); + } + }, + + /** + * sets the value to an HTML element. Checkboxes, text areas and (text) + * input fields are supported. + * + * @param {jQuery} $element - the target element + * @param {string|number|Array} value + */ + setElementValue: function($element, value) { + // deal with check box + if ($element.is('input[type=checkbox]')) { + this._setCheckBox($element, value); + return; + } + + // deal with text area + if ($element.is('textarea') && $.isArray(value)) { + value = value.join("\n"); + } + + if ($element.is('span')) { + $element.text(value); + } else { + $element.val(value); + } + }, + + /** + * replaces options on a multiselect element + * + * @param {jQuery} $element - the multiselect element + * @param {Array} options + */ + equipMultiSelect: function($element, options) { + $element.empty(); + for (var i in options) { + var name = options[i]; + $element.append($('<option>').val(name).text(name).attr('title', name)); + } + if(!$element.hasClass('ldapGroupList')) { + $element.multiselect('refresh'); + this.enableElement($element); + } + }, + + /** + * enables the specified HTML element + * + * @param {jQuery} $element + */ + enableElement: function($element) { + var isMS = $element.is('select[multiple]'); + var hasOptions = isMS ? ($element.find('option').length > 0) : false; + + if($element.hasClass(this.multiSelectPluginClass) && hasOptions) { + $element.multiselect("enable"); + } else if(!isMS || (isMS && hasOptions)) { + $element.prop('disabled', false); + } + }, + + /** + * disables the specified HTML element + * + * @param {jQuery} $element + */ + disableElement: function($element) { + if($element.hasClass(this.multiSelectPluginClass)) { + $element.multiselect("disable"); + } else { + $element.prop('disabled', 'disabled'); + } + }, + + /** + * attaches a spinner icon to the HTML element specified by ID + * + * @param {string} elementID + */ + attachSpinner: function(elementID) { + if($('#' + elementID + ' + .ldapSpinner').length == 0) { + var spinner = this.spinner.clone(); + var $element = $('#' + elementID); + $(spinner).insertAfter($element); + // and special treatment for multiselects: + if ($element.is('select[multiple]')) { + $('#' + elementID + " + img + button").css('display', 'none'); + } + } + }, + + /** + * removes the spinner icon from the HTML element specified by ID + * + * @param {string} elementID + */ + removeSpinner: function(elementID) { + $('#' + elementID+' + .ldapSpinner').remove(); + // and special treatment for multiselects: + $('#' + elementID + " + button").css('display', 'inline'); + }, + + /** + * whether the wizard works in experienced admin mode + * + * @returns {boolean} + */ + isExperiencedMode: function() { + return parseInt(this.configModel.configuration.ldap_experienced_admin, 10) === 1; + }, + + /** + * sets up auto-save functionality to the managed items + * + * @private + */ + _enableAutoSave: function() { + var view = this; + + for(var id in this.managedItems) { + if(_.isUndefined(this.managedItems[id].$element) + || _.isUndefined(this.managedItems[id].setMethod)) { + continue; + } + var $element = this.managedItems[id].$element; + if (!$element.is('select[multiple]')) { + $element.change(function() { + view._requestSave($(this)); + }); + } + } + }, + + /** + * initializes a multiSelect element + * + * @param {jQuery} $element + * @param {string} caption + * @private + */ + _initMultiSelect: function($element, caption) { + var view = this; + $element.multiselect({ + header: false, + selectedList: 9, + noneSelectedText: caption, + classes: this.multiSelectPluginClass, + close: function() { + view._requestSave($element); + } + }); + }, + + /** + * @typedef {object} viewSaveInfo + * @property {function} val + * @property {function} attr + * @property {function} is + */ + + /** + * requests a save operation from the model for a given value + * represented by a HTML element and its ID. + * + * @param {jQuery|viewSaveInfo} $element + * @private + */ + _requestSave: function($element) { + var value = ''; + if($element.is('input[type=checkbox]') + && !$element.is(':checked')) { + value = 0; + } else if ($element.is('select[multiple]')) { + var entries = $element.multiselect("getChecked"); + for(var i = 0; i < entries.length; i++) { + value = value + "\n" + entries[i].value; + } + value = $.trim(value); + } else { + value = $element.val(); + } + this.configModel.set($element.attr('id'), value); + }, + + /** + * updates a checkbox element according to the provided value + * + * @param {jQuery} $element + * @param {string|number} value + * @private + */ + _setCheckBox: function($element, value) { + if(parseInt(value, 10) === 1) { + $element.attr('checked', 'checked'); + } else { + $element.removeAttr('checked'); + } + }, + + /** + * this is called when the filter mode is switched to assisted. The + * concrete tab view should implement this, to load LDAP features + * (e.g. object classes, groups, attributes…), if necessary. + */ + considerFeatureRequests: function() {}, + + /** + * this is called when the filter mode is switched to Assisted. The + * concrete tab view should request the compilation of the respective + * filter. + */ + requestCompileFilter: function() { + this.configModel.requestWizard(this.filterName); + }, + + /** + * sets the filter mode according to the provided configuration value + * + * @param {string} mode + */ + setFilterMode: function(mode) { + if(parseInt(mode, 10) === this.configModel.FILTER_MODE_ASSISTED) { + this.parsedFilterMode = this.configModel.FILTER_MODE_ASSISTED; + this.considerFeatureRequests(); + this._setFilterModeAssisted(); + if(this.isActive) { + // filter compilation should happen only, if the mode was + // switched manually, but not when initiating the view + this.requestCompileFilter(); + } + } else { + this._setFilterModeRaw(); + this.parsedFilterMode = this.configModel.FILTER_MODE_RAW; + } + }, + + /** + * updates the UI so that it represents the assisted mode setting + * + * @private + */ + _setFilterModeAssisted: function() { + var view = this; + this.$filterModeRawContainer.addClass('invisible'); + var filter = this.$filterModeRawContainer.find('.ldapFilterInputElement').val(); + this.$filterModeRawContainer.siblings('.ldapReadOnlyFilterContainer').find('.ldapFilterReadOnlyElement').text(filter); + this.$filterModeRawContainer.siblings('.ldapReadOnlyFilterContainer').removeClass('hidden'); + $.each(this.filterModeDisableableElements, function(i, $element) { + view.enableElement($element); + }); + if(!_.isUndefined(this.filterModeStateElement)) { + if (this.filterModeStateElement.status === 'enabled') { + this.enableElement(this.filterModeStateElement.$element); + } else { + this.filterModeStateElement.status = 'disabled'; + } + } + }, + + /** + * updates the UI so that it represents the raw mode setting + * + * @private + */ + _setFilterModeRaw: function() { + var view = this; + this.$filterModeRawContainer.removeClass('invisible'); + this.$filterModeRawContainer.siblings('.ldapReadOnlyFilterContainer').addClass('hidden'); + $.each(this.filterModeDisableableElements, function (i, $element) { + view.disableElement($element); + }); + + if(!_.isUndefined(this.filterModeStateElement)) { + if(this.filterModeStateElement.$element.multiselect().attr('disabled') === 'disabled') { + this.filterModeStateElement.status = 'disabled'; + } else { + this.filterModeStateElement.status = 'enabled'; + } + } + if(!_.isUndefined(this.filterModeStateElement)) { + this.disableElement(this.filterModeStateElement.$element); + } + }, + + /** + * @callback toggleConfirmCallback + * @param {boolean} isConfirmed + */ + + /** + * shows a confirmation dialogue before switching from raw to assisted + * mode if experienced mode is enabled. + * + * @param {toggleConfirmCallback} toggleFnc + * @private + */ + _toggleRawFilterModeConfirmation: function(toggleFnc) { + if( !this.isExperiencedMode() + || this.parsedFilterMode === this.configModel.FILTER_MODE_ASSISTED + ) { + toggleFnc(true); + } else { + OCdialogs.confirm( + t('user_ldap', 'Switching the mode will enable automatic LDAP queries. Depending on your LDAP size they may take a while. Do you still want to switch the mode?'), + t('user_ldap', 'Mode switch'), + toggleFnc + ); + } + }, + + /** + * toggles the visibility of a raw filter container and so also the + * state of the multi-select controls. The model is requested to save + * the state. + */ + _toggleRawFilterMode: function() { + var view = this; + this._toggleRawFilterModeConfirmation(function(isConfirmed) { + if(!isConfirmed) { + return; + } + /** var {number} */ + var mode; + if (view.parsedFilterMode === view.configModel.FILTER_MODE_ASSISTED) { + mode = view.configModel.FILTER_MODE_RAW; + } else { + mode = view.configModel.FILTER_MODE_ASSISTED; + } + view.setFilterMode(mode); + /** @var {viewSaveInfo} */ + var saveInfo = { + val: function () { + return mode; + }, + attr: function () { + return view.filterModeKey; + }, + is: function () { + return false; + } + }; + view._requestSave(saveInfo); + }); + }, + + /** + * @typedef {object} filterModeStateElementObj + * @property {string} status - either "enabled" or "disabled" + * @property {jQuery} $element + */ + + /** + * initializes a raw filter mode switcher + * + * @param {jQuery} $switcher - the element receiving the click + * @param {jQuery} $filterModeRawContainer - contains the raw filter + * input elements + * @param {jQuery[]} filterModeDisableableElements - an array of elements + * not belonging to the raw filter part that shall be en/disabled. + * @param {string} filterModeKey - the setting key that save the state + * of the mode + * @param {filterModeStateElementObj} [filterModeStateElement] - one element + * which status (enabled or not) is tracked by a setting + * @private + */ + _initFilterModeSwitcher: function( + $switcher, + $filterModeRawContainer, + filterModeDisableableElements, + filterModeKey, + filterModeStateElement + ) { + this.$filterModeRawContainer = $filterModeRawContainer; + this.filterModeDisableableElements = filterModeDisableableElements; + this.filterModeStateElement = filterModeStateElement; + this.filterModeKey = filterModeKey; + $switcher.click(this._toggleRawFilterMode); + } + + }); + + OCA.LDAP.Wizard.WizardTabGeneric = WizardTabGeneric; +})(); |