From 575d21b96280413d714777fc79bd0a5f048ad053 Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Thu, 6 Oct 2011 23:44:55 +0000 Subject: [PATCH] Progress on custom fields widgets --- ...lass.etemplate_widget_customfields.inc.php | 169 ++++++++++++++++ etemplate/js/et2_extension_customfields.js | 190 ++++++++++++++++++ 2 files changed, 359 insertions(+) create mode 100644 etemplate/inc/class.etemplate_widget_customfields.inc.php create mode 100644 etemplate/js/et2_extension_customfields.js diff --git a/etemplate/inc/class.etemplate_widget_customfields.inc.php b/etemplate/inc/class.etemplate_widget_customfields.inc.php new file mode 100644 index 0000000000..24d89f506c --- /dev/null +++ b/etemplate/inc/class.etemplate_widget_customfields.inc.php @@ -0,0 +1,169 @@ + 'Text', + 'float' => 'Float', + 'label' => 'Label', + 'select' => 'Selectbox', + 'ajax_select' => 'Search', + 'radio' => 'Radiobutton', + 'checkbox' => 'Checkbox', + 'date' => 'Date', + 'date-time'=> 'Date+Time', + 'select-account' => 'Select account', + 'button' => 'Button', // button to execute javascript + 'url' => 'Url', + 'url-email'=> 'EMail', + 'url-phone'=> 'Phone number', + 'htmlarea' => 'Formatted Text (HTML)', + 'link-entry' => 'Select entry', // should be last type, as the individual apps get added behind + ); + + /** + * @var $prefix string Prefix for every custiomfield name returned in $content (# for general (admin) customfields) + */ + protected static $prefix = '#'; + + protected $legacy_options = 'sub-type,use-private,field-names'; + + protected static $transformation = array( + 'type' => array( + 'customfields-types' => array( + 'type' => 'select', + 'sel_options' => array() + ), + 'customfields-list' => array( + 'readonly' => true + ) + ) + ); + + public function __construct($xml) + { + parent::__construct($xml); + } + + /** + * Fill type options in self::$request->sel_options to be used on the client + * + * @param string $cname + */ + public function beforeSendToClient($cname) + { + $form_name = self::form_name($cname, $this->id); + $app =& $this->getElementAttribute($form_name, 'app'); + + if(!$app) + { + $app =& $this->setElementAttribute($form_name, 'app', $GLOBALS['egw_info']['flags']['currentapp']); + $customfields =& $this->setElementAttribute($form_name, 'customfields', config::get_customfields($app)); + } + + // if we are in the etemplate editor or the app has no cf's, load the cf's from the app the tpl belongs too + if ($app && $app != 'stylite' && $app != $GLOBALS['egw_info']['flags']['currentapp'] && ( + $GLOBALS['egw_info']['flags']['currentapp'] == 'etemplate' || !$this->attrs['customfields'] || + etemplate::$hooked + )) + { + // app changed + $customfields =& config::get_customfields($app); + } + + // Filter fields + if($this->attrs['field-names']) + { + if($this->attrs['field-names'][0] == '!') { + $negate_field_filter = true; + $this->attrs['field-names'] = substr($this->attrs['field_names'],1); + } + $field_filter = explode(',', $this->attrs['field_names']); + } + $fields = $customfields; + foreach((array)$fields as $key => $field) + { + // remove private or non-private cf's, if only one kind should be displayed + if ((string)$this->attrs['use-private'] !== '' && (boolean)$field['private'] != (boolean)$this->attrs['use-private']) + { + unset($fields[$key]); + } + + // Remove filtered fields + if($field_filter && (!$negate_field_filter && !in_array($key, $field_filter) || + $negate_field_filter && in_array($key, $field_filter))) + { + unset($fields[$key]); + } + } + // check if name refers to a single custom field --> show only that + if (($pos=strpos($form_name,$this->prefix)) !== false && // allow the prefixed name to be an array index too + preg_match("/$this->prefix([^\]]+)/",$form_name,$matches) && isset($fields[$name=$matches[1]])) + { + $fields = array($name => $fields[$name]); + $value = array($this->prefix.$name => $value); + $singlefield = true; + $form_name = substr($form_name,0,-strlen("[$this->prefix$name]")); + } + + switch($type = $this->type) + { + case 'customfields-types': + foreach(self::$cf_types as $lname => $label) + { + $sel_options[$lname] = lang($label); + $fields_with_vals[]=$lname; + } + $link_types = egw_link::app_list(); + ksort($link_types); + foreach($link_types as $lname => $label) $sel_options[$lname] = '- '.$label; + + self::$transformation['type'][$type]['sel_options'] = $sel_options; + self::$transformation['type'][$type]['no_lang'] = true; + return parent::beforeSendToClient($form_name); + case 'customfields-list': + foreach(array_reverse($fields) as $lname => $field) + { + if (!empty($this->attrs['sub-type']) && !empty($field['type2']) && strpos(','.$field['type2'].',',','.$type2.',') === false) continue; // not for our content type// + if (isset($value[$this->prefix.$lname]) && $value[$this->prefix.$lname] !== '') //break; + { + $fields_with_vals[]=$lname; + } + //$stop_at_field = $name; + } + break; + default: + foreach(array_reverse($fields) as $lname => $field) + { + $fields_with_vals[]=$lname; + } + } + parent::beforeSendToClient($cname); + $this->setElementAttribute($form_name, 'fields', $fields_with_vals); + } +} diff --git a/etemplate/js/et2_extension_customfields.js b/etemplate/js/et2_extension_customfields.js new file mode 100644 index 0000000000..69c74a3908 --- /dev/null +++ b/etemplate/js/et2_extension_customfields.js @@ -0,0 +1,190 @@ +/** + * eGroupWare eTemplate2 - JS Custom fields object + * + * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License + * @package etemplate + * @subpackage api + * @link http://www.egroupware.org + * @author Nathan Gray + * @copyright Nathan Gray 2011 + * @version $Id$ + */ + +"use strict"; + +/*egw:uses + lib/tooltip; + jquery.jquery; + et2_core_xml; + et2_core_DOMWidget; + et2_core_inputWidget; +*/ + +var et2_customfields_list = et2_DOMWidget.extend([et2_IDetachedDOM], { + + attributes: { + 'customfields': { + 'name': 'Custom fields', + 'description': 'Auto filled' + }, + 'fields': { + 'name': 'Custom fields', + 'description': 'Auto filled' + }, + 'value': { + 'name': 'Custom fields', + 'description': 'Auto filled' + }, + }, + + prefix: '#', + + init: function() { + this._super.apply(this, arguments); + + // Create the table body and the table + this.tbody = $j(document.createElement("tbody")); + this.table = $j(document.createElement("table")) + .addClass("et2_grid"); + this.table.append(this.tbody); + + this.rows = {}; + this.widgets = {}; + this.detachedNodes = []; + + if(this.options && this.options.customfields) + { + this.loadFields(); + } + }, + + destroy: function() { + this._super.apply(this, arguments); + this.rows = null; + this.widgets = null; + }, + + getDOMNode: function(_sender) { + // If the parent class functions are asking for the DOM-Node, return the + // outer table. + if (_sender == this) + { + return this.table[0]; + } + + // Check whether the _sender object exists inside the management array + if(this.rows && _sender.id && this.rows[_sender.id]) + { + return this.rows[_sender.id]; + } + + return null; + }, + + loadFields: function() { + if(!this.options || !this.options.customfields) return; + if(!this.isInTree()) return; + + // Create the table rows + for(var field_name in this.options.customfields) + { + if(this.rows[field_name]) continue; + + var field = this.options.customfields[field_name]; + var row = jQuery(document.createElement("tr")) + .appendTo(this.tbody); + var cf = jQuery(document.createElement("td")) + .appendTo(row); + var attrs = jQuery.extend(true, {'id': field_name}, field); + if(this._type == 'customfields-list') { + this.detachedNodes.push(cf[0]); + this.rows[field_name] = cf[0]; + } else { + // Label in first column, widget in 2nd + cf.text(field.label + ""); + cf = jQuery(document.createElement("td")) + .appendTo(row); + this.rows[field_name] = cf[0]; + } + // No label on the widget itself + delete(attrs.label); + var widget = this.widgets[field_name] = et2_createWidget(field.type, attrs, this); + } + }, + transformAttributes: function(_attrs) { + this._super.apply(this, arguments); + + if (this.id) + { + // Set the value for this element + var contentMgr = this.getArrayMgr("content"); + if (contentMgr != null) { + var val = contentMgr.getEntry(this.id); + if (val !== null) + { + // Only set the values that match desired custom fields + _attrs["value"] = {}; + for(var key in val) + { + if(key.indexOf(this.prefix) == 0) { + _attrs["value"][key] = val[key]; + } + } + //_attrs["value"] = val; + } + } + } + + // Add in settings that are objects + if(!_attrs.customfields) + { + var data = this.getArrayMgr("modifications").getEntry(this.id); + for(var key in data) + { + if(data[key] instanceof Object && ! _attrs[key]) _attrs[key] = data[key]; + } + } + if(this.options && this.options.customfields) + { + this.loadFields(); + } + }, + + set_value: function(_value) { + if(!this.options.customfields) return; + for(var field_name in this.options.customfields) + { + if(!this.widgets[field_name] || !this.widgets[field_name].set_value) continue; + this.widgets[field_name].set_value(_value[this.prefix + field_name]); + } + }, + + /** + * Code for implementing et2_IDetachedDOM + */ + getDetachedAttributes: function(_attrs) + { + _attrs.push("value", "class"); + }, + + getDetachedNodes: function() + { + return this.detachedNodes ? this.detachedNodes : []; + }, + + setDetachedAttributes: function(_nodes, _values) + { + if (typeof _values["value"] != "undefined") + { + this.set_value(_values["value"]); + } + + if (typeof _values["class"] != "undefined") + { + this.set_class(_values["class"]); + } + } +}); + +et2_register_widget(et2_customfields_list, ["customfields", "customfields-list"]); +