From 4053d1a204898f1fd0bd5acc0cfb3a05db2a08af Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Mon, 5 May 2014 17:25:01 +0000 Subject: [PATCH] - Move function to find selectbox options to public, static so other widgets (read only selectAccount) can use it - Fix selectAccount missing extra app-specific options --- .../class.etemplate_widget_menupopup.inc.php | 9 +- etemplate/js/et2_widget_selectAccount.js | 9 +- etemplate/js/et2_widget_selectbox.js | 200 ++++++++++-------- 3 files changed, 123 insertions(+), 95 deletions(-) diff --git a/etemplate/inc/class.etemplate_widget_menupopup.inc.php b/etemplate/inc/class.etemplate_widget_menupopup.inc.php index 36edb81d5f..b5e179c737 100644 --- a/etemplate/inc/class.etemplate_widget_menupopup.inc.php +++ b/etemplate/inc/class.etemplate_widget_menupopup.inc.php @@ -94,7 +94,11 @@ class etemplate_widget_menupopup extends etemplate_widget switch ($widget_type) { - case 'select-account': // validate accounts independent of options know to server + case 'select-account': + // If in allowed options, skip account check to support app-specific options + if(count($allowed) > 0 && in_array($val,$allowed)) continue; + + // validate accounts independent of options know to server $account_type = $this->attrs['account_type'] ? $this->attrs['account_type'] : 'accounts'; $type = $GLOBALS['egw']->accounts->exists($val); //error_log(__METHOD__."($cname,...) form_name=$form_name, widget_type=$widget_type, account_type=$account_type, type=$type"); @@ -102,7 +106,8 @@ class etemplate_widget_menupopup extends etemplate_widget $type == 2 && $account_type == 'users' || in_array($account_type, array('owngroups', 'memberships')) && !in_array($val, $GLOBALS['egw']->accounts->memberships( - $GLOBALS['egw_info']['user']['account_id'], true))) + $GLOBALS['egw_info']['user']['account_id'], true)) + ) { self::set_validation_error($form_name, lang("'%1' is NOT allowed ('%2')!", $val, !$type?'not found' : ($type == 1 ? 'user' : 'group')),''); diff --git a/etemplate/js/et2_widget_selectAccount.js b/etemplate/js/et2_widget_selectAccount.js index 6425c41595..b199da14bc 100644 --- a/etemplate/js/et2_widget_selectAccount.js +++ b/etemplate/js/et2_widget_selectAccount.js @@ -683,6 +683,13 @@ var et2_selectAccount_ro = et2_link_string.extend([et2_IDetachedDOM], this.options.application = 'home-accounts'; + // Editable version allows app to set options that aren't accounts, so allow for them + var options = et2_selectbox.find_select_options(this,options['select_options']); + if(!jQuery.isEmptyObject(options)) + { + this.options.select_options = options; + } + // Don't make it look like a link though this.list.removeClass("et2_link_string").addClass("et2_selectbox"); }, @@ -699,7 +706,7 @@ var et2_selectAccount_ro = et2_link_string.extend([et2_IDetachedDOM], } // Don't bother to lookup if it's not an array, or a number - if(typeof _value == 'object' || !isNaN(_value)) + if(typeof _value == 'object' || !isNaN(_value) && _value != "") { this._super.apply(this, arguments); // Don't make it look like a link though diff --git a/etemplate/js/et2_widget_selectbox.js b/etemplate/js/et2_widget_selectbox.js index d8c8869ce9..cb1dde786b 100644 --- a/etemplate/js/et2_widget_selectbox.js +++ b/etemplate/js/et2_widget_selectbox.js @@ -169,99 +169,10 @@ var et2_selectbox = et2_inputWidget.extend( return; } - var name_parts = this.id.replace(/[/g,'[').replace(/]|]/g,'').split('['); - - // Try to find the options inside the "sel-options" array - if(this.getArrayMgr("sel_options")) + var sel_options = et2_selectbox.find_select_options(this, _attrs['select_options']); + if(!jQuery.isEmptyObject(sel_options)) { - var content_options = {}; - - // Try first according to ID - content_options = this.getArrayMgr("sel_options").getEntry(this.id); - // ID can get set to an array with 0 => ' ' - not useful - if(content_options && content_options.length == 1 && typeof content_options[0] == 'string' && content_options[0].trim() == '') - { - content_options = null; - } - // We could wind up too far inside options if label,title are defined - if(content_options && !isNaN(name_parts[name_parts.length -1]) && content_options.label && content_options.title) - { - name_parts.pop(); - content_options = this.getArrayMgr("sel_options").getEntry(name_parts.join('[')); - delete content_options["$row"]; - } - - // Select options tend to be defined once, at the top level, so try that - if(!content_options || content_options.length == 0) - { - content_options = this.getArrayMgr("sel_options").getRoot().getEntry(name_parts[name_parts.length-1]); - } - - // Try in correct namespace (inside a grid or something) - if(!content_options || content_options.length == 0) - { - content_options = this.getArrayMgr("sel_options").getEntry(name_parts[name_parts.length-1]); - } - - // Try name like widget[$row] - if(!content_options || content_options.length == 0) - { - var pop_that = jQuery.extend([],name_parts); - while(pop_that.length > 0 && (!content_options || content_options.length == 0)) - { - pop_that.pop(); - content_options = this.getArrayMgr('sel_options').getEntry(pop_that.join('[')); - } - } - - // Maybe in a row, and options got stuck in ${row} instead of top level - // not sure this code is still needed, as server-side no longer creates ${row} or {$row} for select-options - if(!content_options || content_options.length == 0) - { - var row_stuck = ['${row}','{$row}']; - for(var i = 0; i < row_stuck.length; i++) - { - // perspectiveData.row in nm, data["${row}"] in an auto-repeat grid - if(this.getArrayMgr("sel_options").perspectiveData.row || this.getArrayMgr("sel_options").data[row_stuck[i]]) - { - var row_id = this.id.replace(/[0-9]+/,row_stuck[i]); - content_options = this.getArrayMgr("sel_options").getEntry(row_id); - if(!content_options || content_options.length == 0) - { - content_options = this.getArrayMgr("sel_options").getEntry(row_stuck[i] + '[' + this.id + ']'); - } - } - } - } - if(_attrs["select_options"] && !jQuery.isEmptyObject(_attrs['select_options']) && content_options) - { - _attrs["select_options"] = jQuery.extend({},_attrs["select_options"],content_options); - } - else if (content_options) - { - _attrs["select_options"] = content_options; - } - } - - // Check whether the options entry was found, if not read it from the - // content array. - if (jQuery.isEmptyObject(_attrs["select_options"]) && this.getArrayMgr('content') != null) - { - if (content_options) _attrs['select_options'] = content_options; - var content_mgr = this.getArrayMgr('content'); - if (content_mgr) - { - // If that didn't work, check according to ID - if (!content_options) _attrs["select_options"] = content_mgr.getEntry("options-" + this.id); - // Again, try last name part at top level - this is usually just the value - var content_options = content_mgr.getRoot().getEntry(name_parts[name_parts.length-1]); - } - } - - // Default to an empty object - if (_attrs["select_options"] == null) - { - _attrs["select_options"] = {}; + _attrs['select_options'] = sel_options; } }, @@ -824,6 +735,111 @@ et2_register_widget(et2_selectbox, ["menupopup", "listbox", "select", "select-ca 'select-day', 'select-dow', 'select-hour', 'select-number', 'select-app', 'select-lang', 'select-bool', 'select-timezone' ]); +// Static class stuff +jQuery.extend(et2_selectbox, +{ + /** + * Find the select options for a widget, out of the many places they could be. + * @param {et2_widget} Widget to check for. Should be some sort of select widget. + * @param {object} Select options in attributes array + * @return {object} Select options, or empty object + */ + find_select_options: function(widget, attr_options) + { + var name_parts = widget.id.replace(/[/g,'[').replace(/]|]/g,'').split('['); + + var content_options = {}; + + // Try to find the options inside the "sel-options" array + if(widget.getArrayMgr("sel_options")) + { + // Try first according to ID + content_options = widget.getArrayMgr("sel_options").getEntry(widget.id); + // ID can get set to an array with 0 => ' ' - not useful + if(content_options && content_options.length == 1 && typeof content_options[0] == 'string' && content_options[0].trim() == '') + { + content_options = null; + } + // We could wind up too far inside options if label,title are defined + if(content_options && !isNaN(name_parts[name_parts.length -1]) && content_options.label && content_options.title) + { + name_parts.pop(); + content_options = widget.getArrayMgr("sel_options").getEntry(name_parts.join('[')); + delete content_options["$row"]; + } + + // Select options tend to be defined once, at the top level, so try that + if(!content_options || content_options.length == 0) + { + content_options = widget.getArrayMgr("sel_options").getRoot().getEntry(name_parts[name_parts.length-1]); + } + + // Try in correct namespace (inside a grid or something) + if(!content_options || content_options.length == 0) + { + content_options = widget.getArrayMgr("sel_options").getEntry(name_parts[name_parts.length-1]); + } + + // Try name like widget[$row] + if(!content_options || content_options.length == 0) + { + var pop_that = jQuery.extend([],name_parts); + while(pop_that.length > 0 && (!content_options || content_options.length == 0)) + { + pop_that.pop(); + content_options = widget.getArrayMgr('sel_options').getEntry(pop_that.join('[')); + } + } + + // Maybe in a row, and options got stuck in ${row} instead of top level + // not sure this code is still needed, as server-side no longer creates ${row} or {$row} for select-options + if(!content_options || content_options.length == 0) + { + var row_stuck = ['${row}','{$row}']; + for(var i = 0; i < row_stuck.length; i++) + { + // perspectiveData.row in nm, data["${row}"] in an auto-repeat grid + if(widget.getArrayMgr("sel_options").perspectiveData.row || widget.getArrayMgr("sel_options").data[row_stuck[i]]) + { + var row_id = widget.id.replace(/[0-9]+/,row_stuck[i]); + content_options = widget.getArrayMgr("sel_options").getEntry(row_id); + if(!content_options || content_options.length == 0) + { + content_options = widget.getArrayMgr("sel_options").getEntry(row_stuck[i] + '[' + widget.id + ']'); + } + } + } + } + if(attr_options && !jQuery.isEmptyObject(attr_options) && content_options) + { + content_options = jQuery.extend(true, {},attr_options,content_options); + } + } + + // Check whether the options entry was found, if not read it from the + // content array. + if (jQuery.isEmptyObject(content_options) && widget.getArrayMgr('content') != null) + { + if (content_options) attr_options = content_options; + var content_mgr = widget.getArrayMgr('content'); + if (content_mgr) + { + // If that didn't work, check according to ID + if (!content_options) content_options = content_mgr.getEntry("options-" + widget.id); + // Again, try last name part at top level - this is usually just the value + if (!content_options) content_options = content_mgr.getRoot().getEntry(name_parts[name_parts.length-1]); + } + } + + // Default to an empty object + if (content_options == null) + { + content_options = {}; + } + return content_options; + } +}); + /** * et2_selectbox_ro is the readonly implementation of the selectbox. *