PageRenderTime 100ms CodeModel.GetById 61ms RepoModel.GetById 0ms app.codeStats 1ms

/common/libraries/plugin/pear/HTML/QuickForm/advmultiselect.php

https://bitbucket.org/chamilo/chamilo/
PHP | 954 lines | 528 code | 74 blank | 352 comment | 56 complexity | 66024067ef64573797116b3b072cffd4 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, LGPL-2.1, LGPL-3.0, GPL-3.0, MIT
  1. <?php
  2. /**
  3. * Copyright (c) 2005-2008, 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-2008 Laurent Laville
  38. * @license http://www.opensource.org/licenses/bsd-license.php BSD
  39. * @version CVS: $Id: advmultiselect.php 137 2009-11-09 13:24:37Z vanpouckesven $
  40. * @link http://pear.php.net/package/HTML_QuickForm_advmultiselect
  41. * @since File available since Release 0.4.0
  42. */
  43. require_once 'HTML/QuickForm/select.php';
  44. /**
  45. * Element for HTML_QuickForm that emulate a multi-select.
  46. *
  47. * The HTML_QuickForm_advmultiselect package adds an element to the
  48. * HTML_QuickForm package that is two select boxes next to each other
  49. * emulating a multi-select.
  50. *
  51. * @category HTML
  52. * @package HTML_QuickForm_advmultiselect
  53. * @author Laurent Laville <pear@laurent-laville.org>
  54. * @copyright 2005-2008 Laurent Laville
  55. * @license http://www.opensource.org/licenses/bsd-license.php BSD
  56. * @version Release: @package_version@
  57. * @link http://pear.php.net/package/HTML_QuickForm_advmultiselect
  58. * @since Class available since Release 0.4.0
  59. */
  60. class HTML_QuickForm_advmultiselect extends HTML_QuickForm_select
  61. {
  62. /**
  63. * Prefix function name in javascript move selections
  64. *
  65. * @var string
  66. * @access private
  67. * @since 0.4.0
  68. */
  69. var $_jsPrefix;
  70. /**
  71. * Postfix function name in javascript move selections
  72. *
  73. * @var string
  74. * @access private
  75. * @since 0.4.0
  76. */
  77. var $_jsPostfix;
  78. /**
  79. * Associative array of the multi select container attributes
  80. *
  81. * @var array
  82. * @access private
  83. * @since 0.4.0
  84. */
  85. var $_tableAttributes;
  86. /**
  87. * Associative array of the add button attributes
  88. *
  89. * @var array
  90. * @access private
  91. * @since 0.4.0
  92. */
  93. var $_addButtonAttributes;
  94. /**
  95. * Associative array of the remove button attributes
  96. *
  97. * @var array
  98. * @access private
  99. * @since 0.4.0
  100. */
  101. var $_removeButtonAttributes;
  102. /**
  103. * Associative array of the select all button attributes
  104. *
  105. * @var array
  106. * @access private
  107. * @since 1.1.0
  108. */
  109. var $_allButtonAttributes;
  110. /**
  111. * Associative array of the select none button attributes
  112. *
  113. * @var array
  114. * @access private
  115. * @since 1.1.0
  116. */
  117. var $_noneButtonAttributes;
  118. /**
  119. * Associative array of the toggle selection button attributes
  120. *
  121. * @var array
  122. * @access private
  123. * @since 1.1.0
  124. */
  125. var $_toggleButtonAttributes;
  126. /**
  127. * Associative array of the move up button attributes
  128. *
  129. * @var array
  130. * @access private
  131. * @since 0.5.0
  132. */
  133. var $_upButtonAttributes;
  134. /**
  135. * Associative array of the move up button attributes
  136. *
  137. * @var array
  138. * @access private
  139. * @since 0.5.0
  140. */
  141. var $_downButtonAttributes;
  142. /**
  143. * Defines if both list (unselected, selected) will have their elements be
  144. * arranged from lowest to highest (or reverse)
  145. * depending on comparaison function.
  146. *
  147. * SORT_ASC is used to sort in ascending order
  148. * SORT_DESC is used to sort in descending order
  149. *
  150. * @var string ('none' == false, 'asc' == SORT_ASC, 'desc' == SORT_DESC)
  151. * @access private
  152. * @since 0.5.0
  153. */
  154. var $_sort;
  155. /**
  156. * Associative array of the unselected item box attributes
  157. *
  158. * @var array
  159. * @access private
  160. * @since 0.4.0
  161. */
  162. var $_attributesUnselected;
  163. /**
  164. * Associative array of the selected item box attributes
  165. *
  166. * @var array
  167. * @access private
  168. * @since 0.4.0
  169. */
  170. var $_attributesSelected;
  171. /**
  172. * Associative array of the internal hidden box attributes
  173. *
  174. * @var array
  175. * @access private
  176. * @since 0.4.0
  177. */
  178. var $_attributesHidden;
  179. /**
  180. * Default Element template string
  181. *
  182. * @var string
  183. * @access private
  184. * @since 0.4.0
  185. */
  186. var $_elementTemplate = '
  187. {javascript}
  188. <table{class}>
  189. <!-- BEGIN label_2 --><tr><th>{label_2}</th><!-- END label_2 -->
  190. <!-- BEGIN label_3 --><th>&nbsp;</th><th>{label_3}</th></tr><!-- END label_3 -->
  191. <tr>
  192. <td valign="top">{unselected}</td>
  193. <td align="center">{add}{remove}</td>
  194. <td valign="top">{selected}</td>
  195. </tr>
  196. </table>
  197. ';
  198. /**
  199. * Default Element stylesheet string
  200. *
  201. * @var string
  202. * @access private
  203. * @since 0.4.0
  204. */
  205. var $_elementCSS = '
  206. #qfams_{id} {
  207. font: 13.3px sans-serif;
  208. background-color: #fff;
  209. overflow: auto;
  210. height: 14.3em;
  211. width: 12em;
  212. border-left: 1px solid #404040;
  213. border-top: 1px solid #404040;
  214. border-bottom: 1px solid #d4d0c8;
  215. border-right: 1px solid #d4d0c8;
  216. }
  217. #qfams_{id} label {
  218. padding-right: 3px;
  219. display: block;
  220. }
  221. ';
  222. /**
  223. * Class constructor
  224. *
  225. * Class constructors :
  226. * Zend Engine 1 uses HTML_QuickForm_advmultiselect, while
  227. * Zend Engine 2 uses __construct
  228. *
  229. * @param string $elementName Dual Select name attribute
  230. * @param mixed $elementLabel Label(s) for the select boxes
  231. * @param mixed $options Data to be used to populate options
  232. * @param mixed $attributes Either a typical HTML attribute string or
  233. * an associative array
  234. * @param integer $sort Either SORT_ASC for auto ascending arrange,
  235. * SORT_DESC for auto descending arrange, or
  236. * NULL for no sort (append at end: default)
  237. *
  238. * @access public
  239. * @return void
  240. * @since 0.4.0
  241. */
  242. function __construct($elementName = null, $elementLabel = null,
  243. $options = null, $attributes = null,
  244. $sort = null)
  245. {
  246. parent :: __construct($elementName, $elementLabel,
  247. $options, $attributes);
  248. // add multiple selection attribute by default if missing
  249. $this->updateAttributes(array('multiple' => 'multiple'));
  250. if (is_null($this->getAttribute('size'))) {
  251. // default size is ten item on each select box (left and right)
  252. $this->updateAttributes(array('size' => 10));
  253. }
  254. if (is_null($this->getAttribute('style'))) {
  255. // default width of each select box
  256. $this->updateAttributes(array('style' => 'width:100px;'));
  257. }
  258. $this->_tableAttributes = $this->getAttribute('class');
  259. if (is_null($this->_tableAttributes)) {
  260. // default table layout
  261. $attr = array('border' => '0',
  262. 'cellpadding' => '10', 'cellspacing' => '0');
  263. } else {
  264. $attr = array('class' => $this->_tableAttributes);
  265. $this->_removeAttr('class', $this->_attributes);
  266. }
  267. $this->_tableAttributes = $this->_getAttrString($attr);
  268. // set default add button attributes
  269. $this->setButtonAttributes('add');
  270. // set default remove button attributes
  271. $this->setButtonAttributes('remove');
  272. // set default selectall button attributes
  273. $this->setButtonAttributes('all');
  274. // set default selectnone button attributes
  275. $this->setButtonAttributes('none');
  276. // set default toggle selection button attributes
  277. $this->setButtonAttributes('toggle');
  278. // set default move up button attributes
  279. $this->setButtonAttributes('moveup');
  280. // set default move up button attributes
  281. $this->setButtonAttributes('movedown');
  282. // defines javascript functions names
  283. $this->setJsElement();
  284. // set select boxes sort order (none by default)
  285. if (!isset($sort)) {
  286. $sort = false;
  287. }
  288. if ($sort === SORT_ASC) {
  289. $this->_sort = 'asc';
  290. } elseif ($sort === SORT_DESC) {
  291. $this->_sort = 'desc';
  292. } else {
  293. $this->_sort = 'none';
  294. }
  295. }
  296. /**
  297. * Sets the button attributes
  298. *
  299. * In <b>custom example 1</b>, the <i>add</i> and <i>remove</i> buttons
  300. * have look set by the css class <i>inputCommand</i>.
  301. *
  302. * In <b>custom example 2</b>, the basic text <i>add</i> and <i>remove</i>
  303. * buttons are now replaced by images.
  304. *
  305. * In <b>custom example 5</b>, we have ability to sort the selection list
  306. * (on right side) by :
  307. * <pre>
  308. * - <b>user-end</b>: with <i>Up</i> and <i>Down</i> buttons
  309. * - <b>programming</b>: with the QF element constructor $sort option
  310. * </pre>
  311. *
  312. * @param string $button Button identifier, either 'add', 'remove',
  313. * 'all', 'none', 'toggle',
  314. * 'moveup' or 'movedown'
  315. * @param mixed $attributes (optional) Either a typical HTML attribute string
  316. * or an associative array
  317. *
  318. * @return void
  319. * @throws PEAR_Error $button argument
  320. * is not a string, or not in range
  321. * (add, remove, all, none, toggle, moveup, movedown)
  322. * @access public
  323. * @since 0.4.0
  324. *
  325. * @example examples/qfams_custom_5.php
  326. * Custom example 5: source code
  327. * @link http://www.laurent-laville.org/img/qfams/screenshot/custom5.png
  328. * Custom example 5: screenshot
  329. *
  330. * @example examples/qfams_custom_2.php
  331. * Custom example 2: source code
  332. * @link http://www.laurent-laville.org/img/qfams/screenshot/custom2.png
  333. * Custom example 2: screenshot
  334. *
  335. * @example examples/qfams_custom_1.php
  336. * Custom example 1: source code
  337. * @link http://www.laurent-laville.org/img/qfams/screenshot/custom1.png
  338. * Custom example 1: screenshot
  339. */
  340. function setButtonAttributes($button, $attributes = null)
  341. {
  342. if (!is_string($button)) {
  343. return PEAR::raiseError('Argument 1 of ' .
  344. 'advmultiselect::setButtonAttributes is not a string');
  345. }
  346. switch ($button) {
  347. case 'add':
  348. if (is_null($attributes)) {
  349. $this->_addButtonAttributes
  350. = array('name' => 'add',
  351. 'value' => ' >> ',
  352. 'type' => 'button');
  353. } else {
  354. $this->_updateAttrArray($this->_addButtonAttributes,
  355. $this->_parseAttributes($attributes));
  356. }
  357. break;
  358. case 'remove':
  359. if (is_null($attributes)) {
  360. $this->_removeButtonAttributes
  361. = array('name' => 'remove',
  362. 'value' => ' << ',
  363. 'type' => 'button');
  364. } else {
  365. $this->_updateAttrArray($this->_removeButtonAttributes,
  366. $this->_parseAttributes($attributes));
  367. }
  368. break;
  369. case 'all':
  370. if (is_null($attributes)) {
  371. $this->_allButtonAttributes
  372. = array('name' => 'all',
  373. 'value' => ' Select All ',
  374. 'type' => 'button');
  375. } else {
  376. $this->_updateAttrArray($this->_allButtonAttributes,
  377. $this->_parseAttributes($attributes));
  378. }
  379. break;
  380. case 'none':
  381. if (is_null($attributes)) {
  382. $this->_noneButtonAttributes
  383. = array('name' => 'none',
  384. 'value' => ' Select None ',
  385. 'type' => 'button');
  386. } else {
  387. $this->_updateAttrArray($this->_noneButtonAttributes,
  388. $this->_parseAttributes($attributes));
  389. }
  390. break;
  391. case 'toggle':
  392. if (is_null($attributes)) {
  393. $this->_toggleButtonAttributes
  394. = array('name' => 'toggle',
  395. 'value' => ' Toggle Selection ',
  396. 'type' => 'button');
  397. } else {
  398. $this->_updateAttrArray($this->_toggleButtonAttributes,
  399. $this->_parseAttributes($attributes));
  400. }
  401. break;
  402. case 'moveup':
  403. if (is_null($attributes)) {
  404. $this->_upButtonAttributes
  405. = array('name' => 'up',
  406. 'value' => ' Up ',
  407. 'type' => 'button');
  408. } else {
  409. $this->_updateAttrArray($this->_upButtonAttributes,
  410. $this->_parseAttributes($attributes));
  411. }
  412. break;
  413. case 'movedown':
  414. if (is_null($attributes)) {
  415. $this->_downButtonAttributes
  416. = array('name' => 'down',
  417. 'value' => ' Down ',
  418. 'type' => 'button');
  419. } else {
  420. $this->_updateAttrArray($this->_downButtonAttributes,
  421. $this->_parseAttributes($attributes));
  422. }
  423. break;
  424. default;
  425. return PEAR::raiseError('Argument 1 of ' .
  426. 'advmultiselect::setButtonAttributes has unexpected value');
  427. }
  428. }
  429. /**
  430. * Sets element template
  431. *
  432. * @param string $html The HTML surrounding select boxes and buttons
  433. *
  434. * @access public
  435. * @return void
  436. * @since 0.4.0
  437. */
  438. function setElementTemplate($html)
  439. {
  440. $this->_elementTemplate = $html;
  441. }
  442. /**
  443. * Sets JavaScript function name parts. Maybe usefull to avoid conflict names
  444. *
  445. * In <b>multiple example 1</b>, the javascript function prefix
  446. * is set to not null.
  447. *
  448. * @param string $pref (optional) Prefix name
  449. * @param string $post (optional) Postfix name
  450. *
  451. * @access public
  452. * @return void
  453. * @see getElementJs()
  454. * @since 0.4.0
  455. * @deprecated since version 1.3.0
  456. *
  457. * @example examples/qfams_multiple_1.php
  458. * Multiple example 1: source code
  459. * @link http://www.laurent-laville.org/img/qfams/screenshot/multiple1.png
  460. * Multiple example 1: screenshot
  461. */
  462. function setJsElement($pref = null, $post = 'moveSelections')
  463. {
  464. $this->_jsPrefix = 'qfams';
  465. $this->_jsPostfix = 'MoveSelection';
  466. }
  467. /**
  468. * Gets default element stylesheet for a single multi-select shape render
  469. *
  470. * In <b>custom example 4</b>, the template defined allows
  471. * a single multi-select checkboxes shape. Useful when javascript is disabled
  472. * (or when browser is not js compliant). In our example, no need to add
  473. * javascript code, but css is mandatory.
  474. *
  475. * @param boolean $raw (optional) html output with style tags or just raw data
  476. *
  477. * @access public
  478. * @return string
  479. * @since 0.4.0
  480. *
  481. * @example qfams_custom_4.php
  482. * Custom example 4: source code
  483. * @link http://www.laurent-laville.org/img/qfams/screenshot/custom4.png
  484. * Custom example 4: screenshot
  485. */
  486. function getElementCss($raw = true)
  487. {
  488. $id = $this->getAttribute('name');
  489. $css = str_replace('{id}', $id, $this->_elementCSS);
  490. if ($raw !== true) {
  491. $css = '<style type="text/css">' . PHP_EOL
  492. . '<!--' . $css . '// -->' . PHP_EOL
  493. . '</style>';
  494. }
  495. return $css;
  496. }
  497. /**
  498. * Returns the HTML generated for the advanced mutliple select component
  499. *
  500. * @access public
  501. * @return string
  502. * @since 0.4.0
  503. */
  504. function toHtml()
  505. {
  506. if ($this->_flagFrozen) {
  507. return $this->getFrozenHtml();
  508. }
  509. $tabs = $this->_getTabs();
  510. $tab = $this->_getTab();
  511. $strHtml = '';
  512. if ($this->getComment() != '') {
  513. $strHtml .= $tabs . '<!-- ' . $this->getComment() . " //-->" . PHP_EOL;
  514. }
  515. $selectId = $this->getName();
  516. $selectName = $this->getName() . '[]';
  517. $selectNameFrom = $this->getName() . '-f[]';
  518. $selectNameTo = $this->getName() . '-t[]';
  519. $selected_count = 0;
  520. // placeholder {unselected} existence determines if we will render
  521. if (strpos($this->_elementTemplate, '{unselected}') === false) {
  522. // ... a single multi-select with checkboxes
  523. $this->_jsPostfix = 'EditSelection';
  524. $id = $this->getAttribute('name');
  525. $strHtmlSelected = $tab . '<div id="qfams_'.$id.'">' . PHP_EOL;
  526. $unselected_count = count($this->_options);
  527. $checkbox_id_suffix = 0;
  528. foreach ($this->_options as $option) {
  529. $_labelAttributes
  530. = array('style', 'class', 'onmouseover', 'onmouseout');
  531. $labelAttributes = array();
  532. foreach ($_labelAttributes as $attr) {
  533. if (isset($option['attr'][$attr])) {
  534. $labelAttributes[$attr] = $option['attr'][$attr];
  535. unset($option['attr'][$attr]);
  536. }
  537. }
  538. if (is_array($this->_values)
  539. && in_array((string)$option['attr']['value'], $this->_values)) {
  540. // The items is *selected*
  541. $checked = ' checked="checked"';
  542. $selected_count++;
  543. } else {
  544. // The item is *unselected* so we want to put it
  545. $checked = '';
  546. }
  547. $checkbox_id_suffix++;
  548. $strHtmlSelected .= $tab
  549. . '<label'
  550. . $this->_getAttrString($labelAttributes) .'>'
  551. . '<input type="checkbox"'
  552. . ' id="'.$selectId . $checkbox_id_suffix.'"'
  553. . ' name="'.$selectName.'"'
  554. . $checked
  555. . $this->_getAttrString($option['attr'])
  556. . ' />' . $option['text'] . '</label>'
  557. . PHP_EOL;
  558. }
  559. $strHtmlSelected .= $tab . '</div>'. PHP_EOL;
  560. $strHtmlHidden = '';
  561. $strHtmlUnselected = '';
  562. $strHtmlAdd = '';
  563. $strHtmlRemove = '';
  564. // build the select all button with all its attributes
  565. $jsName = $this->_jsPrefix . $this->_jsPostfix;
  566. $attributes = array('onclick' => $jsName .
  567. "('". $selectId ."', 1);");
  568. $this->_allButtonAttributes
  569. = array_merge($this->_allButtonAttributes, $attributes);
  570. $attrStrAll = $this->_getAttrString($this->_allButtonAttributes);
  571. $strHtmlAll = "<input$attrStrAll />". PHP_EOL;
  572. // build the select none button with all its attributes
  573. $attributes = array('onclick' => $jsName .
  574. "('". $selectId ."', 0);");
  575. $this->_noneButtonAttributes
  576. = array_merge($this->_noneButtonAttributes, $attributes);
  577. $attrStrNone = $this->_getAttrString($this->_noneButtonAttributes);
  578. $strHtmlNone = "<input$attrStrNone />". PHP_EOL;
  579. // build the toggle selection button with all its attributes
  580. $attributes = array('onclick' => $jsName .
  581. "('". $selectId ."', 2);");
  582. $this->_toggleButtonAttributes
  583. = array_merge($this->_toggleButtonAttributes,
  584. $attributes);
  585. $attrStrToggle = $this->_getAttrString($this->_toggleButtonAttributes);
  586. $strHtmlToggle = "<input$attrStrToggle />". PHP_EOL;
  587. $strHtmlMoveUp = '';
  588. $strHtmlMoveDown = '';
  589. // default selection counters
  590. $strHtmlSelectedCount = $selected_count . '/' . $unselected_count;
  591. } else {
  592. // ... or a dual multi-select
  593. $this->_jsPostfix = 'MoveSelection';
  594. $jsName = $this->_jsPrefix . $this->_jsPostfix;
  595. // set name of Select From Box
  596. $this->_attributesUnselected
  597. = array('id' => $selectId . '-f',
  598. 'name' => $selectNameFrom,
  599. 'ondblclick' => $jsName .
  600. "('{$selectId}', ".
  601. "this.form.elements['" . $selectNameFrom . "'], " .
  602. "this.form.elements['" . $selectNameTo . "'], " .
  603. "this.form.elements['" . $selectName . "'], " .
  604. "'add', '{$this->_sort}')");
  605. $this->_attributesUnselected
  606. = array_merge($this->_attributes, $this->_attributesUnselected);
  607. $attrUnselected = $this->_getAttrString($this->_attributesUnselected);
  608. // set name of Select To Box
  609. $this->_attributesSelected
  610. = array('id' => $selectId . '-t',
  611. 'name' => $selectNameTo,
  612. 'ondblclick' => $jsName .
  613. "('{$selectId}', " .
  614. "this.form.elements['" . $selectNameFrom . "'], " .
  615. "this.form.elements['" . $selectNameTo . "'], ".
  616. "this.form.elements['" . $selectName . "'], " .
  617. "'remove', '{$this->_sort}')");
  618. $this->_attributesSelected
  619. = array_merge($this->_attributes, $this->_attributesSelected);
  620. $attrSelected = $this->_getAttrString($this->_attributesSelected);
  621. // set name of Select hidden Box
  622. $this->_attributesHidden
  623. = array('name' => $selectName,
  624. 'style' => 'overflow: hidden; visibility: hidden; ' .
  625. 'width: 1px; height: 0;');
  626. $this->_attributesHidden
  627. = array_merge($this->_attributes, $this->_attributesHidden);
  628. $attrHidden = $this->_getAttrString($this->_attributesHidden);
  629. // prepare option tables to be displayed as in POST order
  630. $append = count($this->_values);
  631. if ($append > 0) {
  632. $arrHtmlSelected = array_fill(0, $append, ' ');
  633. } else {
  634. $arrHtmlSelected = array();
  635. }
  636. $options = count($this->_options);
  637. $arrHtmlUnselected = array();
  638. if ($options > 0) {
  639. $arrHtmlHidden = array_fill(0, $options, ' ');
  640. foreach ($this->_options as $option) {
  641. if (is_array($this->_values)
  642. && in_array((string)$option['attr']['value'],
  643. $this->_values)) {
  644. // Get the post order
  645. $key = array_search($option['attr']['value'],
  646. $this->_values);
  647. /** The items is *selected* so we want to put it
  648. in the 'selected' multi-select */
  649. $arrHtmlSelected[$key] = $option;
  650. /** Add it to the 'hidden' multi-select
  651. and set it as 'selected' */
  652. $option['attr']['selected'] = 'selected';
  653. $arrHtmlHidden[$key] = $option;
  654. } else {
  655. /** The item is *unselected* so we want to put it
  656. in the 'unselected' multi-select */
  657. $arrHtmlUnselected[] = $option;
  658. // Add it to the hidden multi-select as 'unselected'
  659. $arrHtmlHidden[$append] = $option;
  660. $append++;
  661. }
  662. }
  663. } else {
  664. $arrHtmlHidden = array();
  665. }
  666. // The 'unselected' multi-select which appears on the left
  667. $unselected_count = count($arrHtmlUnselected);
  668. if ($unselected_count == 0) {
  669. $this->_attributesUnselected['disabled'] = 'disabled';
  670. $this->_attributesUnselected
  671. = array_merge($this->_attributes, $this->_attributesUnselected);
  672. $attrUnselected = $this->_getAttrString($this->_attributesUnselected);
  673. }
  674. $strHtmlUnselected = "<select$attrUnselected>". PHP_EOL;
  675. if ($unselected_count > 0) {
  676. foreach ($arrHtmlUnselected as $data) {
  677. $strHtmlUnselected
  678. .= $tabs . $tab
  679. . '<option' . $this->_getAttrString($data['attr']) . '>'
  680. . $data['text'] . '</option>' . PHP_EOL;
  681. }
  682. } else {
  683. $strHtmlUnselected .= '<option value="">&nbsp;</option>';
  684. }
  685. $strHtmlUnselected .= '</select>';
  686. // The 'selected' multi-select which appears on the right
  687. $selected_count = count($arrHtmlSelected);
  688. if ($selected_count == 0) {
  689. $this->_attributesSelected['disabled'] = 'disabled';
  690. $this->_attributesSelected
  691. = array_merge($this->_attributes, $this->_attributesSelected);
  692. $attrSelected = $this->_getAttrString($this->_attributesSelected);
  693. }
  694. $strHtmlSelected = "<select$attrSelected>". PHP_EOL;
  695. if ($selected_count > 0) {
  696. foreach ($arrHtmlSelected as $data) {
  697. $strHtmlSelected
  698. .= $tabs . $tab
  699. . '<option' . $this->_getAttrString($data['attr']) . '>'
  700. . $data['text'] . '</option>' . PHP_EOL;
  701. }
  702. } else {
  703. $strHtmlSelected .= '<option value="">&nbsp;</option>';
  704. }
  705. $strHtmlSelected .= '</select>';
  706. // The 'hidden' multi-select
  707. $strHtmlHidden = "<select$attrHidden>". PHP_EOL;
  708. if (count($arrHtmlHidden) > 0) {
  709. foreach ($arrHtmlHidden as $data) {
  710. $strHtmlHidden
  711. .= $tabs . $tab
  712. . '<option' . $this->_getAttrString($data['attr']) . '>'
  713. . $data['text'] . '</option>' . PHP_EOL;
  714. }
  715. }
  716. $strHtmlHidden .= '</select>';
  717. // build the remove button with all its attributes
  718. $attributes
  719. = array('onclick' => $jsName .
  720. "('{$selectId}', " .
  721. "this.form.elements['" . $selectNameFrom . "'], " .
  722. "this.form.elements['" . $selectNameTo . "'], " .
  723. "this.form.elements['" . $selectName . "'], " .
  724. "'remove', '{$this->_sort}'); return false;");
  725. $this->_removeButtonAttributes
  726. = array_merge($this->_removeButtonAttributes, $attributes);
  727. $attrStrRemove = $this->_getAttrString($this->_removeButtonAttributes);
  728. $strHtmlRemove = "<input$attrStrRemove />". PHP_EOL;
  729. // build the add button with all its attributes
  730. $attributes
  731. = array('onclick' => $jsName .
  732. "('{$selectId}', " .
  733. "this.form.elements['" . $selectNameFrom . "'], " .
  734. "this.form.elements['" . $selectNameTo . "'], " .
  735. "this.form.elements['" . $selectName . "'], " .
  736. "'add', '{$this->_sort}'); return false;");
  737. $this->_addButtonAttributes
  738. = array_merge($this->_addButtonAttributes, $attributes);
  739. $attrStrAdd = $this->_getAttrString($this->_addButtonAttributes);
  740. $strHtmlAdd = "<input$attrStrAdd />". PHP_EOL;
  741. // build the select all button with all its attributes
  742. $attributes
  743. = array('onclick' => $jsName .
  744. "('{$selectId}', " .
  745. "this.form.elements['" . $selectNameFrom . "'], " .
  746. "this.form.elements['" . $selectNameTo . "'], " .
  747. "this.form.elements['" . $selectName . "'], " .
  748. "'all', '{$this->_sort}'); return false;");
  749. $this->_allButtonAttributes
  750. = array_merge($this->_allButtonAttributes, $attributes);
  751. $attrStrAll = $this->_getAttrString($this->_allButtonAttributes);
  752. $strHtmlAll = "<input$attrStrAll />". PHP_EOL;
  753. // build the select none button with all its attributes
  754. $attributes
  755. = array('onclick' => $jsName .
  756. "('{$selectId}', " .
  757. "this.form.elements['" . $selectNameFrom . "'], " .
  758. "this.form.elements['" . $selectNameTo . "'], " .
  759. "this.form.elements['" . $selectName . "'], " .
  760. "'none', '{$this->_sort}'); return false;");
  761. $this->_noneButtonAttributes
  762. = array_merge($this->_noneButtonAttributes, $attributes);
  763. $attrStrNone = $this->_getAttrString($this->_noneButtonAttributes);
  764. $strHtmlNone = "<input$attrStrNone />". PHP_EOL;
  765. // build the toggle button with all its attributes
  766. $attributes
  767. = array('onclick' => $jsName .
  768. "('{$selectId}', " .
  769. "this.form.elements['" . $selectNameFrom . "'], " .
  770. "this.form.elements['" . $selectNameTo . "'], " .
  771. "this.form.elements['" . $selectName . "'], " .
  772. "'toggle', '{$this->_sort}'); return false;");
  773. $this->_toggleButtonAttributes
  774. = array_merge($this->_toggleButtonAttributes, $attributes);
  775. $attrStrToggle = $this->_getAttrString($this->_toggleButtonAttributes);
  776. $strHtmlToggle = "<input$attrStrToggle />". PHP_EOL;
  777. // build the move up button with all its attributes
  778. $attributes
  779. = array('onclick' => "{$this->_jsPrefix}MoveUp" .
  780. "(this.form.elements['" . $selectNameTo . "'], " .
  781. "this.form.elements['" . $selectName . "']); " .
  782. "return false;");
  783. $this->_upButtonAttributes
  784. = array_merge($this->_upButtonAttributes, $attributes);
  785. $attrStrUp = $this->_getAttrString($this->_upButtonAttributes);
  786. $strHtmlMoveUp = "<input$attrStrUp />". PHP_EOL;
  787. // build the move down button with all its attributes
  788. $attributes
  789. = array('onclick' => "{$this->_jsPrefix}MoveDown" .
  790. "(this.form.elements['" . $selectNameTo . "'], " .
  791. "this.form.elements['" . $selectName . "']); " .
  792. "return false;");
  793. $this->_downButtonAttributes
  794. = array_merge($this->_downButtonAttributes, $attributes);
  795. $attrStrDown = $this->_getAttrString($this->_downButtonAttributes);
  796. $strHtmlMoveDown = "<input$attrStrDown />". PHP_EOL;
  797. // default selection counters
  798. $strHtmlSelectedCount = $selected_count;
  799. }
  800. $strHtmlUnselectedCount = $unselected_count;
  801. $strHtmlSelectedCountId = $selectId .'_selected';
  802. $strHtmlUnselectedCountId = $selectId .'_unselected';
  803. // render all part of the multi select component with the template
  804. $strHtml = $this->_elementTemplate;
  805. // Prepare multiple labels
  806. $labels = $this->getLabel();
  807. if (is_array($labels)) {
  808. array_shift($labels);
  809. }
  810. // render extra labels, if any
  811. if (is_array($labels)) {
  812. foreach ($labels as $key => $text) {
  813. $key = is_int($key)? $key + 2: $key;
  814. $strHtml = str_replace("{label_{$key}}", $text, $strHtml);
  815. $strHtml = str_replace("<!-- BEGIN label_{$key} -->", '', $strHtml);
  816. $strHtml = str_replace("<!-- END label_{$key} -->", '', $strHtml);
  817. }
  818. }
  819. // clean up useless label tags
  820. if (strpos($strHtml, '{label_')) {
  821. $strHtml = preg_replace('/\s*<!-- BEGIN label_(\S+) -->'.
  822. '.*<!-- END label_\1 -->\s*/i', '', $strHtml);
  823. }
  824. $placeHolders = array(
  825. '{stylesheet}', '{javascript}',
  826. '{class}',
  827. '{unselected_count_id}', '{selected_count_id}',
  828. '{unselected_count}', '{selected_count}',
  829. '{unselected}', '{selected}',
  830. '{add}', '{remove}',
  831. '{all}', '{none}', '{toggle}',
  832. '{moveup}', '{movedown}'
  833. );
  834. $htmlElements = array(
  835. $this->getElementCss(false), $this->getElementJs(false),
  836. $this->_tableAttributes,
  837. $strHtmlUnselectedCountId, $strHtmlSelectedCountId,
  838. $strHtmlUnselectedCount, $strHtmlSelectedCount,
  839. $strHtmlUnselected, $strHtmlSelected . $strHtmlHidden,
  840. $strHtmlAdd, $strHtmlRemove,
  841. $strHtmlAll, $strHtmlNone, $strHtmlToggle,
  842. $strHtmlMoveUp, $strHtmlMoveDown
  843. );
  844. $strHtml = str_replace($placeHolders, $htmlElements, $strHtml);
  845. return $strHtml;
  846. }
  847. /**
  848. * Returns the javascript code generated to handle this element
  849. *
  850. * @param boolean $raw (optional) html output with script tags or just raw data
  851. *
  852. * @access public
  853. * @return string
  854. * @see setJsElement()
  855. * @since 0.4.0
  856. */
  857. function getElementJs($raw = true)
  858. {
  859. $js = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'qfamsHandler.js';
  860. if (file_exists($js)) {
  861. $js = file_get_contents($js);
  862. } else {
  863. $js = '';
  864. }
  865. if ($raw !== true) {
  866. $js = '<script type="text/javascript">'
  867. . PHP_EOL . '//<![CDATA['
  868. . PHP_EOL . $js
  869. . PHP_EOL . '//]]>'
  870. . PHP_EOL . '</script>'
  871. . PHP_EOL;
  872. }
  873. return $js;
  874. }
  875. }
  876. if (class_exists('HTML_QuickForm')) {
  877. HTML_QuickForm::registerElementType('advmultiselect',
  878. 'HTML/QuickForm/advmultiselect.php', 'HTML_QuickForm_advmultiselect');
  879. }
  880. ?>