forked from extern/egroupware
Work in progress on tree
This commit is contained in:
parent
8b20b2d314
commit
548ac686d8
232
etemplate/inc/class.etemplate_widget_tree.inc.php
Normal file
232
etemplate/inc/class.etemplate_widget_tree.inc.php
Normal file
@ -0,0 +1,232 @@
|
||||
<?php
|
||||
/**
|
||||
* EGroupware - eTemplate serverside tree widget
|
||||
*
|
||||
* @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 2012 Nathan Gray
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
/**
|
||||
* eTemplate tree widget
|
||||
*/
|
||||
egw_framework::includeCSS('/phpgwapi/js/dhtmlxtree/css/dhtmlXTree.css');
|
||||
class etemplate_widget_tree extends etemplate_widget
|
||||
{
|
||||
|
||||
/**
|
||||
* Parse and set extra attributes from xml in template object
|
||||
*
|
||||
* Reimplemented to parse our differnt attributes
|
||||
*
|
||||
* @param string|XMLReader $xml
|
||||
* @return etemplate_widget_template current object or clone, if any attribute was set
|
||||
*/
|
||||
public function set_attrs($xml)
|
||||
{
|
||||
$this->attrs['type'] = $xml->localName;
|
||||
parent::set_attrs($xml);
|
||||
|
||||
// set attrs[multiple] from attrs[options], unset options only if it just contains number or rows
|
||||
if ($this->attrs['options'] > 1)
|
||||
{
|
||||
$this->attrs['multiple'] = (int)$this->attrs['options'];
|
||||
if ((string)$this->attrs['multiple'] == $this->attrs['options'])
|
||||
{
|
||||
unset($this->attrs['options']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate input
|
||||
*
|
||||
* @param string $cname current namespace
|
||||
* @param array $content
|
||||
* @param array &$validated=array() validated content
|
||||
*/
|
||||
public function validate($cname, array $content, &$validated=array())
|
||||
{
|
||||
$form_name = self::form_name($cname, $this->id);
|
||||
|
||||
$ok = true;
|
||||
if (!$this->is_readonly($cname))
|
||||
{
|
||||
$value = $value_in = self::get_array($content, $form_name);
|
||||
|
||||
$allowed = $this->attrs['multiple'] ? array() : array('' => $this->attrs['options']);
|
||||
$allowed += self::selOptions($form_name);
|
||||
foreach((array) $value as $val)
|
||||
{
|
||||
if (!($this->attrs['multiple'] && !$val) && !isset($allowed[$val]))
|
||||
{
|
||||
self::set_validation_error($form_name,lang("'%1' is NOT allowed ('%2')!",$val,implode("','",array_keys($allowed))),'');
|
||||
$value = '';
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (is_array($value)) $value = implode(',',$value);
|
||||
if ($ok && $value === '' && $this->attrs['needed'])
|
||||
{
|
||||
self::set_validation_error($form_name,lang('Field must not be empty !!!',$value),'');
|
||||
}
|
||||
$valid =& self::get_array($validated, $form_name, true);
|
||||
$valid = $value;
|
||||
error_log(__METHOD__."() $form_name: ".array2string($value_in).' --> '.array2string($value).', allowed='.array2string($allowed));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
if (!is_array(self::$request->sel_options[$form_name])) self::$request->sel_options[$form_name] = array();
|
||||
if ($this->attrs['type'])
|
||||
{
|
||||
// += to keep further options set by app code
|
||||
self::$request->sel_options[$form_name] += self::typeOptions($this->attrs['type'], $this->attrs['options'],
|
||||
$no_lang, $this->attrs['readonly'], self::get_array(self::$request->content, $form_name));
|
||||
|
||||
// if no_lang was modified, forward modification to the client
|
||||
if ($no_lang != $this->attr['no_lang'])
|
||||
{
|
||||
self::setElementAttribute($form_name, 'no_lang', $no_lang);
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure s, etc. are properly encoded when sent, and not double-encoded
|
||||
foreach(self::$request->sel_options[$form_name] as &$label)
|
||||
{
|
||||
if(!is_array($label))
|
||||
{
|
||||
$label = html_entity_decode($label, ENT_NOQUOTES,'utf-8');
|
||||
}
|
||||
elseif($label['label'])
|
||||
{
|
||||
$label['label'] = html_entity_decode($label['label'], ENT_NOQUOTES,'utf-8');
|
||||
}
|
||||
}
|
||||
error_log(array2string(self::$request->sel_options[$form_name]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get options from $sel_options array for a given selectbox name
|
||||
*
|
||||
* @param string $name
|
||||
* @param boolean $no_lang=false value of no_lang attribute
|
||||
* @return array
|
||||
*/
|
||||
public static function selOptions($name)
|
||||
{
|
||||
$options = array();
|
||||
if (isset(self::$request->sel_options[$name]) && is_array(self::$request->sel_options[$name]))
|
||||
{
|
||||
$options += self::$request->sel_options[$name];
|
||||
}
|
||||
else
|
||||
{
|
||||
$name_parts = explode('[',str_replace(']','',$name));
|
||||
if (count($name_parts))
|
||||
{
|
||||
$org_name = $name_parts[count($name_parts)-1];
|
||||
if (isset(self::$request->sel_options[$org_name]) && is_array(self::$request->sel_options[$org_name]))
|
||||
{
|
||||
$options += self::$request->sel_options[$org_name];
|
||||
}
|
||||
elseif (isset(self::$request->sel_options[$name_parts[0]]) && is_array(self::$request->sel_options[$name_parts[0]]))
|
||||
{
|
||||
$options += self::$request->sel_options[$name_parts[0]];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset(self::$request->content['options-'.$name]))
|
||||
{
|
||||
$options += self::$request->content['options-'.$name];
|
||||
}
|
||||
//error_log(__METHOD__."('$name') returning ".array2string($options));
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch options for certain tree types
|
||||
*
|
||||
* @param string $widget_type
|
||||
* @param string $legacy_options options string of widget
|
||||
* @param boolean $no_lang=false initial value of no_lang attribute (some types set it to true)
|
||||
* @param boolean $readonly=false
|
||||
* @param mixed $value=null value for readonly
|
||||
* @return array with value => label pairs
|
||||
*/
|
||||
public static function typeOptions($widget_type, $legacy_options, &$no_lang=false, $readonly=false, $value=null)
|
||||
{
|
||||
list($rows,$type,$type2,$type3) = explode(',',$legacy_options);
|
||||
|
||||
$no_lang = false;
|
||||
$options = array();
|
||||
switch ($widget_type)
|
||||
{
|
||||
case 'tree-cat': // !$type == globals cats too, $type2: extraStyleMultiselect, $type3: application, if not current-app, $type4: parent-id, $type5=owner (-1=global),$type6=show missing
|
||||
if ($readonly) // for readonly we dont need to fetch all cat's, nor do we need to indent them by level
|
||||
{
|
||||
$cell['no_lang'] = True;
|
||||
foreach(is_array($value) ? $value : (strpos($value,',') !== false ? explode(',',$value) : array($value)) as $id)
|
||||
{
|
||||
if ($id) $cell['sel_options'][$id] = stripslashes($GLOBALS['egw']->categories->id2name($id));
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!$type3 || $type3 === $GLOBALS['egw']->categories->app_name)
|
||||
{
|
||||
$categories =& $GLOBALS['egw']->categories;
|
||||
}
|
||||
else // we need to instanciate a new cat object for the correct application
|
||||
{
|
||||
$categories = new categories('',$type3);
|
||||
}
|
||||
$cat2path=array();
|
||||
foreach((array)$categories->return_sorted_array(0,False,'','','',!$type) as $cat)
|
||||
{
|
||||
$s = stripslashes($cat['name']);
|
||||
|
||||
if ($cat['app_name'] == 'phpgw' || $cat['owner'] == '-1')
|
||||
{
|
||||
$s .= ' ♦';
|
||||
}
|
||||
$cat2path[$cat['id']] = $path = ($cat['parent'] ? $cat2path[$cat['parent']].'/' : '').(string)$cat['id'];
|
||||
//$options[$cat['id']] = $cat + array('text' => $cat['name'], 'path' => $path);
|
||||
$options[] = array($cat['id'],$cat['parent'],$cat['name']);
|
||||
}
|
||||
// change cat-ids to pathes and preserv unavailible cats (eg. private user-cats)
|
||||
if ($value)
|
||||
{
|
||||
$pathes = $extension_data['unavailable'] = array();
|
||||
foreach(is_array($value) ? $value : explode(',',$value) as $cat)
|
||||
{
|
||||
if (isset($cat2path[$cat]))
|
||||
{
|
||||
$pathes[] = $cat2path[$cat];
|
||||
}
|
||||
else
|
||||
{
|
||||
$extension_data['unavailable'][] = $cat;
|
||||
}
|
||||
}
|
||||
$value = $rows ? $pathes : $pathes[0];
|
||||
}
|
||||
$cell['size'] = $rows.($type2 ? ','.$type2 : '');
|
||||
$no_lang = True;
|
||||
break;
|
||||
}
|
||||
|
||||
error_log(__METHOD__."('$widget_type', '$legacy_options', no_lang=".array2string($no_lang).', readonly='.array2string($readonly).", value=$value) returning ".array2string($options));
|
||||
return $options;
|
||||
}
|
||||
}
|
148
etemplate/js/et2_widget_tree.js
Normal file
148
etemplate/js/et2_widget_tree.js
Normal file
@ -0,0 +1,148 @@
|
||||
/**
|
||||
* eGroupWare eTemplate2 - JS Tree 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
|
||||
et2_core_inputWidget;
|
||||
/phpgwapi/js/dhtmlxtree/js/dhtmlXCommon.js;
|
||||
/phpgwapi/js/dhtmlxtree/js/dhtmlXTree.js;
|
||||
/phpgwapi/js/dhtmlxtree/dhtmlxTree/codebase/ext/dhtmlxtree_json.js;
|
||||
/phpgwapi/js/dhtmlxtree/dhtmlxTree/sources/ext/dhtmlxtree_start.js;
|
||||
*/
|
||||
|
||||
var et2_tree = et2_baseWidget.extend({
|
||||
|
||||
attributes: {
|
||||
"multiple": {
|
||||
"name": "multiple",
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Allow selecting multiple options"
|
||||
},
|
||||
"select_options": {
|
||||
"type": "any",
|
||||
"name": "Select options",
|
||||
"default": {},
|
||||
"description": "Used to set the tree options."
|
||||
},
|
||||
"onnodeselect": {
|
||||
"name": "onNodeSelect",
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"description": "Javascript executed when user selects a node"
|
||||
},
|
||||
"oncheck": {
|
||||
"name": "onNodeSelect",
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"description": "Javascript executed when user checks a node"
|
||||
},
|
||||
"value": {
|
||||
"type": "any",
|
||||
"default": {}
|
||||
}
|
||||
},
|
||||
init: function() {
|
||||
this._super.apply(this, arguments);
|
||||
|
||||
this.input = null;
|
||||
|
||||
this.div = $j(document.createElement("div")).addClass("dhtmlxTree");
|
||||
this.setDOMNode(this.div[0]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get tree items from the sel_options data array
|
||||
*/
|
||||
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))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var name_parts = this.id.replace(/]/g,'').split('[');
|
||||
|
||||
// Try to find the options inside the "sel-options" array
|
||||
if(this.getArrayMgr("sel_options"))
|
||||
{
|
||||
// Select options tend to be defined once, at the top level, so try that first
|
||||
var content_options = this.getArrayMgr("sel_options").getRoot().getEntry(name_parts[name_parts.length-1]);
|
||||
|
||||
// Try again according to ID
|
||||
if(!content_options) content_options = this.getArrayMgr("sel_options").getEntry(this.id);
|
||||
if(_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 (_attrs["select_options"] == null)
|
||||
{
|
||||
// Again, try last name part at top level
|
||||
var content_options = this.getArrayMgr('content').getRoot().getEntry(name_parts[name_parts.length-1]);
|
||||
// If that didn't work, check according to ID
|
||||
_attrs["select_options"] = content_options ? content_options : this.getArrayMgr('content')
|
||||
.getEntry("options-" + this.id)
|
||||
}
|
||||
|
||||
// Default to an empty object
|
||||
if (_attrs["select_options"] == null)
|
||||
{
|
||||
_attrs["select_options"] = {};
|
||||
}
|
||||
},
|
||||
|
||||
createTree: function(widget) {
|
||||
this.egw().debug("log","ID",widget.div.attr("id"));
|
||||
this.egw().debug("log",widget.div[0].parentElement);
|
||||
window = this.egw().window;
|
||||
widget.input = new dhtmlXTreeObject({
|
||||
parent: widget.div[0],
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
checkbox: (widget.options.oncheck),
|
||||
onCheck: widget.options.oncheck,
|
||||
// multiselect: widget.options.multiple // Documented, but not available
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
set_select_options: function(options) {
|
||||
if(this.input !== null)
|
||||
{
|
||||
this.input.loadJSArray(options);
|
||||
return;
|
||||
}
|
||||
|
||||
var xmp = jQuery(document.createElement('ul')).attr("container",true).appendTo(this.div);
|
||||
for(var key in options)
|
||||
{
|
||||
var name = (!this.options.no_lang) ? options[key][2] : this.egw().lang(options[key].name ? options[key].name : options[key][2]);
|
||||
var item = jQuery(document.createElement('li'))
|
||||
.attr("id", options[key][0])
|
||||
.text( name)
|
||||
.appendTo(xmp);
|
||||
}
|
||||
this.input = dhtmlXTreeFromHTML(this.div[0]);
|
||||
|
||||
}
|
||||
});
|
||||
et2_register_widget(et2_tree, ["tree","tree-cat"]);
|
||||
|
Loading…
Reference in New Issue
Block a user