qfamsHandler.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514
  1. /**
  2. * JavaScript functions to handle standard behaviors of a QuickForm advmultiselect element
  3. *
  4. * @category HTML
  5. * @package HTML_QuickForm_advmultiselect
  6. * @author Laurent Laville <pear@laurent-laville.org>
  7. * @copyright 2007-2009 Laurent Laville
  8. * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
  9. * @version CVS: $Id: qfamsHandler.js,v 1.13 2009/02/06 09:49:22 farell Exp $
  10. * @since File available since Release 1.3.0
  11. */
  12. if (typeof QFAMS === "undefined" || !QFAMS) {
  13. /**
  14. * The QFAMS global namespace object. If QFAMS is already defined, the
  15. * existing QFAMS object will not be overwritten so that defined
  16. * namespaces are preserved.
  17. * @class QFAMS
  18. * @static
  19. * @public
  20. * @since 1.5.0
  21. */
  22. var QFAMS = {};
  23. }
  24. /**
  25. * QFAMS.env is used to keep track of end-user preferences
  26. * for persistant values.
  27. *
  28. * @class QFAMS.env
  29. * @static
  30. */
  31. QFAMS.env = QFAMS.env || {
  32. /**
  33. * Keeps the persistant selection preference when items are selected or unselected
  34. *
  35. * @property persistantSelection
  36. * @type Boolean
  37. */
  38. persistantSelection: false,
  39. /**
  40. * Keeps the persistant selection preference when items are moved up or down
  41. *
  42. * @property persistantMove
  43. * @type Boolean
  44. */
  45. persistantMove: true
  46. };
  47. /**
  48. * Uses QFAMS.updateCounter as a
  49. * text tools to replace all childs of 'c' element by a new text node of 'v' value
  50. *
  51. * @param dom element c html element; <span> is best use in most case
  52. * @param string v new counter value
  53. *
  54. * @method updateCounter
  55. * @static
  56. * @return void
  57. * @public
  58. * @since 1.5.0
  59. */
  60. QFAMS.updateCounter = function (c, v) {
  61. var i;
  62. var nodeText = null;
  63. if (c !== null) {
  64. // remove all previous child nodes of 'c' element
  65. if (c.childNodes) {
  66. for (i = 0; i < c.childNodes.length; i++) {
  67. c.removeChild(c.childNodes[i]);
  68. }
  69. }
  70. // add new text value 'v'
  71. nodeText = document.createTextNode(v);
  72. c.appendChild(nodeText);
  73. }
  74. };
  75. /**
  76. * Uses QFAMS.updateLiveCounter as a
  77. * standard onclick event handler to dynamic change value of counter
  78. * that display current selection
  79. *
  80. * @method updateLiveCounter
  81. * @static
  82. * @return void
  83. * @private
  84. * @since 1.5.0
  85. */
  86. QFAMS.updateLiveCounter = function () {
  87. var lbl = this.parentNode;
  88. var selectedCount = 0;
  89. // Find all the checkboxes...
  90. var div = lbl.parentNode;
  91. var inputs = div.getElementsByTagName('input');
  92. for (var i = 0; i < inputs.length; i++) {
  93. if (inputs[i].checked == 1) {
  94. selectedCount++;
  95. }
  96. }
  97. var e = div.id;
  98. var qfamsName = e.substring(e.indexOf('_', 0) + 1, e.length);
  99. // updates item count
  100. var span = document.getElementById(qfamsName + '_selected');
  101. QFAMS.updateCounter(span, selectedCount + '/' + inputs.length);
  102. };
  103. /**
  104. * Uses QFAMS.editSelection
  105. * in single select box mode, to edit current selection and update live counter
  106. *
  107. * @param string qfamsName QuickForm advmultiselect element name
  108. * @param integer selectMode Selection mode (0 = uncheck, 1 = check, 2 = toggle)
  109. *
  110. * @method editSelection
  111. * @static
  112. * @return void
  113. * @public
  114. * @since 1.5.0
  115. */
  116. QFAMS.editSelection = function (qfamsName, selectMode) {
  117. if (selectMode !== 0 && selectMode !== 1 && selectMode !== 2) {
  118. return;
  119. }
  120. var selectedCount = 0;
  121. // Find all the checkboxes...
  122. var ams = document.getElementById('qfams_' + qfamsName);
  123. var inputs = ams.getElementsByTagName('input');
  124. // Loop through all checkboxes (input element)
  125. for (var i = 0; i < inputs.length; i++) {
  126. if (selectMode === 2) {
  127. if (inputs[i].checked == 0) {
  128. inputs[i].checked = 1;
  129. } else if (inputs[i].checked == 1) {
  130. inputs[i].checked = 0;
  131. }
  132. } else {
  133. inputs[i].checked = selectMode;
  134. }
  135. if (inputs[i].checked == 1) {
  136. selectedCount++;
  137. }
  138. }
  139. // updates selected item count
  140. var span = document.getElementById(qfamsName + '_selected');
  141. QFAMS.updateCounter(span, selectedCount + '/' + inputs.length);
  142. };
  143. /**
  144. * Uses QFAMS.moveSelection
  145. * in double select box mode, to move current selection and update live counter
  146. *
  147. * @param string qfamsName QuickForm advmultiselect element name
  148. * @param dom element selectLeft Data source list
  149. * @param dom element selectRight Target data list
  150. * @param dom element selectHidden Full data source (selected, unselected)
  151. * private usage
  152. * @param string action Action name (add, remove, all, none, toggle)
  153. * @param string arrange Sort option (none, asc, desc)
  154. *
  155. * @method moveSelection
  156. * @static
  157. * @return void
  158. * @public
  159. * @since 1.5.0
  160. */
  161. QFAMS.moveSelection = function (qfamsName, selectLeft, selectRight, selectHidden, action, arrange) {
  162. var isIE = /*@cc_on!@*/false; //IE detector
  163. var source = null;
  164. var target = null;
  165. var option;
  166. var c = null;
  167. var s = null;
  168. var i;
  169. var maxFrom, maxTo;
  170. if (action === 'add' || action === 'all' || action === 'toggle') {
  171. source = selectLeft;
  172. target = selectRight;
  173. } else {
  174. source = selectRight;
  175. target = selectLeft;
  176. }
  177. // Don't do anything if nothing selected. Otherwise we throw javascript errors.
  178. if (source.selectedIndex === -1 && (action === 'add' || action === 'remove')) {
  179. return;
  180. }
  181. maxFrom = source.options.length;
  182. maxTo = target.options.length;
  183. // check if target list is empty and remove fake empty option (tip to be XHTML compliant)
  184. if (maxTo > 0 && target.options[0].value === "") {
  185. target.removeAttribute("disabled");
  186. target.options[0] = null;
  187. }
  188. // Add items to the 'TO' list.
  189. for (i = (maxFrom - 1); i >= 0; i--) {
  190. if (action === 'all' || action === 'none' || action === 'toggle' || source.options[i].selected === true) {
  191. if (source.options[i].disabled === false) {
  192. if (isIE) {
  193. option = source.options[i].removeNode(true);
  194. option.selected = QFAMS.env.persistantSelection;
  195. target.appendChild(option);
  196. } else {
  197. option = source.options[i].cloneNode(true);
  198. option.selected = QFAMS.env.persistantSelection;
  199. target.options[target.options.length] = option;
  200. }
  201. }
  202. }
  203. }
  204. // Remove items from the 'FROM' list.
  205. if (!isIE) {
  206. for (i = (maxFrom - 1); i >= 0; i--) {
  207. if (action === 'all' || action === 'none' || action === 'toggle' || source.options[i].selected === true) {
  208. if (source.options[i].disabled === false) {
  209. source.options[i] = null;
  210. }
  211. }
  212. }
  213. }
  214. // Add items to the 'FROM' list for toggle function
  215. if (action === 'toggle') {
  216. for (i = (maxTo - 1); i >= 0; i--) {
  217. if (target.options[i].disabled === false) {
  218. if (isIE) {
  219. option = target.options[i].removeNode(true);
  220. option.selected = QFAMS.env.persistantSelection;
  221. source.appendChild(option);
  222. } else {
  223. option = target.options[i].cloneNode(true);
  224. option.selected = QFAMS.env.persistantSelection;
  225. source.options[source.options.length] = option;
  226. }
  227. }
  228. }
  229. if (!isIE) {
  230. for (i = (maxTo - 1); i >= 0; i--) {
  231. if (target.options[i].disabled === false) {
  232. target.options[i] = null;
  233. }
  234. }
  235. }
  236. }
  237. // updates unselected item count
  238. c = document.getElementById(qfamsName + '_unselected');
  239. s = document.getElementById(qfamsName + '-f');
  240. QFAMS.updateCounter(c, s.length);
  241. // updates selected item count
  242. c = document.getElementById(qfamsName + '_selected');
  243. s = document.getElementById(qfamsName + '-t');
  244. QFAMS.updateCounter(c, s.length);
  245. // Sort list if required
  246. if (arrange !== 'none') {
  247. QFAMS.sortList(target, QFAMS.compareText, arrange);
  248. }
  249. // Set the appropriate items as 'selected in the hidden select.
  250. // These are the values that will actually be posted with the form.
  251. QFAMS.updateHidden(selectHidden, selectRight);
  252. };
  253. /**
  254. * Uses QFAMS.sortList to
  255. * sort selection list if option is given in HTML_QuickForm_advmultiselect class constructor
  256. *
  257. * @param dom element list Selection data list
  258. * @param prototype compareFunction to sort each element of a list
  259. * @param string arrange Sort option (none, asc, desc)
  260. *
  261. * @method sortList
  262. * @static
  263. * @return void
  264. * @private
  265. * @since 1.5.0
  266. */
  267. QFAMS.sortList = function (list, compareFunction, arrange)
  268. {
  269. var i;
  270. var options = new Array(list.options.length);
  271. for (i = 0; i < options.length; i++) {
  272. options[i] = new Option(list.options[i].text,
  273. list.options[i].value,
  274. list.options[i].defaultSelected,
  275. list.options[i].selected);
  276. }
  277. options.sort(compareFunction);
  278. if (arrange === 'desc') {
  279. options.reverse();
  280. }
  281. list.options.length = 0;
  282. for (i = 0; i < options.length; i++) {
  283. list.options[i] = options[i];
  284. }
  285. };
  286. /**
  287. * QFAMS.compareText
  288. * is a callback function to sort each element of two lists A and B
  289. *
  290. * @param string option1 single element of list A
  291. * @param string option2 single element of list B
  292. *
  293. * @method compareText
  294. * @static
  295. * @return integer -1 if option1 is less than option2,
  296. * 0 if option1 is equal to option2
  297. * 1 if option1 is greater than option2
  298. * @private
  299. * @since 1.5.0
  300. */
  301. QFAMS.compareText = function (option1, option2) {
  302. if (option1.text === option2.text) {
  303. return 0;
  304. }
  305. return option1.text < option2.text ? -1 : 1;
  306. };
  307. /**
  308. * QFAMS.updateHidden
  309. * updates the private list that handle selection of all elements (selected and unselected)
  310. *
  311. * @param dom element h hidden list (contains all elements)
  312. * @param dom element r selection list (contains only elements selected)
  313. *
  314. * @method updateHidden
  315. * @static
  316. * @return void
  317. * @private
  318. * @since 1.5.0
  319. */
  320. QFAMS.updateHidden = function (h, r) {
  321. var i;
  322. for (i = 0; i < h.length; i++) {
  323. h.options[i].selected = false;
  324. }
  325. for (i = 0; i < r.length; i++) {
  326. h.options[h.length] = new Option(r.options[i].text, r.options[i].value);
  327. h.options[h.length - 1].selected = true;
  328. }
  329. };
  330. /**
  331. * With QFAMS.moveUp
  332. * end-user may arrange and element up to the selection list
  333. *
  334. * @param dom element l selection list (contains only elements selected)
  335. * @param dom element h hidden list (contains all elements)
  336. *
  337. * @method moveUp
  338. * @static
  339. * @return void
  340. * @public
  341. * @since 1.5.0
  342. */
  343. QFAMS.moveUp = function (l, h) {
  344. var indice = l.selectedIndex;
  345. if (indice < 0) {
  346. return;
  347. }
  348. if (indice > 0) {
  349. QFAMS.moveSwap(l, indice, indice - 1);
  350. QFAMS.updateHidden(h, l);
  351. }
  352. };
  353. /**
  354. * With QFAMS.moveDown
  355. * end-user may arrange and element down to the selection list
  356. *
  357. * @param dom element l selection list (contains only elements selected)
  358. * @param dom element h hidden list (contains all elements)
  359. *
  360. * @method moveDown
  361. * @static
  362. * @return void
  363. * @public
  364. * @since 1.5.0
  365. */
  366. QFAMS.moveDown = function (l, h) {
  367. var indice = l.selectedIndex;
  368. if (indice < 0) {
  369. return;
  370. }
  371. if (indice < l.options.length - 1) {
  372. QFAMS.moveSwap(l, indice, indice + 1);
  373. QFAMS.updateHidden(h, l);
  374. }
  375. };
  376. /**
  377. * With QFAMS.moveTop
  378. * end-user may arrange and element up to the top of selection list
  379. *
  380. * @param dom element l selection list (contains only elements selected)
  381. * @param dom element h hidden list (contains all elements)
  382. *
  383. * @method moveTop
  384. * @static
  385. * @return void
  386. * @public
  387. * @since 1.5.0
  388. */
  389. QFAMS.moveTop = function (l, h) {
  390. var indice = l.selectedIndex;
  391. if (indice < 0) {
  392. return;
  393. }
  394. while (indice > 0) {
  395. QFAMS.moveSwap(l, indice, indice - 1);
  396. QFAMS.updateHidden(h, l);
  397. indice--;
  398. }
  399. };
  400. /**
  401. * With QFAMS.moveBottom
  402. * end-user may arrange and element down to the bottom of selection list
  403. *
  404. * @param dom element l selection list (contains only elements selected)
  405. * @param dom element h hidden list (contains all elements)
  406. *
  407. * @method moveBottom
  408. * @static
  409. * @return void
  410. * @public
  411. * @since 1.5.0
  412. */
  413. QFAMS.moveBottom = function (l, h) {
  414. var indice = l.selectedIndex;
  415. if (indice < 0) {
  416. return;
  417. }
  418. while (indice < l.options.length - 1) {
  419. QFAMS.moveSwap(l, indice, indice + 1);
  420. QFAMS.updateHidden(h, l);
  421. indice++;
  422. }
  423. };
  424. /**
  425. * With QFAMS.moveSwap
  426. * end-user may invert two elements position in the selection list
  427. *
  428. * @param dom element l selection list (contains only elements selected)
  429. * @param integer i element source indice
  430. * @param integer j element target indice
  431. *
  432. * @method moveSwap
  433. * @static
  434. * @return void
  435. * @public
  436. * @since 1.5.0
  437. */
  438. QFAMS.moveSwap = function (l, i, j) {
  439. var node;
  440. node = l.replaceChild(l.options[i], l.options[j]);
  441. if (i > j) {
  442. l.insertBefore(node, l.options[j].nextSibling);
  443. } else {
  444. l.insertBefore(node, l.options[i]);
  445. }
  446. if (QFAMS.env.persistantMove) {
  447. l.selectedIndex = j;
  448. } else {
  449. l.selectedIndex = -1;
  450. }
  451. };
  452. /**
  453. * Uses QFAMS.init to
  454. * initialize onclick event handler for all checkbox element
  455. * of a QuickForm advmultiselect element with single select box.
  456. *
  457. * @method init
  458. * @static
  459. * @return void
  460. * @public
  461. * @since 1.5.0
  462. */
  463. QFAMS.init = function (elm)
  464. {
  465. var e, i;
  466. for (e = 0; e < elm.length; e++) {
  467. var div = document.getElementById('qfams_' + elm[e]);
  468. if (div !== null) {
  469. var inputs = div.getElementsByTagName('input');
  470. if (inputs !== null) {
  471. for (i = 0; i < inputs.length; i++) {
  472. inputs[i].onclick = QFAMS.updateLiveCounter;
  473. }
  474. }
  475. }
  476. }
  477. };