mirror of
https://github.com/EGroupware/egroupware.git
synced 2025-01-09 07:28:43 +01:00
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