1 : <?php
2 : /**
3 : * Copyright (c) 2005-2009, Laurent Laville <pear@laurent-laville.org>
4 : *
5 : * All rights reserved.
6 : *
7 : * Redistribution and use in source and binary forms, with or without
8 : * modification, are permitted provided that the following conditions
9 : * are met:
10 : *
11 : * * Redistributions of source code must retain the above copyright
12 : * notice, this list of conditions and the following disclaimer.
13 : * * Redistributions in binary form must reproduce the above copyright
14 : * notice, this list of conditions and the following disclaimer in the
15 : * documentation and/or other materials provided with the distribution.
16 : * * Neither the name of the authors nor the names of its contributors
17 : * may be used to endorse or promote products derived from this software
18 : * without specific prior written permission.
19 : *
20 : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 : * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 : * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
24 : * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 : * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 : * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 : * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 : * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 : * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 : * POSSIBILITY OF SUCH DAMAGE.
31 : *
32 : * PHP versions 4 and 5
33 : *
34 : * @category HTML
35 : * @package HTML_QuickForm_advmultiselect
36 : * @author Laurent Laville <pear@laurent-laville.org>
37 : * @copyright 2005-2009 Laurent Laville
38 : * @license http://www.opensource.org/licenses/bsd-license.php BSD
39 : * @version CVS: $Id: advmultiselect.php,v 1.36 2009/04/05 07:03:39 farell Exp $
40 : * @link http://pear.php.net/package/HTML_QuickForm_advmultiselect
41 : * @since File available since Release 0.4.0
42 : */
43 :
44 : require_once 'HTML/QuickForm/select.php';
45 :
46 : /**
47 : * Basic error codes
48 : *
49 : * @var integer
50 : * @since 1.5.0
51 : */
52 : define('HTML_QUICKFORM_ADVMULTISELECT_ERROR_INVALID_INPUT', 1);
53 :
54 : /**
55 : * Element for HTML_QuickForm that emulate a multi-select.
56 : *
57 : * The HTML_QuickForm_advmultiselect package adds an element to the
58 : * HTML_QuickForm package that is two select boxes next to each other
59 : * emulating a multi-select.
60 : *
61 : * @category HTML
62 : * @package HTML_QuickForm_advmultiselect
63 : * @author Laurent Laville <pear@laurent-laville.org>
64 : * @copyright 2005-2009 Laurent Laville
65 : * @license http://www.opensource.org/licenses/bsd-license.php BSD
66 : * @version Release: 1.5.1
67 : * @link http://pear.php.net/package/HTML_QuickForm_advmultiselect
68 : * @since Class available since Release 0.4.0
69 : */
70 : class HTML_QuickForm_advmultiselect extends HTML_QuickForm_select
71 : {
72 : /**
73 : * Prefix function name in javascript move selections
74 : *
75 : * @var string
76 : * @access private
77 : * @since 0.4.0
78 : */
79 : var $_jsPrefix;
80 :
81 : /**
82 : * Postfix function name in javascript move selections
83 : *
84 : * @var string
85 : * @access private
86 : * @since 0.4.0
87 : */
88 : var $_jsPostfix;
89 :
90 : /**
91 : * Associative array of the multi select container attributes
92 : *
93 : * @var array
94 : * @access private
95 : * @since 0.4.0
96 : */
97 : var $_tableAttributes;
98 :
99 : /**
100 : * Associative array of the add button attributes
101 : *
102 : * @var array
103 : * @access private
104 : * @since 0.4.0
105 : */
106 : var $_addButtonAttributes;
107 :
108 : /**
109 : * Associative array of the remove button attributes
110 : *
111 : * @var array
112 : * @access private
113 : * @since 0.4.0
114 : */
115 : var $_removeButtonAttributes;
116 :
117 : /**
118 : * Associative array of the select all button attributes
119 : *
120 : * @var array
121 : * @access private
122 : * @since 1.1.0
123 : */
124 : var $_allButtonAttributes;
125 :
126 : /**
127 : * Associative array of the select none button attributes
128 : *
129 : * @var array
130 : * @access private
131 : * @since 1.1.0
132 : */
133 : var $_noneButtonAttributes;
134 :
135 : /**
136 : * Associative array of the toggle selection button attributes
137 : *
138 : * @var array
139 : * @access private
140 : * @since 1.1.0
141 : */
142 : var $_toggleButtonAttributes;
143 :
144 : /**
145 : * Associative array of the move up button attributes
146 : *
147 : * @var array
148 : * @access private
149 : * @since 0.5.0
150 : */
151 : var $_upButtonAttributes;
152 :
153 : /**
154 : * Associative array of the move up button attributes
155 : *
156 : * @var array
157 : * @access private
158 : * @since 0.5.0
159 : */
160 : var $_downButtonAttributes;
161 :
162 : /**
163 : * Associative array of the move top button attributes
164 : *
165 : * @var array
166 : * @access private
167 : * @since 1.5.0
168 : */
169 : var $_topButtonAttributes;
170 :
171 : /**
172 : * Associative array of the move bottom button attributes
173 : *
174 : * @var array
175 : * @access private
176 : * @since 1.5.0
177 : */
178 : var $_bottomButtonAttributes;
179 :
180 : /**
181 : * Defines if both list (unselected, selected) will have their elements be
182 : * arranged from lowest to highest (or reverse)
183 : * depending on comparaison function.
184 : *
185 : * SORT_ASC is used to sort in ascending order
186 : * SORT_DESC is used to sort in descending order
187 : *
188 : * @var string ('none' == false, 'asc' == SORT_ASC, 'desc' == SORT_DESC)
189 : * @access private
190 : * @since 0.5.0
191 : */
192 : var $_sort;
193 :
194 : /**
195 : * Associative array of the unselected item box attributes
196 : *
197 : * @var array
198 : * @access private
199 : * @since 0.4.0
200 : */
201 : var $_attributesUnselected;
202 :
203 : /**
204 : * Associative array of the selected item box attributes
205 : *
206 : * @var array
207 : * @access private
208 : * @since 0.4.0
209 : */
210 : var $_attributesSelected;
211 :
212 : /**
213 : * Associative array of the internal hidden box attributes
214 : *
215 : * @var array
216 : * @access private
217 : * @since 0.4.0
218 : */
219 : var $_attributesHidden;
220 :
221 : /**
222 : * Default Element template string
223 : *
224 : * @var string
225 : * @access private
226 : * @since 0.4.0
227 : */
228 : var $_elementTemplate;
229 :
230 : /**
231 : * Default Element stylesheet string
232 : *
233 : * @var string
234 : * @access private
235 : * @since 0.4.0
236 : */
237 : var $_elementCSS = '
238 : #qfams_{id} {
239 : font: 13.3px sans-serif;
240 : background-color: #fff;
241 : overflow: auto;
242 : height: 14.3em;
243 : width: 12em;
244 : border-left: 1px solid #404040;
245 : border-top: 1px solid #404040;
246 : border-bottom: 1px solid #d4d0c8;
247 : border-right: 1px solid #d4d0c8;
248 : }
249 : #qfams_{id} label {
250 : padding-right: 3px;
251 : display: block;
252 : }
253 : ';
254 :
255 : /**
256 : * Class constructor
257 : *
258 : * Class constructors :
259 : * Zend Engine 1 uses HTML_QuickForm_advmultiselect, while
260 : * Zend Engine 2 uses __construct
261 : *
262 : * @param string $elementName Dual Select name attribute
263 : * @param mixed $elementLabel Label(s) for the select boxes
264 : * @param mixed $options Data to be used to populate options
265 : * @param mixed $attributes Either a typical HTML attribute string or
266 : * an associative array
267 : * @param integer $sort Either SORT_ASC for auto ascending arrange,
268 : * SORT_DESC for auto descending arrange, or
269 : * NULL for no sort (append at end: default)
270 : *
271 : * @access public
272 : * @return void
273 : * @since version 0.4.0 (2005-06-25)
274 : */
275 : function HTML_QuickForm_advmultiselect($elementName = null, $elementLabel = null,
276 : $options = null, $attributes = null,
277 : $sort = null)
278 : {
279 21 : $opts = $options;
280 21 : $options = null; // prevent to use the default select element load options
281 21 : $this->HTML_QuickForm_select($elementName, $elementLabel,
282 21 : $options, $attributes);
283 :
284 : // allow to load options at once and take care of fancy attributes
285 21 : $this->load($opts);
286 :
287 : // add multiple selection attribute by default if missing
288 21 : $this->updateAttributes(array('multiple' => 'multiple'));
289 :
290 21 : if (is_null($this->getAttribute('size'))) {
291 : // default size is ten item on each select box (left and right)
292 20 : $this->updateAttributes(array('size' => 10));
293 20 : }
294 21 : if (is_null($this->getAttribute('style'))) {
295 : // default width of each select box
296 18 : $this->updateAttributes(array('style' => 'width:100px;'));
297 18 : }
298 21 : $this->_tableAttributes = $this->getAttribute('class');
299 21 : if (is_null($this->_tableAttributes)) {
300 : // default table layout
301 20 : $attr = array('border' => '0',
302 20 : 'cellpadding' => '10', 'cellspacing' => '0');
303 20 : } else {
304 1 : $attr = array('class' => $this->_tableAttributes);
305 1 : $this->_removeAttr('class', $this->_attributes);
306 : }
307 21 : $this->_tableAttributes = $this->_getAttrString($attr);
308 :
309 : // set default add button attributes
310 21 : $this->setButtonAttributes('add');
311 : // set default remove button attributes
312 21 : $this->setButtonAttributes('remove');
313 : // set default selectall button attributes
314 21 : $this->setButtonAttributes('all');
315 : // set default selectnone button attributes
316 21 : $this->setButtonAttributes('none');
317 : // set default toggle selection button attributes
318 21 : $this->setButtonAttributes('toggle');
319 : // set default move up button attributes
320 21 : $this->setButtonAttributes('moveup');
321 : // set default move up button attributes
322 21 : $this->setButtonAttributes('movedown');
323 : // set default move top button attributes
324 21 : $this->setButtonAttributes('movetop');
325 : // set default move bottom button attributes
326 21 : $this->setButtonAttributes('movebottom');
327 : // defines javascript functions names
328 21 : $this->_jsPrefix = 'QFAMS.';
329 21 : $this->_jsPostfix = 'moveSelection';
330 :
331 : // set select boxes sort order (none by default)
332 21 : if (!isset($sort)) {
333 19 : $sort = false;
334 19 : }
335 21 : if ($sort === SORT_ASC) {
336 1 : $this->_sort = 'asc';
337 21 : } elseif ($sort === SORT_DESC) {
338 1 : $this->_sort = 'desc';
339 1 : } else {
340 19 : $this->_sort = 'none';
341 : }
342 :
343 : // set the default advmultiselect element template (with javascript embedded)
344 21 : $this->setElementTemplate();
345 21 : }
346 :
347 : /**
348 : * Sets the button attributes
349 : *
350 : * In <b>custom example 1</b>, the <i>add</i> and <i>remove</i> buttons
351 : * have look set by the css class <i>inputCommand</i>.
352 : *
353 : * In <b>custom example 2</b>, the basic text <i>add</i> and <i>remove</i>
354 : * buttons are now replaced by images.
355 : *
356 : * In <b>custom example 5</b>, we have ability to sort the selection list
357 : * (on right side) by :
358 : * <pre>
359 : * - <b>user-end</b>: with <i>Up</i> and <i>Down</i> buttons
360 : * - <b>programming</b>: with the QF element constructor $sort option
361 : * </pre>
362 : *
363 : * @param string $button Button identifier, either 'add', 'remove',
364 : * 'all', 'none', 'toggle',
365 : * 'movetop', 'movebottom'
366 : * 'moveup' or 'movedown'
367 : * @param mixed $attributes (optional) Either a typical HTML attribute string
368 : * or an associative array
369 : *
370 : * @return void
371 : * @throws PEAR_Error $button argument
372 : * is not a string, or not in range
373 : * (add, remove, all, none, toggle,
374 : * movetop, movebottom, moveup, movedown)
375 : * @access public
376 : * @since version 0.4.0 (2005-06-25)
377 : *
378 : * @example examples/qfams_custom_5.php
379 : * Custom example 5: source code
380 : * @link http://www.laurent-laville.org/img/qfams/screenshot/custom5.png
381 : * Custom example 5: screenshot
382 : *
383 : * @example examples/qfams_custom_2.php
384 : * Custom example 2: source code
385 : * @link http://www.laurent-laville.org/img/qfams/screenshot/custom2.png
386 : * Custom example 2: screenshot
387 : *
388 : * @example examples/qfams_custom_1.php
389 : * Custom example 1: source code
390 : * @link http://www.laurent-laville.org/img/qfams/screenshot/custom1.png
391 : * Custom example 1: screenshot
392 : */
393 : function setButtonAttributes($button, $attributes = null)
394 : {
395 21 : if (!is_string($button)) {
396 1 : return PEAR::throwError('Argument 1 of HTML_QuickForm_advmultiselect::' .
397 1 : 'setButtonAttributes is not a string',
398 1 : HTML_QUICKFORM_ADVMULTISELECT_ERROR_INVALID_INPUT,
399 1 : array('level' => 'exception'));
400 : }
401 :
402 : switch ($button) {
403 21 : case 'add':
404 21 : if (is_null($attributes)) {
405 21 : $this->_addButtonAttributes
406 21 : = array('name' => 'add',
407 21 : 'value' => ' >> ',
408 21 : 'type' => 'button');
409 21 : } else {
410 2 : $this->_updateAttrArray($this->_addButtonAttributes,
411 2 : $this->_parseAttributes($attributes));
412 : }
413 21 : break;
414 21 : case 'remove':
415 21 : if (is_null($attributes)) {
416 21 : $this->_removeButtonAttributes
417 21 : = array('name' => 'remove',
418 21 : 'value' => ' << ',
419 21 : 'type' => 'button');
420 21 : } else {
421 2 : $this->_updateAttrArray($this->_removeButtonAttributes,
422 2 : $this->_parseAttributes($attributes));
423 : }
424 21 : break;
425 21 : case 'all':
426 21 : if (is_null($attributes)) {
427 21 : $this->_allButtonAttributes
428 21 : = array('name' => 'all',
429 21 : 'value' => ' Select All ',
430 21 : 'type' => 'button');
431 21 : } else {
432 1 : $this->_updateAttrArray($this->_allButtonAttributes,
433 1 : $this->_parseAttributes($attributes));
434 : }
435 21 : break;
436 21 : case 'none':
437 21 : if (is_null($attributes)) {
438 21 : $this->_noneButtonAttributes
439 21 : = array('name' => 'none',
440 21 : 'value' => ' Select None ',
441 21 : 'type' => 'button');
442 21 : } else {
443 1 : $this->_updateAttrArray($this->_noneButtonAttributes,
444 1 : $this->_parseAttributes($attributes));
445 : }
446 21 : break;
447 21 : case 'toggle':
448 21 : if (is_null($attributes)) {
449 21 : $this->_toggleButtonAttributes
450 21 : = array('name' => 'toggle',
451 21 : 'value' => ' Toggle Selection ',
452 21 : 'type' => 'button');
453 21 : } else {
454 1 : $this->_updateAttrArray($this->_toggleButtonAttributes,
455 1 : $this->_parseAttributes($attributes));
456 : }
457 21 : break;
458 21 : case 'moveup':
459 21 : if (is_null($attributes)) {
460 21 : $this->_upButtonAttributes
461 21 : = array('name' => 'up',
462 21 : 'value' => ' Up ',
463 21 : 'type' => 'button');
464 21 : } else {
465 1 : $this->_updateAttrArray($this->_upButtonAttributes,
466 1 : $this->_parseAttributes($attributes));
467 : }
468 21 : break;
469 21 : case 'movedown':
470 21 : if (is_null($attributes)) {
471 21 : $this->_downButtonAttributes
472 21 : = array('name' => 'down',
473 21 : 'value' => ' Down ',
474 21 : 'type' => 'button');
475 21 : } else {
476 1 : $this->_updateAttrArray($this->_downButtonAttributes,
477 1 : $this->_parseAttributes($attributes));
478 : }
479 21 : break;
480 21 : case 'movetop':
481 21 : if (is_null($attributes)) {
482 21 : $this->_topButtonAttributes
483 21 : = array('name' => 'top',
484 21 : 'value' => ' Top ',
485 21 : 'type' => 'button');
486 21 : } else {
487 1 : $this->_updateAttrArray($this->_topButtonAttributes,
488 1 : $this->_parseAttributes($attributes));
489 : }
490 21 : break;
491 21 : case 'movebottom':
492 21 : if (is_null($attributes)) {
493 21 : $this->_bottomButtonAttributes
494 21 : = array('name' => 'bottom',
495 21 : 'value' => ' Bottom ',
496 21 : 'type' => 'button');
497 21 : } else {
498 1 : $this->_updateAttrArray($this->_bottomButtonAttributes,
499 1 : $this->_parseAttributes($attributes));
500 : }
501 21 : break;
502 1 : default;
503 1 : return PEAR::throwError('Argument 1 of HTML_QuickForm_advmultiselect::' .
504 1 : 'setButtonAttributes has unexpected value',
505 1 : HTML_QUICKFORM_ADVMULTISELECT_ERROR_INVALID_INPUT,
506 1 : array('level' => 'error'));
507 1 : }
508 21 : }
509 :
510 : /**
511 : * Sets element template
512 : *
513 : * @param string $html (optional) The HTML surrounding select boxes and buttons
514 : * @param string $js (optional) if we need to include qfams javascript handler
515 : *
516 : * @access public
517 : * @return string
518 : * @since version 0.4.0 (2005-06-25)
519 : */
520 : function setElementTemplate($html = null, $js = true)
521 : {
522 21 : $oldTemplate = $this->_elementTemplate;
523 :
524 21 : if (isset($html) && is_string($html)) {
525 6 : $this->_elementTemplate = $html;
526 6 : } else {
527 21 : $this->_elementTemplate = '
528 : {javascript}
529 : <table{class}>
530 : <!-- BEGIN label_2 --><tr><th>{label_2}</th><!-- END label_2 -->
531 : <!-- BEGIN label_3 --><th> </th><th>{label_3}</th></tr><!-- END label_3 -->
532 : <tr>
533 : <td valign="top">{unselected}</td>
534 : <td align="center">{add}{remove}</td>
535 : <td valign="top">{selected}</td>
536 : </tr>
537 : </table>
538 : ';
539 : }
540 21 : if ($js == false) {
541 1 : $this->_elementTemplate = str_replace('{javascript}', '',
542 1 : $this->_elementTemplate);
543 1 : }
544 21 : return $oldTemplate;
545 : }
546 :
547 : /**
548 : * Gets default element stylesheet for a single multi-select shape render
549 : *
550 : * In <b>custom example 4</b>, the template defined allows
551 : * a single multi-select checkboxes shape. Useful when javascript is disabled
552 : * (or when browser is not js compliant). In our example, no need to add
553 : * javascript code, but css is mandatory.
554 : *
555 : * @param boolean $raw (optional) html output with style tags or just raw data
556 : *
557 : * @access public
558 : * @return string
559 : * @since version 0.4.0 (2005-06-25)
560 : *
561 : * @example qfams_custom_4.php
562 : * Custom example 4: source code
563 : * @link http://www.laurent-laville.org/img/qfams/screenshot/custom4.png
564 : * Custom example 4: screenshot
565 : */
566 : function getElementCss($raw = true)
567 : {
568 13 : $id = $this->getAttribute('name');
569 13 : $css = str_replace('{id}', $id, $this->_elementCSS);
570 :
571 13 : if ($raw !== true) {
572 : $css = '<style type="text/css">' . PHP_EOL
573 13 : . '<!--' . $css . ' -->' . PHP_EOL
574 13 : . '</style>';
575 13 : }
576 13 : return $css;
577 : }
578 :
579 : /**
580 : * Returns the HTML generated for the advanced mutliple select component
581 : *
582 : * @access public
583 : * @return string
584 : * @since version 0.4.0 (2005-06-25)
585 : */
586 : function toHtml()
587 : {
588 14 : if ($this->_flagFrozen) {
589 1 : return $this->getFrozenHtml();
590 : }
591 :
592 13 : $tabs = $this->_getTabs();
593 13 : $tab = $this->_getTab();
594 :
595 13 : $selectId = $this->getName();
596 13 : $selectName = $this->getName() . '[]';
597 13 : $selectNameFrom = $this->getName() . '-f[]';
598 13 : $selectNameTo = $this->getName() . '-t[]';
599 13 : $selected_count = 0;
600 :
601 : // placeholder {unselected} existence determines if we will render
602 13 : if (strpos($this->_elementTemplate, '{unselected}') === false) {
603 : // ... a single multi-select with checkboxes
604 3 : $this->_jsPostfix = 'editSelection';
605 :
606 3 : $id = $this->getAttribute('name');
607 :
608 3 : $strHtmlSelected = $tab . '<div id="qfams_'.$id.'">' . PHP_EOL;
609 3 : $unselected_count = count($this->_options);
610 :
611 3 : $checkbox_id_suffix = 0;
612 :
613 3 : foreach ($this->_options as $option) {
614 : $_labelAttributes
615 3 : = array('style', 'class', 'onmouseover', 'onmouseout');
616 3 : $labelAttributes = array();
617 3 : foreach ($_labelAttributes as $attr) {
618 3 : if (isset($option['attr'][$attr])) {
619 1 : $labelAttributes[$attr] = $option['attr'][$attr];
620 1 : unset($option['attr'][$attr]);
621 1 : }
622 3 : }
623 :
624 3 : if (is_array($this->_values)
625 3 : && in_array((string)$option['attr']['value'], $this->_values)) {
626 : // The items is *selected*
627 1 : $checked = ' checked="checked"';
628 1 : $selected_count++;
629 1 : } else {
630 : // The item is *unselected* so we want to put it
631 3 : $checked = '';
632 : }
633 3 : $checkbox_id_suffix++;
634 : $strHtmlSelected .= $tab
635 : . '<label'
636 3 : . $this->_getAttrString($labelAttributes) .'>'
637 3 : . '<input type="checkbox"'
638 3 : . ' id="'.$selectId . $checkbox_id_suffix.'"'
639 3 : . ' name="'.$selectName.'"'
640 3 : . $checked
641 3 : . $this->_getAttrString($option['attr'])
642 3 : . ' />' . $option['text'] . '</label>'
643 3 : . PHP_EOL;
644 3 : }
645 3 : $strHtmlSelected .= $tab . '</div>'. PHP_EOL;
646 :
647 3 : $strHtmlHidden = '';
648 3 : $strHtmlUnselected = '';
649 3 : $strHtmlAdd = '';
650 3 : $strHtmlRemove = '';
651 :
652 : // build the select all button with all its attributes
653 3 : $jsName = $this->_jsPrefix . $this->_jsPostfix;
654 : $attributes = array('onclick' => $jsName .
655 3 : "('". $selectId ."', 1);");
656 3 : $this->_allButtonAttributes
657 3 : = array_merge($this->_allButtonAttributes, $attributes);
658 3 : $attrStrAll = $this->_getAttrString($this->_allButtonAttributes);
659 3 : $strHtmlAll = "<input$attrStrAll />". PHP_EOL;
660 :
661 : // build the select none button with all its attributes
662 : $attributes = array('onclick' => $jsName .
663 3 : "('". $selectId ."', 0);");
664 3 : $this->_noneButtonAttributes
665 3 : = array_merge($this->_noneButtonAttributes, $attributes);
666 3 : $attrStrNone = $this->_getAttrString($this->_noneButtonAttributes);
667 3 : $strHtmlNone = "<input$attrStrNone />". PHP_EOL;
668 :
669 : // build the toggle selection button with all its attributes
670 : $attributes = array('onclick' => $jsName .
671 3 : "('". $selectId ."', 2);");
672 3 : $this->_toggleButtonAttributes
673 3 : = array_merge($this->_toggleButtonAttributes,
674 3 : $attributes);
675 3 : $attrStrToggle = $this->_getAttrString($this->_toggleButtonAttributes);
676 3 : $strHtmlToggle = "<input$attrStrToggle />". PHP_EOL;
677 :
678 3 : $strHtmlMoveUp = '';
679 3 : $strHtmlMoveDown = '';
680 3 : $strHtmlMoveTop = '';
681 3 : $strHtmlMoveBottom = '';
682 :
683 : // default selection counters
684 3 : $strHtmlSelectedCount = $selected_count . '/' . $unselected_count;
685 3 : } else {
686 : // ... or a dual multi-select
687 10 : $this->_jsPostfix = 'moveSelection';
688 10 : $jsName = $this->_jsPrefix . $this->_jsPostfix;
689 :
690 : // set name of Select From Box
691 10 : $this->_attributesUnselected
692 10 : = array('id' => $selectId . '-f',
693 10 : 'name' => $selectNameFrom,
694 : 'ondblclick' => $jsName .
695 10 : "('{$selectId}', ".
696 10 : "this.form.elements['" . $selectNameFrom . "'], " .
697 10 : "this.form.elements['" . $selectNameTo . "'], " .
698 10 : "this.form.elements['" . $selectName . "'], " .
699 10 : "'add', '{$this->_sort}')");
700 10 : $this->_attributesUnselected
701 10 : = array_merge($this->_attributes, $this->_attributesUnselected);
702 10 : $attrUnselected = $this->_getAttrString($this->_attributesUnselected);
703 :
704 : // set name of Select To Box
705 10 : $this->_attributesSelected
706 10 : = array('id' => $selectId . '-t',
707 10 : 'name' => $selectNameTo,
708 : 'ondblclick' => $jsName .
709 10 : "('{$selectId}', " .
710 10 : "this.form.elements['" . $selectNameFrom . "'], " .
711 10 : "this.form.elements['" . $selectNameTo . "'], ".
712 10 : "this.form.elements['" . $selectName . "'], " .
713 10 : "'remove', '{$this->_sort}')");
714 10 : $this->_attributesSelected
715 10 : = array_merge($this->_attributes, $this->_attributesSelected);
716 10 : $attrSelected = $this->_getAttrString($this->_attributesSelected);
717 :
718 : // set name of Select hidden Box
719 10 : $this->_attributesHidden
720 10 : = array('name' => $selectName,
721 : 'style' => 'overflow: hidden; visibility: hidden; ' .
722 10 : 'width: 1px; height: 0;');
723 10 : $this->_attributesHidden
724 10 : = array_merge($this->_attributes, $this->_attributesHidden);
725 10 : $attrHidden = $this->_getAttrString($this->_attributesHidden);
726 :
727 : // prepare option tables to be displayed as in POST order
728 10 : $append = count($this->_values);
729 10 : if ($append > 0) {
730 3 : $arrHtmlSelected = array_fill(0, $append, ' ');
731 3 : } else {
732 7 : $arrHtmlSelected = array();
733 : }
734 :
735 10 : $options = count($this->_options);
736 10 : $arrHtmlUnselected = array();
737 10 : if ($options > 0) {
738 5 : $arrHtmlHidden = array_fill(0, $options, ' ');
739 :
740 5 : foreach ($this->_options as $option) {
741 5 : if (is_array($this->_values)
742 3 : && in_array((string)$option['attr']['value'],
743 5 : $this->_values)) {
744 : // Get the post order
745 3 : $key = array_search($option['attr']['value'],
746 3 : $this->_values);
747 :
748 : /** The items is *selected* so we want to put it
749 : in the 'selected' multi-select */
750 3 : $arrHtmlSelected[$key] = $option;
751 : /** Add it to the 'hidden' multi-select
752 : and set it as 'selected' */
753 3 : if (isset($option['attr']['disabled'])) {
754 1 : unset($option['attr']['disabled']);
755 1 : }
756 3 : $option['attr']['selected'] = 'selected';
757 3 : $arrHtmlHidden[$key] = $option;
758 3 : } else {
759 : /** The item is *unselected* so we want to put it
760 : in the 'unselected' multi-select */
761 5 : $arrHtmlUnselected[] = $option;
762 : // Add it to the hidden multi-select as 'unselected'
763 5 : $arrHtmlHidden[$append] = $option;
764 5 : $append++;
765 : }
766 5 : }
767 5 : } else {
768 5 : $arrHtmlHidden = array();
769 : }
770 :
771 : // The 'unselected' multi-select which appears on the left
772 10 : $unselected_count = count($arrHtmlUnselected);
773 :
774 10 : if ($unselected_count == 0) {
775 5 : $this->_attributesUnselected['disabled'] = 'disabled';
776 5 : $this->_attributesUnselected
777 5 : = array_merge($this->_attributes, $this->_attributesUnselected);
778 5 : $attrUnselected = $this->_getAttrString($this->_attributesUnselected);
779 5 : }
780 10 : $strHtmlUnselected = "<select$attrUnselected>". PHP_EOL;
781 10 : if ($unselected_count > 0) {
782 5 : foreach ($arrHtmlUnselected as $data) {
783 : $strHtmlUnselected
784 : .= $tabs . $tab
785 5 : . '<option' . $this->_getAttrString($data['attr']) . '>'
786 5 : . $data['text'] . '</option>' . PHP_EOL;
787 5 : }
788 5 : } else {
789 5 : $strHtmlUnselected .= '<option value=""> </option>';
790 : }
791 10 : $strHtmlUnselected .= '</select>';
792 :
793 : // The 'selected' multi-select which appears on the right
794 10 : $selected_count = count($arrHtmlSelected);
795 :
796 10 : if ($selected_count == 0) {
797 7 : $this->_attributesSelected['disabled'] = 'disabled';
798 7 : $this->_attributesSelected
799 7 : = array_merge($this->_attributes, $this->_attributesSelected);
800 7 : $attrSelected = $this->_getAttrString($this->_attributesSelected);
801 7 : }
802 10 : $strHtmlSelected = "<select$attrSelected>". PHP_EOL;
803 10 : if ($selected_count > 0) {
804 3 : foreach ($arrHtmlSelected as $data) {
805 : $strHtmlSelected
806 : .= $tabs . $tab
807 3 : . '<option' . $this->_getAttrString($data['attr']) . '>'
808 3 : . $data['text'] . '</option>' . PHP_EOL;
809 3 : }
810 3 : } else {
811 7 : $strHtmlSelected .= '<option value=""> </option>';
812 : }
813 10 : $strHtmlSelected .= '</select>';
814 :
815 : // The 'hidden' multi-select
816 10 : $strHtmlHidden = "<select$attrHidden>". PHP_EOL;
817 10 : if (count($arrHtmlHidden) > 0) {
818 5 : foreach ($arrHtmlHidden as $data) {
819 : $strHtmlHidden
820 : .= $tabs . $tab
821 5 : . '<option' . $this->_getAttrString($data['attr']) . '>'
822 5 : . $data['text'] . '</option>' . PHP_EOL;
823 5 : }
824 5 : }
825 10 : $strHtmlHidden .= '</select>';
826 :
827 : // build the remove button with all its attributes
828 : $attributes
829 : = array('onclick' => $jsName .
830 10 : "('{$selectId}', " .
831 10 : "this.form.elements['" . $selectNameFrom . "'], " .
832 10 : "this.form.elements['" . $selectNameTo . "'], " .
833 10 : "this.form.elements['" . $selectName . "'], " .
834 10 : "'remove', '{$this->_sort}'); return false;");
835 10 : $this->_removeButtonAttributes
836 10 : = array_merge($this->_removeButtonAttributes, $attributes);
837 10 : $attrStrRemove = $this->_getAttrString($this->_removeButtonAttributes);
838 10 : $strHtmlRemove = "<input$attrStrRemove />". PHP_EOL;
839 :
840 : // build the add button with all its attributes
841 : $attributes
842 : = array('onclick' => $jsName .
843 10 : "('{$selectId}', " .
844 10 : "this.form.elements['" . $selectNameFrom . "'], " .
845 10 : "this.form.elements['" . $selectNameTo . "'], " .
846 10 : "this.form.elements['" . $selectName . "'], " .
847 10 : "'add', '{$this->_sort}'); return false;");
848 10 : $this->_addButtonAttributes
849 10 : = array_merge($this->_addButtonAttributes, $attributes);
850 10 : $attrStrAdd = $this->_getAttrString($this->_addButtonAttributes);
851 10 : $strHtmlAdd = "<input$attrStrAdd />". PHP_EOL;
852 :
853 : // build the select all button with all its attributes
854 : $attributes
855 : = array('onclick' => $jsName .
856 10 : "('{$selectId}', " .
857 10 : "this.form.elements['" . $selectNameFrom . "'], " .
858 10 : "this.form.elements['" . $selectNameTo . "'], " .
859 10 : "this.form.elements['" . $selectName . "'], " .
860 10 : "'all', '{$this->_sort}'); return false;");
861 10 : $this->_allButtonAttributes
862 10 : = array_merge($this->_allButtonAttributes, $attributes);
863 10 : $attrStrAll = $this->_getAttrString($this->_allButtonAttributes);
864 10 : $strHtmlAll = "<input$attrStrAll />". PHP_EOL;
865 :
866 : // build the select none button with all its attributes
867 : $attributes
868 : = array('onclick' => $jsName .
869 10 : "('{$selectId}', " .
870 10 : "this.form.elements['" . $selectNameFrom . "'], " .
871 10 : "this.form.elements['" . $selectNameTo . "'], " .
872 10 : "this.form.elements['" . $selectName . "'], " .
873 10 : "'none', '{$this->_sort}'); return false;");
874 10 : $this->_noneButtonAttributes
875 10 : = array_merge($this->_noneButtonAttributes, $attributes);
876 10 : $attrStrNone = $this->_getAttrString($this->_noneButtonAttributes);
877 10 : $strHtmlNone = "<input$attrStrNone />". PHP_EOL;
878 :
879 : // build the toggle button with all its attributes
880 : $attributes
881 : = array('onclick' => $jsName .
882 10 : "('{$selectId}', " .
883 10 : "this.form.elements['" . $selectNameFrom . "'], " .
884 10 : "this.form.elements['" . $selectNameTo . "'], " .
885 10 : "this.form.elements['" . $selectName . "'], " .
886 10 : "'toggle', '{$this->_sort}'); return false;");
887 10 : $this->_toggleButtonAttributes
888 10 : = array_merge($this->_toggleButtonAttributes, $attributes);
889 10 : $attrStrToggle = $this->_getAttrString($this->_toggleButtonAttributes);
890 10 : $strHtmlToggle = "<input$attrStrToggle />". PHP_EOL;
891 :
892 : // build the move up button with all its attributes
893 : $attributes
894 10 : = array('onclick' => "{$this->_jsPrefix}moveUp" .
895 10 : "(this.form.elements['" . $selectNameTo . "'], " .
896 10 : "this.form.elements['" . $selectName . "']); " .
897 10 : "return false;");
898 10 : $this->_upButtonAttributes
899 10 : = array_merge($this->_upButtonAttributes, $attributes);
900 10 : $attrStrUp = $this->_getAttrString($this->_upButtonAttributes);
901 10 : $strHtmlMoveUp = "<input$attrStrUp />". PHP_EOL;
902 :
903 : // build the move down button with all its attributes
904 : $attributes
905 10 : = array('onclick' => "{$this->_jsPrefix}moveDown" .
906 10 : "(this.form.elements['" . $selectNameTo . "'], " .
907 10 : "this.form.elements['" . $selectName . "']); " .
908 10 : "return false;");
909 10 : $this->_downButtonAttributes
910 10 : = array_merge($this->_downButtonAttributes, $attributes);
911 10 : $attrStrDown = $this->_getAttrString($this->_downButtonAttributes);
912 10 : $strHtmlMoveDown = "<input$attrStrDown />". PHP_EOL;
913 :
914 : // build the move top button with all its attributes
915 : $attributes
916 10 : = array('onclick' => "{$this->_jsPrefix}moveTop" .
917 10 : "(this.form.elements['" . $selectNameTo . "'], " .
918 10 : "this.form.elements['" . $selectName . "']); " .
919 10 : "return false;");
920 10 : $this->_topButtonAttributes
921 10 : = array_merge($this->_topButtonAttributes, $attributes);
922 10 : $attrStrTop = $this->_getAttrString($this->_topButtonAttributes);
923 10 : $strHtmlMoveTop = "<input$attrStrTop />". PHP_EOL;
924 :
925 : // build the move bottom button with all its attributes
926 : $attributes
927 10 : = array('onclick' => "{$this->_jsPrefix}moveBottom" .
928 10 : "(this.form.elements['" . $selectNameTo . "'], " .
929 10 : "this.form.elements['" . $selectName . "']); " .
930 10 : "return false;");
931 10 : $this->_bottomButtonAttributes
932 10 : = array_merge($this->_bottomButtonAttributes, $attributes);
933 10 : $attrStrBottom = $this->_getAttrString($this->_bottomButtonAttributes);
934 10 : $strHtmlMoveBottom = "<input$attrStrBottom />". PHP_EOL;
935 :
936 : // default selection counters
937 10 : $strHtmlSelectedCount = $selected_count;
938 : }
939 13 : $strHtmlUnselectedCount = $unselected_count;
940 :
941 13 : $strHtmlSelectedCountId = $selectId .'_selected';
942 13 : $strHtmlUnselectedCountId = $selectId .'_unselected';
943 :
944 : // render all part of the multi select component with the template
945 13 : $strHtml = $this->_elementTemplate;
946 :
947 : // Prepare multiple labels
948 13 : $labels = $this->getLabel();
949 13 : if (is_array($labels)) {
950 1 : array_shift($labels);
951 1 : }
952 : // render extra labels, if any
953 13 : if (is_array($labels)) {
954 1 : foreach ($labels as $key => $text) {
955 1 : $key = is_int($key)? $key + 2: $key;
956 1 : $strHtml = str_replace("{label_{$key}}", $text, $strHtml);
957 1 : $strHtml = str_replace("<!-- BEGIN label_{$key} -->", '', $strHtml);
958 1 : $strHtml = str_replace("<!-- END label_{$key} -->", '', $strHtml);
959 1 : }
960 1 : }
961 : // clean up useless label tags
962 13 : if (strpos($strHtml, '{label_')) {
963 12 : $strHtml = preg_replace('/\s*<!-- BEGIN label_(\S+) -->'.
964 12 : '.*<!-- END label_\1 -->\s*/i', '', $strHtml);
965 12 : }
966 :
967 : $placeHolders = array(
968 13 : '{stylesheet}', '{javascript}',
969 13 : '{class}',
970 13 : '{unselected_count_id}', '{selected_count_id}',
971 13 : '{unselected_count}', '{selected_count}',
972 13 : '{unselected}', '{selected}',
973 13 : '{add}', '{remove}',
974 13 : '{all}', '{none}', '{toggle}',
975 13 : '{moveup}', '{movedown}',
976 13 : '{movetop}', '{movebottom}'
977 13 : );
978 : $htmlElements = array(
979 13 : $this->getElementCss(false), $this->getElementJs(false),
980 13 : $this->_tableAttributes,
981 13 : $strHtmlUnselectedCountId, $strHtmlSelectedCountId,
982 13 : $strHtmlUnselectedCount, $strHtmlSelectedCount,
983 13 : $strHtmlUnselected, $strHtmlSelected . $strHtmlHidden,
984 13 : $strHtmlAdd, $strHtmlRemove,
985 13 : $strHtmlAll, $strHtmlNone, $strHtmlToggle,
986 13 : $strHtmlMoveUp, $strHtmlMoveDown,
987 13 : $strHtmlMoveTop, $strHtmlMoveBottom
988 13 : );
989 :
990 13 : $strHtml = str_replace($placeHolders, $htmlElements, $strHtml);
991 :
992 13 : $comment = $this->getComment();
993 :
994 13 : if (!empty($comment)) {
995 1 : $strHtml = $tabs . '<!-- ' . $comment . " //-->" . PHP_EOL . $strHtml;
996 1 : }
997 :
998 13 : return $strHtml;
999 : }
1000 :
1001 : /**
1002 : * Returns the javascript code generated to handle this element
1003 : *
1004 : * @param boolean $raw (optional) html output with script tags or just raw data
1005 : * @param boolean $min (optional) uses javascript compressed version
1006 : *
1007 : * @access public
1008 : * @return string
1009 : * @since version 0.4.0 (2005-06-25)
1010 : */
1011 : function getElementJs($raw = true, $min = false)
1012 : {
1013 : $js = 'C:\wamp\bin\php\php5.2.9-1\data' . DIRECTORY_SEPARATOR
1014 13 : . 'HTML_QuickForm_advmultiselect' . DIRECTORY_SEPARATOR;
1015 :
1016 13 : if ($min) {
1017 1 : $js .= 'qfamsHandler-min.js';
1018 1 : } else {
1019 13 : $js .= 'qfamsHandler.js';
1020 : }
1021 :
1022 13 : if (file_exists($js)) {
1023 13 : $js = file_get_contents($js);
1024 13 : } else {
1025 0 : $js = '';
1026 : }
1027 :
1028 13 : if ($raw !== true) {
1029 : $js = '<script type="text/javascript">'
1030 13 : . PHP_EOL . '//<![CDATA['
1031 13 : . PHP_EOL . $js
1032 13 : . PHP_EOL . '//]]>'
1033 13 : . PHP_EOL . '</script>'
1034 13 : . PHP_EOL;
1035 13 : }
1036 13 : return $js;
1037 : }
1038 :
1039 : /**
1040 : * Loads options from different types of data sources
1041 : *
1042 : * This method overloaded parent method of select element, to allow
1043 : * loading options with fancy attributes.
1044 : *
1045 : * @param mixed &$options Options source currently supports assoc array or DB_result
1046 : * @param mixed $param1 (optional) See function detail
1047 : * @param mixed $param2 (optional) See function detail
1048 : * @param mixed $param3 (optional) See function detail
1049 : * @param mixed $param4 (optional) See function detail
1050 : *
1051 : * @access public
1052 : * @since version 1.5.0 (2009-02-15)
1053 : * @return PEAR_Error|NULL on error and TRUE on success
1054 : * @throws PEAR_Error
1055 : * @see loadArray()
1056 : */
1057 : function load(&$options,
1058 : $param1 = null, $param2 = null, $param3 = null, $param4 = null)
1059 : {
1060 21 : if (is_array($options)) {
1061 11 : $ret = $this->loadArray($options, $param1);
1062 11 : } else {
1063 11 : $ret = parent::load($options, $param1, $param2, $param3, $param4);
1064 : }
1065 21 : return $ret;
1066 : }
1067 :
1068 : /**
1069 : * Loads the options from an associative array
1070 : *
1071 : * This method overloaded parent method of select element, to allow to load
1072 : * array of options with fancy attributes.
1073 : *
1074 : * @param array $arr Associative array of options
1075 : * @param mixed $values (optional) Array or comma delimited string of selected values
1076 : *
1077 : * @since version 1.5.0 (2009-02-15)
1078 : * @access public
1079 : * @return PEAR_Error on error and TRUE on success
1080 : * @throws PEAR_Error
1081 : * @see load()
1082 : */
1083 : function loadArray($arr, $values = null)
1084 : {
1085 12 : if (!is_array($arr)) {
1086 1 : return PEAR::throwError('Argument 1 of HTML_QuickForm_advmultiselect::' .
1087 1 : 'loadArray is not a valid array',
1088 1 : HTML_QUICKFORM_ADVMULTISELECT_ERROR_INVALID_INPUT,
1089 1 : array('level' => 'exception'));
1090 : }
1091 11 : if (isset($values)) {
1092 1 : $this->setSelected($values);
1093 1 : }
1094 11 : if (is_array($arr)) {
1095 11 : foreach ($arr as $key => $val) {
1096 11 : if (is_array($val)) {
1097 4 : $this->addOption($val[0], $key, $val[1]);
1098 4 : } else {
1099 11 : $this->addOption($val, $key);
1100 : }
1101 11 : }
1102 11 : }
1103 11 : return true;
1104 : }
1105 :
1106 : /**
1107 : * Sets which items should be persistant
1108 : *
1109 : * Sets which items should have the disabled attribute
1110 : * to keep it persistant
1111 : *
1112 : * @param mixed $optionValues Options (key-values) that should be persistant
1113 : * @param bool $persistant (optional) TRUE if persistant, FALSE otherwise
1114 : *
1115 : * @since version 1.5.0 (2009-02-15)
1116 : * @access public
1117 : * @return PEAR_Error on error and TRUE on success
1118 : * @throws PEAR_Error
1119 : */
1120 : function setPersistantOptions($optionValues, $persistant = true)
1121 : {
1122 3 : if (!is_bool($persistant)) {
1123 1 : return PEAR::throwError('Argument 2 of HTML_QuickForm_advmultiselect::' .
1124 1 : 'setPersistantOptions is not a boolean',
1125 1 : HTML_QUICKFORM_ADVMULTISELECT_ERROR_INVALID_INPUT,
1126 1 : array('level' => 'exception'));
1127 : }
1128 3 : if (is_string($optionValues)) {
1129 1 : $optionValues = array($optionValues);
1130 1 : }
1131 3 : if (!is_array($optionValues)) {
1132 1 : return PEAR::throwError('Argument 1 of HTML_QuickForm_advmultiselect::' .
1133 1 : 'setPersistantOptions is not a valid array',
1134 1 : HTML_QUICKFORM_ADVMULTISELECT_ERROR_INVALID_INPUT,
1135 1 : array('level' => 'exception'));
1136 : }
1137 :
1138 2 : foreach ($this->_options as $k => $v) {
1139 2 : if (in_array($v['attr']['value'], $optionValues)) {
1140 2 : if ($persistant) {
1141 2 : $this->_options[$k]['attr']['disabled'] = 'disabled';
1142 2 : } else {
1143 1 : unset($this->_options[$k]['attr']['disabled']);
1144 : }
1145 2 : }
1146 2 : }
1147 2 : return true;
1148 : }
1149 :
1150 : /**
1151 : * Returns list of persistant options
1152 : *
1153 : * Returns list of persistant options (key-values) that could not
1154 : * be selected or unselected.
1155 : *
1156 : * @since version 1.5.0 (2009-02-15)
1157 : * @access public
1158 : * @return array
1159 : */
1160 : function getPersistantOptions()
1161 : {
1162 1 : $options = array();
1163 :
1164 1 : foreach ($this->_options as $k => $v) {
1165 1 : if (isset($v['attr']['disabled'])) {
1166 1 : $options[] = $this->_options[$k]['attr']['value'];
1167 1 : }
1168 1 : }
1169 :
1170 1 : return $options;
1171 : }
1172 : }
1173 :
1174 : if (class_exists('HTML_QuickForm')) {
1175 : HTML_QuickForm::registerElementType('advmultiselect',
1176 : 'HTML/QuickForm/advmultiselect.php', 'HTML_QuickForm_advmultiselect');
1177 : }
|