jekyll-theme-ici3d 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (330) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +50 -0
  4. data/_data/publications/pulliam2012.yml +12 -0
  5. data/_data/team/ackley.yml +25 -0
  6. data/_data/team/are.yml +22 -0
  7. data/_data/team/beauclair.yml +14 -0
  8. data/_data/team/bekele.yml +14 -0
  9. data/_data/team/bellan.yml +46 -0
  10. data/_data/team/bolton.yml +33 -0
  11. data/_data/team/borchering.yml +65 -0
  12. data/_data/team/brook.yml +15 -0
  13. data/_data/team/brown.yml +18 -0
  14. data/_data/team/bruce.yml +26 -0
  15. data/_data/team/brucePA.yml +9 -0
  16. data/_data/team/deleo.yml +49 -0
  17. data/_data/team/delva.yml +15 -0
  18. data/_data/team/dushoff.yml +52 -0
  19. data/_data/team/ervin.yml +10 -0
  20. data/_data/team/faikah.yml +26 -0
  21. data/_data/team/grebe.yml +36 -0
  22. data/_data/team/hargrove.yml +36 -0
  23. data/_data/team/hitchcock.yml +10 -0
  24. data/_data/team/hladish.yml +45 -0
  25. data/_data/team/january.yml +9 -0
  26. data/_data/team/kassanjee.yml +20 -0
  27. data/_data/team/li.yml +45 -0
  28. data/_data/team/lord.yml +20 -0
  29. data/_data/team/marx.yml +14 -0
  30. data/_data/team/mcintosh.yml +20 -0
  31. data/_data/team/mhlanga.yml +22 -0
  32. data/_data/team/mthombothi.yml +23 -0
  33. data/_data/team/mugwagwa.yml +18 -0
  34. data/_data/team/mwangi.yml +24 -0
  35. data/_data/team/mwebaze.yml +20 -0
  36. data/_data/team/ndifon.yml +18 -0
  37. data/_data/team/ngonghala.yml +30 -0
  38. data/_data/team/nondi.yml +14 -0
  39. data/_data/team/nyamai.yml +18 -0
  40. data/_data/team/october.yml +9 -0
  41. data/_data/team/paradza.yml +19 -0
  42. data/_data/team/pearson.yml +58 -0
  43. data/_data/team/porco.yml +14 -0
  44. data/_data/team/pulliam.yml +51 -0
  45. data/_data/team/reiner.yml +18 -0
  46. data/_data/team/scheepers.yml +9 -0
  47. data/_data/team/scott.yml +51 -0
  48. data/_data/team/sempa.yml +32 -0
  49. data/_data/team/sikhondze.yml +14 -0
  50. data/_data/team/template.yml +18 -0
  51. data/_data/team/ujeneza.yml +38 -0
  52. data/_data/team/vanschalkwyk.yml +32 -0
  53. data/_data/team/welte.yml +18 -0
  54. data/_data/team/williams.yml +28 -0
  55. data/_data/team/ying.yml +21 -0
  56. data/_includes/MedPH/.DS_Store +0 -0
  57. data/_includes/MedPH/assignments.md +42 -0
  58. data/_includes/MedPH/assignmentsStandard.md +74 -0
  59. data/_includes/MedPH/computerlabs.md +38 -0
  60. data/_includes/MedPH/computerlabsStandard.md +38 -0
  61. data/_includes/MedPH/lectures.md +12 -0
  62. data/_includes/MedPH/references.md +71 -0
  63. data/_includes/MedPH/schedule.md +85 -0
  64. data/_includes/MedPH/scheduleStandard.md +93 -0
  65. data/_includes/bottomTable.html +5 -0
  66. data/_includes/centerTable.html +5 -0
  67. data/_includes/clinicNavbar.html +46 -0
  68. data/_includes/contact.html +12 -0
  69. data/_includes/directors.html +47 -0
  70. data/_includes/footer.html +23 -0
  71. data/_includes/head.html +28 -0
  72. data/_includes/header.html +31 -0
  73. data/_includes/hero.html +14 -0
  74. data/_includes/index.md +9 -0
  75. data/_includes/mission.html +13 -0
  76. data/_includes/navStructure.html +70 -0
  77. data/_includes/navbar.html +65 -0
  78. data/_includes/outputs.html +74 -0
  79. data/_includes/partners.html +75 -0
  80. data/_includes/profile.html +67 -0
  81. data/_includes/publications/faculty.md +13 -0
  82. data/_includes/publications/instructional.md +5 -0
  83. data/_includes/publications/participant.md +33 -0
  84. data/_includes/talk.html +12 -0
  85. data/_includes/topTable.html +6 -0
  86. data/_includes/upcoming.html +43 -0
  87. data/_layouts/clinic.liquid +43 -0
  88. data/_layouts/example.liquid +601 -0
  89. data/_layouts/main.liquid +34 -0
  90. data/_layouts/medph.page.liquid +60 -0
  91. data/_layouts/page.liquid +41 -0
  92. data/_layouts/people.page.liquid +27 -0
  93. data/_layouts/profile.liquid +44 -0
  94. data/_layouts/redirect.liquid +15 -0
  95. data/_layouts/talk.liquid +42 -0
  96. data/assets/css/academicons.css +249 -0
  97. data/assets/css/academicons.min.css +1 -0
  98. data/assets/css/bootstrap.css +6760 -0
  99. data/assets/css/bootstrap.css.map +1 -0
  100. data/assets/css/bootstrap.min.css +6 -0
  101. data/assets/css/font-awesome.css +2086 -0
  102. data/assets/css/font-awesome.min.css +4 -0
  103. data/assets/css/ie.css +5 -0
  104. data/assets/css/main-one-page.css +6433 -0
  105. data/assets/css/main.css +7160 -0
  106. data/assets/css/my-custom-styles.css +14 -0
  107. data/assets/css/shop-main.css +3117 -0
  108. data/assets/css/skins/brown.css +299 -0
  109. data/assets/css/skins/deepskyblue.css +299 -0
  110. data/assets/css/skins/goldenrod.css +299 -0
  111. data/assets/css/skins/ici3dBlue.css +229 -0
  112. data/assets/css/skins/ici3dBlue.css.map +7 -0
  113. data/assets/css/skins/ici3dIndigo.css +229 -0
  114. data/assets/css/skins/ici3dIndigo.css.map +7 -0
  115. data/assets/css/skins/indianred.css +299 -0
  116. data/assets/css/skins/lightgreen.css +299 -0
  117. data/assets/css/skins/orange.css +299 -0
  118. data/assets/css/skins/seagreen.css +299 -0
  119. data/assets/css/skins/slategray.css +299 -0
  120. data/assets/fonts/academicons.eot +0 -0
  121. data/assets/fonts/academicons.svg +66 -0
  122. data/assets/fonts/academicons.ttf +0 -0
  123. data/assets/fonts/academicons.woff +0 -0
  124. data/assets/fonts/fontawesome-webfont.eot +0 -0
  125. data/assets/fonts/fontawesome-webfont.svg +655 -0
  126. data/assets/fonts/fontawesome-webfont.ttf +0 -0
  127. data/assets/fonts/fontawesome-webfont.woff +0 -0
  128. data/assets/fonts/fontawesome-webfont.woff2 +0 -0
  129. data/assets/fonts/glyphicons-halflings-regular.eot +0 -0
  130. data/assets/fonts/glyphicons-halflings-regular.svg +288 -0
  131. data/assets/fonts/glyphicons-halflings-regular.ttf +0 -0
  132. data/assets/fonts/glyphicons-halflings-regular.woff +0 -0
  133. data/assets/fonts/glyphicons-halflings-regular.woff2 +0 -0
  134. data/assets/ico/favicon.ico +0 -0
  135. data/assets/ico/favicon.png +0 -0
  136. data/assets/ico/ici3d114x114.png +0 -0
  137. data/assets/ico/ici3d144x144.png +0 -0
  138. data/assets/ico/ici3d57x57.png +0 -0
  139. data/assets/ico/ici3d72x72.png +0 -0
  140. data/assets/img/8hearts.png +0 -0
  141. data/assets/img/MMED2015_tutorials.jpg +0 -0
  142. data/assets/img/badge.png +0 -0
  143. data/assets/img/blog/balloon-med.jpg +0 -0
  144. data/assets/img/blog/balloon.jpg +0 -0
  145. data/assets/img/blog/buildings-med.jpg +0 -0
  146. data/assets/img/blog/buildings.jpg +0 -0
  147. data/assets/img/blog/people-med.jpg +0 -0
  148. data/assets/img/blog/people.jpg +0 -0
  149. data/assets/img/bx_loader.gif +0 -0
  150. data/assets/img/clients/logo1.png +0 -0
  151. data/assets/img/clients/logo2.png +0 -0
  152. data/assets/img/clients/logo3.png +0 -0
  153. data/assets/img/clients/logo4.png +0 -0
  154. data/assets/img/clients/logo5.png +0 -0
  155. data/assets/img/flags/China.png +0 -0
  156. data/assets/img/flags/Germany.png +0 -0
  157. data/assets/img/flags/Japan.png +0 -0
  158. data/assets/img/flags/South-Africa.png +0 -0
  159. data/assets/img/flags/United-Kingdom.png +0 -0
  160. data/assets/img/flags/United-States.png +0 -0
  161. data/assets/img/free.png +0 -0
  162. data/assets/img/fullscreen-bg.jpg +0 -0
  163. data/assets/img/gray_jean.png +0 -0
  164. data/assets/img/hero-unit-bg.png +0 -0
  165. data/assets/img/hero-unit-obj.png +0 -0
  166. data/assets/img/hero-unit-obj2.png +0 -0
  167. data/assets/img/hero-unit-obj3.png +0 -0
  168. data/assets/img/intro-img.png +0 -0
  169. data/assets/img/location-pin.png +0 -0
  170. data/assets/img/logo/ici3d-logo-light.png +0 -0
  171. data/assets/img/logo/ici3d-logo-nav.png +0 -0
  172. data/assets/img/logo/ici3d-logo-white.png +0 -0
  173. data/assets/img/logo/ici3d-logo-white_v2.png +0 -0
  174. data/assets/img/logo/ici3d-logo-white_v3.png +0 -0
  175. data/assets/img/logo/repute-logo-light-brown.png +0 -0
  176. data/assets/img/logo/repute-logo-light-deepskyblue.png +0 -0
  177. data/assets/img/logo/repute-logo-light-goldenrod.png +0 -0
  178. data/assets/img/logo/repute-logo-light-indianred.png +0 -0
  179. data/assets/img/logo/repute-logo-light-lightgreen.png +0 -0
  180. data/assets/img/logo/repute-logo-light-orange.png +0 -0
  181. data/assets/img/logo/repute-logo-light-seagreen.png +0 -0
  182. data/assets/img/logo/repute-logo-light-slategray.png +0 -0
  183. data/assets/img/logo/repute-logo-light.png +0 -0
  184. data/assets/img/logo/repute-logo-nav-brown.png +0 -0
  185. data/assets/img/logo/repute-logo-nav-deepskyblue.png +0 -0
  186. data/assets/img/logo/repute-logo-nav-goldenrod.png +0 -0
  187. data/assets/img/logo/repute-logo-nav-indianred.png +0 -0
  188. data/assets/img/logo/repute-logo-nav-light.png +0 -0
  189. data/assets/img/logo/repute-logo-nav-lightgreen.png +0 -0
  190. data/assets/img/logo/repute-logo-nav-orange.png +0 -0
  191. data/assets/img/logo/repute-logo-nav-seagreen.png +0 -0
  192. data/assets/img/logo/repute-logo-nav-slategray.png +0 -0
  193. data/assets/img/logo/repute-logo-nav.png +0 -0
  194. data/assets/img/mentors/are.jpg +0 -0
  195. data/assets/img/mentors/bolton.jpg +0 -0
  196. data/assets/img/mentors/brown.jpg +0 -0
  197. data/assets/img/mentors/kassanjee.jpg +0 -0
  198. data/assets/img/mentors/mhlanga.jpg +0 -0
  199. data/assets/img/mentors/nyamai.png +0 -0
  200. data/assets/img/news/featured-news.png +0 -0
  201. data/assets/img/news/news1.png +0 -0
  202. data/assets/img/news/news2.png +0 -0
  203. data/assets/img/news/news3.png +0 -0
  204. data/assets/img/news/news4.png +0 -0
  205. data/assets/img/news/news5.png +0 -0
  206. data/assets/img/other/snoep.jpg +0 -0
  207. data/assets/img/page-header-bg.png +0 -0
  208. data/assets/img/participants/SempaJB.jpg +0 -0
  209. data/assets/img/partners/AIMS-SA.jpg +0 -0
  210. data/assets/img/partners/CEMA_UN.pdf +0 -0
  211. data/assets/img/partners/CEMA_UN.png +0 -0
  212. data/assets/img/partners/CIDID.png +0 -0
  213. data/assets/img/partners/CIDID_long.png +0 -0
  214. data/assets/img/partners/Colby.png +0 -0
  215. data/assets/img/partners/MIDAS.png +0 -0
  216. data/assets/img/partners/McMaster.jpg +0 -0
  217. data/assets/img/partners/PSU.png +0 -0
  218. data/assets/img/partners/Proctor.png +0 -0
  219. data/assets/img/partners/SACEMA_228.png +0 -0
  220. data/assets/img/partners/UCSF.png +0 -0
  221. data/assets/img/partners/UF.png +0 -0
  222. data/assets/img/partners/UGA_228.png +0 -0
  223. data/assets/img/pattern-geometry.png +0 -0
  224. data/assets/img/portfolio/800x500/work1.png +0 -0
  225. data/assets/img/portfolio/800x500/work2.png +0 -0
  226. data/assets/img/portfolio/800x500/work3.png +0 -0
  227. data/assets/img/portfolio/800x500/work4.png +0 -0
  228. data/assets/img/portfolio/800x500/work5.png +0 -0
  229. data/assets/img/portfolio/800x500/work6.png +0 -0
  230. data/assets/img/portfolio/800x500/work7.png +0 -0
  231. data/assets/img/portfolio/800x500/work8.png +0 -0
  232. data/assets/img/portfolio/800x800/work1.png +0 -0
  233. data/assets/img/portfolio/800x800/work2.png +0 -0
  234. data/assets/img/portfolio/800x800/work3.png +0 -0
  235. data/assets/img/portfolio/800x800/work4.png +0 -0
  236. data/assets/img/portfolio/800x800/work5.png +0 -0
  237. data/assets/img/portfolio/800x800/work6.png +0 -0
  238. data/assets/img/portfolio/800x800/work7.png +0 -0
  239. data/assets/img/portfolio/800x800/work8.png +0 -0
  240. data/assets/img/portfolio/single/bicycle.jpg +0 -0
  241. data/assets/img/portfolio/single/blurred_lines.jpg +0 -0
  242. data/assets/img/portfolio/single/edge.jpg +0 -0
  243. data/assets/img/scholars/ackley.jpg +0 -0
  244. data/assets/img/scholars/beauclair.jpg +0 -0
  245. data/assets/img/scholars/beauclair.png +0 -0
  246. data/assets/img/scholars/bekele.jpg +0 -0
  247. data/assets/img/scholars/lord.jpg +0 -0
  248. data/assets/img/scholars/marx.jpg +0 -0
  249. data/assets/img/scholars/mcintosh.jpg +0 -0
  250. data/assets/img/scholars/mwebaze.jpg +0 -0
  251. data/assets/img/scholars/nondi.jpg +0 -0
  252. data/assets/img/scholars/sempa.jpg +0 -0
  253. data/assets/img/scholars/ying.jpg +0 -0
  254. data/assets/img/sliders/full-slide-color.jpg +0 -0
  255. data/assets/img/sliders/full-slide-color2.jpg +0 -0
  256. data/assets/img/sliders/full-slide-color3.jpg +0 -0
  257. data/assets/img/sliders/full-slide.jpg +0 -0
  258. data/assets/img/sliders/full-slide2.jpg +0 -0
  259. data/assets/img/sliders/full-slide3.jpg +0 -0
  260. data/assets/img/sliders/slider1-h500.png +0 -0
  261. data/assets/img/sliders/slider2-h500.png +0 -0
  262. data/assets/img/sliders/slider3-h500.png +0 -0
  263. data/assets/img/team/bellan.jpg +0 -0
  264. data/assets/img/team/borchering.jpg +0 -0
  265. data/assets/img/team/brook.jpg +0 -0
  266. data/assets/img/team/bruce.jpg +0 -0
  267. data/assets/img/team/deleo.jpg +0 -0
  268. data/assets/img/team/delva.jpg +0 -0
  269. data/assets/img/team/dushoff.jpg +0 -0
  270. data/assets/img/team/ervin.jpg +0 -0
  271. data/assets/img/team/grebe.jpg +0 -0
  272. data/assets/img/team/hargrove.jpg +0 -0
  273. data/assets/img/team/hitchcock.jpg +0 -0
  274. data/assets/img/team/hladish.jpg +0 -0
  275. data/assets/img/team/january.jpg +0 -0
  276. data/assets/img/team/li.jpg +0 -0
  277. data/assets/img/team/mthombothi.jpg +0 -0
  278. data/assets/img/team/mugwagwa.jpg +0 -0
  279. data/assets/img/team/mwangi.png +0 -0
  280. data/assets/img/team/ndifon.jpg +0 -0
  281. data/assets/img/team/ngonghala.jpg +0 -0
  282. data/assets/img/team/october.jpg +0 -0
  283. data/assets/img/team/paradza.jpg +0 -0
  284. data/assets/img/team/pearson.jpg +0 -0
  285. data/assets/img/team/porco.jpg +0 -0
  286. data/assets/img/team/pulliam.jpg +0 -0
  287. data/assets/img/team/reiner.jpg +0 -0
  288. data/assets/img/team/scheepers.jpg +0 -0
  289. data/assets/img/team/scott.jpg +0 -0
  290. data/assets/img/team/ujeneza.jpg +0 -0
  291. data/assets/img/team/vanschalkwyk.jpg +0 -0
  292. data/assets/img/team/welte.jpg +0 -0
  293. data/assets/img/team/williams.jpg +0 -0
  294. data/assets/img/testimonial-bg.png +0 -0
  295. data/assets/img/transmission.png +0 -0
  296. data/assets/js/bootstrap.js +2363 -0
  297. data/assets/js/bootstrap.min.js +7 -0
  298. data/assets/js/jquery-2.1.1.min.js +4 -0
  299. data/assets/js/plugins/autohidingnavbar/jquery.bootstrap-autohidingnavbar.js +213 -0
  300. data/assets/js/plugins/autohidingnavbar/jquery.bootstrap-autohidingnavbar.min.js +9 -0
  301. data/assets/js/plugins/bootstrap-datepicker/bootstrap-datepicker.js +474 -0
  302. data/assets/js/plugins/bootstrap-multiselect/bootstrap-multiselect.js +994 -0
  303. data/assets/js/plugins/daterangepicker/daterangepicker.js +868 -0
  304. data/assets/js/plugins/easing/jquery.easing.js +205 -0
  305. data/assets/js/plugins/easing/jquery.easing.min.js +71 -0
  306. data/assets/js/plugins/fitvids/jquery.fitvids.js +83 -0
  307. data/assets/js/plugins/google-map/google-map.js +160 -0
  308. data/assets/js/plugins/isotope/isotope.pkgd.js +4049 -0
  309. data/assets/js/plugins/isotope/isotope.pkgd.min.js +8 -0
  310. data/assets/js/plugins/jquery-cycle/jquery.cycle.all.js +1543 -0
  311. data/assets/js/plugins/jquery-easypiechart/jquery.easypiechart.js +359 -0
  312. data/assets/js/plugins/jquery-easypiechart/jquery.easypiechart.min.js +9 -0
  313. data/assets/js/plugins/jquery-maskedinput/jquery.masked-input.js +338 -0
  314. data/assets/js/plugins/jquery-maskedinput/jquery.masked-input.min.js +7 -0
  315. data/assets/js/plugins/maximage/jquery.maximage.js +697 -0
  316. data/assets/js/plugins/maximage/jquery.maximage.min.js +4 -0
  317. data/assets/js/plugins/moment/moment.js +1662 -0
  318. data/assets/js/plugins/moment/moment.min.js +6 -0
  319. data/assets/js/plugins/parsley-validation/parsley.js +2074 -0
  320. data/assets/js/plugins/parsley-validation/parsley.min.js +9 -0
  321. data/assets/js/plugins/scrollto/jquery.localscroll-1.2.7-min.js +9 -0
  322. data/assets/js/plugins/scrollto/jquery.localscroll-1.2.7.js +133 -0
  323. data/assets/js/plugins/scrollto/jquery.scrollTo-1.4.3.1-min.js +7 -0
  324. data/assets/js/plugins/scrollto/jquery.scrollTo-1.4.3.1.js +218 -0
  325. data/assets/js/plugins/slick/slick.js +2643 -0
  326. data/assets/js/plugins/slick/slick.min.js +18 -0
  327. data/assets/js/plugins/stellar/jquery.stellar.js +660 -0
  328. data/assets/js/plugins/stellar/jquery.stellar.min.js +2 -0
  329. data/assets/js/repute-scripts.js +539 -0
  330. metadata +385 -0
@@ -0,0 +1,994 @@
1
+ /**
2
+ * bootstrap-multiselect.js
3
+ * https://github.com/davidstutz/bootstrap-multiselect
4
+ *
5
+ * Copyright 2012 - 2014 David Stutz
6
+ *
7
+ * Dual licensed under the BSD-3-Clause and the Apache License, Version 2.0.
8
+ */
9
+ !function($) {
10
+
11
+ "use strict";// jshint ;_;
12
+
13
+ if (typeof ko !== 'undefined' && ko.bindingHandlers && !ko.bindingHandlers.multiselect) {
14
+ ko.bindingHandlers.multiselect = {
15
+
16
+ init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
17
+
18
+ var listOfSelectedItems = allBindingsAccessor().selectedOptions,
19
+ config = ko.utils.unwrapObservable(valueAccessor());
20
+
21
+ $(element).multiselect(config);
22
+
23
+ if (isObservableArray(listOfSelectedItems)) {
24
+ // Subscribe to the selectedOptions: ko.observableArray
25
+ listOfSelectedItems.subscribe(function (changes) {
26
+ var addedArray = [], deletedArray = [];
27
+ changes.forEach(function (change) {
28
+ switch (change.status) {
29
+ case 'added':
30
+ addedArray.push(change.value);
31
+ break;
32
+ case 'deleted':
33
+ deletedArray.push(change.value);
34
+ break;
35
+ }
36
+ });
37
+ if (addedArray.length > 0) {
38
+ $(element).multiselect('select', addedArray);
39
+ };
40
+ if (deletedArray.length > 0) {
41
+ $(element).multiselect('deselect', deletedArray);
42
+ };
43
+ }, null, "arrayChange");
44
+ }
45
+ },
46
+
47
+ update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
48
+
49
+ var listOfItems = allBindingsAccessor().options,
50
+ ms = $(element).data('multiselect'),
51
+ config = ko.utils.unwrapObservable(valueAccessor());
52
+
53
+ if (isObservableArray(listOfItems)) {
54
+ // Subscribe to the options: ko.observableArray incase it changes later
55
+ listOfItems.subscribe(function (theArray) {
56
+ $(element).multiselect('rebuild');
57
+ });
58
+ }
59
+
60
+ if (!ms) {
61
+ $(element).multiselect(config);
62
+ }
63
+ else {
64
+ ms.updateOriginalOptions();
65
+ }
66
+ }
67
+ };
68
+ }
69
+
70
+ function isObservableArray(obj) {
71
+ return ko.isObservable(obj) && !(obj.destroyAll === undefined);
72
+ }
73
+
74
+ /**
75
+ * Constructor to create a new multiselect using the given select.
76
+ *
77
+ * @param {jQuery} select
78
+ * @param {Object} options
79
+ * @returns {Multiselect}
80
+ */
81
+ function Multiselect(select, options) {
82
+
83
+ this.options = this.mergeOptions(options);
84
+ this.$select = $(select);
85
+
86
+ // Initialization.
87
+ // We have to clone to create a new reference.
88
+ this.originalOptions = this.$select.clone()[0].options;
89
+ this.query = '';
90
+ this.searchTimeout = null;
91
+
92
+ this.options.multiple = this.$select.attr('multiple') === "multiple";
93
+ this.options.onChange = $.proxy(this.options.onChange, this);
94
+ this.options.onDropdownShow = $.proxy(this.options.onDropdownShow, this);
95
+ this.options.onDropdownHide = $.proxy(this.options.onDropdownHide, this);
96
+
97
+ // Build select all if enabled.
98
+ this.buildContainer();
99
+ this.buildButton();
100
+ this.buildSelectAll();
101
+ this.buildDropdown();
102
+ this.buildDropdownOptions();
103
+ this.buildFilter();
104
+
105
+ this.updateButtonText();
106
+ this.updateSelectAll();
107
+
108
+ this.$select.hide().after(this.$container);
109
+ };
110
+
111
+ Multiselect.prototype = {
112
+
113
+ defaults: {
114
+ /**
115
+ * Default text function will either print 'None selected' in case no
116
+ * option is selected or a list of the selected options up to a length of 3 selected options.
117
+ *
118
+ * @param {jQuery} options
119
+ * @param {jQuery} select
120
+ * @returns {String}
121
+ */
122
+ buttonText: function(options, select) {
123
+ if (options.length === 0) {
124
+ return this.nonSelectedText + ' <b class="caret"></b>';
125
+ }
126
+ else {
127
+ if (options.length > this.numberDisplayed) {
128
+ return options.length + ' ' + this.nSelectedText + ' <b class="caret"></b>';
129
+ }
130
+ else {
131
+ var selected = '';
132
+ options.each(function() {
133
+ var label = ($(this).attr('label') !== undefined) ? $(this).attr('label') : $(this).html();
134
+
135
+ selected += label + ', ';
136
+ });
137
+ return selected.substr(0, selected.length - 2) + ' <b class="caret"></b>';
138
+ }
139
+ }
140
+ },
141
+ /**
142
+ * Updates the title of the button similar to the buttonText function.
143
+ * @param {jQuery} options
144
+ * @param {jQuery} select
145
+ * @returns {@exp;selected@call;substr}
146
+ */
147
+ buttonTitle: function(options, select) {
148
+ if (options.length === 0) {
149
+ return this.nonSelectedText;
150
+ }
151
+ else {
152
+ var selected = '';
153
+ options.each(function () {
154
+ selected += $(this).text() + ', ';
155
+ });
156
+ return selected.substr(0, selected.length - 2);
157
+ }
158
+ },
159
+ /**
160
+ * Create a label.
161
+ *
162
+ * @param {jQuery} element
163
+ * @returns {String}
164
+ */
165
+ label: function(element){
166
+ return $(element).attr('label') || $(element).html();
167
+ },
168
+ /**
169
+ * Triggered on change of the multiselect.
170
+ * Not triggered when selecting/deselecting options manually.
171
+ *
172
+ * @param {jQuery} option
173
+ * @param {Boolean} checked
174
+ */
175
+ onChange : function(option, checked) {
176
+
177
+ },
178
+ /**
179
+ * Triggered when the dropdown is shown.
180
+ *
181
+ * @param {jQuery} event
182
+ */
183
+ onDropdownShow: function(event) {
184
+
185
+ },
186
+ /**
187
+ * Triggered when the dropdown is hidden.
188
+ *
189
+ * @param {jQuery} event
190
+ */
191
+ onDropdownHide: function(event) {
192
+
193
+ },
194
+ buttonClass: 'btn btn-default',
195
+ dropRight: false,
196
+ selectedClass: 'active',
197
+ buttonWidth: 'auto',
198
+ buttonContainer: '<div class="btn-group" />',
199
+ // Maximum height of the dropdown menu.
200
+ // If maximum height is exceeded a scrollbar will be displayed.
201
+ maxHeight: false,
202
+ checkboxName: 'multiselect',
203
+ includeSelectAllOption: false,
204
+ includeSelectAllIfMoreThan: 0,
205
+ selectAllText: ' Select all',
206
+ selectAllValue: 'multiselect-all',
207
+ enableFiltering: false,
208
+ enableCaseInsensitiveFiltering: false,
209
+ filterPlaceholder: 'Search',
210
+ // possible options: 'text', 'value', 'both'
211
+ filterBehavior: 'text',
212
+ preventInputChangeEvent: false,
213
+ nonSelectedText: 'None selected',
214
+ nSelectedText: 'selected',
215
+ numberDisplayed: 3,
216
+ templates: {
217
+ button: '<button type="button" class="multiselect dropdown-toggle" data-toggle="dropdown"></button>',
218
+ ul: '<ul class="multiselect-container dropdown-menu"></ul>',
219
+ filter: '<div class="input-group"><span class="input-group-addon"><i class="glyphicon glyphicon-search"></i></span><input class="form-control multiselect-search" type="text"></div>',
220
+ li: '<li><a href="javascript:void(0);"><label></label></a></li>',
221
+ divider: '<li class="divider"></li>',
222
+ liGroup: '<li><label class="multiselect-group"></label></li>'
223
+ }
224
+ },
225
+
226
+ constructor: Multiselect,
227
+
228
+ /**
229
+ * Builds the container of the multiselect.
230
+ */
231
+ buildContainer: function() {
232
+ this.$container = $(this.options.buttonContainer);
233
+ this.$container.on('show.bs.dropdown', this.options.onDropdownShow);
234
+ this.$container.on('hide.bs.dropdown', this.options.onDropdownHide);
235
+ },
236
+
237
+ /**
238
+ * Builds the button of the multiselect.
239
+ */
240
+ buildButton: function() {
241
+ this.$button = $(this.options.templates.button).addClass(this.options.buttonClass);
242
+
243
+ // Adopt active state.
244
+ if (this.$select.prop('disabled')) {
245
+ this.disable();
246
+ }
247
+ else {
248
+ this.enable();
249
+ }
250
+
251
+ // Manually add button width if set.
252
+ if (this.options.buttonWidth && this.options.buttonWidth !== 'auto') {
253
+ this.$button.css({
254
+ 'width' : this.options.buttonWidth
255
+ });
256
+ }
257
+
258
+ // Keep the tab index from the select.
259
+ var tabindex = this.$select.attr('tabindex');
260
+ if (tabindex) {
261
+ this.$button.attr('tabindex', tabindex);
262
+ }
263
+
264
+ this.$container.prepend(this.$button);
265
+ },
266
+
267
+ /**
268
+ * Builds the ul representing the dropdown menu.
269
+ */
270
+ buildDropdown: function() {
271
+
272
+ // Build ul.
273
+ this.$ul = $(this.options.templates.ul);
274
+
275
+ if (this.options.dropRight) {
276
+ this.$ul.addClass('pull-right');
277
+ }
278
+
279
+ // Set max height of dropdown menu to activate auto scrollbar.
280
+ if (this.options.maxHeight) {
281
+ // TODO: Add a class for this option to move the css declarations.
282
+ this.$ul.css({
283
+ 'max-height': this.options.maxHeight + 'px',
284
+ 'overflow-y': 'auto',
285
+ 'overflow-x': 'hidden'
286
+ });
287
+ }
288
+
289
+ this.$container.append(this.$ul);
290
+ },
291
+
292
+ /**
293
+ * Build the dropdown options and binds all nessecary events.
294
+ * Uses createDivider and createOptionValue to create the necessary options.
295
+ */
296
+ buildDropdownOptions: function() {
297
+
298
+ this.$select.children().each($.proxy(function(index, element) {
299
+
300
+ // Support optgroups and options without a group simultaneously.
301
+ var tag = $(element).prop('tagName')
302
+ .toLowerCase();
303
+
304
+ if (tag === 'optgroup') {
305
+ this.createOptgroup(element);
306
+ }
307
+ else if (tag === 'option') {
308
+
309
+ if ($(element).data('role') === 'divider') {
310
+ this.createDivider();
311
+ }
312
+ else {
313
+ this.createOptionValue(element);
314
+ }
315
+
316
+ }
317
+
318
+ // Other illegal tags will be ignored.
319
+ }, this));
320
+
321
+ // Bind the change event on the dropdown elements.
322
+ $('li input', this.$ul).on('change', $.proxy(function(event) {
323
+ var $target = $(event.target);
324
+
325
+ var checked = $target.prop('checked') || false;
326
+ var isSelectAllOption = $target.val() === this.options.selectAllValue;
327
+
328
+ // Apply or unapply the configured selected class.
329
+ if (this.options.selectedClass) {
330
+ if (checked) {
331
+ $target.parents('li')
332
+ .addClass(this.options.selectedClass);
333
+ }
334
+ else {
335
+ $target.parents('li')
336
+ .removeClass(this.options.selectedClass);
337
+ }
338
+ }
339
+
340
+ // Get the corresponding option.
341
+ var value = $target.val();
342
+ var $option = this.getOptionByValue(value);
343
+
344
+ var $optionsNotThis = $('option', this.$select).not($option);
345
+ var $checkboxesNotThis = $('input', this.$container).not($target);
346
+
347
+ if (isSelectAllOption) {
348
+ var values = [];
349
+
350
+ // Select the visible checkboxes except the "select-all" and possible divider.
351
+ var availableInputs = $('li input[value!="' + this.options.selectAllValue + '"][data-role!="divider"]', this.$ul).filter(':visible');
352
+ for (var i = 0, j = availableInputs.length; i < j; i++) {
353
+ values.push(availableInputs[i].value);
354
+ }
355
+
356
+ if (checked) {
357
+ this.select(values);
358
+ }
359
+ else {
360
+ this.deselect(values);
361
+ }
362
+ }
363
+
364
+ if (checked) {
365
+ $option.prop('selected', true);
366
+
367
+ if (this.options.multiple) {
368
+ // Simply select additional option.
369
+ $option.prop('selected', true);
370
+ }
371
+ else {
372
+ // Unselect all other options and corresponding checkboxes.
373
+ if (this.options.selectedClass) {
374
+ $($checkboxesNotThis).parents('li').removeClass(this.options.selectedClass);
375
+ }
376
+
377
+ $($checkboxesNotThis).prop('checked', false);
378
+ $optionsNotThis.prop('selected', false);
379
+
380
+ // It's a single selection, so close.
381
+ this.$button.click();
382
+ }
383
+
384
+ if (this.options.selectedClass === "active") {
385
+ $optionsNotThis.parents("a").css("outline", "");
386
+ }
387
+ }
388
+ else {
389
+ // Unselect option.
390
+ $option.prop('selected', false);
391
+ }
392
+
393
+ this.$select.change();
394
+ this.options.onChange($option, checked);
395
+
396
+ this.updateButtonText();
397
+ this.updateSelectAll();
398
+
399
+ if(this.options.preventInputChangeEvent) {
400
+ return false;
401
+ }
402
+ }, this));
403
+
404
+ $('li a', this.$ul).on('touchstart click', function(event) {
405
+ event.stopPropagation();
406
+
407
+ var $target = $(event.target);
408
+
409
+ if (event.shiftKey) {
410
+ var checked = $target.prop('checked') || false;
411
+
412
+ if (checked) {
413
+ var prev = $target.parents('li:last')
414
+ .siblings('li[class="active"]:first');
415
+
416
+ var currentIdx = $target.parents('li')
417
+ .index();
418
+ var prevIdx = prev.index();
419
+
420
+ if (currentIdx > prevIdx) {
421
+ $target.parents("li:last").prevUntil(prev).each(
422
+ function() {
423
+ $(this).find("input:first").prop("checked", true)
424
+ .trigger("change");
425
+ }
426
+ );
427
+ }
428
+ else {
429
+ $target.parents("li:last").nextUntil(prev).each(
430
+ function() {
431
+ $(this).find("input:first").prop("checked", true)
432
+ .trigger("change");
433
+ }
434
+ );
435
+ }
436
+ }
437
+ }
438
+
439
+ $target.blur();
440
+ });
441
+
442
+ // Keyboard support.
443
+ this.$container.on('keydown', $.proxy(function(event) {
444
+ if ($('input[type="text"]', this.$container).is(':focus')) {
445
+ return;
446
+ }
447
+ if ((event.keyCode === 9 || event.keyCode === 27)
448
+ && this.$container.hasClass('open')) {
449
+
450
+ // Close on tab or escape.
451
+ this.$button.click();
452
+ }
453
+ else {
454
+ var $items = $(this.$container).find("li:not(.divider):visible a");
455
+
456
+ if (!$items.length) {
457
+ return;
458
+ }
459
+
460
+ var index = $items.index($items.filter(':focus'));
461
+
462
+ // Navigation up.
463
+ if (event.keyCode === 38 && index > 0) {
464
+ index--;
465
+ }
466
+ // Navigate down.
467
+ else if (event.keyCode === 40 && index < $items.length - 1) {
468
+ index++;
469
+ }
470
+ else if (!~index) {
471
+ index = 0;
472
+ }
473
+
474
+ var $current = $items.eq(index);
475
+ $current.focus();
476
+
477
+ if (event.keyCode === 32 || event.keyCode === 13) {
478
+ var $checkbox = $current.find('input');
479
+
480
+ $checkbox.prop("checked", !$checkbox.prop("checked"));
481
+ $checkbox.change();
482
+ }
483
+
484
+ event.stopPropagation();
485
+ event.preventDefault();
486
+ }
487
+ }, this));
488
+ },
489
+
490
+ /**
491
+ * Create an option using the given select option.
492
+ *
493
+ * @param {jQuery} element
494
+ */
495
+ createOptionValue: function(element) {
496
+ if ($(element).is(':selected')) {
497
+ $(element).prop('selected', true);
498
+ }
499
+
500
+ // Support the label attribute on options.
501
+ var label = this.options.label(element);
502
+ var value = $(element).val();
503
+ var inputType = this.options.multiple ? "checkbox" : "radio";
504
+
505
+ var $li = $(this.options.templates.li);
506
+ $('label', $li).addClass(inputType);
507
+ $('label', $li).append('<input type="' + inputType + '" name="' + this.options.checkboxName + '" />');
508
+
509
+ var selected = $(element).prop('selected') || false;
510
+ var $checkbox = $('input', $li);
511
+ $checkbox.val(value);
512
+
513
+ if (value === this.options.selectAllValue) {
514
+ $checkbox.parent().parent()
515
+ .addClass('multiselect-all');
516
+ }
517
+
518
+ $('label', $li).append(" " + label);
519
+
520
+ this.$ul.append($li);
521
+
522
+ if ($(element).is(':disabled')) {
523
+ $checkbox.attr('disabled', 'disabled')
524
+ .prop('disabled', true)
525
+ .parents('li')
526
+ .addClass('disabled');
527
+ }
528
+
529
+ $checkbox.prop('checked', selected);
530
+
531
+ if (selected && this.options.selectedClass) {
532
+ $checkbox.parents('li')
533
+ .addClass(this.options.selectedClass);
534
+ }
535
+ },
536
+
537
+ /**
538
+ * Creates a divider using the given select option.
539
+ *
540
+ * @param {jQuery} element
541
+ */
542
+ createDivider: function(element) {
543
+ var $divider = $(this.options.templates.divider);
544
+ this.$ul.append($divider);
545
+ },
546
+
547
+ /**
548
+ * Creates an optgroup.
549
+ *
550
+ * @param {jQuery} group
551
+ */
552
+ createOptgroup: function(group) {
553
+ var groupName = $(group).prop('label');
554
+
555
+ // Add a header for the group.
556
+ var $li = $(this.options.templates.liGroup);
557
+ $('label', $li).text(groupName);
558
+
559
+ this.$ul.append($li);
560
+
561
+ if ($(group).is(':disabled')) {
562
+ $li.addClass('disabled');
563
+ }
564
+
565
+ // Add the options of the group.
566
+ $('option', group).each($.proxy(function(index, element) {
567
+ this.createOptionValue(element);
568
+ }, this));
569
+ },
570
+
571
+ /**
572
+ * Build the selct all.
573
+ * Checks if a select all ahs already been created.
574
+ */
575
+ buildSelectAll: function() {
576
+ var alreadyHasSelectAll = this.hasSelectAll();
577
+
578
+ if (!alreadyHasSelectAll && this.options.includeSelectAllOption && this.options.multiple
579
+ && $('option[data-role!="divider"]', this.$select).length > this.options.includeSelectAllIfMoreThan) {
580
+
581
+ // Check whether to add a divider after the select all.
582
+ if (this.options.includeSelectAllDivider) {
583
+ this.$select.prepend('<option value="" disabled="disabled" data-role="divider">');
584
+ }
585
+
586
+ this.$select.prepend('<option value="' + this.options.selectAllValue + '">' + this.options.selectAllText + '</option>');
587
+ }
588
+ },
589
+
590
+ /**
591
+ * Builds the filter.
592
+ */
593
+ buildFilter: function() {
594
+
595
+ // Build filter if filtering OR case insensitive filtering is enabled and the number of options exceeds (or equals) enableFilterLength.
596
+ if (this.options.enableFiltering || this.options.enableCaseInsensitiveFiltering) {
597
+ var enableFilterLength = Math.max(this.options.enableFiltering, this.options.enableCaseInsensitiveFiltering);
598
+
599
+ if (this.$select.find('option').length >= enableFilterLength) {
600
+
601
+ this.$filter = $(this.options.templates.filter);
602
+ $('input', this.$filter).attr('placeholder', this.options.filterPlaceholder);
603
+ this.$ul.prepend(this.$filter);
604
+
605
+ this.$filter.val(this.query).on('click', function(event) {
606
+ event.stopPropagation();
607
+ }).on('input keydown', $.proxy(function(event) {
608
+ // This is useful to catch "keydown" events after the browser has updated the control.
609
+ clearTimeout(this.searchTimeout);
610
+
611
+ this.searchTimeout = this.asyncFunction($.proxy(function() {
612
+
613
+ if (this.query !== event.target.value) {
614
+ this.query = event.target.value;
615
+
616
+ $.each($('li', this.$ul), $.proxy(function(index, element) {
617
+ var value = $('input', element).val();
618
+ var text = $('label', element).text();
619
+
620
+ var filterCandidate = '';
621
+ if ((this.options.filterBehavior === 'text')) {
622
+ filterCandidate = text;
623
+ }
624
+ else if ((this.options.filterBehavior === 'value')) {
625
+ filterCandidate = value;
626
+ }
627
+ else if (this.options.filterBehavior === 'both') {
628
+ filterCandidate = text + '\n' + value;
629
+ }
630
+
631
+ if (value !== this.options.selectAllValue && text) {
632
+ // by default lets assume that element is not
633
+ // interesting for this search
634
+ var showElement = false;
635
+
636
+ if (this.options.enableCaseInsensitiveFiltering && filterCandidate.toLowerCase().indexOf(this.query.toLowerCase()) > -1) {
637
+ showElement = true;
638
+ }
639
+ else if (filterCandidate.indexOf(this.query) > -1) {
640
+ showElement = true;
641
+ }
642
+
643
+ if (showElement) {
644
+ $(element).show();
645
+ }
646
+ else {
647
+ $(element).hide();
648
+ }
649
+ }
650
+ }, this));
651
+ }
652
+
653
+ // TODO: check whether select all option needs to be updated.
654
+ }, this), 300, this);
655
+ }, this));
656
+ }
657
+ }
658
+ },
659
+
660
+ /**
661
+ * Unbinds the whole plugin.
662
+ */
663
+ destroy: function() {
664
+ this.$container.remove();
665
+ this.$select.show();
666
+ this.$select.data('multiselect', null);
667
+ },
668
+
669
+ /**
670
+ * Refreshs the multiselect based on the selected options of the select.
671
+ */
672
+ refresh: function() {
673
+ $('option', this.$select).each($.proxy(function(index, element) {
674
+ var $input = $('li input', this.$ul).filter(function() {
675
+ return $(this).val() === $(element).val();
676
+ });
677
+
678
+ if ($(element).is(':selected')) {
679
+ $input.prop('checked', true);
680
+
681
+ if (this.options.selectedClass) {
682
+ $input.parents('li')
683
+ .addClass(this.options.selectedClass);
684
+ }
685
+ }
686
+ else {
687
+ $input.prop('checked', false);
688
+
689
+ if (this.options.selectedClass) {
690
+ $input.parents('li')
691
+ .removeClass(this.options.selectedClass);
692
+ }
693
+ }
694
+
695
+ if ($(element).is(":disabled")) {
696
+ $input.attr('disabled', 'disabled')
697
+ .prop('disabled', true)
698
+ .parents('li')
699
+ .addClass('disabled');
700
+ }
701
+ else {
702
+ $input.prop('disabled', false)
703
+ .parents('li')
704
+ .removeClass('disabled');
705
+ }
706
+ }, this));
707
+
708
+ this.updateButtonText();
709
+ this.updateSelectAll();
710
+ },
711
+
712
+ /**
713
+ * Select all options of the given values.
714
+ *
715
+ * @param {Array} selectValues
716
+ */
717
+ select: function(selectValues) {
718
+ if(!$.isArray(selectValues)) {
719
+ selectValues = [selectValues];
720
+ }
721
+
722
+ for (var i = 0; i < selectValues.length; i++) {
723
+ var value = selectValues[i];
724
+
725
+ var $option = this.getOptionByValue(value);
726
+ var $checkbox = this.getInputByValue(value);
727
+
728
+ if (this.options.selectedClass) {
729
+ $checkbox.parents('li')
730
+ .addClass(this.options.selectedClass);
731
+ }
732
+
733
+ $checkbox.prop('checked', true);
734
+ $option.prop('selected', true);
735
+ }
736
+
737
+ this.updateButtonText();
738
+ },
739
+
740
+ /**
741
+ * Clears all selected items
742
+ *
743
+ */
744
+ clearSelection: function () {
745
+
746
+ var selected = this.getSelected();
747
+
748
+ if (selected.length) {
749
+
750
+ var arry = [];
751
+
752
+ for (var i = 0; i < selected.length; i = i + 1) {
753
+ arry.push(selected[i].value);
754
+ }
755
+
756
+ this.deselect(arry);
757
+ this.$select.change();
758
+ }
759
+ },
760
+
761
+ /**
762
+ * Deselects all options of the given values.
763
+ *
764
+ * @param {Array} deselectValues
765
+ */
766
+ deselect: function(deselectValues) {
767
+ if(!$.isArray(deselectValues)) {
768
+ deselectValues = [deselectValues];
769
+ }
770
+
771
+ for (var i = 0; i < deselectValues.length; i++) {
772
+
773
+ var value = deselectValues[i];
774
+
775
+ var $option = this.getOptionByValue(value);
776
+ var $checkbox = this.getInputByValue(value);
777
+
778
+ if (this.options.selectedClass) {
779
+ $checkbox.parents('li')
780
+ .removeClass(this.options.selectedClass);
781
+ }
782
+
783
+ $checkbox.prop('checked', false);
784
+ $option.prop('selected', false);
785
+ }
786
+
787
+ this.updateButtonText();
788
+ },
789
+
790
+ /**
791
+ * Rebuild the plugin.
792
+ * Rebuilds the dropdown, the filter and the select all option.
793
+ */
794
+ rebuild: function() {
795
+ this.$ul.html('');
796
+
797
+ // Remove select all option in select.
798
+ $('option[value="' + this.options.selectAllValue + '"]', this.$select).remove();
799
+
800
+ // Important to distinguish between radios and checkboxes.
801
+ this.options.multiple = this.$select.attr('multiple') === "multiple";
802
+
803
+ this.buildSelectAll();
804
+ this.buildDropdownOptions();
805
+ this.buildFilter();
806
+
807
+ this.updateButtonText();
808
+ this.updateSelectAll();
809
+ },
810
+
811
+ /**
812
+ * The provided data will be used to build the dropdown.
813
+ *
814
+ * @param {Array} dataprovider
815
+ */
816
+ dataprovider: function(dataprovider) {
817
+ var optionDOM = "";
818
+ dataprovider.forEach(function (option) {
819
+ optionDOM += '<option value="' + option.value + '">' + option.label + '</option>';
820
+ });
821
+
822
+ this.$select.html(optionDOM);
823
+ this.rebuild();
824
+ },
825
+
826
+ /**
827
+ * Enable the multiselect.
828
+ */
829
+ enable: function() {
830
+ this.$select.prop('disabled', false);
831
+ this.$button.prop('disabled', false)
832
+ .removeClass('disabled');
833
+ },
834
+
835
+ /**
836
+ * Disable the multiselect.
837
+ */
838
+ disable: function() {
839
+ this.$select.prop('disabled', true);
840
+ this.$button.prop('disabled', true)
841
+ .addClass('disabled');
842
+ },
843
+
844
+ /**
845
+ * Set the options.
846
+ *
847
+ * @param {Array} options
848
+ */
849
+ setOptions: function(options) {
850
+ this.options = this.mergeOptions(options);
851
+ },
852
+
853
+ /**
854
+ * Merges the given options with the default options.
855
+ *
856
+ * @param {Array} options
857
+ * @returns {Array}
858
+ */
859
+ mergeOptions: function(options) {
860
+ return $.extend(true, {}, this.defaults, options);
861
+ },
862
+
863
+ /**
864
+ * Checks whether a select all option is present.
865
+ *
866
+ * @returns {Boolean}
867
+ */
868
+ hasSelectAll: function() {
869
+ return $('option[value="' + this.options.selectAllValue + '"]', this.$select).length > 0;
870
+ },
871
+
872
+ /**
873
+ * Updates the select all option based on the currently selected options.
874
+ */
875
+ updateSelectAll: function() {
876
+ if (this.hasSelectAll()) {
877
+ var selected = this.getSelected();
878
+
879
+ if (selected.length === $('option:not([data-role=divider])', this.$select).length - 1) {
880
+ this.select(this.options.selectAllValue);
881
+ }
882
+ else {
883
+ this.deselect(this.options.selectAllValue);
884
+ }
885
+ }
886
+ },
887
+
888
+ /**
889
+ * Update the button text and its title based on the currently selected options.
890
+ */
891
+ updateButtonText: function() {
892
+ var options = this.getSelected();
893
+
894
+ // First update the displayed button text.
895
+ $('button', this.$container).html(this.options.buttonText(options, this.$select));
896
+
897
+ // Now update the title attribute of the button.
898
+ $('button', this.$container).attr('title', this.options.buttonTitle(options, this.$select));
899
+
900
+ },
901
+
902
+ /**
903
+ * Get all selected options.
904
+ *
905
+ * @returns {jQUery}
906
+ */
907
+ getSelected: function() {
908
+ return $('option[value!="' + this.options.selectAllValue + '"]:selected', this.$select).filter(function() {
909
+ return $(this).prop('selected');
910
+ });
911
+ },
912
+
913
+ /**
914
+ * Gets a select option by its value.
915
+ *
916
+ * @param {String} value
917
+ * @returns {jQuery}
918
+ */
919
+ getOptionByValue: function (value) {
920
+
921
+ var options = $('option', this.$select);
922
+ var valueToCompare = value.toString();
923
+
924
+ for (var i = 0; i < options.length; i = i + 1) {
925
+ var option = options[i];
926
+ if (option.value === valueToCompare) {
927
+ return $(option);
928
+ }
929
+ }
930
+ },
931
+
932
+ /**
933
+ * Get the input (radio/checkbox) by its value.
934
+ *
935
+ * @param {String} value
936
+ * @returns {jQuery}
937
+ */
938
+ getInputByValue: function (value) {
939
+
940
+ var checkboxes = $('li input', this.$ul);
941
+ var valueToCompare = value.toString();
942
+
943
+ for (var i = 0; i < checkboxes.length; i = i + 1) {
944
+ var checkbox = checkboxes[i];
945
+ if (checkbox.value === valueToCompare) {
946
+ return $(checkbox);
947
+ }
948
+ }
949
+ },
950
+
951
+ /**
952
+ * Used for knockout integration.
953
+ */
954
+ updateOriginalOptions: function() {
955
+ this.originalOptions = this.$select.clone()[0].options;
956
+ },
957
+
958
+ asyncFunction: function(callback, timeout, self) {
959
+ var args = Array.prototype.slice.call(arguments, 3);
960
+ return setTimeout(function() {
961
+ callback.apply(self || window, args);
962
+ }, timeout);
963
+ }
964
+ };
965
+
966
+ $.fn.multiselect = function(option, parameter) {
967
+ return this.each(function() {
968
+ var data = $(this).data('multiselect');
969
+ var options = typeof option === 'object' && option;
970
+
971
+ // Initialize the multiselect.
972
+ if (!data) {
973
+ data = new Multiselect(this, options);
974
+ $(this).data('multiselect', data);
975
+ }
976
+
977
+ // Call multiselect method.
978
+ if (typeof option === 'string') {
979
+ data[option](parameter);
980
+
981
+ if (option === 'destroy') {
982
+ $(this).data('multiselect', false);
983
+ }
984
+ }
985
+ });
986
+ };
987
+
988
+ $.fn.multiselect.Constructor = Multiselect;
989
+
990
+ $(function() {
991
+ $("select[data-role=multiselect]").multiselect();
992
+ });
993
+
994
+ }(window.jQuery);