advmultiselect.php 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814
  1. <?php
  2. /**
  3. * Element for HTML_QuickForm that emulate a multi-select.
  4. *
  5. * The HTML_QuickForm_advmultiselect package adds an element to the
  6. * HTML_QuickForm package that is two select boxes next to each other
  7. * emulating a multi-select.
  8. *
  9. * PHP versions 4 and 5
  10. *
  11. * LICENSE: This source file is subject to version 3.0 of the PHP license
  12. * that is available through the world-wide-web at the following URI:
  13. * http://www.php.net/license/3_0.txt. If you did not receive a copy of
  14. * the PHP License and are unable to obtain it through the web, please
  15. * send a note to license@php.net so we can mail you a copy immediately.
  16. *
  17. * @category HTML
  18. * @package HTML_QuickForm_advmultiselect
  19. * @author Laurent Laville <pear@laurent-laville.org>
  20. * @copyright 1997-2005 The PHP Group
  21. * @license http://www.php.net/license/3_0.txt PHP License 3.0
  22. * @version CVS: $Id: advmultiselect.php 20028 2009-04-23 19:32:35Z cfasanando $
  23. * @link http://pear.php.net/package/HTML_QuickForm_advmultiselect
  24. */
  25. require_once 'HTML/QuickForm/select.php';
  26. /**
  27. * Replace PHP_EOL constant
  28. *
  29. * category PHP
  30. * package PHP_Compat
  31. * @link http://php.net/reserved.constants.core
  32. * @author Aidan Lister <aidan@php.net>
  33. * @since PHP 5.0.2
  34. */
  35. if (!defined('PHP_EOL')) {
  36. switch (strtoupper(substr(PHP_OS, 0, 3))) {
  37. // Windows
  38. case 'WIN':
  39. define('PHP_EOL', "\r\n");
  40. break;
  41. // Mac
  42. case 'DAR':
  43. define('PHP_EOL', "\r");
  44. break;
  45. // Unix
  46. default:
  47. define('PHP_EOL', "\n");
  48. }
  49. }
  50. /**
  51. * Element for HTML_QuickForm that emulate a multi-select.
  52. *
  53. * The HTML_QuickForm_advmultiselect package adds an element to the
  54. * HTML_QuickForm package that is two select boxes next to each other
  55. * emulating a multi-select.
  56. *
  57. * PHP versions 4 and 5
  58. *
  59. * LICENSE: This source file is subject to version 3.0 of the PHP license
  60. * that is available through the world-wide-web at the following URI:
  61. * http://www.php.net/license/3_0.txt. If you did not receive a copy of
  62. * the PHP License and are unable to obtain it through the web, please
  63. * send a note to license@php.net so we can mail you a copy immediately.
  64. *
  65. * @category HTML
  66. * @package HTML_QuickForm_advmultiselect
  67. * @author Laurent Laville <pear@laurent-laville.org>
  68. * @copyright 1997-2005 The PHP Group
  69. * @license http://www.php.net/license/3_0.txt PHP License 3.0
  70. * @version Release: 0.5.1
  71. * @link http://pear.php.net/package/HTML_QuickForm_advmultiselect
  72. */
  73. class HTML_QuickForm_advmultiselect extends HTML_QuickForm_select
  74. {
  75. /**
  76. * Prefix function name in javascript move selections
  77. *
  78. * @var string
  79. * @access private
  80. * @since 0.4.0
  81. */
  82. var $_jsPrefix;
  83. /**
  84. * Postfix function name in javascript move selections
  85. *
  86. * @var string
  87. * @access private
  88. * @since 0.4.0
  89. */
  90. var $_jsPostfix;
  91. /**
  92. * Associative array of the multi select container attributes
  93. *
  94. * @var array
  95. * @access private
  96. * @since 0.4.0
  97. */
  98. var $_tableAttributes;
  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. * Associative array of the remove button attributes
  109. *
  110. * @var array
  111. * @access private
  112. * @since 0.4.0
  113. */
  114. var $_removeButtonAttributes;
  115. /**
  116. * Associative array of the move up button attributes
  117. *
  118. * @var array
  119. * @access private
  120. * @since 0.5.0
  121. */
  122. var $_upButtonAttributes;
  123. /**
  124. * Associative array of the move up button attributes
  125. *
  126. * @var array
  127. * @access private
  128. * @since 0.5.0
  129. */
  130. var $_downButtonAttributes;
  131. /**
  132. * Defines if both list (unselected, selected) will have their elements be
  133. * arranged from lowest to highest (or reverse) depending on comparaison function.
  134. *
  135. * SORT_ASC is used to sort in ascending order
  136. * SORT_DESC is used to sort in descending order
  137. *
  138. * @var integer
  139. * @access private
  140. * @since 0.5.0
  141. */
  142. var $_sort;
  143. /**
  144. * Associative array of the unselected item box attributes
  145. *
  146. * @var array
  147. * @access private
  148. * @since 0.4.0
  149. */
  150. var $_attributesUnselected;
  151. /**
  152. * Associative array of the selected item box attributes
  153. *
  154. * @var array
  155. * @access private
  156. * @since 0.4.0
  157. */
  158. var $_attributesSelected;
  159. /**
  160. * Associative array of the internal hidden box attributes
  161. *
  162. * @var array
  163. * @access private
  164. * @since 0.4.0
  165. */
  166. var $_attributesHidden;
  167. /**
  168. * Default Element template string
  169. *
  170. * @var string
  171. * @access private
  172. * @since 0.4.0
  173. */
  174. var $_elementTemplate = '
  175. {javascript}
  176. <table{class}>
  177. <!-- BEGIN label_2 --><tr><th>{label_2}</th><!-- END label_2 -->
  178. <!-- BEGIN label_3 --><th>&nbsp;</th><th>{label_3}</th></tr><!-- END label_3 -->
  179. <tr>
  180. <td valign="top">{unselected}</td>
  181. <td align="center">{add}{remove}</td>
  182. <td valign="top">{selected}</td>
  183. </tr>
  184. </table>
  185. ';
  186. /**
  187. * Default Element stylesheet string
  188. *
  189. * @var string
  190. * @access private
  191. * @since 0.4.0
  192. */
  193. var $_elementCSS = '
  194. #{id}amsSelected {
  195. font: 13.3px sans-serif;
  196. background-color: #fff;
  197. overflow: auto;
  198. height: 14.3em;
  199. width: 12em;
  200. border-left: 1px solid #404040;
  201. border-top: 1px solid #404040;
  202. border-bottom: 1px solid #d4d0c8;
  203. border-right: 1px solid #d4d0c8;
  204. }
  205. #{id}amsSelected label {
  206. padding-right: 3px;
  207. display: block;
  208. }
  209. ';
  210. /**
  211. * Class constructor
  212. *
  213. * @param string $elementName Dual Select name attribute
  214. * @param mixed $elementLabel Label(s) for the select boxes
  215. * @param mixed $options Data to be used to populate options
  216. * @param mixed $attributes Either a typical HTML attribute string or an associative array
  217. * @param integer $sortOptions Either SORT_ASC for auto ascending arrange,
  218. * SORT_DESC for auto descending arrange, or
  219. * NULL for no sort (append at end: default)
  220. *
  221. * @access public
  222. * @return void
  223. * @since 0.4.0
  224. */
  225. function HTML_QuickForm_advmultiselect($elementName = null, $elementLabel = null,
  226. $options = null, $attributes = null,
  227. $sortOptions = null)
  228. {
  229. $this->HTML_QuickForm_select($elementName, $elementLabel, $options, $attributes);
  230. // add multiple selection attribute by default if missing
  231. $this->updateAttributes(array('multiple' => 'multiple'));
  232. if (is_null($this->getAttribute('size'))) {
  233. // default size is ten item on each select box (left and right)
  234. $this->updateAttributes(array('size' => 10));
  235. }
  236. if (is_null($this->getAttribute('style'))) {
  237. // default width of each select box
  238. $this->updateAttributes(array('style' => 'width:100px;'));
  239. }
  240. $this->_tableAttributes = $this->getAttribute('class');
  241. if (is_null($this->_tableAttributes)) {
  242. // default table layout
  243. $attr = array('border' => '0', 'cellpadding' => '10', 'cellspacing' => '0');
  244. } else {
  245. $attr = array('class' => $this->_tableAttributes);
  246. $this->_removeAttr('class', $this->_attributes);
  247. }
  248. $this->_tableAttributes = $this->_getAttrString($attr);
  249. // set default add button attributes
  250. $this->setButtonAttributes('add');
  251. // set default remove button attributes
  252. $this->setButtonAttributes('remove');
  253. // set default move up button attributes
  254. $this->setButtonAttributes('moveup');
  255. // set default move up button attributes
  256. $this->setButtonAttributes('movedown');
  257. // defines javascript functions names
  258. $this->setJsElement();
  259. // set select boxes sort order (none by default)
  260. if (isset($sortOptions)) {
  261. $this->_sort = $sortOptions;
  262. } else {
  263. $this->_sort = false;
  264. }
  265. }
  266. /**
  267. * Sets the button attributes
  268. *
  269. * In <b>custom example 1</b>, the <i>add</i> and <i>remove</i> buttons have look set
  270. * by the css class <i>inputCommand</i>. See especially lines 43-48 and 98-103.
  271. *
  272. * In <b>custom example 2</b>, the basic text <i>add</i> and <i>remove</i> buttons
  273. * are now replaced by images. See lines 43-44.
  274. *
  275. * In <b>custom example 5</b>, we have ability to sort the selection list (on right side)
  276. * by :
  277. * <pre>
  278. * - <b>user-end</b>: with <i>Up</i> and <i>Down</i> buttons
  279. * (see lines 65,65,76 and 128-130)
  280. * - <b>programming</b>: with the QF element constructor $sort option
  281. * (see lines 34,36,38 and 59)
  282. * </pre>
  283. *
  284. * @example examples/qfams_custom_5.php Custom example 5: source code
  285. * @link http://www.laurent-laville.org/img/qfams/screenshot/custom5.png Custom example 5: screenshot
  286. *
  287. * @example examples/qfams_custom_2.php Custom example 2: source code
  288. * @link http://www.laurent-laville.org/img/qfams/screenshot/custom2.png Custom example 2: screenshot
  289. *
  290. * @example examples/qfams_custom_1.php Custom example 1: source code
  291. * @link http://www.laurent-laville.org/img/qfams/screenshot/custom1.png Custom example 1: screenshot
  292. *
  293. * @param string $button Button identifier, either 'add', 'remove', 'moveup' or 'movedown'
  294. * @param mixed $attributes (optional) Either a typical HTML attribute string
  295. * or an associative array
  296. * @access public
  297. * @since 0.4.0
  298. */
  299. function setButtonAttributes($button, $attributes = null)
  300. {
  301. if (!is_string($button)) {
  302. return PEAR::raiseError('Argument 1 of advmultiselect::setButtonAttributes'
  303. .' is not a string');
  304. }
  305. switch ($button) {
  306. case 'add':
  307. if (is_null($attributes)) {
  308. $this->_addButtonAttributes = array('name' => 'add',
  309. 'type' => 'button'
  310. );
  311. } else {
  312. $this->_updateAttrArray($this->_addButtonAttributes,
  313. $this->_parseAttributes($attributes)
  314. );
  315. }
  316. break;
  317. case 'remove':
  318. if (is_null($attributes)) {
  319. $this->_removeButtonAttributes = array('name' => 'remove',
  320. 'type' => 'button'
  321. );
  322. } else {
  323. $this->_updateAttrArray($this->_removeButtonAttributes,
  324. $this->_parseAttributes($attributes)
  325. );
  326. }
  327. break;
  328. case 'moveup':
  329. if (is_null($attributes)) {
  330. $this->_upButtonAttributes = array('name' => 'up',
  331. 'value' => ' Up ',
  332. 'type' => 'button'
  333. );
  334. } else {
  335. $this->_updateAttrArray($this->_upButtonAttributes,
  336. $this->_parseAttributes($attributes)
  337. );
  338. }
  339. break;
  340. case 'movedown':
  341. if (is_null($attributes)) {
  342. $this->_downButtonAttributes = array('name' => 'down',
  343. 'value' => ' Down ',
  344. 'type' => 'button'
  345. );
  346. } else {
  347. $this->_updateAttrArray($this->_downButtonAttributes,
  348. $this->_parseAttributes($attributes)
  349. );
  350. }
  351. break;
  352. default;
  353. return PEAR::raiseError('Argument 1 of advmultiselect::setButtonAttributes'
  354. .' has unexpected value');
  355. }
  356. }
  357. /**
  358. * Sets element template
  359. *
  360. * @param string $html The HTML surrounding select boxes and buttons
  361. *
  362. * @access public
  363. * @return void
  364. * @since 0.4.0
  365. */
  366. function setElementTemplate($html)
  367. {
  368. $this->_elementTemplate = $html;
  369. }
  370. /**
  371. * Sets JavaScript function name parts. Maybe usefull to avoid conflict names
  372. *
  373. * In <b>multiple example 1</b>, the javascript function prefix is set to not null
  374. * (see line 60).
  375. *
  376. * @example examples/qfams_multiple_1.php Multiple example 1: source code
  377. * @link http://www.laurent-laville.org/img/qfams/screenshot/multiple1.png Multiple example 1: screenshot
  378. *
  379. * @param string $pref (optional) Prefix name
  380. * @param string $post (optional) Postfix name
  381. *
  382. * @access public
  383. * @return void
  384. * @see getElementJs()
  385. * @since 0.4.0
  386. */
  387. function setJsElement($pref = null, $post = 'moveSelections')
  388. {
  389. $this->_jsPrefix = $pref;
  390. $this->_jsPostfix = $post;
  391. }
  392. /**
  393. * Gets default element stylesheet for a single multi-select shape render
  394. *
  395. * In <b>custom example 4</b>, the template defined lines 80-87 allows
  396. * a single multi-select checkboxes shape. Useful when javascript is disabled
  397. * (or when browser is not js compliant). In our example, no need to add javascript code
  398. * (see lines 170-172), but css is mandatory (see line 142).
  399. *
  400. * @example qfams_custom_4.php Custom example 4: source code
  401. * @link http://www.laurent-laville.org/img/qfams/screenshot/custom4.png Custom example 4: screenshot
  402. *
  403. * @param boolean $raw (optional) html output with style tags or just raw data
  404. *
  405. * @access public
  406. * @return string
  407. * @since 0.4.0
  408. */
  409. function getElementCss($raw = true)
  410. {
  411. $id = $this->getAttribute('id');
  412. $css = str_replace('{id}', $id, $this->_elementCSS);
  413. if ($raw !== true) {
  414. $css = '<style type="text/css">' . PHP_EOL
  415. . '/*<![CDATA[*/' . PHP_EOL
  416. . $css . PHP_EOL
  417. . '/*]]>*/' . PHP_EOL
  418. . '</style>';
  419. }
  420. return $css;
  421. }
  422. /**
  423. * Returns the HTML generated for the advanced mutliple select component
  424. *
  425. * @access public
  426. * @return string
  427. * @since 0.4.0
  428. */
  429. function toHtml()
  430. {
  431. if ($this->_flagFrozen) {
  432. return $this->getFrozenHtml();
  433. }
  434. $tabs = $this->_getTabs();
  435. $tab = $this->_getTab();
  436. $strHtml = '';
  437. if ($this->getComment() != '') {
  438. $strHtml .= $tabs . '<!-- ' . $this->getComment() . " //-->" . PHP_EOL;
  439. }
  440. $selectName = $this->getName() . '[]';
  441. // placeholder {unselected} existence determines if we will render
  442. if (strpos($this->_elementTemplate, '{unselected}') === false) {
  443. // ... a single multi-select with checkboxes
  444. $id = $this->getAttribute('id');
  445. $strHtmlSelected = $tab . '<div id="'.$id.'amsSelected">' . PHP_EOL;
  446. foreach ($this->_options as $option) {
  447. $_labelAttributes = array('style', 'class', 'onmouseover', 'onmouseout');
  448. $labelAttributes = array();
  449. foreach ($_labelAttributes as $attr) {
  450. if (isset($option['attr'][$attr])) {
  451. $labelAttributes[$attr] = $option['attr'][$attr];
  452. unset($option['attr'][$attr]);
  453. }
  454. }
  455. if (is_array($this->_values) && in_array((string)$option['attr']['value'], $this->_values)) {
  456. // The items is *selected*
  457. $checked = ' checked="checked"';
  458. } else {
  459. // The item is *unselected* so we want to put it
  460. $checked = '';
  461. }
  462. $strHtmlSelected .= $tab
  463. . '<label'
  464. . $this->_getAttrString($labelAttributes) .'>'
  465. . '<input type="checkbox"'
  466. . ' name="'.$selectName.'"'
  467. . $checked
  468. . $this->_getAttrString($option['attr'])
  469. . ' />' . $option['text'] . '</label>'
  470. . PHP_EOL;
  471. }
  472. $strHtmlSelected .= $tab . '</div>'. PHP_EOL;
  473. $strHtmlHidden = '';
  474. $strHtmlUnselected = '';
  475. $strHtmlAdd = '';
  476. $strHtmlRemove = '';
  477. $strHtmlMoveUp = '';
  478. $strHtmlMoveDown = '';
  479. } else {
  480. // ... or a dual multi-select
  481. // set name of Select From Box
  482. $this->_attributesUnselected = array('name' => '__'.$selectName, 'ondblclick' => "{$this->_jsPrefix}{$this->_jsPostfix}(this.form.elements['__" . $selectName . "'], this.form.elements['_" . $selectName . "'], this.form.elements['" . $selectName . "'], 'add')");
  483. $this->_attributesUnselected = array_merge($this->_attributes, $this->_attributesUnselected);
  484. $attrUnselected = $this->_getAttrString($this->_attributesUnselected);
  485. // set name of Select To Box
  486. $this->_attributesSelected = array('name' => '_'.$selectName, 'ondblclick' => "{$this->_jsPrefix}{$this->_jsPostfix}(this.form.elements['__" . $selectName . "'], this.form.elements['_" . $selectName . "'], this.form.elements['" . $selectName . "'], 'remove')");
  487. $this->_attributesSelected = array_merge($this->_attributes, $this->_attributesSelected);
  488. $attrSelected = $this->_getAttrString($this->_attributesSelected);
  489. // set name of Select hidden Box
  490. $this->_attributesHidden = array('name' => $selectName, 'style' => 'overflow: hidden; visibility: hidden; width: 1px; height: 0;');
  491. $this->_attributesHidden = array_merge($this->_attributes, $this->_attributesHidden);
  492. $attrHidden = $this->_getAttrString($this->_attributesHidden);
  493. // prepare option tables to be displayed as in POST order
  494. $append = count($this->_values);
  495. if ($append > 0) {
  496. $arrHtmlSelected = array_fill(0, $append, ' ');
  497. }
  498. $arrHtmlHidden = array_fill(0, count($this->_options), ' ');
  499. foreach ($this->_options as $option) {
  500. if (is_array($this->_values) &&
  501. in_array((string)$option['attr']['value'], $this->_values)) {
  502. // Get the post order
  503. $key = array_search($option['attr']['value'], $this->_values);
  504. // The items is *selected* so we want to put it in the 'selected' multi-select
  505. $arrHtmlSelected[$key] = $option;
  506. // Add it to the 'hidden' multi-select and set it as 'selected'
  507. $option['attr']['selected'] = 'selected';
  508. $arrHtmlHidden[$key] = $option;
  509. } else {
  510. // The item is *unselected* so we want to put it in the 'unselected' multi-select
  511. $arrHtmlUnselected[] = $option;
  512. // Add it to the hidden multi-select as 'unselected'
  513. $arrHtmlHidden[$append] = $option;
  514. $append++;
  515. }
  516. }
  517. // The 'unselected' multi-select which appears on the left
  518. $strHtmlUnselected = "<select$attrUnselected>". PHP_EOL;
  519. if (is_array($arrHtmlUnselected) && count($arrHtmlUnselected) > 0) {
  520. foreach ($arrHtmlUnselected as $data) {
  521. $strHtmlUnselected .= $tabs . $tab
  522. . '<option' . $this->_getAttrString($data['attr']) . '>'
  523. . $data['text'] . '</option>' . PHP_EOL;
  524. }
  525. }
  526. $strHtmlUnselected .= '</select>';
  527. // The 'selected' multi-select which appears on the right
  528. $strHtmlSelected = "<select$attrSelected>". PHP_EOL;
  529. if (isset($arrHtmlSelected)) {
  530. foreach ($arrHtmlSelected as $data) {
  531. $strHtmlSelected .= $tabs . $tab
  532. . '<option' . $this->_getAttrString($data['attr']) . '>'
  533. . $data['text'] . '</option>' . PHP_EOL;
  534. }
  535. }
  536. $strHtmlSelected .= '</select>';
  537. // The 'hidden' multi-select
  538. $strHtmlHidden = "<select$attrHidden>". PHP_EOL;
  539. foreach ($arrHtmlHidden as $data) {
  540. $strHtmlHidden .= $tabs . $tab
  541. . '<option' . $this->_getAttrString($data['attr']) . '>'
  542. . $data['text'] . '</option>' . PHP_EOL;
  543. }
  544. $strHtmlHidden .= '</select>';
  545. // build the remove button with all its attributes
  546. $attributes = array('onclick' => "{$this->_jsPrefix}{$this->_jsPostfix}(this.form.elements['__" . $selectName . "'], this.form.elements['_" . $selectName . "'], this.form.elements['" . $selectName . "'], 'remove'); return false;");
  547. $this->_removeButtonAttributes = array_merge($this->_removeButtonAttributes, $attributes);
  548. $attrStrRemove = $this->_getAttrString($this->_removeButtonAttributes);
  549. $strHtmlRemove = "<input$attrStrRemove />". PHP_EOL;
  550. // build the add button with all its attributes
  551. $attributes = array('onclick' => "{$this->_jsPrefix}{$this->_jsPostfix}(this.form.elements['__" . $selectName . "'], this.form.elements['_" . $selectName . "'], this.form.elements['" . $selectName . "'], 'add'); return false;");
  552. $this->_addButtonAttributes = array_merge($this->_addButtonAttributes, $attributes);
  553. $attrStrAdd = $this->_getAttrString($this->_addButtonAttributes);
  554. $strHtmlAdd = "<input$attrStrAdd />". PHP_EOL;
  555. // build the move up button with all its attributes
  556. $attributes = array('onclick' => "{$this->_jsPrefix}moveUp(this.form.elements['_" . $selectName . "'], this.form.elements['" . $selectName . "']); return false;");
  557. $this->_upButtonAttributes = array_merge($this->_upButtonAttributes, $attributes);
  558. $attrStrUp = $this->_getAttrString($this->_upButtonAttributes);
  559. $strHtmlMoveUp = "<input$attrStrUp />". PHP_EOL;
  560. // build the move down button with all its attributes
  561. $attributes = array('onclick' => "{$this->_jsPrefix}moveDown(this.form.elements['_" . $selectName . "'], this.form.elements['" . $selectName . "']); return false;");
  562. $this->_downButtonAttributes = array_merge($this->_downButtonAttributes, $attributes);
  563. $attrStrDown = $this->_getAttrString($this->_downButtonAttributes);
  564. $strHtmlMoveDown = "<input$attrStrDown />". PHP_EOL;
  565. }
  566. // render all part of the multi select component with the template
  567. $strHtml = $this->_elementTemplate;
  568. // Prepare multiple labels
  569. $labels = $this->getLabel();
  570. if (is_array($labels)) {
  571. array_shift($labels);
  572. }
  573. // render extra labels, if any
  574. if (is_array($labels)) {
  575. foreach($labels as $key => $text) {
  576. $key = is_int($key)? $key + 2: $key;
  577. $strHtml = str_replace("{label_{$key}}", $text, $strHtml);
  578. $strHtml = str_replace("<!-- BEGIN label_{$key} -->", '', $strHtml);
  579. $strHtml = str_replace("<!-- END label_{$key} -->", '', $strHtml);
  580. }
  581. }
  582. // clean up useless label tags
  583. if (strpos($strHtml, '{label_')) {
  584. $strHtml = preg_replace('/\s*<!-- BEGIN label_(\S+) -->.*<!-- END label_\1 -->\s*/i', '', $strHtml);
  585. }
  586. $placeHolders = array(
  587. '{stylesheet}', '{javascript}', '{class}',
  588. '{unselected}', '{selected}',
  589. '{add}', '{remove}',
  590. '{moveup}', '{movedown}'
  591. );
  592. $htmlElements = array(
  593. $this->getElementCss(false), $this->getElementJs(false), $this->_tableAttributes,
  594. $strHtmlUnselected, $strHtmlSelected . $strHtmlHidden,
  595. $strHtmlAdd, $strHtmlRemove,
  596. $strHtmlMoveUp, $strHtmlMoveDown
  597. );
  598. $strHtml = str_replace($placeHolders, $htmlElements, $strHtml);
  599. return $strHtml;
  600. }
  601. /**
  602. * Returns the javascript code generated to handle this element
  603. *
  604. * @param boolean $raw (optional) html output with script tags or just raw data
  605. *
  606. * @access public
  607. * @return string
  608. * @see setJsElement()
  609. * @since 0.4.0
  610. */
  611. function getElementJs($raw = true)
  612. {
  613. $js = '';
  614. $jsfuncName = $this->_jsPrefix . $this->_jsPostfix;
  615. if (!defined('HTML_QUICKFORM_ADVMULTISELECT_'.$jsfuncName.'_EXISTS')) {
  616. // We only want to include the javascript code once per form
  617. define('HTML_QUICKFORM_ADVMULTISELECT_'.$jsfuncName.'_EXISTS', true);
  618. $js .= "
  619. /* begin javascript for HTML_QuickForm_advmultiselect */
  620. function {$jsfuncName}(selectLeft, selectRight, selectHidden, action) {
  621. if (action == 'add') {
  622. menuFrom = selectLeft;
  623. menuTo = selectRight;
  624. }
  625. else {
  626. menuFrom = selectRight;
  627. menuTo = selectLeft;
  628. }
  629. // Don't do anything if nothing selected. Otherwise we throw javascript errors.
  630. if (menuFrom.selectedIndex == -1) {
  631. return;
  632. }
  633. // Add items to the 'TO' list.
  634. for (i=0; i < menuFrom.length; i++) {
  635. if (menuFrom.options[i].selected == true ) {
  636. menuTo.options[menuTo.length]= new Option(menuFrom.options[i].text, menuFrom.options[i].value);
  637. }
  638. }
  639. // Remove items from the 'FROM' list.
  640. for (i=(menuFrom.length - 1); i>=0; i--){
  641. if (menuFrom.options[i].selected == true ) {
  642. menuFrom.options[i] = null;
  643. }
  644. }
  645. ";
  646. if ($this->_sort === false) {
  647. $js .= "
  648. // Set the appropriate items as 'selected in the hidden select.
  649. // These are the values that will actually be posted with the form.
  650. {$this->_jsPrefix}updateHidden(selectHidden, selectRight);
  651. }
  652. ";
  653. } else {
  654. $reverse = ($this->_sort === SORT_DESC) ? 'options.reverse();' : '';
  655. $js .= "
  656. // Sort list if required
  657. {$this->_jsPrefix}sortList(menuTo, {$this->_jsPrefix}compareText);
  658. // Set the appropriate items as 'selected in the hidden select.
  659. // These are the values that will actually be posted with the form.
  660. {$this->_jsPrefix}updateHidden(selectHidden, selectRight);
  661. }
  662. function {$this->_jsPrefix}sortList(list, compareFunction) {
  663. var options = new Array (list.options.length);
  664. for (var i = 0; i < options.length; i++) {
  665. options[i] = new Option (
  666. list.options[i].text,
  667. list.options[i].value,
  668. list.options[i].defaultSelected,
  669. list.options[i].selected
  670. );
  671. }
  672. options.sort(compareFunction);
  673. {$reverse}
  674. list.options.length = 0;
  675. for (var i = 0; i < options.length; i++) {
  676. list.options[i] = options[i];
  677. }
  678. }
  679. function {$this->_jsPrefix}compareText(option1, option2) {
  680. if (option1.text == option2.text) {
  681. return 0;
  682. }
  683. return option1.text < option2.text ? -1 : 1;
  684. }
  685. ";
  686. }
  687. $js .= "
  688. function {$this->_jsPrefix}updateHidden(h,r) {
  689. for (i=0; i < h.length; i++) {
  690. h.options[i].selected = false;
  691. }
  692. for (i=0; i < r.length; i++) {
  693. h.options[h.length] = new Option(r.options[i].text, r.options[i].value);
  694. h.options[h.length-1].selected = true;
  695. }
  696. }
  697. function {$this->_jsPrefix}moveUp(l,h) {
  698. var indice = l.selectedIndex;
  699. if (indice < 0) {
  700. return;
  701. }
  702. if (indice > 0) {
  703. {$this->_jsPrefix}moveSwap(l, indice, indice-1);
  704. {$this->_jsPrefix}updateHidden(h, l);
  705. }
  706. }
  707. function {$this->_jsPrefix}moveDown(l,h) {
  708. var indice = l.selectedIndex;
  709. if (indice < 0) {
  710. return;
  711. }
  712. if (indice < l.options.length-1) {
  713. {$this->_jsPrefix}moveSwap(l, indice, indice+1);
  714. {$this->_jsPrefix}updateHidden(h, l);
  715. }
  716. }
  717. function {$this->_jsPrefix}moveSwap(l,i,j) {
  718. var valeur = l.options[i].value;
  719. var texte = l.options[i].text;
  720. l.options[i].value = l.options[j].value;
  721. l.options[i].text = l.options[j].text;
  722. l.options[j].value = valeur;
  723. l.options[j].text = texte;
  724. l.selectedIndex = j
  725. }
  726. /* end javascript for HTML_QuickForm_advmultiselect */
  727. ";
  728. if ($raw !== true) {
  729. $js = '<script type="text/javascript">' . PHP_EOL
  730. . '/* <![CDATA[ */' . $js . '/* ]]> */' . PHP_EOL
  731. . '</script>';
  732. }
  733. }
  734. return $js;
  735. }
  736. }
  737. if (class_exists('HTML_QuickForm')) {
  738. HTML_QuickForm::registerElementType('advmultiselect', 'HTML/QuickForm/advmultiselect.php', 'HTML_QuickForm_advmultiselect');
  739. }
  740. ?>