1: <?php
2: /**
3: * CTreeView class file.
4: *
5: * @author Qiang Xue <qiang.xue@gmail.com>
6: * @link http://www.yiiframework.com/
7: * @copyright 2008-2013 Yii Software LLC
8: * @license http://www.yiiframework.com/license/
9: */
10:
11: /**
12: * CTreeView displays a tree view of hierarchical data.
13: *
14: * It encapsulates the excellent tree view plugin for jQuery
15: * ({@link http://bassistance.de/jquery-plugins/jquery-plugin-treeview/}).
16: *
17: * To use CTreeView, simply sets {@link data} to the data that you want
18: * to present and you are there.
19: *
20: * CTreeView also supports dynamic data loading via AJAX. To do so, set
21: * {@link url} to be the URL that can serve the tree view data upon request.
22: *
23: * @author Qiang Xue <qiang.xue@gmail.com>
24: * @package system.web.widgets
25: * @since 1.0
26: */
27: class CTreeView extends CWidget
28: {
29: /**
30: * @var array the data that can be used to generate the tree view content.
31: * Each array element corresponds to a tree view node with the following structure:
32: * <ul>
33: * <li>text: string, required, the HTML text associated with this node.</li>
34: * <li>expanded: boolean, optional, whether the tree view node is expanded.</li>
35: * <li>id: string, optional, the ID identifying the node. This is used
36: * in dynamic loading of tree view (see {@link url}).</li>
37: * <li>hasChildren: boolean, optional, defaults to false, whether clicking on this
38: * node should trigger dynamic loading of more tree view nodes from server.
39: * The {@link url} property must be set in order to make this effective.</li>
40: * <li>children: array, optional, child nodes of this node.</li>
41: * <li>htmlOptions: array, additional HTML attributes (see {@link CHtml::tag}).
42: * This option has been available since version 1.1.7.</li>
43: * </ul>
44: * Note, anything enclosed between the beginWidget and endWidget calls will
45: * also be treated as tree view content, which appends to the content generated
46: * from this data.
47: */
48: public $data;
49: /**
50: * @var mixed the CSS file used for the widget. Defaults to null, meaning
51: * using the default CSS file included together with the widget.
52: * If false, no CSS file will be used. Otherwise, the specified CSS file
53: * will be included when using this widget.
54: */
55: public $cssFile;
56: /**
57: * @var string|array the URL to which the treeview can be dynamically loaded (in AJAX).
58: * See {@link CHtml::normalizeUrl} for possible URL formats.
59: * Setting this property will enable the dynamic treeview loading.
60: * When the page is displayed, the browser will request this URL with a GET parameter
61: * named 'root' whose value is 'source'. The server script should then generate the
62: * needed tree view data corresponding to the root of the tree (see {@link saveDataAsJson}.)
63: * When a node has a CSS class 'hasChildren', then expanding this node will also
64: * cause a dynamic loading of its child nodes. In this case, the value of the 'root' GET parameter
65: * is the 'id' property of the node.
66: */
67: public $url;
68: /**
69: * @var string|integer animation speed. This can be one of the three predefined speeds
70: * ("slow", "normal", or "fast") or the number of milliseconds to run the animation (e.g. 1000).
71: * If not set, no animation is used.
72: */
73: public $animated;
74: /**
75: * @var boolean whether the tree should start with all branches collapsed. Defaults to false.
76: */
77: public $collapsed;
78: /**
79: * @var string container for a tree-control, allowing the user to expand, collapse and toggle all branches with one click.
80: * In the container, clicking on the first hyperlink will collapse the tree;
81: * the second hyperlink will expand the tree; while the third hyperlink will toggle the tree.
82: * The property should be a valid jQuery selector (e.g. '#treecontrol' where 'treecontrol' is
83: * the ID of the 'div' element containing the hyperlinks.)
84: */
85: public $control;
86: /**
87: * @var boolean set to allow only one branch on one level to be open (closing siblings which opening).
88: * Defaults to false.
89: */
90: public $unique;
91: /**
92: * @var string Callback when toggling a branch. Arguments: "this" refers to the UL that was shown or hidden
93: */
94: public $toggle;
95: /**
96: * @var string Persist the tree state in cookies or the page location. If set to "location", looks for
97: * the anchor that matches location.href and activates that part of the treeview it.
98: * Great for href-based state-saving. If set to "cookie", saves the state of the tree on
99: * each click to a cookie and restores that state on page load.
100: */
101: public $persist;
102: /**
103: * @var string The cookie name to use when persisting via persist:"cookie". Defaults to 'treeview'.
104: */
105: public $cookieId;
106: /**
107: * @var boolean Set to skip rendering of classes and hitarea divs, assuming that is done by the serverside. Defaults to false.
108: */
109: public $prerendered;
110: /**
111: * @var array additional options that can be passed to the constructor of the treeview js object.
112: */
113: public $options=array();
114: /**
115: * @var array additional HTML attributes that will be rendered in the UL tag.
116: * The default tree view CSS has defined the following CSS classes which can be enabled
117: * by specifying the 'class' option here:
118: * <ul>
119: * <li>treeview-black</li>
120: * <li>treeview-gray</li>
121: * <li>treeview-red</li>
122: * <li>treeview-famfamfam</li>
123: * <li>filetree</li>
124: * </ul>
125: */
126: public $htmlOptions;
127:
128:
129: /**
130: * Initializes the widget.
131: * This method registers all needed client scripts and renders
132: * the tree view content.
133: */
134: public function init()
135: {
136: if(isset($this->htmlOptions['id']))
137: $id=$this->htmlOptions['id'];
138: else
139: $id=$this->htmlOptions['id']=$this->getId();
140: if($this->url!==null)
141: $this->url=CHtml::normalizeUrl($this->url);
142: $cs=Yii::app()->getClientScript();
143: $cs->registerCoreScript('treeview');
144: $options=$this->getClientOptions();
145: $options=$options===array()?'{}' : CJavaScript::encode($options);
146: $cs->registerScript('Yii.CTreeView#'.$id,"jQuery(\"#{$id}\").treeview($options);");
147: if($this->cssFile===null)
148: $cs->registerCssFile($cs->getCoreScriptUrl().'/treeview/jquery.treeview.css');
149: elseif($this->cssFile!==false)
150: $cs->registerCssFile($this->cssFile);
151:
152: echo CHtml::tag('ul',$this->htmlOptions,false,false)."\n";
153: echo self::saveDataAsHtml($this->data);
154: }
155:
156: /**
157: * Ends running the widget.
158: */
159: public function run()
160: {
161: echo "</ul>";
162: }
163:
164: /**
165: * @return array the javascript options
166: */
167: protected function getClientOptions()
168: {
169: $options=$this->options;
170: foreach(array('url','animated','collapsed','control','unique','toggle','persist','cookieId','prerendered') as $name)
171: {
172: if($this->$name!==null)
173: $options[$name]=$this->$name;
174: }
175: return $options;
176: }
177:
178: /**
179: * Generates tree view nodes in HTML from the data array.
180: * @param array $data the data for the tree view (see {@link data} for possible data structure).
181: * @return string the generated HTML for the tree view
182: */
183: public static function saveDataAsHtml($data)
184: {
185: $html='';
186: if(is_array($data))
187: {
188: foreach($data as $node)
189: {
190: if(!isset($node['text']))
191: continue;
192:
193: if(isset($node['expanded']))
194: $css=$node['expanded'] ? 'open' : 'closed';
195: else
196: $css='';
197:
198: if(isset($node['hasChildren']) && $node['hasChildren'])
199: {
200: if($css!=='')
201: $css.=' ';
202: $css.='hasChildren';
203: }
204:
205: $options=isset($node['htmlOptions']) ? $node['htmlOptions'] : array();
206: if($css!=='')
207: {
208: if(isset($options['class']))
209: $options['class'].=' '.$css;
210: else
211: $options['class']=$css;
212: }
213:
214: if(isset($node['id']))
215: $options['id']=$node['id'];
216:
217: $html.=CHtml::tag('li',$options,$node['text'],false);
218: if(!empty($node['children']))
219: {
220: $html.="\n<ul>\n";
221: $html.=self::saveDataAsHtml($node['children']);
222: $html.="</ul>\n";
223: }
224: $html.=CHtml::closeTag('li')."\n";
225: }
226: }
227: return $html;
228: }
229:
230: /**
231: * Saves tree view data in JSON format.
232: * This method is typically used in dynamic tree view loading
233: * when the server code needs to send to the client the dynamic
234: * tree view data.
235: * @param array $data the data for the tree view (see {@link data} for possible data structure).
236: * @return string the JSON representation of the data
237: */
238: public static function saveDataAsJson($data)
239: {
240: if(empty($data))
241: return '[]';
242: else
243: return CJavaScript::jsonEncode($data);
244: }
245: }
246: