From ec7f8931b2a56174fd2aca46bc40d8c7fcb2f2ef Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Wed, 22 Jan 2020 20:12:36 +0100 Subject: [PATCH] selectbox widget and some fixes --- api/js/etemplate/et2_core_inputWidget.js | 2 +- api/js/etemplate/et2_core_inputWidget.ts | 2 +- api/js/etemplate/et2_core_widget.ts | 2 +- api/js/etemplate/et2_types.d.ts | 10 +- api/js/etemplate/et2_widget_date.js | 7 +- api/js/etemplate/et2_widget_date.ts | 13 +- api/js/etemplate/et2_widget_selectbox.js | 3229 ++++++++++------------ api/js/etemplate/et2_widget_selectbox.ts | 1838 ++++++++++++ 8 files changed, 3329 insertions(+), 1774 deletions(-) create mode 100644 api/js/etemplate/et2_widget_selectbox.ts diff --git a/api/js/etemplate/et2_core_inputWidget.js b/api/js/etemplate/et2_core_inputWidget.js index e933bda57b..c5e6a37ba9 100644 --- a/api/js/etemplate/et2_core_inputWidget.js +++ b/api/js/etemplate/et2_core_inputWidget.js @@ -96,7 +96,7 @@ var et2_inputWidget = /** @class */ (function (_super) { // } _super.prototype.detachFromDOM.call(this); }; - et2_inputWidget.prototype.change = function (_node) { + et2_inputWidget.prototype.change = function (_node, _widget, _value) { var messages = []; var valid = this.isValid(messages); // Passing false will clear any set messages diff --git a/api/js/etemplate/et2_core_inputWidget.ts b/api/js/etemplate/et2_core_inputWidget.ts index 3dba37724c..134f30093d 100644 --- a/api/js/etemplate/et2_core_inputWidget.ts +++ b/api/js/etemplate/et2_core_inputWidget.ts @@ -146,7 +146,7 @@ export class et2_inputWidget extends et2_valueWidget implements et2_IInput, et2_ super.detachFromDOM(); } - change(_node) + change(_node, _widget?, _value?) { var messages = []; var valid = this.isValid(messages); diff --git a/api/js/etemplate/et2_core_widget.ts b/api/js/etemplate/et2_core_widget.ts index 3a137c892c..c3d2b39a26 100644 --- a/api/js/etemplate/et2_core_widget.ts +++ b/api/js/etemplate/et2_core_widget.ts @@ -775,7 +775,7 @@ export class et2_widget extends ClassWithAttributes * * @param {Promise[]} promises List of promises from widgets that are not done. Pass an empty array, it will be filled if needed. */ - loadingFinished(promises) + loadingFinished(promises?) { // Call all availble setters this.initAttributes(this.options); diff --git a/api/js/etemplate/et2_types.d.ts b/api/js/etemplate/et2_types.d.ts index 21cef642a7..ab9875853d 100644 --- a/api/js/etemplate/et2_types.d.ts +++ b/api/js/etemplate/et2_types.d.ts @@ -119,12 +119,7 @@ declare var et2_radioGroup : any; declare var et2_script : any; declare var et2_selectAccount : any; declare var et2_selectAccount_ro : any; -declare class et2_selectbox extends et2_inputWidget { - loadingFinished() - getDOMNode() - set_value(s: string) - getValue() -} +declare class et2_selectbox extends et2_inputWidget {} declare var et2_selectbox_ro : any; declare var et2_menulist : any; declare var et2_split : any; @@ -164,4 +159,5 @@ declare function et2_compileLegacyJS(_code : string, _widget : et2_widget, _cont declare function et2_loadXMLFromURL(_url : string, _callback : Function, _context? : object, _fail_callback? : Function) : void; declare function et2_directChildrenByTagName(_node, _tagName); declare function et2_filteredNodeIterator(_node, _callback, _context); -declare function et2_readAttrWithDefault(_node, _name, _default?); \ No newline at end of file +declare function et2_readAttrWithDefault(_node, _name, _default?); +declare function sprintf(format : string, ...args : any) : string; \ No newline at end of file diff --git a/api/js/etemplate/et2_widget_date.js b/api/js/etemplate/et2_widget_date.js index b8306ff05d..e9d32820d5 100644 --- a/api/js/etemplate/et2_widget_date.js +++ b/api/js/etemplate/et2_widget_date.js @@ -156,7 +156,7 @@ var et2_date = /** @class */ (function (_super) { */ et2_date.prototype.set_readonly = function (_ro) { if (this.input_date && !this.input_date.attr('disabled') != !_ro) { - this.input_date.attr('disabled', !_ro ? 0 : 1) + this.input_date.prop('disabled', !!_ro) .datepicker('option', 'disabled', !!_ro); } }; @@ -573,6 +573,7 @@ String: A string in the user\'s date format, or a relative date. Relative dates }; return et2_date; }(et2_core_inputWidget_1.et2_inputWidget)); +exports.et2_date = et2_date; et2_core_widget_1.et2_register_widget(et2_date, ["date", "date-time", "date-timeonly"]); /** * Class which implements the "date-duration" XET-Tag @@ -820,6 +821,7 @@ var et2_date_duration = /** @class */ (function (_super) { }; return et2_date_duration; }(et2_date)); +exports.et2_date_duration = et2_date_duration; et2_core_widget_1.et2_register_widget(et2_date_duration, ["date-duration"]); /** * r/o date-duration @@ -885,6 +887,7 @@ var et2_date_duration_ro = /** @class */ (function (_super) { }; return et2_date_duration_ro; }(et2_date_duration)); +exports.et2_date_duration_ro = et2_date_duration_ro; et2_core_widget_1.et2_register_widget(et2_date_duration_ro, ["date-duration_ro"]); /** * et2_date_ro is the readonly implementation of some date widget. @@ -1090,6 +1093,7 @@ var et2_date_ro = /** @class */ (function (_super) { }; return et2_date_ro; }(et2_core_valueWidget_1.et2_valueWidget)); +exports.et2_date_ro = et2_date_ro; et2_core_widget_1.et2_register_widget(et2_date_ro, ["date_ro", "date-time_ro", "date-since", "date-time_today", "time_or_date", "date-timeonly_ro"]); /** * Widget for selecting a date range @@ -1360,5 +1364,6 @@ var et2_date_range = /** @class */ (function (_super) { ]; return et2_date_range; }(et2_core_inputWidget_1.et2_inputWidget)); +exports.et2_date_range = et2_date_range; et2_core_widget_1.et2_register_widget(et2_date_range, ["date-range"]); //# sourceMappingURL=et2_widget_date.js.map \ No newline at end of file diff --git a/api/js/etemplate/et2_widget_date.ts b/api/js/etemplate/et2_widget_date.ts index 38e6416a71..040139a36b 100644 --- a/api/js/etemplate/et2_widget_date.ts +++ b/api/js/etemplate/et2_widget_date.ts @@ -22,6 +22,7 @@ import { ClassWithAttributes } from "./et2_core_inheritance"; import { et2_widget, et2_createWidget, et2_register_widget, WidgetConfig } from "./et2_core_widget"; import { et2_valueWidget } from './et2_core_valueWidget' import { et2_inputWidget } from './et2_core_inputWidget' +import { et2_selectbox } from './et2_widget_selectbox' import './et2_types'; import {et2_DOMWidget} from "./et2_core_DOMWidget"; @@ -40,7 +41,7 @@ declare function date (format : string, timestamp? : string | number | Date); * Widgets uses jQuery date- and time-picker for desktop browsers and * HTML5 input fields for mobile devices to get their native UI for date/time entry. */ -class et2_date extends et2_inputWidget +export class et2_date extends et2_inputWidget { static readonly _attributes: any = { "value": { @@ -228,7 +229,7 @@ String: A string in the user\'s date format, or a relative date. Relative dates { if (this.input_date && !this.input_date.attr('disabled') != !_ro) { - this.input_date.attr('disabled', !_ro ? 0 : 1) + this.input_date.prop('disabled', !!_ro) .datepicker('option', 'disabled', !!_ro); } } @@ -655,7 +656,7 @@ et2_register_widget(et2_date, ["date", "date-time", "date-timeonly"]); /** * Class which implements the "date-duration" XET-Tag */ -class et2_date_duration extends et2_date +export class et2_date_duration extends et2_date { static readonly _attributes: any = { "data_format": { @@ -963,7 +964,7 @@ et2_register_widget(et2_date_duration, ["date-duration"]); /** * r/o date-duration */ -class et2_date_duration_ro extends et2_date_duration implements et2_IDetachedDOM +export class et2_date_duration_ro extends et2_date_duration implements et2_IDetachedDOM { createInputWidget() { @@ -1037,7 +1038,7 @@ et2_register_widget(et2_date_duration_ro, ["date-duration_ro"]); /** * et2_date_ro is the readonly implementation of some date widget. */ -class et2_date_ro extends et2_valueWidget implements et2_IDetachedDOM +export class et2_date_ro extends et2_valueWidget implements et2_IDetachedDOM { /** * Ignore all more advanced attributes. @@ -1282,7 +1283,7 @@ et2_register_widget(et2_date_ro, ["date_ro", "date-time_ro", "date-since", "date /** * Widget for selecting a date range */ -class et2_date_range extends et2_inputWidget +export class et2_date_range extends et2_inputWidget { static readonly _attributes: any = { value: { diff --git a/api/js/etemplate/et2_widget_selectbox.js b/api/js/etemplate/et2_widget_selectbox.js index 47ba765f81..54209eddbc 100644 --- a/api/js/etemplate/et2_widget_selectbox.js +++ b/api/js/etemplate/et2_widget_selectbox.js @@ -1,3 +1,4 @@ +"use strict"; /** * EGroupware eTemplate2 - JS Selectbox object * @@ -8,1788 +9,1502 @@ * @author Nathan Gray * @author Andreas Stöckel * @copyright Nathan Gray 2011 - * @version $Id$ */ - +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); /*egw:uses - /vendor/bower-asset/jquery/dist/jquery.js; - /api/js/jquery/chosen/chosen.jquery.js; - et2_core_xml; - et2_core_DOMWidget; - et2_core_inputWidget; + /vendor/bower-asset/jquery/dist/jquery.js; + /api/js/jquery/chosen/chosen.jquery.js; + et2_core_xml; + et2_core_DOMWidget; + et2_core_inputWidget; */ - +require("./et2_core_common"); +var et2_core_inheritance_1 = require("./et2_core_inheritance"); +var et2_core_widget_1 = require("./et2_core_widget"); +var et2_core_inputWidget_1 = require("./et2_core_inputWidget"); +require("./et2_types"); +var et2_core_DOMWidget_1 = require("./et2_core_DOMWidget"); +// all calls to Chosen jQuery plugin as jQuery.(un)chosen() give errors which are currently suppressed with @ts-ignore +// adding npm package @types/chosen-js did NOT help :( /** - * @augments et2_inputWidget + * et2 select(box) widget */ -var et2_selectbox = (function(){ "use strict"; return et2_inputWidget.extend( -{ - attributes: { - // todo fully implement attr[multiple] === "dynamic" to render widget with a button to switch to multiple - // as it is used in account_id selection in admin >> mailaccount (app.admin.edit_multiple method client-side) - "multiple": { - "name": "multiple", - "type": "boolean", - "default": false, - "description": "Allow selecting multiple options" - }, - "expand_multiple_rows": { - "name": "Expand multiple", - "type": "integer", - "default": et2_no_init, - "description": "Shows single select widget, with a button. If the "+ - "user clicks the button, the input will toggle to a multiselect,"+ - "with this many rows. " - }, - "rows": { - "name": "Rows", - "type": "any", // Old options put either rows or empty_label in first space - "default": 1, - "description": "Number of rows to display" - }, - "empty_label": { - "name": "Empty label", - "type": "string", - "default": "", - "description": "Textual label for first row, eg: 'All' or 'None'. ID will be ''", - translate:true - }, - "select_options": { - "type": "any", - "name": "Select options", - "default": {}, - "description": "Internaly used to hold the select options." - }, - "selected_first": { - "name": "Selected options first", - "type": "boolean", - "default": true, - "description": "For multi-selects, put the selected options at the top of the list when first loaded" - }, - - // Chosen options - "search": { - "name": "Search", - "type": "boolean", - "default": false, - "description": "For single selects, add a search box to the drop-down list" - }, - "tags": { - "name": "Tag style", - "type": "boolean", - "default": false, - "description": "For multi-selects, displays selected as a list of tags instead of a big list" - }, - "allow_single_deselect": { - "name": "Allow Single Deselect", - "type": "boolean", - "default": true, - "description": "Allow user to unset current selected value" - }, - - // Value can be string or integer - "value": { - "type": "any" - }, - // Type specific legacy options. Avoid using. - "other": { - "ignore": true, - "type": "any" - }, - value_class: { - name: "Value class", - type: "string", - default: "", - description: "Allow to set a custom css class combined with selected value. (e.g. cat_23)" - } - }, - - legacyOptions: ["rows","other"], // Other is sub-type specific - - /** - * Construtor - * - * @memberOf et2_selectbox - */ - init: function() { - this._super.apply(this, arguments); - - this.input = null; - // Start at '' to avoid infinite loops while setting value/select options - this.value = ''; - - // Allow no other widgets inside this one - this.supportedWidgetClasses = []; - - // Legacy options could have row count or empty label in first slot - if(typeof this.options.rows == "string") - { - if(isNaN(this.options.rows)) - { - this.options.empty_label = this.egw().lang(this.options.rows); - this.options.rows = 1; - } - else - { - this.options.rows = parseInt(this.options.rows); - } - } - - if(this.options.rows > 1) - { - this.options.multiple = true; - if(this.options.tags) - { - this.createInputWidget(); - } - else - { - this.createMultiSelect(); - } - } - else - { - this.createInputWidget(); - } - if(!this.options.empty_label && !this.options.readonly && this.options.multiple) - { - this.options.empty_label = this.egw().lang('Select some options'); - } - }, - - destroy: function() { - if(this.input != null) - { - this.input.unchosen(); - } - if(this.expand_button) - { - this.expand_button.off(); - this.expand_button.remove(); - this.expand_button = null; - } - this._super.apply(this, arguments); - - this.input = null; - }, - - transformAttributes: function(_attrs) { - this._super.apply(this, arguments); - - // If select_options are already known, skip the rest - if(this.options && this.options.select_options && !jQuery.isEmptyObject(this.options.select_options) || - _attrs.select_options && !jQuery.isEmptyObject(_attrs.select_options) || - // Allow children to skip select_options - check to make sure default got set to something (should be {}) - typeof _attrs.select_options == 'undefined' || _attrs.select_options === null - ) - { - // do not return inside nextmatch, as get_rows data might have changed select_options - // for performance reasons we only do it for first row, which should have id "0[...]" - if (this.getParent()._type != 'rowWidget' || !_attrs.id || _attrs.id[0] != '0') return; - } - - var sel_options = et2_selectbox.find_select_options(this, _attrs['select_options'], _attrs); - if(!jQuery.isEmptyObject(sel_options)) - { - _attrs['select_options'] = sel_options; - } - }, - - /** - * Switch instanciated widget to multi-selection and back, optionally enabeling tags too - * - * If you want to switch tags on too, you need to do so after switching to multiple! - * - * @param {boolean} _multiple - * @param {integer} _size default=3 - */ - set_multiple: function(_multiple, _size) - { - this.options.multiple = _multiple; - - if (this.input) - { - if (_multiple) - { - this.input.attr('size', _size || 3); - this.input.attr('multiple', true); - this.input.attr('name', this.id + '[]'); - - if (this.input[0].options.length && this.input[0].options[0].value === '') - { - this.input[0].options[0] = null; - } - } - else - { - this.input.attr('multiple', false); - this.input.removeAttr('size'); - this.input.attr('name', this.id); - - if (this.options.empty_label && this.input[0].options[0].value !== '') - { - this._appendOptionElement('', this.options.empty_label); - } - } - if(this.expand_button) - { - if(_multiple) - { - this.expand_button.addClass('ui-icon-minus').removeClass('ui-icon-plus'); - } - else - { - this.expand_button.removeClass('ui-icon-minus').addClass('ui-icon-plus'); - } - } - } - }, - - change: function(_node, _widget, _value) { - var valid = this._super.apply(this, arguments); - if (!this.input) return valid; - var selected = this.input.siblings().find('a.chzn-single'); - var val = _value && _value.selected ? _value.selected : this.input.val(); - switch (this._type) - { - case 'select-country': - if (selected && selected.length == 1 && val) - { - selected.removeClass (function (index, className) { - return (className.match (/(^|\s)flag-\S+/g) || []).join(' '); - }); - selected.find('span.img').remove(); - selected.prepend(''); - selected.addClass('et2_country-select flag-'+ val.toLowerCase()); - } - else if(selected) - { - selected.removeClass('et2_country-select'); - } - break; - } - return valid; - }, - - /** - * Add an option to regular drop-down select - * - * @param {string} _value value attribute of option - * @param {string} _label label of option - * @param {string} _title title attribute of option - * @param {node} dom_element parent of new option - * @param {string} _class specify classes of option - */ - _appendOptionElement: function(_value, _label, _title, dom_element, _class) { - if(_value == "" && (_label == null || _label == "")) { - return; // empty_label is added in set_select_options anyway, ignoring it here to not add it twice - } - - if(this.input == null) - { - return this._appendMultiOption(_value, _label, _title, dom_element); - } - - var option = jQuery(document.createElement("option")) - .attr("value", _value) - .text(_label+""); - option.addClass(_class); - if (this.options.tags) - { - switch (this._type) - { - case 'select-cat': - option.addClass('cat_'+_value); - break; - case 'select-country': - // jQuery(document.createElement("span")).addClass('et2_country-select').appenTo(option); - option.addClass('et2_country-select flag-'+_value.toLowerCase()); - break; - } - if (this.options.value_class != '') option.addClass(this.options.value_class+_value); - } - if (typeof _title != "undefined" && _title) - { - option.attr("title", _title); - } - if(_label == this.options.empty_label || this.options.empty_label == "" && _value === "") - { - // Make sure empty / all option is first - option.prependTo(this.input); - } - else - { - option.appendTo(dom_element || this.input); - } - }, - - /** - * Append a value to multi-select - * - * @param {string} _value value attribute of option - * @param {string} _label label of option - * @param {string} _title title attribute of option - * @param {node} dom_element parent of new option - */ - _appendMultiOption: function(_value, _label, _title, dom_element) { - var option_data = null; - if(typeof _label == "object") - { - option_data = _label; - _label = option_data.label; - } - - // Already in header - if(_label == this.options.empty_label) return; - - var opt_id = this.dom_id + "_opt_" + _value; - var label = jQuery(document.createElement("label")) - .attr("for", opt_id) - .hover( - function() {jQuery(this).addClass("ui-state-hover");}, - function() {jQuery(this).removeClass("ui-state-hover");} - ); - var option = jQuery(document.createElement("input")) - .attr("type", "checkbox") - .attr("id",opt_id) - .attr("value", _value) - .appendTo(label); - if(typeof _title !== "undefined") - { - option.attr("title",_title); - } - - // Some special stuff for categories - if(option_data ) - { - if(option_data.icon) - { - var img = this.egw().image(option_data.icon); - jQuery(document.createElement(img ? "img" : "div")) - .attr("src", img) - .addClass('cat_icon cat_' + _value) - .appendTo(label); - } - if(option_data.color) - { - label.css("background-color",option_data.color) - .addClass('cat_' + _value); - } - } - label.append(jQuery(""+_label+"")); - var li = jQuery(document.createElement("li")).append(label); - if (this.options.value_class !='') li.addClass(this.options.value_class+_value); - li.appendTo(dom_element || this.multiOptions); - }, - - /** - * Create a regular drop-down select box - */ - createInputWidget: function() { - // Create the base input widget - this.input = jQuery(document.createElement("select")) - .addClass("et2_selectbox") - .attr("size", this.options.rows); - - this.setDOMNode(this.input[0]); - - // Add the empty label - if(this.options.empty_label) - { - this._appendOptionElement("", this.options.empty_label); - } - - // Set multiple - if(this.options.multiple) - { - this.input.attr("multiple", "multiple"); - } - }, - - /** - * Create a list of checkboxes - */ - createMultiSelect: function() { - var node = jQuery(document.createElement("div")) - .addClass("et2_selectbox"); - - var header = jQuery(document.createElement("div")) - .addClass("ui-widget-header ui-helper-clearfix") - .appendTo(node); - var controls = jQuery(document.createElement("ul")) - .addClass('ui-helper-reset') - .appendTo(header); - - jQuery(document.createElement("span")) - .text(this.options.empty_label) - .addClass("ui-multiselect-header") - .appendTo(header); - - - // Set up for options to be added later - var options = this.multiOptions = jQuery(document.createElement("ul")); - this.multiOptions.addClass("ui-multiselect-checkboxes ui-helper-reset") - .css("height", 1.9*this.options.rows + "em") - .appendTo(node); - - if(this.options.rows >= 5) - { - // Check / uncheck all - var header_controls = { - check: { - icon_class: 'ui-icon-check', - label: this.egw().lang('Check all'), - click: function(e) { - var all_off = false; - jQuery("input[type='checkbox']",e.data).each(function() { - if(!jQuery(this).prop("checked")) all_off = true; - }); - jQuery("input[type='checkbox']",e.data).prop("checked", all_off); - } - } - }; - for(var key in header_controls) - { - jQuery(document.createElement("li")) - .addClass("et2_clickable") - .click(options, header_controls[key].click) - .attr("title", header_controls[key].label) - .append('') - .appendTo(controls); - } - - } - - this.setDOMNode(node[0]); - }, - - doLoadingFinished: function() { - this._super.apply(this, arguments); - - this.set_tags(this.options.tags, this.options.width); - - return true; - }, - - loadFromXML: function(_node) { - // Handle special case where legacy option for empty label is used (conflicts with rows), and rows is set as an attribute - var legacy = _node.getAttribute("options"); - if(legacy) - { - var legacy = legacy.split(","); - if(legacy.length && isNaN(legacy[0])) - { - this.options.empty_label = legacy[0]; - } - } - - // Read the option-tags - var options = et2_directChildrenByTagName(_node, "option"); - if(options.length) - { - // Break reference to content manager, we don't want to add to it - this.options.select_options = jQuery.extend([], this.options.select_options); - } - var egw = this.egw(); - for (var i = 0; i < options.length; i++) - { - this.options.select_options.push({ - value: et2_readAttrWithDefault(options[i], "value", options[i].textContent), - // allow options to contain multiple translated sub-strings eg: {Firstname}.{Lastname} - "label": options[i].textContent.replace(/{([^}]+)}/g, function(str,p1) - { - return egw.lang(p1); - }), - "title": et2_readAttrWithDefault(options[i], "title", "") - }); - } - - this.set_select_options(this.options.select_options); - }, - - /** - * Regular expression, to check string-value contains multiple comma-separated values - */ - _is_multiple_regexp: /^[,0-9A-Za-z/_ -]+$/, - - /** - * Regular expression and replace value for escaping values in jQuery selectors used to find options - */ - _escape_value_replace: /\\/g, - _escape_value_with: '\\\\', - - /** - * Find an option by it's value - * - * Taking care of escaping values correctly eg. EGroupware\Api\Mail\Smtp using above regular expression - * - * @param {string} _value - * @return {array} - */ - find_option: function(_value) - { - return jQuery("option[value='"+(typeof _value === 'string' ? _value.replace(this._escape_value_replace, this._escape_value_with) : _value)+"']", this.input); - }, - - /** - * Set value - * - * @param {string|number} _value - * @param {boolean} _dont_try_set_options true: if _value is not in options, use "" instead of calling set_select_options - * (which would go into an infinit loop) - */ - set_value: function(_value, _dont_try_set_options) - { - if (typeof _value == "number") _value = ""+_value; // convert to string for consitent matching - if(typeof _value == "string" && (this.options.multiple || this.options.expand_multiple_rows) && _value.match(this._is_multiple_regexp) !== null) - { - _value = _value.split(','); - } - if(this.input !== null && this.options.select_options && ( - !jQuery.isEmptyObject(this.options.select_options) || this.options.select_options.length > 0 - ) && this.input.children().length == 0) - { - // No options set yet - this.set_select_options(this.options.select_options); - } - // select-cat set/unset right cat_ color for selected value - if ((this._type == 'select-cat' || this.options.value_class) && this.options.tags) { - var chosen = this.input.next(); - var prefix_c = this.options.value_class ? this.options.value_class : 'cat_'; - this.input.removeClass(prefix_c+this._oldValue); - this.input.addClass(prefix_c+this.value); - if (chosen.length > 0) { - chosen.removeClass(prefix_c+this._oldValue); - chosen.addClass(prefix_c+this.value); - } - } - if (this._type == 'select-country' && this.options.tags) - { - var selected = this.input.siblings().find('a.chzn-single'); - if (selected && selected.length == 1 && _value) - { - selected.removeClass (function (index, className) { - return (className.match (/(^|\s)flag-\S+/g) || []).join(' '); - }); - selected.find('span.img').remove(); - selected.prepend(''); - selected.addClass('et2_country-select flag-'+ _value.toLowerCase()); - } - } - if(this._type == "select-bitwise" && _value && !isNaN(_value) && this.options.select_options) - { - var new_value = []; - for(var index in this.options.select_options) - { - var right = this.options.select_options[index].value; - if(!!(_value & right)) - { - new_value.push(right); - } - } - _value = new_value; - } - this._oldValue = this.value; - if(this.input !== null && (this.options.tags || this.options.search)) - { - // Value must be a real Array, not an object - this.input.val(typeof _value == 'object' && _value != null ? jQuery.map(_value,function(value,index){return [value];}) : _value); - this.input.trigger("liszt:updated"); - var self = this; - if (this._type == 'listbox' && this.options.value_class != '') - { - var chosen = this.input.next(); - chosen.find('.search-choice-close').each(function(i,v){ - jQuery(v).parent().addClass(self.options.value_class + self.options.select_options[v.rel]['value']); - }); - } - this.value = _value; - return; - } - if(this.input == null) - { - return this.set_multi_value(_value); - } - // Auto-expand multiple if not yet turned on, and value has multiple - if(this.options.expand_multiple_rows && !this.options.multiple && jQuery.isArray(_value) && _value.length > 1) - { - this.set_multiple(true, this.options.expand_multiple_rows); - } - - jQuery("option",this.input).prop("selected", false); - if (typeof _value == "object") - { - for(var i in _value) - { - this.find_option(_value[i]).prop("selected", true); - } - } - else - { - if(_value && this.find_option(_value).prop("selected", true).length == 0) - { - if(this.options.select_options[_value] || - this.options.select_options.filter && - this.options.select_options.filter(function(value) {return value == _value;}) && - !_dont_try_set_options) - { - // Options not set yet? Do that now, which will try again. - return this.set_select_options(this.options.select_options); - } - else if (_dont_try_set_options) - { - this.value = ""; - } - else if (jQuery.isEmptyObject(this.options.select_options)) - { - this.egw().debug("warn", "Can't set value to '%s', widget has no options set",_value, this); - } - else - { - var debug_value = _value; - if(debug_value === null) debug_value == 'NULL'; - this.egw().debug("warn", "Tried to set value '%s' that isn't an option", debug_value, this); - } - return; - } - } - this.value = _value; - if(this.isAttached() && this._oldValue !== et2_no_init && this._oldValue !== _value) - { - this.input.change(); - } - }, - - /** - * Find an option by it's value - * - * Taking care of escaping values correctly eg. EGroupware\Api\Mail\Smtp - * - * @param {string} _value - * @return {array} - */ - find_multi_option: function(_value) - { - return jQuery("input[value='"+ - (typeof _value === 'string' ? _value.replace(this._escape_value_replace, this._escape_value_with) : _value)+ - "']", this.multiOptions - ); - }, - - set_multi_value: function(_value) - { - jQuery("input",this.multiOptions).prop("checked", false); - if (typeof _value == "object") - { - for(var i in _value) - { - this.find_multi_option(_value[i]).prop("checked", true); - } - } - else - { - if(this.find_multi_option(_value).prop("checked", true).length == 0) - { - var debug_value = _value; - if(debug_value === null) debug_value == 'NULL'; - this.egw().debug("warn", "Tried to set value '%s' that isn't an option", debug_value, this); - } - } - - // Sort selected to the top - if(this.selected_first) - { - this.multiOptions.find("li:has(input:checked)").prependTo(this.multiOptions); - } - this.value = _value; - }, - - /** - * Method to check all options of a multi-select, if not all are selected, or none if all where selected - * - * @todo: add an attribute to automatic add a button calling this method - */ - select_all_toggle: function() - { - var all = jQuery("input",this.multiOptions); - all.prop("checked", jQuery("input:checked",this.multiOptions).length == all.length ? false : true); - }, - - /** - * Add a button to toggle between single select and multi select. - * - * @param {number} _rows How many rows for multi-select - */ - set_expand_multiple_rows: function(_rows) - { - this.options.expand_multiple_rows = _rows; - - var surroundings = this.getSurroundings(); - if(_rows <= 1 && this.expand_button ) - { - // Remove - surroundings.removeDOMNode(this.expand_button.get(0)); - } - else - { - if (!this.expand_button) - { - var button_id = this.getInstanceManager().uniqueId+'_'+this.id.replace(/\./g, '-') + "_expand"; - this.expand_button = jQuery("