commiting uncommited changes on live site
[weblabels.fsf.org.git] / crm.fsf.org / 20131203 / files / sites / all / modules-new / civicrm / packages / HTML / QuickForm / hierselect.php
1 <?php
2 /* vim: set expandtab tabstop=4 shiftwidth=4: */
3 // +----------------------------------------------------------------------+
4 // | PHP version 4.0 |
5 // +----------------------------------------------------------------------+
6 // | Copyright (c) 1997-2004 The PHP Group |
7 // +----------------------------------------------------------------------+
8 // | This source file is subject to version 2.0 of the PHP license, |
9 // | that is bundled with this package in the file LICENSE, and is |
10 // | available at through the world-wide-web at |
11 // | http://www.php.net/license/2_02.txt. |
12 // | If you did not receive a copy of the PHP license and are unable to |
13 // | obtain it through the world-wide-web, please send a note to |
14 // | license@php.net so we can mail you a copy immediately. |
15 // +----------------------------------------------------------------------+
16 // | Authors: Herim Vasquez <vasquezh@iro.umontreal.ca> |
17 // | Bertrand Mansion <bmansion@mamasam.com> |
18 // +----------------------------------------------------------------------+
19 //
20 // $Id: hierselect.php,v 1.12 2004/10/20 10:03:49 avb Exp $
21
22 require_once('HTML/QuickForm/group.php');
23 require_once('HTML/QuickForm/select.php');
24
25 /**
26 * Class to dynamically create two or more HTML Select elements
27 * The first select changes the content of the second select and so on.
28 * This element is considered as a group. Selects will be named
29 * groupName[0], groupName[1], groupName[2]...
30 *
31 * @author Herim Vasquez <vasquezh@iro.umontreal.ca>
32 * @author Bertrand Mansion <bmansion@mamasam.com>
33 * @version 1.0
34 * @since PHP4.04pl1
35 * @access public
36 */
37 class HTML_QuickForm_hierselect extends HTML_QuickForm_group
38 {
39 // {{{ properties
40
41 /**
42 * Options for all the select elements
43 *
44 * Format is a bit more complex as we need to know which options
45 * are related to the ones in the previous select:
46 *
47 * Ex:
48 * // first select
49 * $select1[0] = 'Pop';
50 * $select1[1] = 'Classical';
51 * $select1[2] = 'Funeral doom';
52 *
53 * // second select
54 * $select2[0][0] = 'Red Hot Chil Peppers';
55 * $select2[0][1] = 'The Pixies';
56 * $select2[1][0] = 'Wagner';
57 * $select2[1][1] = 'Strauss';
58 * $select2[2][0] = 'Pantheist';
59 * $select2[2][1] = 'Skepticism';
60 *
61 * // If only need two selects
62 * // - and using the depracated functions
63 * $sel =& $form->addElement('hierselect', 'cds', 'Choose CD:');
64 * $sel->setMainOptions($select1);
65 * $sel->setSecOptions($select2);
66 *
67 * // - and using the new setOptions function
68 * $sel =& $form->addElement('hierselect', 'cds', 'Choose CD:');
69 * $sel->setOptions(array($select1, $select2));
70 *
71 * // If you have a third select with prices for the cds
72 * $select3[0][0][0] = '15.00$';
73 * $select3[0][0][1] = '17.00$';
74 * etc
75 *
76 * // You can now use
77 * $sel =& $form->addElement('hierselect', 'cds', 'Choose CD:');
78 * $sel->setOptions(array($select1, $select2, $select3));
79 *
80 * @var array
81 * @access private
82 */
83 var $_options = array();
84
85 /**
86 * Number of select elements on this group
87 *
88 * @var int
89 * @access private
90 */
91 var $_nbElements = 0;
92
93 /**
94 * The javascript used to set and change the options
95 *
96 * @var string
97 * @access private
98 */
99 var $_js = '';
100
101 /**
102 * The javascript array name
103 */
104 var $_jsArrayName = '';
105
106 // }}}
107 // {{{ constructor
108
109 /**
110 * Class constructor
111 *
112 * @param string $elementName (optional)Input field name attribute
113 * @param string $elementLabel (optional)Input field label in form
114 * @param mixed $attributes (optional)Either a typical HTML attribute string
115 * or an associative array. Date format is passed along the attributes.
116 * @param mixed $separator (optional)Use a string for one separator,
117 * use an array to alternate the separators.
118 * @access public
119 * @return void
120 */
121 function HTML_QuickForm_hierselect($elementName=null, $elementLabel=null, $attributes=null, $separator=null)
122 {
123 $this->HTML_QuickForm_element($elementName, $elementLabel, $attributes);
124 $this->_persistantFreeze = true;
125 if (isset($separator)) {
126 $this->_separator = $separator;
127 }
128 $this->_type = 'hierselect';
129 $this->_appendName = true;
130 } //end constructor
131
132 // }}}
133 // {{{ setOptions()
134
135 /**
136 * Initialize the array structure containing the options for each select element.
137 * Call the functions that actually do the magic.
138 *
139 * @param array $options Array of options defining each element
140 *
141 * @access public
142 * @return void
143 */
144 function setOptions($options)
145 {
146 $this->_options = $options;
147
148 if (empty($this->_elements)) {
149 $this->_nbElements = count($this->_options);
150 $this->_createElements();
151 } else {
152 // setDefaults has probably been called before this function
153 // check if all elements have been created
154 $totalNbElements = count($this->_options);
155 for ($i = $this->_nbElements; $i < $totalNbElements; $i ++) {
156 $this->_elements[] = new HTML_QuickForm_select($i, null, array(), $this->getAttributes());
157 $this->_nbElements++;
158 }
159 }
160
161 $this->_setOptions();
162 $this->_setJS();
163 } // end func setMainOptions
164
165 // }}}
166 // {{{ setMainOptions()
167
168 /**
169 * Sets the options for the first select element. Deprecated. setOptions() should be used.
170 *
171 * @param array $array Options for the first select element
172 *
173 * @access public
174 * @return void
175 */
176 function setMainOptions($array)
177 {
178 $this->_options[0] = $array;
179
180 if (empty($this->_elements)) {
181 $this->_nbElements = 2;
182 $this->_createElements();
183 }
184 } // end func setMainOptions
185
186 // }}}
187 // {{{ setSecOptions()
188
189 /**
190 * Sets the options for the second select element. Deprecated. setOptions() should be used.
191 * The main _options array is initialized and the _setOptions function is called.
192 *
193 * @param array $array Options for the second select element
194 *
195 * @access public
196 * @return void
197 */
198 function setSecOptions($array)
199 {
200 $this->_options[1] = $array;
201
202 if (empty($this->_elements)) {
203 $this->_nbElements = 2;
204 $this->_createElements();
205 } else {
206 // setDefaults has probably been called before this function
207 // check if all elements have been created
208 $totalNbElements = 2;
209 for ($i = $this->_nbElements; $i < $totalNbElements; $i ++) {
210 $this->_elements[] = new HTML_QuickForm_select($i, null, array(), $this->getAttributes());
211 $this->_nbElements++;
212 }
213 }
214
215 $this->_setOptions();
216 $this->_setJS();
217 } // end func setSecOptions
218
219 // }}}
220 // {{{ _setOptions()
221
222 /**
223 * Sets the options for each select element
224 *
225 * @access private
226 * @return void
227 */
228 function _setOptions()
229 {
230 $toLoad = '';
231 foreach (array_keys($this->_elements) AS $key) {
232 if (eval("return isset(\$this->_options[{$key}]{$toLoad});") ) {
233 $array = eval("return \$this->_options[{$key}]{$toLoad};");
234 if (is_array($array)) {
235 $select =& $this->_elements[$key];
236 $select->_options = array();
237 $select->loadArray($array);
238
239 $value = is_array($v = $select->getValue()) ? $v[0] : key($array);
240 $toLoad .= '[\''.$value.'\']';
241 }
242 }
243 }
244 } // end func _setOptions
245
246 // }}}
247 // {{{ setValue()
248
249 /**
250 * Sets values for group's elements
251 *
252 * @param array $value An array of 2 or more values, for the first,
253 * the second, the third etc. select
254 *
255 * @access public
256 * @return void
257 */
258 function setValue($value)
259 {
260 $this->_nbElements = count($value);
261 parent::setValue($value);
262 $this->_setOptions();
263 } // end func setValue
264
265 // }}}
266 // {{{ _createElements()
267
268 /**
269 * Creates all the elements for the group
270 *
271 * @access private
272 * @return void
273 */
274 function _createElements()
275 {
276 //hack to add id attribute for hier select
277 $attributes = $this->getAttributes();
278 $id = null;
279 if ( isset( $attributes['id'] ) ) {
280 $id = "{$attributes['id']}";
281 }
282
283 for ($i = 0; $i < $this->_nbElements; $i++) {
284 if ( isset( $id ) ) {
285 $attributes['id'] = "{$id}_{$i}";
286 }
287
288 $this->_elements[] = new HTML_QuickForm_select($i, null, array(), $attributes);
289 }
290 } // end func _createElements
291
292 // }}}
293 // {{{ _setJS()
294
295 /**
296 * Set the JavaScript for each select element (excluding de main one).
297 *
298 * @access private
299 * @return void
300 */
301 function _setJS()
302 {
303 static $jsArrayName = null;
304
305 $this->_js = $js = '';
306 if ( ! $jsArrayName ) {
307 $this->_jsArrayName = 'hs_' . preg_replace('/\[|\]/', '_', $this->getName());
308 for ($i = 1; $i < $this->_nbElements; $i++) {
309 $this->_setJSArray($this->_jsArrayName, $this->_options[$i], $js);
310 }
311 $jsArrayName = $this->_jsArrayName;
312 } else {
313 $this->_jsArrayName = $jsArrayName;
314 }
315 } // end func _setJS
316
317 // }}}
318 // {{{ _setJSArray()
319
320 /**
321 * Recursively builds the JavaScript array defining the options that a select
322 * element can have.
323 *
324 * @param string $grpName Group Name attribute
325 * @param array $options Select element options
326 * @param string $js JavaScript definition is build using this variable
327 * @param string $optValue The value for the current JavaScript option
328 *
329 * @access private
330 * @return void
331 */
332 function _setJSArray($grpName, $options, &$js, $optValue = '')
333 {
334 static $jsNameCache = array( );
335 if (is_array($options)) {
336 $js = '';
337 // For a hierselect containing 3 elements:
338 // if option 1 has been selected for the 1st element
339 // and option 3 has been selected for the 2nd element,
340 // then the javascript array containing the values to load
341 // on the 3rd element will have the following name: grpName_1_3
342 $name = ($optValue === '') ? $grpName : $grpName.'_'.$optValue;
343 foreach($options AS $k => $v) {
344 $this->_setJSArray($name, $v, $js, $k);
345 }
346
347 // if $js !== '' add it to the JavaScript
348
349 if ( $js !== '' ) {
350 // check if we have already this js in cache, if so reuse it
351 $cacheKey = md5( $js );
352 if ( array_key_exists( $cacheKey, $jsNameCache ) ) {
353 $this->_js .= "$name = {$jsNameCache[$cacheKey]}\n";
354 } else {
355 $this->_js .= $name." = {\n".$js."\n}\n";
356 $jsNameCache[$cacheKey] = $name;
357 }
358 }
359 $js = '';
360 } else {
361 // $js empty means that we are adding the first element to the JavaScript.
362 if ($js != '') {
363 $js .= ",\n";
364 }
365 $js .= '"'.$optValue.'":"'.addcslashes($options,'"').'"';
366 }
367 }
368
369 // }}}
370 // {{{ toHtml()
371
372 /**
373 * Returns Html for the group
374 *
375 * @access public
376 * @return string
377 */
378 function toHtml()
379 {
380 if ($this->_flagFrozen) {
381 $this->_js = '';
382 } else {
383 // set the onchange attribute for each element
384 $keys = array_keys($this->_elements);
385 $nbElements = count($keys);
386 $nbElementsUsingFnc = $nbElements - 1; // last element doesn't need it
387 for ($i = 0; $i < $nbElementsUsingFnc; $i++) {
388 $select =& $this->_elements[$keys[$i]];
389 $select->updateAttributes(
390 array('onChange' => 'swapOptions(this.form, \''.$this->getName().'\', '.$keys[$i].', '.$nbElements.', \''.$this->_jsArrayName.'\');')
391 );
392 }
393
394 // create the js function to call
395 if (!defined('HTML_QUICKFORM_HIERSELECT_EXISTS')) {
396 $this->_js .= "function swapOptions(frm, grpName, eleIndex, nbElements, arName)\n"
397 ."{\n"
398 ." var n = \"\";\n"
399 ." var ctl;\n\n"
400 ." for (var i = 0; i < nbElements; i++) {\n"
401 ." ctl = frm[grpName+'['+i+']'];\n"
402 ." if (!ctl) {\n"
403 ." ctl = frm[grpName+'['+i+'][]'];\n"
404 ." }\n"
405 ." if (i <= eleIndex) {\n"
406 ." n += \"_\"+ctl.value;\n"
407 ." } else {\n"
408 ." ctl.length = 0;\n"
409 ." }\n"
410 ." }\n\n"
411 ." var t = eval(\"typeof(\"+arName + n +\")\");\n"
412 ." if (t != 'undefined') {\n"
413 ." var the_array = eval(arName+n);\n"
414 ." var j = 0;\n"
415 ." n = eleIndex + 1;\n"
416 ." ctl = frm[grpName+'['+ n +']'];\n"
417 ." if (!ctl) {\n"
418 ." ctl = frm[grpName+'['+ n +'][]'];\n"
419 ." }\n"
420 ." ctl.style.display = 'inline';\n"
421 ." for (var i in the_array) {\n"
422 ." opt = new Option(the_array[i], i, false, false);\n"
423 ." ctl.options[j++] = opt;\n"
424 ." }\n"
425 ." } else {\n"
426 ." n = eleIndex + 1;\n"
427 ." ctl = frm[grpName+'['+n+']'];\n"
428 ." if (!ctl) {\n"
429 ." ctl = frm[grpName+'['+ n +'][]'];\n"
430 ." }\n"
431 ." if (ctl) {\n"
432 ." ctl.style.display = 'none';\n"
433 ." }\n"
434 ." }\n"
435 ." if (eleIndex+1 < nbElements) {\n"
436 ." swapOptions(frm, grpName, eleIndex+1, nbElements, arName);\n"
437 ." }\n"
438 ."}\n";
439 define('HTML_QUICKFORM_HIERSELECT_EXISTS', true);
440 }
441 }
442 include_once('HTML/QuickForm/Renderer/Default.php');
443 $renderer = new HTML_QuickForm_Renderer_Default();
444 $renderer->setElementTemplate('{element}');
445 parent::accept($renderer);
446 $result = null;
447 if ( ! empty( $this->_js ) ) {
448 $result .= "<script type=\"text/javascript\">\n//<![CDATA[\n" . $this->_js . "//]]>\n</script>";
449 }
450 return $result .
451 $renderer->toHtml();
452 } // end func toHtml
453
454 // }}}
455 // {{{ accept()
456
457 /**
458 * Accepts a renderer
459 *
460 * @param object An HTML_QuickForm_Renderer object
461 * @param bool Whether a group is required
462 * @param string An error message associated with a group
463 * @access public
464 * @return void
465 */
466 function accept(&$renderer, $required = false, $error = null)
467 {
468 $renderer->renderElement($this, $required, $error);
469 } // end func accept
470
471 // }}}
472 // {{{ onQuickFormEvent()
473
474 function onQuickFormEvent($event, $arg, &$caller)
475 {
476 if ('updateValue' == $event) {
477 // we need to call setValue() so that the secondary option
478 // matches the main option
479 return HTML_QuickForm_element::onQuickFormEvent($event, $arg, $caller);
480 } else {
481 return parent::onQuickFormEvent($event, $arg, $caller);
482 }
483 } // end func onQuickFormEvent
484
485 // }}}
486 } // end class HTML_QuickForm_hierselect
487 ?>