rbbt-rest 1.6.13 → 1.6.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (562) hide show
  1. checksums.yaml +4 -4
  2. data/lib/rbbt/rest/common/misc.rb +1 -0
  3. data/lib/rbbt/rest/main.rb +3 -1
  4. data/lib/rbbt/rest/workflow.rb +4 -4
  5. data/lib/rbbt/rest/workflow/jobs.rb +2 -1
  6. data/share/views/compass/app.sass +15 -4
  7. data/share/views/layout.haml +1 -2
  8. data/share/views/layout/coda.haml +0 -2
  9. data/share/views/layout/footer.haml +20 -7
  10. data/share/views/layout/header.haml +4 -9
  11. data/share/views/layout/top_menu.haml +44 -32
  12. data/share/views/public/js/app.js +9 -10
  13. data/share/views/public/js/defer.js +1 -1
  14. data/share/views/public/js/helpers.js +14 -0
  15. data/share/views/public/js/rbbt.aesthetics.js +0 -3
  16. data/share/views/public/js/rbbt.exception.js +21 -0
  17. data/share/views/public/js/rbbt.favourites.js +24 -14
  18. data/share/views/public/js/rbbt.job.js +14 -5
  19. data/share/views/public/js/rbbt.modal.js +26 -4
  20. data/share/views/public/js/rbbt.page.js +111 -1
  21. data/share/views/public/js/rbbt/list.js +36 -26
  22. data/share/views/public/js/rbbt/modal.js +1 -0
  23. data/share/views/public/js/rbbt/reveal.js +2 -4
  24. data/share/views/public/js/rbbt/table.js +6 -4
  25. data/share/views/public/plugins/jquery/js/jquery-2.1.4.js +9210 -0
  26. data/share/views/public/plugins/semantic-ui/CONTRIBUTING.md +16 -31
  27. data/share/views/public/plugins/semantic-ui/LICENSE.md +0 -0
  28. data/share/views/public/plugins/semantic-ui/README.md +57 -64
  29. data/share/views/public/plugins/semantic-ui/RELEASE-NOTES.md +957 -7
  30. data/share/views/public/plugins/semantic-ui/bower.json +2 -4
  31. data/share/views/public/plugins/semantic-ui/composer.json +11 -8
  32. data/share/views/public/plugins/semantic-ui/dist/components/accordion.css +32 -26
  33. data/share/views/public/plugins/semantic-ui/dist/components/accordion.js +182 -94
  34. data/share/views/public/plugins/semantic-ui/dist/components/accordion.min.css +6 -7
  35. data/share/views/public/plugins/semantic-ui/dist/components/accordion.min.js +6 -6
  36. data/share/views/public/plugins/semantic-ui/dist/components/ad.css +19 -8
  37. data/share/views/public/plugins/semantic-ui/dist/components/ad.min.css +6 -7
  38. data/share/views/public/plugins/semantic-ui/dist/components/api.js +428 -190
  39. data/share/views/public/plugins/semantic-ui/dist/components/api.min.js +6 -6
  40. data/share/views/public/plugins/semantic-ui/dist/components/breadcrumb.css +22 -22
  41. data/share/views/public/plugins/semantic-ui/dist/components/breadcrumb.min.css +6 -7
  42. data/share/views/public/plugins/semantic-ui/dist/components/button.css +1569 -707
  43. data/share/views/public/plugins/semantic-ui/dist/components/button.min.css +6 -7
  44. data/share/views/public/plugins/semantic-ui/dist/components/card.css +334 -143
  45. data/share/views/public/plugins/semantic-ui/dist/components/card.min.css +6 -7
  46. data/share/views/public/plugins/semantic-ui/dist/components/checkbox.css +234 -131
  47. data/share/views/public/plugins/semantic-ui/dist/components/checkbox.js +348 -111
  48. data/share/views/public/plugins/semantic-ui/dist/components/checkbox.min.css +6 -7
  49. data/share/views/public/plugins/semantic-ui/dist/components/checkbox.min.js +6 -6
  50. data/share/views/public/plugins/semantic-ui/dist/components/colorize.js +6 -4
  51. data/share/views/public/plugins/semantic-ui/dist/components/colorize.min.js +6 -6
  52. data/share/views/public/plugins/semantic-ui/dist/components/comment.css +9 -10
  53. data/share/views/public/plugins/semantic-ui/dist/components/comment.min.css +6 -7
  54. data/share/views/public/plugins/semantic-ui/dist/components/container.css +125 -0
  55. data/share/views/public/plugins/semantic-ui/dist/components/container.min.css +10 -0
  56. data/share/views/public/plugins/semantic-ui/dist/components/dimmer.css +34 -21
  57. data/share/views/public/plugins/semantic-ui/dist/components/dimmer.js +89 -48
  58. data/share/views/public/plugins/semantic-ui/dist/components/dimmer.min.css +6 -7
  59. data/share/views/public/plugins/semantic-ui/dist/components/dimmer.min.js +6 -6
  60. data/share/views/public/plugins/semantic-ui/dist/components/divider.css +54 -38
  61. data/share/views/public/plugins/semantic-ui/dist/components/divider.min.css +6 -7
  62. data/share/views/public/plugins/semantic-ui/dist/components/dropdown.css +575 -153
  63. data/share/views/public/plugins/semantic-ui/dist/components/dropdown.js +2263 -536
  64. data/share/views/public/plugins/semantic-ui/dist/components/dropdown.min.css +6 -7
  65. data/share/views/public/plugins/semantic-ui/dist/components/dropdown.min.js +8 -6
  66. data/share/views/public/plugins/semantic-ui/dist/components/embed.css +162 -0
  67. data/share/views/public/plugins/semantic-ui/dist/components/embed.js +662 -0
  68. data/share/views/public/plugins/semantic-ui/dist/components/embed.min.css +10 -0
  69. data/share/views/public/plugins/semantic-ui/dist/components/embed.min.js +11 -0
  70. data/share/views/public/plugins/semantic-ui/dist/components/feed.css +54 -30
  71. data/share/views/public/plugins/semantic-ui/dist/components/feed.min.css +6 -7
  72. data/share/views/public/plugins/semantic-ui/dist/components/flag.css +12 -6
  73. data/share/views/public/plugins/semantic-ui/dist/components/flag.min.css +6 -7
  74. data/share/views/public/plugins/semantic-ui/dist/components/form.css +322 -162
  75. data/share/views/public/plugins/semantic-ui/dist/components/form.js +654 -193
  76. data/share/views/public/plugins/semantic-ui/dist/components/form.min.css +6 -7
  77. data/share/views/public/plugins/semantic-ui/dist/components/form.min.js +6 -6
  78. data/share/views/public/plugins/semantic-ui/dist/components/grid.css +622 -427
  79. data/share/views/public/plugins/semantic-ui/dist/components/grid.min.css +6 -7
  80. data/share/views/public/plugins/semantic-ui/dist/components/header.css +360 -171
  81. data/share/views/public/plugins/semantic-ui/dist/components/header.min.css +6 -7
  82. data/share/views/public/plugins/semantic-ui/dist/components/icon.css +611 -153
  83. data/share/views/public/plugins/semantic-ui/dist/components/icon.min.css +6 -7
  84. data/share/views/public/plugins/semantic-ui/dist/components/image.css +68 -18
  85. data/share/views/public/plugins/semantic-ui/dist/components/image.min.css +6 -7
  86. data/share/views/public/plugins/semantic-ui/dist/components/input.css +172 -131
  87. data/share/views/public/plugins/semantic-ui/dist/components/input.min.css +6 -7
  88. data/share/views/public/plugins/semantic-ui/dist/components/item.css +72 -48
  89. data/share/views/public/plugins/semantic-ui/dist/components/item.min.css +6 -7
  90. data/share/views/public/plugins/semantic-ui/dist/components/label.css +494 -316
  91. data/share/views/public/plugins/semantic-ui/dist/components/label.min.css +6 -7
  92. data/share/views/public/plugins/semantic-ui/dist/components/list.css +192 -158
  93. data/share/views/public/plugins/semantic-ui/dist/components/list.min.css +6 -7
  94. data/share/views/public/plugins/semantic-ui/dist/components/loader.css +25 -18
  95. data/share/views/public/plugins/semantic-ui/dist/components/loader.min.css +6 -7
  96. data/share/views/public/plugins/semantic-ui/dist/components/menu.css +952 -667
  97. data/share/views/public/plugins/semantic-ui/dist/components/menu.min.css +1 -11
  98. data/share/views/public/plugins/semantic-ui/dist/components/message.css +140 -98
  99. data/share/views/public/plugins/semantic-ui/dist/components/message.min.css +6 -7
  100. data/share/views/public/plugins/semantic-ui/dist/components/modal.css +167 -93
  101. data/share/views/public/plugins/semantic-ui/dist/components/modal.js +280 -202
  102. data/share/views/public/plugins/semantic-ui/dist/components/modal.min.css +6 -7
  103. data/share/views/public/plugins/semantic-ui/dist/components/modal.min.js +6 -6
  104. data/share/views/public/plugins/semantic-ui/dist/components/nag.css +11 -12
  105. data/share/views/public/plugins/semantic-ui/dist/components/nag.js +10 -11
  106. data/share/views/public/plugins/semantic-ui/dist/components/nag.min.css +6 -7
  107. data/share/views/public/plugins/semantic-ui/dist/components/nag.min.js +6 -6
  108. data/share/views/public/plugins/semantic-ui/dist/components/popup.css +86 -30
  109. data/share/views/public/plugins/semantic-ui/dist/components/popup.js +473 -233
  110. data/share/views/public/plugins/semantic-ui/dist/components/popup.min.css +6 -7
  111. data/share/views/public/plugins/semantic-ui/dist/components/popup.min.js +6 -6
  112. data/share/views/public/plugins/semantic-ui/dist/components/progress.css +217 -127
  113. data/share/views/public/plugins/semantic-ui/dist/components/progress.js +252 -111
  114. data/share/views/public/plugins/semantic-ui/dist/components/progress.min.css +6 -7
  115. data/share/views/public/plugins/semantic-ui/dist/components/progress.min.js +6 -6
  116. data/share/views/public/plugins/semantic-ui/dist/components/rail.css +19 -12
  117. data/share/views/public/plugins/semantic-ui/dist/components/rail.min.css +6 -7
  118. data/share/views/public/plugins/semantic-ui/dist/components/rating.css +77 -73
  119. data/share/views/public/plugins/semantic-ui/dist/components/rating.js +85 -61
  120. data/share/views/public/plugins/semantic-ui/dist/components/rating.min.css +6 -7
  121. data/share/views/public/plugins/semantic-ui/dist/components/rating.min.js +6 -6
  122. data/share/views/public/plugins/semantic-ui/dist/components/reset.css +15 -13
  123. data/share/views/public/plugins/semantic-ui/dist/components/reset.min.css +6 -7
  124. data/share/views/public/plugins/semantic-ui/dist/components/reveal.css +47 -17
  125. data/share/views/public/plugins/semantic-ui/dist/components/reveal.min.css +6 -7
  126. data/share/views/public/plugins/semantic-ui/dist/components/search.css +102 -56
  127. data/share/views/public/plugins/semantic-ui/dist/components/search.js +688 -296
  128. data/share/views/public/plugins/semantic-ui/dist/components/search.min.css +6 -7
  129. data/share/views/public/plugins/semantic-ui/dist/components/search.min.js +6 -6
  130. data/share/views/public/plugins/semantic-ui/dist/components/segment.css +311 -164
  131. data/share/views/public/plugins/semantic-ui/dist/components/segment.min.css +6 -7
  132. data/share/views/public/plugins/semantic-ui/dist/components/shape.css +14 -15
  133. data/share/views/public/plugins/semantic-ui/dist/components/shape.js +102 -56
  134. data/share/views/public/plugins/semantic-ui/dist/components/shape.min.css +6 -7
  135. data/share/views/public/plugins/semantic-ui/dist/components/shape.min.js +6 -6
  136. data/share/views/public/plugins/semantic-ui/dist/components/sidebar.css +167 -38
  137. data/share/views/public/plugins/semantic-ui/dist/components/sidebar.js +296 -249
  138. data/share/views/public/plugins/semantic-ui/dist/components/sidebar.min.css +6 -7
  139. data/share/views/public/plugins/semantic-ui/dist/components/sidebar.min.js +6 -6
  140. data/share/views/public/plugins/semantic-ui/dist/components/site.css +56 -30
  141. data/share/views/public/plugins/semantic-ui/dist/components/site.js +8 -8
  142. data/share/views/public/plugins/semantic-ui/dist/components/site.min.css +6 -7
  143. data/share/views/public/plugins/semantic-ui/dist/components/site.min.js +6 -6
  144. data/share/views/public/plugins/semantic-ui/dist/components/state.js +37 -32
  145. data/share/views/public/plugins/semantic-ui/dist/components/state.min.js +6 -6
  146. data/share/views/public/plugins/semantic-ui/dist/components/statistic.css +268 -94
  147. data/share/views/public/plugins/semantic-ui/dist/components/statistic.min.css +6 -7
  148. data/share/views/public/plugins/semantic-ui/dist/components/step.css +348 -102
  149. data/share/views/public/plugins/semantic-ui/dist/components/step.min.css +6 -7
  150. data/share/views/public/plugins/semantic-ui/dist/components/sticky.css +7 -8
  151. data/share/views/public/plugins/semantic-ui/dist/components/sticky.js +222 -108
  152. data/share/views/public/plugins/semantic-ui/dist/components/sticky.min.css +6 -7
  153. data/share/views/public/plugins/semantic-ui/dist/components/sticky.min.js +6 -6
  154. data/share/views/public/plugins/semantic-ui/dist/components/tab.css +6 -7
  155. data/share/views/public/plugins/semantic-ui/dist/components/tab.js +268 -172
  156. data/share/views/public/plugins/semantic-ui/dist/components/tab.min.css +6 -7
  157. data/share/views/public/plugins/semantic-ui/dist/components/tab.min.js +6 -6
  158. data/share/views/public/plugins/semantic-ui/dist/components/table.css +372 -201
  159. data/share/views/public/plugins/semantic-ui/dist/components/table.min.css +6 -7
  160. data/share/views/public/plugins/semantic-ui/dist/components/transition.css +1546 -557
  161. data/share/views/public/plugins/semantic-ui/dist/components/transition.js +355 -210
  162. data/share/views/public/plugins/semantic-ui/dist/components/transition.min.css +6 -7
  163. data/share/views/public/plugins/semantic-ui/dist/components/transition.min.js +6 -6
  164. data/share/views/public/plugins/semantic-ui/dist/components/video.css +19 -20
  165. data/share/views/public/plugins/semantic-ui/dist/components/video.js +16 -23
  166. data/share/views/public/plugins/semantic-ui/dist/components/video.min.css +5 -6
  167. data/share/views/public/plugins/semantic-ui/dist/components/video.min.js +6 -6
  168. data/share/views/public/plugins/semantic-ui/dist/components/visibility.js +423 -161
  169. data/share/views/public/plugins/semantic-ui/dist/components/visibility.min.js +6 -6
  170. data/share/views/public/plugins/semantic-ui/dist/components/visit.js +18 -14
  171. data/share/views/public/plugins/semantic-ui/dist/components/visit.min.js +6 -6
  172. data/share/views/public/plugins/semantic-ui/dist/semantic.css +24827 -17141
  173. data/share/views/public/plugins/semantic-ui/dist/semantic.js +15072 -11354
  174. data/share/views/public/plugins/semantic-ui/dist/semantic.min.css +2 -2
  175. data/share/views/public/plugins/semantic-ui/dist/semantic.min.js +10 -8
  176. data/share/views/public/plugins/semantic-ui/dist/themes/default/assets/fonts/icons.eot +0 -0
  177. data/share/views/public/plugins/semantic-ui/dist/themes/default/assets/fonts/icons.otf +0 -0
  178. data/share/views/public/plugins/semantic-ui/dist/themes/default/assets/fonts/icons.svg +526 -465
  179. data/share/views/public/plugins/semantic-ui/dist/themes/default/assets/fonts/icons.ttf +0 -0
  180. data/share/views/public/plugins/semantic-ui/dist/themes/default/assets/fonts/icons.woff +0 -0
  181. data/share/views/public/plugins/semantic-ui/dist/themes/default/assets/fonts/icons.woff2 +0 -0
  182. data/share/views/public/plugins/semantic-ui/dist/themes/default/assets/images/flags.png +0 -0
  183. data/share/views/public/plugins/semantic-ui/examples/assets/images/avatar/nan.jpg +0 -0
  184. data/share/views/public/plugins/semantic-ui/examples/assets/images/avatar/tom.jpg +0 -0
  185. data/share/views/public/plugins/semantic-ui/examples/assets/images/bg.jpg +0 -0
  186. data/share/views/public/plugins/semantic-ui/examples/assets/images/logo.png +0 -0
  187. data/share/views/public/plugins/semantic-ui/examples/{images → assets/images}/wireframe/centered-paragraph.png +0 -0
  188. data/share/views/public/plugins/semantic-ui/examples/{images → assets/images}/wireframe/image-square.png +0 -0
  189. data/share/views/public/plugins/semantic-ui/examples/{images → assets/images}/wireframe/image-text.png +0 -0
  190. data/share/views/public/plugins/semantic-ui/examples/{images → assets/images}/wireframe/image.png +0 -0
  191. data/share/views/public/plugins/semantic-ui/examples/{images → assets/images}/wireframe/media-paragraph-alt.png +0 -0
  192. data/share/views/public/plugins/semantic-ui/examples/{images → assets/images}/wireframe/media-paragraph.png +0 -0
  193. data/share/views/public/plugins/semantic-ui/examples/{images → assets/images}/wireframe/paragraph.png +0 -0
  194. data/share/views/public/plugins/semantic-ui/examples/{images → assets/images}/wireframe/short-paragraph.png +0 -0
  195. data/share/views/public/plugins/semantic-ui/examples/{images → assets/images}/wireframe/square-image.png +0 -0
  196. data/share/views/public/plugins/semantic-ui/examples/{images → assets/images}/wireframe/text-image.png +0 -0
  197. data/share/views/public/plugins/semantic-ui/examples/{images → assets/images}/wireframe/white-image.png +0 -0
  198. data/share/views/public/plugins/semantic-ui/examples/assets/library/iframe-content.js +707 -0
  199. data/share/views/public/plugins/semantic-ui/examples/assets/library/iframe.js +642 -0
  200. data/share/views/public/plugins/semantic-ui/examples/assets/library/jquery.min.js +4 -0
  201. data/share/views/public/plugins/semantic-ui/examples/assets/show-examples.js +15 -0
  202. data/share/views/public/plugins/semantic-ui/examples/bootstrap.html +453 -0
  203. data/share/views/public/plugins/semantic-ui/examples/components/button.html +222 -0
  204. data/share/views/public/plugins/semantic-ui/examples/components/card.html +313 -0
  205. data/share/views/public/plugins/semantic-ui/examples/components/input.html +159 -0
  206. data/share/views/public/plugins/semantic-ui/examples/components/menu.html +183 -0
  207. data/share/views/public/plugins/semantic-ui/examples/components/site.html +74 -0
  208. data/share/views/public/plugins/semantic-ui/examples/components/table.html +471 -0
  209. data/share/views/public/plugins/semantic-ui/examples/fixed.html +137 -0
  210. data/share/views/public/plugins/semantic-ui/examples/grid.html +366 -1397
  211. data/share/views/public/plugins/semantic-ui/examples/homepage.html +249 -268
  212. data/share/views/public/plugins/semantic-ui/examples/login.html +125 -0
  213. data/share/views/public/plugins/semantic-ui/examples/responsive.html +689 -0
  214. data/share/views/public/plugins/semantic-ui/examples/sticky.html +230 -0
  215. data/share/views/public/plugins/semantic-ui/examples/theming.html +88 -0
  216. data/share/views/public/plugins/semantic-ui/gulpfile.js +47 -1082
  217. data/share/views/public/plugins/semantic-ui/karma.conf.js +0 -0
  218. data/share/views/public/plugins/semantic-ui/logo.png +0 -0
  219. data/share/views/public/plugins/semantic-ui/package.json +70 -36
  220. data/share/views/public/plugins/semantic-ui/semantic.json.example +4 -1
  221. data/share/views/public/plugins/semantic-ui/src/README.md +127 -0
  222. data/share/views/public/plugins/semantic-ui/src/_site/collections/breadcrumb.overrides +0 -0
  223. data/share/views/public/plugins/semantic-ui/src/_site/collections/breadcrumb.variables +0 -0
  224. data/share/views/public/plugins/semantic-ui/src/_site/collections/form.overrides +0 -0
  225. data/share/views/public/plugins/semantic-ui/src/_site/collections/grid.overrides +0 -0
  226. data/share/views/public/plugins/semantic-ui/src/_site/collections/menu.overrides +0 -0
  227. data/share/views/public/plugins/semantic-ui/src/_site/collections/table.overrides +0 -0
  228. data/share/views/public/plugins/semantic-ui/src/_site/elements/button.overrides +0 -0
  229. data/share/views/public/plugins/semantic-ui/src/_site/{modules/video.overrides → elements/container.overrides} +0 -0
  230. data/share/views/public/plugins/semantic-ui/src/_site/elements/container.variables +3 -0
  231. data/share/views/public/plugins/semantic-ui/src/_site/elements/divider.overrides +0 -0
  232. data/share/views/public/plugins/semantic-ui/src/_site/elements/flag.overrides +0 -0
  233. data/share/views/public/plugins/semantic-ui/src/_site/elements/header.overrides +0 -0
  234. data/share/views/public/plugins/semantic-ui/src/_site/elements/icon.overrides +0 -0
  235. data/share/views/public/plugins/semantic-ui/src/_site/elements/image.overrides +0 -0
  236. data/share/views/public/plugins/semantic-ui/src/_site/elements/input.overrides +0 -0
  237. data/share/views/public/plugins/semantic-ui/src/_site/elements/label.overrides +0 -0
  238. data/share/views/public/plugins/semantic-ui/src/_site/elements/loader.overrides +0 -0
  239. data/share/views/public/plugins/semantic-ui/src/_site/elements/rail.overrides +0 -0
  240. data/share/views/public/plugins/semantic-ui/src/_site/elements/reveal.overrides +0 -0
  241. data/share/views/public/plugins/semantic-ui/src/_site/elements/segment.overrides +0 -0
  242. data/share/views/public/plugins/semantic-ui/src/_site/elements/step.overrides +0 -0
  243. data/share/views/public/plugins/semantic-ui/src/_site/globals/reset.overrides +0 -0
  244. data/share/views/public/plugins/semantic-ui/src/_site/globals/site.overrides +0 -0
  245. data/share/views/public/plugins/semantic-ui/src/_site/modules/checkbox.overrides +0 -0
  246. data/share/views/public/plugins/semantic-ui/src/_site/modules/embed.overrides +3 -0
  247. data/share/views/public/plugins/semantic-ui/src/_site/modules/{video.variables → embed.variables} +0 -0
  248. data/share/views/public/plugins/semantic-ui/src/_site/modules/modal.overrides +0 -0
  249. data/share/views/public/plugins/semantic-ui/src/_site/modules/modal.variables +0 -0
  250. data/share/views/public/plugins/semantic-ui/src/_site/modules/progress.overrides +0 -0
  251. data/share/views/public/plugins/semantic-ui/src/_site/modules/rating.overrides +0 -0
  252. data/share/views/public/plugins/semantic-ui/src/_site/modules/rating.variables +0 -0
  253. data/share/views/public/plugins/semantic-ui/src/_site/modules/search.overrides +0 -0
  254. data/share/views/public/plugins/semantic-ui/src/_site/modules/search.variables +0 -0
  255. data/share/views/public/plugins/semantic-ui/src/_site/modules/sidebar.overrides +0 -0
  256. data/share/views/public/plugins/semantic-ui/src/_site/modules/sidebar.variables +0 -0
  257. data/share/views/public/plugins/semantic-ui/src/_site/modules/sticky.overrides +0 -0
  258. data/share/views/public/plugins/semantic-ui/src/_site/modules/sticky.variables +0 -0
  259. data/share/views/public/plugins/semantic-ui/src/_site/modules/transition.overrides +0 -0
  260. data/share/views/public/plugins/semantic-ui/src/definitions/behaviors/api.js +428 -190
  261. data/share/views/public/plugins/semantic-ui/src/definitions/behaviors/colorize.js +6 -4
  262. data/share/views/public/plugins/semantic-ui/src/definitions/behaviors/form.js +654 -193
  263. data/share/views/public/plugins/semantic-ui/src/definitions/behaviors/state.js +37 -32
  264. data/share/views/public/plugins/semantic-ui/src/definitions/behaviors/visibility.js +423 -161
  265. data/share/views/public/plugins/semantic-ui/src/definitions/behaviors/visit.js +18 -14
  266. data/share/views/public/plugins/semantic-ui/src/definitions/collections/breadcrumb.less +7 -6
  267. data/share/views/public/plugins/semantic-ui/src/definitions/collections/form.less +243 -103
  268. data/share/views/public/plugins/semantic-ui/src/definitions/collections/grid.less +522 -430
  269. data/share/views/public/plugins/semantic-ui/src/definitions/collections/menu.less +872 -640
  270. data/share/views/public/plugins/semantic-ui/src/definitions/collections/message.less +97 -79
  271. data/share/views/public/plugins/semantic-ui/src/definitions/collections/table.less +314 -132
  272. data/share/views/public/plugins/semantic-ui/src/definitions/elements/button.less +1300 -480
  273. data/share/views/public/plugins/semantic-ui/src/definitions/elements/container.less +125 -0
  274. data/share/views/public/plugins/semantic-ui/src/definitions/elements/divider.less +36 -37
  275. data/share/views/public/plugins/semantic-ui/src/definitions/elements/flag.less +12 -5
  276. data/share/views/public/plugins/semantic-ui/src/definitions/elements/header.less +308 -157
  277. data/share/views/public/plugins/semantic-ui/src/definitions/elements/icon.less +207 -106
  278. data/share/views/public/plugins/semantic-ui/src/definitions/elements/image.less +71 -13
  279. data/share/views/public/plugins/semantic-ui/src/definitions/elements/input.less +127 -104
  280. data/share/views/public/plugins/semantic-ui/src/definitions/elements/label.less +454 -268
  281. data/share/views/public/plugins/semantic-ui/src/definitions/elements/list.less +127 -96
  282. data/share/views/public/plugins/semantic-ui/src/definitions/elements/loader.less +13 -6
  283. data/share/views/public/plugins/semantic-ui/src/definitions/elements/rail.less +40 -31
  284. data/share/views/public/plugins/semantic-ui/src/definitions/elements/reveal.less +31 -15
  285. data/share/views/public/plugins/semantic-ui/src/definitions/elements/segment.less +265 -140
  286. data/share/views/public/plugins/semantic-ui/src/definitions/elements/step.less +243 -67
  287. data/share/views/public/plugins/semantic-ui/src/definitions/globals/reset.less +8 -6
  288. data/share/views/public/plugins/semantic-ui/src/definitions/globals/site.js +8 -8
  289. data/share/views/public/plugins/semantic-ui/src/definitions/globals/site.less +44 -13
  290. data/share/views/public/plugins/semantic-ui/src/definitions/modules/accordion.js +182 -94
  291. data/share/views/public/plugins/semantic-ui/src/definitions/modules/accordion.less +13 -9
  292. data/share/views/public/plugins/semantic-ui/src/definitions/modules/checkbox.js +348 -111
  293. data/share/views/public/plugins/semantic-ui/src/definitions/modules/checkbox.less +196 -96
  294. data/share/views/public/plugins/semantic-ui/src/definitions/modules/dimmer.js +89 -48
  295. data/share/views/public/plugins/semantic-ui/src/definitions/modules/dimmer.less +30 -20
  296. data/share/views/public/plugins/semantic-ui/src/definitions/modules/dropdown.js +2263 -536
  297. data/share/views/public/plugins/semantic-ui/src/definitions/modules/dropdown.less +498 -97
  298. data/share/views/public/plugins/semantic-ui/src/definitions/modules/embed.js +662 -0
  299. data/share/views/public/plugins/semantic-ui/src/definitions/modules/embed.less +164 -0
  300. data/share/views/public/plugins/semantic-ui/src/definitions/modules/modal.js +280 -202
  301. data/share/views/public/plugins/semantic-ui/src/definitions/modules/modal.less +91 -47
  302. data/share/views/public/plugins/semantic-ui/src/definitions/modules/nag.js +10 -11
  303. data/share/views/public/plugins/semantic-ui/src/definitions/modules/nag.less +6 -6
  304. data/share/views/public/plugins/semantic-ui/src/definitions/modules/popup.js +473 -233
  305. data/share/views/public/plugins/semantic-ui/src/definitions/modules/popup.less +55 -13
  306. data/share/views/public/plugins/semantic-ui/src/definitions/modules/progress.js +252 -111
  307. data/share/views/public/plugins/semantic-ui/src/definitions/modules/progress.less +182 -107
  308. data/share/views/public/plugins/semantic-ui/src/definitions/modules/rating.js +85 -61
  309. data/share/views/public/plugins/semantic-ui/src/definitions/modules/rating.less +64 -70
  310. data/share/views/public/plugins/semantic-ui/src/definitions/modules/search.js +688 -296
  311. data/share/views/public/plugins/semantic-ui/src/definitions/modules/search.less +60 -14
  312. data/share/views/public/plugins/semantic-ui/src/definitions/modules/shape.js +102 -56
  313. data/share/views/public/plugins/semantic-ui/src/definitions/modules/shape.less +10 -11
  314. data/share/views/public/plugins/semantic-ui/src/definitions/modules/sidebar.js +296 -249
  315. data/share/views/public/plugins/semantic-ui/src/definitions/modules/sidebar.less +140 -44
  316. data/share/views/public/plugins/semantic-ui/src/definitions/modules/sticky.js +222 -108
  317. data/share/views/public/plugins/semantic-ui/src/definitions/modules/sticky.less +6 -5
  318. data/share/views/public/plugins/semantic-ui/src/definitions/modules/tab.js +268 -172
  319. data/share/views/public/plugins/semantic-ui/src/definitions/modules/tab.less +6 -5
  320. data/share/views/public/plugins/semantic-ui/src/definitions/modules/transition.js +355 -210
  321. data/share/views/public/plugins/semantic-ui/src/definitions/modules/transition.less +8 -18
  322. data/share/views/public/plugins/semantic-ui/src/definitions/views/ad.less +6 -4
  323. data/share/views/public/plugins/semantic-ui/src/definitions/views/card.less +385 -92
  324. data/share/views/public/plugins/semantic-ui/src/definitions/views/comment.less +6 -6
  325. data/share/views/public/plugins/semantic-ui/src/definitions/views/feed.less +19 -12
  326. data/share/views/public/plugins/semantic-ui/src/definitions/views/item.less +18 -19
  327. data/share/views/public/plugins/semantic-ui/src/definitions/views/statistic.less +232 -90
  328. data/share/views/public/plugins/semantic-ui/src/semantic.less +66 -0
  329. data/share/views/public/plugins/semantic-ui/src/theme.config.example +19 -23
  330. data/share/views/public/plugins/semantic-ui/src/theme.less +24 -17
  331. data/share/views/public/plugins/semantic-ui/src/themes/amazon/elements/button.overrides +5 -5
  332. data/share/views/public/plugins/semantic-ui/src/themes/amazon/elements/button.variables +5 -4
  333. data/share/views/public/plugins/semantic-ui/src/themes/basic/collections/table.variables +1 -0
  334. data/share/views/public/plugins/semantic-ui/src/themes/basic/elements/icon.overrides +156 -156
  335. data/share/views/public/plugins/semantic-ui/src/themes/basic/elements/icon.variables +7 -0
  336. data/share/views/public/plugins/semantic-ui/src/themes/basic/views/card.variables +7 -6
  337. data/share/views/public/plugins/semantic-ui/src/themes/bookish/elements/header.variables +4 -4
  338. data/share/views/public/plugins/semantic-ui/src/themes/bootstrap3/elements/button.variables +1 -1
  339. data/share/views/public/plugins/semantic-ui/src/themes/chubby/collections/form.overrides +8 -0
  340. data/share/views/public/plugins/semantic-ui/src/themes/chubby/collections/menu.overrides +0 -0
  341. data/share/views/public/plugins/semantic-ui/src/themes/chubby/collections/menu.variables +40 -0
  342. data/share/views/public/plugins/semantic-ui/src/themes/chubby/elements/header.variables +4 -4
  343. data/share/views/public/plugins/semantic-ui/src/themes/classic/modules/progress.variables +1 -0
  344. data/share/views/public/plugins/semantic-ui/src/themes/classic/views/card.overrides +1 -1
  345. data/share/views/public/plugins/semantic-ui/src/themes/colored/modules/checkbox.overrides +0 -0
  346. data/share/views/public/plugins/semantic-ui/src/themes/colored/modules/checkbox.variables +17 -0
  347. data/share/views/public/plugins/semantic-ui/src/themes/default/assets/fonts/icons.eot +0 -0
  348. data/share/views/public/plugins/semantic-ui/src/themes/default/assets/fonts/icons.svg +526 -465
  349. data/share/views/public/plugins/semantic-ui/src/themes/default/assets/fonts/icons.ttf +0 -0
  350. data/share/views/public/plugins/semantic-ui/src/themes/default/assets/fonts/icons.woff +0 -0
  351. data/share/views/public/plugins/semantic-ui/src/themes/default/assets/fonts/icons.woff2 +0 -0
  352. data/share/views/public/plugins/semantic-ui/src/themes/default/assets/images/flags.png +0 -0
  353. data/share/views/public/plugins/semantic-ui/src/themes/default/collections/breadcrumb.overrides +0 -0
  354. data/share/views/public/plugins/semantic-ui/src/themes/default/collections/breadcrumb.variables +7 -17
  355. data/share/views/public/plugins/semantic-ui/src/themes/default/collections/form.overrides +0 -0
  356. data/share/views/public/plugins/semantic-ui/src/themes/default/collections/form.variables +39 -39
  357. data/share/views/public/plugins/semantic-ui/src/themes/default/collections/grid.overrides +0 -0
  358. data/share/views/public/plugins/semantic-ui/src/themes/default/collections/grid.variables +34 -29
  359. data/share/views/public/plugins/semantic-ui/src/themes/default/collections/menu.overrides +0 -0
  360. data/share/views/public/plugins/semantic-ui/src/themes/default/collections/menu.variables +265 -157
  361. data/share/views/public/plugins/semantic-ui/src/themes/default/collections/message.overrides +0 -0
  362. data/share/views/public/plugins/semantic-ui/src/themes/default/collections/message.variables +42 -19
  363. data/share/views/public/plugins/semantic-ui/src/themes/default/collections/table.overrides +0 -3
  364. data/share/views/public/plugins/semantic-ui/src/themes/default/collections/table.variables +64 -60
  365. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/button.overrides +0 -0
  366. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/button.variables +110 -36
  367. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/container.overrides +3 -0
  368. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/container.variables +45 -0
  369. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/divider.overrides +15 -0
  370. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/divider.variables +3 -4
  371. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/flag.overrides +0 -1
  372. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/header.overrides +0 -0
  373. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/header.variables +59 -34
  374. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/icon.overrides +142 -38
  375. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/icon.variables +30 -4
  376. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/image.overrides +0 -0
  377. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/image.variables +5 -3
  378. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/input.overrides +0 -0
  379. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/input.variables +12 -26
  380. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/label.overrides +0 -0
  381. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/label.variables +101 -38
  382. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/list.overrides +0 -0
  383. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/list.variables +53 -34
  384. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/loader.overrides +0 -0
  385. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/loader.variables +9 -10
  386. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/rail.overrides +0 -0
  387. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/rail.variables +15 -5
  388. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/reveal.overrides +0 -0
  389. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/reveal.variables +6 -4
  390. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/segment.overrides +0 -0
  391. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/segment.variables +66 -28
  392. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/step.overrides +0 -0
  393. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/step.variables +64 -30
  394. data/share/views/public/plugins/semantic-ui/src/themes/default/globals/reset.overrides +0 -0
  395. data/share/views/public/plugins/semantic-ui/src/themes/default/globals/site.variables +519 -331
  396. data/share/views/public/plugins/semantic-ui/src/themes/default/modules/accordion.overrides +0 -0
  397. data/share/views/public/plugins/semantic-ui/src/themes/default/modules/accordion.variables +10 -11
  398. data/share/views/public/plugins/semantic-ui/src/themes/default/modules/chatroom.overrides +0 -0
  399. data/share/views/public/plugins/semantic-ui/src/themes/default/modules/checkbox.overrides +19 -16
  400. data/share/views/public/plugins/semantic-ui/src/themes/default/modules/checkbox.variables +72 -43
  401. data/share/views/public/plugins/semantic-ui/src/themes/default/modules/dimmer.overrides +0 -0
  402. data/share/views/public/plugins/semantic-ui/src/themes/default/modules/dimmer.variables +20 -10
  403. data/share/views/public/plugins/semantic-ui/src/themes/default/modules/dropdown.overrides +5 -0
  404. data/share/views/public/plugins/semantic-ui/src/themes/default/modules/dropdown.variables +188 -63
  405. data/share/views/public/plugins/semantic-ui/src/themes/default/modules/{video.overrides → embed.overrides} +0 -0
  406. data/share/views/public/plugins/semantic-ui/src/themes/default/modules/embed.variables +53 -0
  407. data/share/views/public/plugins/semantic-ui/src/themes/default/modules/modal.overrides +0 -0
  408. data/share/views/public/plugins/semantic-ui/src/themes/default/modules/modal.variables +26 -22
  409. data/share/views/public/plugins/semantic-ui/src/themes/default/modules/nag.overrides +0 -0
  410. data/share/views/public/plugins/semantic-ui/src/themes/default/modules/popup.overrides +0 -0
  411. data/share/views/public/plugins/semantic-ui/src/themes/default/modules/popup.variables +6 -12
  412. data/share/views/public/plugins/semantic-ui/src/themes/default/modules/progress.variables +14 -8
  413. data/share/views/public/plugins/semantic-ui/src/themes/default/modules/rating.overrides +0 -1
  414. data/share/views/public/plugins/semantic-ui/src/themes/default/modules/rating.variables +72 -34
  415. data/share/views/public/plugins/semantic-ui/src/themes/default/modules/search.overrides +0 -0
  416. data/share/views/public/plugins/semantic-ui/src/themes/default/modules/search.variables +36 -34
  417. data/share/views/public/plugins/semantic-ui/src/themes/default/modules/shape.overrides +0 -0
  418. data/share/views/public/plugins/semantic-ui/src/themes/default/modules/shape.variables +7 -2
  419. data/share/views/public/plugins/semantic-ui/src/themes/default/modules/sidebar.overrides +0 -0
  420. data/share/views/public/plugins/semantic-ui/src/themes/default/modules/sidebar.variables +19 -13
  421. data/share/views/public/plugins/semantic-ui/src/themes/default/modules/sticky.overrides +0 -0
  422. data/share/views/public/plugins/semantic-ui/src/themes/default/modules/sticky.variables +2 -7
  423. data/share/views/public/plugins/semantic-ui/src/themes/default/modules/tab.variables +1 -3
  424. data/share/views/public/plugins/semantic-ui/src/themes/default/modules/transition.overrides +689 -224
  425. data/share/views/public/plugins/semantic-ui/src/themes/default/modules/transition.variables +1 -1
  426. data/share/views/public/plugins/semantic-ui/src/themes/default/views/ad.variables +2 -2
  427. data/share/views/public/plugins/semantic-ui/src/themes/default/views/card.variables +61 -37
  428. data/share/views/public/plugins/semantic-ui/src/themes/default/views/comment.overrides +0 -0
  429. data/share/views/public/plugins/semantic-ui/src/themes/default/views/feed.overrides +0 -0
  430. data/share/views/public/plugins/semantic-ui/src/themes/default/views/feed.variables +15 -23
  431. data/share/views/public/plugins/semantic-ui/src/themes/default/views/item.overrides +0 -0
  432. data/share/views/public/plugins/semantic-ui/src/themes/default/views/item.variables +17 -15
  433. data/share/views/public/plugins/semantic-ui/src/themes/default/views/statistic.overrides +0 -0
  434. data/share/views/public/plugins/semantic-ui/src/themes/default/views/statistic.variables +25 -24
  435. data/share/views/public/plugins/semantic-ui/src/themes/fixed-width/collections/grid.variables +1 -3
  436. data/share/views/public/plugins/semantic-ui/src/themes/flat/collections/form.overrides +4 -0
  437. data/share/views/public/plugins/semantic-ui/src/themes/flat/collections/form.variables +1 -2
  438. data/share/views/public/plugins/semantic-ui/src/themes/flat/globals/site.variables +1 -0
  439. data/share/views/public/plugins/semantic-ui/src/themes/github/collections/form.variables +1 -1
  440. data/share/views/public/plugins/semantic-ui/src/themes/github/collections/menu.variables +10 -15
  441. data/share/views/public/plugins/semantic-ui/src/themes/github/elements/button.variables +2 -2
  442. data/share/views/public/plugins/semantic-ui/src/themes/github/elements/step.variables +2 -2
  443. data/share/views/public/plugins/semantic-ui/src/themes/instagram/views/card.overrides +12 -0
  444. data/share/views/public/plugins/semantic-ui/src/themes/instagram/views/card.variables +23 -0
  445. data/share/views/public/plugins/semantic-ui/src/themes/material/collections/menu.overrides +1 -0
  446. data/share/views/public/plugins/semantic-ui/src/themes/material/collections/menu.variables +10 -0
  447. data/share/views/public/plugins/semantic-ui/src/themes/material/elements/button.overrides +4 -4
  448. data/share/views/public/plugins/semantic-ui/src/themes/material/elements/button.variables +14 -6
  449. data/share/views/public/plugins/semantic-ui/src/themes/material/globals/site.variables +3 -2
  450. data/share/views/public/plugins/semantic-ui/src/themes/material/modules/dropdown.overrides +5 -0
  451. data/share/views/public/plugins/semantic-ui/src/themes/material/modules/dropdown.variables +20 -0
  452. data/share/views/public/plugins/semantic-ui/src/themes/raised/elements/button.variables +5 -5
  453. data/share/views/public/plugins/semantic-ui/src/themes/round/elements/button.variables +1 -1
  454. data/share/views/public/plugins/semantic-ui/src/themes/rtl/globals/site.overrides +6 -0
  455. data/share/views/public/plugins/semantic-ui/src/themes/rtl/globals/site.variables +14 -0
  456. data/share/views/public/plugins/semantic-ui/src/themes/timeline/views/feed.overrides +4 -12
  457. data/share/views/public/plugins/semantic-ui/src/themes/timeline/views/feed.variables +3 -7
  458. data/share/views/public/plugins/semantic-ui/tasks/README.md +17 -0
  459. data/share/views/public/plugins/semantic-ui/tasks/admin/components/create.js +332 -0
  460. data/share/views/public/plugins/semantic-ui/tasks/admin/components/init.js +170 -0
  461. data/share/views/public/plugins/semantic-ui/tasks/admin/components/update.js +184 -0
  462. data/share/views/public/plugins/semantic-ui/tasks/admin/distributions/create.js +219 -0
  463. data/share/views/public/plugins/semantic-ui/tasks/admin/distributions/init.js +170 -0
  464. data/share/views/public/plugins/semantic-ui/tasks/admin/distributions/update.js +182 -0
  465. data/share/views/public/plugins/semantic-ui/tasks/admin/publish.js +25 -0
  466. data/share/views/public/plugins/semantic-ui/tasks/admin/register.js +55 -0
  467. data/share/views/public/plugins/semantic-ui/tasks/admin/release.js +20 -76
  468. data/share/views/public/plugins/semantic-ui/tasks/build.js +37 -0
  469. data/share/views/public/plugins/semantic-ui/tasks/build/assets.js +35 -0
  470. data/share/views/public/plugins/semantic-ui/tasks/build/css.js +105 -0
  471. data/share/views/public/plugins/semantic-ui/tasks/build/javascript.js +77 -0
  472. data/share/views/public/plugins/semantic-ui/tasks/check-install.js +28 -0
  473. data/share/views/public/plugins/semantic-ui/tasks/clean.js +14 -0
  474. data/share/views/public/plugins/semantic-ui/tasks/collections/README.md +16 -0
  475. data/share/views/public/plugins/semantic-ui/tasks/collections/admin.js +49 -0
  476. data/share/views/public/plugins/semantic-ui/tasks/collections/internal.js +214 -0
  477. data/share/views/public/plugins/semantic-ui/tasks/config/admin/github.js +38 -0
  478. data/share/views/public/plugins/semantic-ui/tasks/{admin → config/admin}/oauth.example.js +5 -0
  479. data/share/views/public/plugins/semantic-ui/tasks/config/admin/release.js +110 -0
  480. data/share/views/public/plugins/semantic-ui/tasks/{admin → config/admin}/templates/README.md +6 -0
  481. data/share/views/public/plugins/semantic-ui/tasks/{admin → config/admin}/templates/bower.json +0 -0
  482. data/share/views/public/plugins/semantic-ui/tasks/config/admin/templates/component-package.js +14 -0
  483. data/share/views/public/plugins/semantic-ui/tasks/{admin → config/admin}/templates/composer.json +0 -0
  484. data/share/views/public/plugins/semantic-ui/tasks/config/admin/templates/css-package.js +34 -0
  485. data/share/views/public/plugins/semantic-ui/tasks/config/admin/templates/less-package.js +21 -0
  486. data/share/views/public/plugins/semantic-ui/tasks/{admin → config/admin}/templates/package.json +0 -0
  487. data/share/views/public/plugins/semantic-ui/tasks/config/defaults.js +117 -0
  488. data/share/views/public/plugins/semantic-ui/tasks/config/docs.js +32 -0
  489. data/share/views/public/plugins/semantic-ui/tasks/config/npm/gulpfile.js +72 -0
  490. data/share/views/public/plugins/semantic-ui/tasks/config/project/config.js +142 -0
  491. data/share/views/public/plugins/semantic-ui/tasks/config/project/install.js +756 -0
  492. data/share/views/public/plugins/semantic-ui/tasks/config/project/release.js +61 -0
  493. data/share/views/public/plugins/semantic-ui/tasks/config/tasks.js +160 -0
  494. data/share/views/public/plugins/semantic-ui/tasks/config/user.js +58 -0
  495. data/share/views/public/plugins/semantic-ui/tasks/docs/build.js +189 -0
  496. data/share/views/public/plugins/semantic-ui/tasks/docs/metadata.js +137 -0
  497. data/share/views/public/plugins/semantic-ui/tasks/docs/serve.js +255 -0
  498. data/share/views/public/plugins/semantic-ui/tasks/install.js +397 -0
  499. data/share/views/public/plugins/semantic-ui/tasks/rtl/build.js +132 -0
  500. data/share/views/public/plugins/semantic-ui/tasks/rtl/watch.js +221 -0
  501. data/share/views/public/plugins/semantic-ui/tasks/version.js +11 -0
  502. data/share/views/public/plugins/semantic-ui/tasks/watch.js +228 -0
  503. data/share/views/public/plugins/semantic-ui/test/coverage/PhantomJS 1.9.2 (Linux)/index.html b/data/share/views/public/plugins/semantic-ui/test/coverage/PhantomJS 1.9.2 → (Linux)/index.html +0 -0
  504. data/share/views/public/plugins/semantic-ui/test/coverage/PhantomJS 1.9.2 (Linux)/prettify.css b/data/share/views/public/plugins/semantic-ui/test/coverage/PhantomJS 1.9.2 → (Linux)/prettify.css +0 -0
  505. data/share/views/public/plugins/semantic-ui/test/coverage/PhantomJS 1.9.2 (Linux)/prettify.js b/data/share/views/public/plugins/semantic-ui/test/coverage/PhantomJS 1.9.2 → (Linux)/prettify.js +0 -0
  506. data/share/views/public/plugins/semantic-ui/test/coverage/coverage-PhantomJS 1.9.2 (Linux)-20131014_012621.json b/data/share/views/public/plugins/semantic-ui/test/coverage/coverage-PhantomJS 1.9.2 → (Linux)-20131014_012621.json +0 -0
  507. data/share/views/public/plugins/semantic-ui/test/coverage/coverage-PhantomJS 1.9.2 (Linux)-20131014_012811.json b/data/share/views/public/plugins/semantic-ui/test/coverage/coverage-PhantomJS 1.9.2 → (Linux)-20131014_012811.json +0 -0
  508. data/share/views/public/plugins/semantic-ui/test/fixtures/accordion.html +0 -0
  509. data/share/views/public/plugins/semantic-ui/test/fixtures/checkbox.html +0 -0
  510. data/share/views/public/plugins/semantic-ui/test/fixtures/dropdown.html +0 -0
  511. data/share/views/public/plugins/semantic-ui/test/fixtures/modal.html +0 -0
  512. data/share/views/public/plugins/semantic-ui/test/fixtures/popup.html +0 -0
  513. data/share/views/public/plugins/semantic-ui/test/fixtures/rating.html +0 -0
  514. data/share/views/public/plugins/semantic-ui/test/fixtures/shape.html +0 -0
  515. data/share/views/public/plugins/semantic-ui/test/fixtures/sidebar.html +0 -0
  516. data/share/views/public/plugins/semantic-ui/test/fixtures/tab.html +0 -0
  517. data/share/views/public/plugins/semantic-ui/test/fixtures/transition.html +0 -0
  518. data/share/views/public/plugins/semantic-ui/test/fixtures/video.html +0 -0
  519. data/share/views/public/plugins/semantic-ui/test/helpers/jasmine-clog.js +0 -0
  520. data/share/views/public/plugins/semantic-ui/test/helpers/jasmine-jquery.js +0 -0
  521. data/share/views/public/plugins/semantic-ui/test/helpers/jasmine-sinon.js +0 -0
  522. data/share/views/public/plugins/semantic-ui/test/helpers/jquery-events.js +0 -0
  523. data/share/views/public/plugins/semantic-ui/test/helpers/sinon.js +0 -0
  524. data/share/views/public/plugins/semantic-ui/test/meteor/assets.js +20 -0
  525. data/share/views/public/plugins/semantic-ui/test/meteor/fonts.js +16 -0
  526. data/share/views/public/plugins/semantic-ui/test/modules/accordion.spec.js +0 -0
  527. data/share/views/public/plugins/semantic-ui/test/modules/checkbox.spec.js +0 -0
  528. data/share/views/public/plugins/semantic-ui/test/modules/dropdown.spec.js +0 -0
  529. data/share/views/public/plugins/semantic-ui/test/modules/modal.spec.js +0 -0
  530. data/share/views/public/plugins/semantic-ui/test/modules/module.spec.js +0 -0
  531. data/share/views/public/plugins/semantic-ui/test/modules/popup.spec.js +0 -0
  532. data/share/views/public/plugins/semantic-ui/test/modules/search.spec.js +0 -0
  533. data/share/views/public/plugins/semantic-ui/test/modules/shape.spec.js +0 -0
  534. data/share/views/public/plugins/semantic-ui/test/modules/sidebar.spec.js +0 -0
  535. data/share/views/public/plugins/semantic-ui/test/modules/tab.spec.js +0 -0
  536. data/share/views/public/plugins/semantic-ui/test/modules/transition.spec.js +0 -0
  537. data/share/views/public/plugins/semantic-ui/test/modules/video.spec.js +0 -0
  538. metadata +114 -45
  539. data/share/views/public/js/jquery-ui.js +0 -313
  540. data/share/views/public/plugins/semantic-ui/GETTING-STARTED.md +0 -96
  541. data/share/views/public/plugins/semantic-ui/examples/feed.css +0 -93
  542. data/share/views/public/plugins/semantic-ui/examples/feed.html +0 -174
  543. data/share/views/public/plugins/semantic-ui/examples/feed.js +0 -23
  544. data/share/views/public/plugins/semantic-ui/examples/grid.css +0 -102
  545. data/share/views/public/plugins/semantic-ui/examples/homepage.css +0 -134
  546. data/share/views/public/plugins/semantic-ui/examples/homepage.js +0 -57
  547. data/share/views/public/plugins/semantic-ui/examples/images/bg.jpg +0 -0
  548. data/share/views/public/plugins/semantic-ui/examples/images/cat.png +0 -0
  549. data/share/views/public/plugins/semantic-ui/examples/kitchensink.css +0 -49
  550. data/share/views/public/plugins/semantic-ui/examples/kitchensink.html +0 -5454
  551. data/share/views/public/plugins/semantic-ui/src/definitions/modules/video.js +0 -539
  552. data/share/views/public/plugins/semantic-ui/src/definitions/modules/video.less +0 -125
  553. data/share/views/public/plugins/semantic-ui/src/themes/default/assets/fonts/icons.otf +0 -0
  554. data/share/views/public/plugins/semantic-ui/src/themes/default/modules/video.variables +0 -16
  555. data/share/views/public/plugins/semantic-ui/tasks/admin/docs.json +0 -19
  556. data/share/views/public/plugins/semantic-ui/tasks/admin/questions.js +0 -50
  557. data/share/views/public/plugins/semantic-ui/tasks/banner.js +0 -12
  558. data/share/views/public/plugins/semantic-ui/tasks/comments.js +0 -20
  559. data/share/views/public/plugins/semantic-ui/tasks/defaults.js +0 -69
  560. data/share/views/public/plugins/semantic-ui/tasks/gulp-settings.js +0 -51
  561. data/share/views/public/plugins/semantic-ui/tasks/log.js +0 -8
  562. data/share/views/public/plugins/semantic-ui/tasks/questions.js +0 -425
@@ -1,9 +1,9 @@
1
- /*
2
- * # Semantic - Dimmer
1
+ /*!
2
+ * # Semantic UI - Dimmer
3
3
  * http://github.com/semantic-org/semantic-ui/
4
4
  *
5
5
  *
6
- * Copyright 2014 Contributor
6
+ * Copyright 2015 Contributors
7
7
  * Released under the MIT license
8
8
  * http://opensource.org/licenses/MIT
9
9
  *
@@ -11,6 +11,8 @@
11
11
 
12
12
  ;(function ( $, window, document, undefined ) {
13
13
 
14
+ "use strict";
15
+
14
16
  $.fn.dimmer = function(parameters) {
15
17
  var
16
18
  $allModules = $(this),
@@ -58,6 +60,7 @@ $.fn.dimmer = function(parameters) {
58
60
 
59
61
  preinitialize: function() {
60
62
  if( module.is.dimmer() ) {
63
+
61
64
  $dimmable = $module.parent();
62
65
  $dimmer = $module;
63
66
  }
@@ -65,10 +68,10 @@ $.fn.dimmer = function(parameters) {
65
68
  $dimmable = $module;
66
69
  if( module.has.dimmer() ) {
67
70
  if(settings.dimmerName) {
68
- $dimmer = $dimmable.children(selector.dimmer).filter('.' + settings.dimmerName);
71
+ $dimmer = $dimmable.find(selector.dimmer).filter('.' + settings.dimmerName);
69
72
  }
70
73
  else {
71
- $dimmer = $dimmable.children(selector.dimmer);
74
+ $dimmer = $dimmable.find(selector.dimmer);
72
75
  }
73
76
  }
74
77
  else {
@@ -97,8 +100,8 @@ $.fn.dimmer = function(parameters) {
97
100
 
98
101
  if( module.is.closable() ) {
99
102
  module.verbose('Adding dimmer close event', $dimmer);
100
- $dimmer
101
- .on(clickEvent + eventNamespace, module.event.click)
103
+ $dimmable
104
+ .on(clickEvent + eventNamespace, selector.dimmer, module.event.click)
102
105
  ;
103
106
  }
104
107
  module.set.dimmable();
@@ -121,15 +124,12 @@ $.fn.dimmer = function(parameters) {
121
124
  $dimmable
122
125
  .off(eventNamespace)
123
126
  ;
124
- $dimmer
125
- .off(eventNamespace)
126
- ;
127
127
  },
128
128
 
129
129
  event: {
130
130
  click: function(event) {
131
131
  module.verbose('Determining if event occured on dimmer', event);
132
- if( $dimmer.find(event.target).size() === 0 || $(event.target).is(selector.content) ) {
132
+ if( $dimmer.find(event.target).length === 0 || $(event.target).is(selector.content) ) {
133
133
  module.hide();
134
134
  event.stopImmediatePropagation();
135
135
  }
@@ -152,7 +152,7 @@ $.fn.dimmer = function(parameters) {
152
152
  ;
153
153
  if(settings.variation) {
154
154
  module.debug('Creating dimmer with variation', settings.variation);
155
- $element.addClass(className.variation);
155
+ $element.addClass(settings.variation);
156
156
  }
157
157
  if(settings.dimmerName) {
158
158
  module.debug('Creating named dimmer', settings.dimmerName);
@@ -172,8 +172,8 @@ $.fn.dimmer = function(parameters) {
172
172
  module.debug('Showing dimmer', $dimmer, settings);
173
173
  if( (!module.is.dimmed() || module.is.animating()) && module.is.enabled() ) {
174
174
  module.animate.show(callback);
175
- $.proxy(settings.onShow, element)();
176
- $.proxy(settings.onChange, element)();
175
+ settings.onShow.call(element);
176
+ settings.onChange.call(element);
177
177
  }
178
178
  else {
179
179
  module.debug('Dimmer is already shown or disabled');
@@ -188,8 +188,8 @@ $.fn.dimmer = function(parameters) {
188
188
  if( module.is.dimmed() || module.is.animating() ) {
189
189
  module.debug('Hiding dimmer', $dimmer);
190
190
  module.animate.hide(callback);
191
- $.proxy(settings.onHide, element)();
192
- $.proxy(settings.onChange, element)();
191
+ settings.onHide.call(element);
192
+ settings.onChange.call(element);
193
193
  }
194
194
  else {
195
195
  module.debug('Dimmer is not visible');
@@ -213,15 +213,19 @@ $.fn.dimmer = function(parameters) {
213
213
  : function(){}
214
214
  ;
215
215
  if(settings.useCSS && $.fn.transition !== undefined && $dimmer.transition('is supported')) {
216
+ if(settings.opacity !== 'auto') {
217
+ module.set.opacity();
218
+ }
216
219
  $dimmer
217
220
  .transition({
218
- animation : settings.transition + ' in',
221
+ animation : settings.transition + ' in',
219
222
  queue : false,
220
- duration : module.get.duration(),
221
- onStart : function() {
223
+ duration : module.get.duration(),
224
+ useFailSafe : true,
225
+ onStart : function() {
222
226
  module.set.dimmed();
223
227
  },
224
- onComplete : function() {
228
+ onComplete : function() {
225
229
  module.set.active();
226
230
  callback();
227
231
  }
@@ -231,6 +235,9 @@ $.fn.dimmer = function(parameters) {
231
235
  else {
232
236
  module.verbose('Showing dimmer animation with javascript');
233
237
  module.set.dimmed();
238
+ if(settings.opacity == 'auto') {
239
+ settings.opacity = 0.8;
240
+ }
234
241
  $dimmer
235
242
  .stop()
236
243
  .css({
@@ -238,7 +245,7 @@ $.fn.dimmer = function(parameters) {
238
245
  width : '100%',
239
246
  height : '100%'
240
247
  })
241
- .fadeTo(module.get.duration(), 1, function() {
248
+ .fadeTo(module.get.duration(), settings.opacity, function() {
242
249
  $dimmer.removeAttr('style');
243
250
  module.set.active();
244
251
  callback();
@@ -255,13 +262,14 @@ $.fn.dimmer = function(parameters) {
255
262
  module.verbose('Hiding dimmer with css');
256
263
  $dimmer
257
264
  .transition({
258
- animation : settings.transition + ' out',
259
- queue : false,
260
- duration : module.get.duration(),
261
- onStart : function() {
265
+ animation : settings.transition + ' out',
266
+ queue : false,
267
+ duration : module.get.duration(),
268
+ useFailSafe : true,
269
+ onStart : function() {
262
270
  module.remove.dimmed();
263
271
  },
264
- onComplete : function() {
272
+ onComplete : function() {
265
273
  module.remove.active();
266
274
  callback();
267
275
  }
@@ -303,10 +311,10 @@ $.fn.dimmer = function(parameters) {
303
311
  has: {
304
312
  dimmer: function() {
305
313
  if(settings.dimmerName) {
306
- return ($module.children(selector.dimmer).filter('.' + settings.dimmerName).size() > 0);
314
+ return ($module.find(selector.dimmer).filter('.' + settings.dimmerName).length > 0);
307
315
  }
308
316
  else {
309
- return ( $module.children(selector.dimmer).size() > 0 );
317
+ return ( $module.find(selector.dimmer).length > 0 );
310
318
  }
311
319
  }
312
320
  },
@@ -328,10 +336,10 @@ $.fn.dimmer = function(parameters) {
328
336
  return settings.closable;
329
337
  },
330
338
  dimmer: function() {
331
- return $module.is(selector.dimmer);
339
+ return $module.hasClass(className.dimmer);
332
340
  },
333
341
  dimmable: function() {
334
- return $module.is(selector.dimmable);
342
+ return $module.hasClass(className.dimmable);
335
343
  },
336
344
  dimmed: function() {
337
345
  return $dimmable.hasClass(className.dimmed);
@@ -357,6 +365,23 @@ $.fn.dimmer = function(parameters) {
357
365
  },
358
366
 
359
367
  set: {
368
+ opacity: function(opacity) {
369
+ var
370
+ opacity = settings.opacity || opacity,
371
+ color = $dimmer.css('background-color'),
372
+ colorArray = color.split(','),
373
+ isRGBA = (colorArray && colorArray.length == 4)
374
+ ;
375
+ if(isRGBA) {
376
+ colorArray[3] = opacity + ')';
377
+ color = colorArray.join(',');
378
+ }
379
+ else {
380
+ color = 'rgba(0, 0, 0, ' + opacity + ')';
381
+ }
382
+ module.debug('Setting opacity to', opacity);
383
+ $dimmer.css('background-color', color);
384
+ },
360
385
  active: function() {
361
386
  $dimmer.addClass(className.active);
362
387
  },
@@ -457,7 +482,7 @@ $.fn.dimmer = function(parameters) {
457
482
  });
458
483
  }
459
484
  clearTimeout(module.performance.timer);
460
- module.performance.timer = setTimeout(module.performance.display, 100);
485
+ module.performance.timer = setTimeout(module.performance.display, 500);
461
486
  },
462
487
  display: function() {
463
488
  var
@@ -473,8 +498,8 @@ $.fn.dimmer = function(parameters) {
473
498
  if(moduleSelector) {
474
499
  title += ' \'' + moduleSelector + '\'';
475
500
  }
476
- if($allModules.size() > 1) {
477
- title += ' ' + '(' + $allModules.size() + ')';
501
+ if($allModules.length > 1) {
502
+ title += ' ' + '(' + $allModules.length + ')';
478
503
  }
479
504
  if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
480
505
  console.groupCollapsed(title);
@@ -523,6 +548,7 @@ $.fn.dimmer = function(parameters) {
523
548
  return false;
524
549
  }
525
550
  else {
551
+ module.error(error.method, query);
526
552
  return false;
527
553
  }
528
554
  });
@@ -556,7 +582,7 @@ $.fn.dimmer = function(parameters) {
556
582
  }
557
583
  else {
558
584
  if(instance !== undefined) {
559
- module.destroy();
585
+ instance.invoke('destroy');
560
586
  }
561
587
  module.initialize();
562
588
  }
@@ -575,16 +601,31 @@ $.fn.dimmer.settings = {
575
601
  namespace : 'dimmer',
576
602
 
577
603
  debug : false,
578
- verbose : true,
604
+ verbose : false,
579
605
  performance : true,
580
606
 
607
+ // name to distinguish between multiple dimmers in context
581
608
  dimmerName : false,
609
+
610
+ // whether to add a variation type
582
611
  variation : false,
612
+
613
+ // whether to bind close events
583
614
  closable : 'auto',
584
- transition : 'fade',
615
+
616
+ // whether to use css animations
585
617
  useCSS : true,
618
+
619
+ // css animation to use
620
+ transition : 'fade',
621
+
622
+ // event to bind to
586
623
  on : false,
587
624
 
625
+ // overriding opacity value
626
+ opacity : 'auto',
627
+
628
+ // transition durations
588
629
  duration : {
589
630
  show : 500,
590
631
  hide : 500
@@ -598,27 +639,27 @@ $.fn.dimmer.settings = {
598
639
  method : 'The method you called is not defined.'
599
640
  },
600
641
 
601
- selector: {
602
- dimmable : '.dimmable',
603
- dimmer : '.ui.dimmer',
604
- content : '.ui.dimmer > .content, .ui.dimmer > .content > .center'
605
- },
606
-
607
- template: {
608
- dimmer: function() {
609
- return $('<div />').attr('class', 'ui dimmer');
610
- }
611
- },
612
-
613
642
  className : {
614
643
  active : 'active',
615
644
  animating : 'animating',
616
645
  dimmable : 'dimmable',
617
646
  dimmed : 'dimmed',
647
+ dimmer : 'dimmer',
618
648
  disabled : 'disabled',
619
649
  hide : 'hide',
620
650
  pageDimmer : 'page',
621
651
  show : 'show'
652
+ },
653
+
654
+ selector: {
655
+ dimmer : '> .ui.dimmer',
656
+ content : '.ui.dimmer > .content, .ui.dimmer > .content > .center'
657
+ },
658
+
659
+ template: {
660
+ dimmer: function() {
661
+ return $('<div />').attr('class', 'ui dimmer');
662
+ }
622
663
  }
623
664
 
624
665
  };
@@ -1,9 +1,9 @@
1
- /*
2
- * # Semantic - Dimmer
1
+ /*!
2
+ * # Semantic UI - Dimmer
3
3
  * http://github.com/semantic-org/semantic-ui/
4
4
  *
5
5
  *
6
- * Copyright 2014 Contributor
6
+ * Copyright 2015 Contributors
7
7
  * Released under the MIT license
8
8
  * http://opensource.org/licenses/MIT
9
9
  *
@@ -16,8 +16,7 @@
16
16
  @type : 'module';
17
17
  @element : 'dimmer';
18
18
 
19
- @import '../../theme.config';
20
-
19
+ @import (multiple) '../../theme.config';
21
20
 
22
21
  /*******************************
23
22
  Dimmer
@@ -39,7 +38,7 @@
39
38
  text-align: @textAlign;
40
39
  vertical-align: @verticalAlign;
41
40
 
42
- background: @background;
41
+ background-color: @backgroundColor;
43
42
  opacity: @hiddenOpacity;
44
43
  line-height: @lineHeight;
45
44
 
@@ -59,7 +58,7 @@
59
58
  display: @contentDisplay;
60
59
  user-select: text;
61
60
  }
62
- .ui.dimmer > .content > div {
61
+ .ui.dimmer > .content > * {
63
62
  display: @contentChildDisplay;
64
63
  vertical-align: @verticalAlign;
65
64
  color: @textColor;
@@ -111,19 +110,30 @@ body.animating.in.dimmable,
111
110
  body.dimmed.dimmable {
112
111
  overflow: hidden;
113
112
  }
113
+
114
114
  body.dimmable > .dimmer {
115
115
  position: fixed;
116
116
  }
117
117
 
118
- /*
119
- body.dimmable > :not(.dimmer) {
120
- filter: @elementStartFilter;
118
+ /*--------------
119
+ Blurring
120
+ ---------------*/
121
+
122
+ .blurring.dimmable > :not(.dimmer) {
123
+ filter: @blurredStartFilter;
124
+ transition: @blurredTransition;
125
+ }
126
+ .blurring.dimmed.dimmable > :not(.dimmer) {
127
+ filter: @blurredEndFilter;
128
+ }
129
+
130
+ /* Dimmer Color */
131
+ .blurring.dimmable > .dimmer {
132
+ background-color: @blurredBackgroundColor;
121
133
  }
122
- body.dimmed.dimmable > :not(.dimmer) {
123
- filter: @elementEndFilter;
124
- transition: @elementTransition;
134
+ .blurring.dimmable > .inverted.dimmer {
135
+ background-color: @blurredInvertedBackgroundColor;
125
136
  }
126
- */
127
137
 
128
138
  /*--------------
129
139
  Aligned
@@ -141,7 +151,7 @@ body.dimmed.dimmable > :not(.dimmer) {
141
151
  ---------------*/
142
152
 
143
153
  .ui.inverted.dimmer {
144
- background: @invertedBackground;
154
+ background-color: @invertedBackgroundColor;
145
155
  }
146
156
  .ui.inverted.dimmer > .content > * {
147
157
  color: @textColor;
@@ -159,22 +169,22 @@ body.dimmed.dimmable > :not(.dimmer) {
159
169
  width: 0%;
160
170
  height: 0%;
161
171
  z-index: -100;
162
- background-color: @simpleStartBackground;
172
+ background-color: @simpleStartBackgroundColor;
163
173
  }
164
174
  .dimmed.dimmable > .ui.simple.dimmer {
165
175
  overflow: visible;
166
176
  opacity: 1;
167
177
  width: 100%;
168
178
  height: 100%;
169
- background: @simpleEndBackground;
179
+ background-color: @simpleEndBackgroundColor;
170
180
  z-index: @simpleZIndex;
171
181
  }
172
182
 
173
183
  .ui.simple.inverted.dimmer {
174
- background: @simpleInvertedStartBackground;
184
+ background-color: @simpleInvertedStartBackgroundColor;
175
185
  }
176
186
  .dimmed.dimmable > .ui.simple.inverted.dimmer {
177
- background: @simpleInvertedEndBackground;
187
+ background-color: @simpleInvertedEndBackgroundColor;
178
188
  }
179
189
 
180
- .loadUIOverrides();
190
+ .loadUIOverrides();
@@ -1,9 +1,9 @@
1
- /*
2
- * # Semantic - Dropdown
1
+ /*!
2
+ * # Semantic UI - Dropdown
3
3
  * http://github.com/semantic-org/semantic-ui/
4
4
  *
5
5
  *
6
- * Copyright 2014 Contributor
6
+ * Copyright 2015 Contributors
7
7
  * Released under the MIT license
8
8
  * http://opensource.org/licenses/MIT
9
9
  *
@@ -31,27 +31,32 @@ $.fn.dropdown = function(parameters) {
31
31
  ;
32
32
 
33
33
  $allModules
34
- .each(function() {
34
+ .each(function(elementIndex) {
35
35
  var
36
36
  settings = ( $.isPlainObject(parameters) )
37
37
  ? $.extend(true, {}, $.fn.dropdown.settings, parameters)
38
38
  : $.extend({}, $.fn.dropdown.settings),
39
39
 
40
40
  className = settings.className,
41
+ message = settings.message,
41
42
  metadata = settings.metadata,
42
43
  namespace = settings.namespace,
44
+ regExp = settings.regExp,
43
45
  selector = settings.selector,
44
46
  error = settings.error,
47
+ templates = settings.templates,
45
48
 
46
49
  eventNamespace = '.' + namespace,
47
50
  moduleNamespace = 'module-' + namespace,
48
51
 
49
52
  $module = $(this),
53
+ $context = $(settings.context),
50
54
  $text = $module.find(selector.text),
51
55
  $search = $module.find(selector.search),
52
56
  $input = $module.find(selector.input),
57
+ $icon = $module.find(selector.icon),
53
58
 
54
- $combo = ($module.prev().find(selector.text).size() > 0)
59
+ $combo = ($module.prev().find(selector.text).length > 0)
55
60
  ? $module.prev().find(selector.text)
56
61
  : $module.prev(),
57
62
 
@@ -60,10 +65,15 @@ $.fn.dropdown = function(parameters) {
60
65
 
61
66
  activated = false,
62
67
  itemActivated = false,
63
-
64
68
  element = this,
65
69
  instance = $module.data(moduleNamespace),
66
- observer,
70
+
71
+ initialLoad,
72
+ pageLostFocus,
73
+ elementNamespace,
74
+ id,
75
+ selectObserver,
76
+ menuObserver,
67
77
  module
68
78
  ;
69
79
 
@@ -71,18 +81,28 @@ $.fn.dropdown = function(parameters) {
71
81
 
72
82
  initialize: function() {
73
83
  module.debug('Initializing dropdown', settings);
74
- module.setup.layout();
75
- module.save.defaults();
76
- module.set.selected();
77
84
 
78
- if(hasTouch) {
79
- module.bind.touchEvents();
85
+ if( module.is.alreadySetup() ) {
86
+ module.setup.reference();
87
+ }
88
+ else {
89
+ module.setup.layout();
90
+ module.refreshData();
91
+
92
+ module.save.defaults();
93
+ module.restore.selected();
94
+
95
+ module.create.id();
96
+ if(hasTouch) {
97
+ module.bind.touchEvents();
98
+ }
99
+ module.bind.mouseEvents();
100
+ module.bind.keyboardEvents();
101
+
102
+ module.observeChanges();
103
+ module.instantiate();
80
104
  }
81
- module.bind.mouseEvents();
82
- module.bind.keyboardEvents();
83
105
 
84
- module.observeChanges();
85
- module.instantiate();
86
106
  },
87
107
 
88
108
  instantiate: function() {
@@ -94,35 +114,163 @@ $.fn.dropdown = function(parameters) {
94
114
  },
95
115
 
96
116
  destroy: function() {
97
- module.verbose('Destroying previous dropdown for', $module);
117
+ module.verbose('Destroying previous dropdown', $module);
98
118
  module.remove.tabbable();
99
119
  $module
100
120
  .off(eventNamespace)
101
121
  .removeData(moduleNamespace)
102
122
  ;
123
+ $menu
124
+ .off(eventNamespace)
125
+ ;
126
+ $document
127
+ .off(elementNamespace)
128
+ ;
129
+ if(selectObserver) {
130
+ selectObserver.disconnect();
131
+ }
132
+ if(menuObserver) {
133
+ menuObserver.disconnect();
134
+ }
103
135
  },
104
136
 
105
137
  observeChanges: function() {
106
138
  if('MutationObserver' in window) {
107
- observer = new MutationObserver(function(mutations) {
108
- module.debug('DOM tree modified, updating selector cache');
139
+ selectObserver = new MutationObserver(function(mutations) {
140
+ module.debug('<select> modified, recreating menu');
141
+ module.setup.select();
142
+ });
143
+ menuObserver = new MutationObserver(function(mutations) {
144
+ module.debug('Menu modified, updating selector cache');
109
145
  module.refresh();
110
146
  });
111
- observer.observe(element, {
112
- childList : true,
113
- subtree : true
147
+ if(module.has.input()) {
148
+ selectObserver.observe($input[0], {
149
+ childList : true,
150
+ subtree : true
151
+ });
152
+ }
153
+ if(module.has.menu()) {
154
+ menuObserver.observe($menu[0], {
155
+ childList : true,
156
+ subtree : true
157
+ });
158
+ }
159
+ module.debug('Setting up mutation observer', selectObserver, menuObserver);
160
+ }
161
+ },
162
+
163
+ create: {
164
+ id: function() {
165
+ id = (Math.random().toString(16) + '000000000').substr(2, 8);
166
+ elementNamespace = '.' + id;
167
+ module.verbose('Creating unique id for element', id);
168
+ },
169
+ userChoice: function(values) {
170
+ var
171
+ $userChoices,
172
+ $userChoice,
173
+ isUserValue,
174
+ html
175
+ ;
176
+ values = values || module.get.userValues();
177
+ if(!values) {
178
+ return false;
179
+ }
180
+ values = $.isArray(values)
181
+ ? values
182
+ : [values]
183
+ ;
184
+ $.each(values, function(index, value) {
185
+ if(module.get.item(value) === false) {
186
+ html = settings.templates.addition(value);
187
+ $userChoice = $('<div />')
188
+ .html(html)
189
+ .data(metadata.value, value)
190
+ .addClass(className.addition)
191
+ .addClass(className.item)
192
+ ;
193
+ $userChoices = ($userChoices === undefined)
194
+ ? $userChoice
195
+ : $userChoices.add($userChoice)
196
+ ;
197
+ module.verbose('Creating user choices for value', value, $userChoice);
198
+ }
114
199
  });
115
- module.debug('Setting up mutation observer', observer);
200
+ return $userChoices;
201
+ },
202
+ userLabels: function(value) {
203
+ var
204
+ userValues = module.get.userValues()
205
+ ;
206
+ if(userValues) {
207
+ module.debug('Adding user labels', userValues);
208
+ $.each(userValues, function(index, value) {
209
+ module.verbose('Adding custom user value');
210
+ module.add.label(value, value);
211
+ });
212
+ }
213
+ },
214
+ },
215
+
216
+ search: function(query) {
217
+ query = (query !== undefined)
218
+ ? query
219
+ : module.get.query()
220
+ ;
221
+ module.verbose('Searching for query', query);
222
+ module.filter(query);
223
+ },
224
+
225
+ select: {
226
+ firstUnfiltered: function() {
227
+ module.verbose('Selecting first non-filtered element');
228
+ module.remove.selectedItem();
229
+ $item
230
+ .not(selector.unselectable)
231
+ .eq(0)
232
+ .addClass(className.selected)
233
+ ;
234
+ },
235
+ nextAvailable: function($selected) {
236
+ $selected = $selected.eq(0);
237
+ var
238
+ $nextAvailable = $selected.nextAll(selector.item).not(selector.unselectable).eq(0),
239
+ $prevAvailable = $selected.prevAll(selector.item).not(selector.unselectable).eq(0),
240
+ hasNext = ($nextAvailable.length > 0)
241
+ ;
242
+ if(hasNext) {
243
+ module.verbose('Moving selection to', $nextAvailable);
244
+ $nextAvailable.addClass(className.selected);
245
+ }
246
+ else {
247
+ module.verbose('Moving selection to', $prevAvailable);
248
+ $prevAvailable.addClass(className.selected);
249
+ }
116
250
  }
117
251
  },
118
252
 
119
253
  setup: {
120
-
254
+ api: function() {
255
+ var
256
+ apiSettings = {
257
+ debug : settings.debug,
258
+ on : false
259
+ }
260
+ ;
261
+ module.verbose('First request, initializing API');
262
+ $module
263
+ .api(apiSettings)
264
+ ;
265
+ },
121
266
  layout: function() {
122
267
  if( $module.is('select') ) {
123
268
  module.setup.select();
269
+ module.setup.returnedObject();
270
+ console.log($module);
124
271
  }
125
- if( module.is.search() && !module.is.searchable() ) {
272
+ if( module.is.search() && !module.has.search() ) {
273
+ module.verbose('Adding search input');
126
274
  $search = $('<input />')
127
275
  .addClass(className.search)
128
276
  .insertBefore($text)
@@ -131,51 +279,108 @@ $.fn.dropdown = function(parameters) {
131
279
  if(settings.allowTab) {
132
280
  module.set.tabbable();
133
281
  }
282
+ if($menu.length === 0) {
283
+ $menu = $('<div />')
284
+ .addClass(className.menu)
285
+ .appendTo($module)
286
+ ;
287
+ }
134
288
  },
135
289
  select: function() {
136
290
  var
137
- selectValues = module.get.selectValues()
291
+ selectValues = module.get.selectValues()
138
292
  ;
139
293
  module.debug('Dropdown initialized on a select', selectValues);
140
- // see if select exists inside a dropdown
141
- $input = $module;
142
- if($input.parents(selector.dropdown).size() > 0) {
143
- module.debug('Creating dropdown menu only from template');
294
+ if( $module.is('select') ) {
295
+ $input = $module;
296
+ }
297
+ // see if select is placed correctly already
298
+ if($input.parent(selector.dropdown).length > 0) {
299
+ module.debug('UI dropdown already exists. Creating dropdown menu only');
144
300
  $module = $input.closest(selector.dropdown);
145
- if($module.find('.' + className.dropdown).size() === 0) {
146
- $('<div />')
147
- .addClass(className.menu)
148
- .html( settings.templates.menu( selectValues ))
149
- .appendTo($module)
150
- ;
151
- }
301
+ $menu = $module.children(selector.menu);
302
+ module.setup.menu(selectValues);
152
303
  }
153
304
  else {
154
- module.debug('Creating entire dropdown from template');
305
+ module.debug('Creating entire dropdown from select');
155
306
  $module = $('<div />')
156
307
  .attr('class', $input.attr('class') )
157
308
  .addClass(className.selection)
158
309
  .addClass(className.dropdown)
159
- .html( settings.templates.dropdown(selectValues) )
310
+ .html( templates.dropdown(selectValues) )
160
311
  .insertBefore($input)
161
312
  ;
162
313
  $input
163
314
  .removeAttr('class')
315
+ .detach()
164
316
  .prependTo($module)
165
317
  ;
318
+ console.log($module);
166
319
  }
320
+ if($input.is('[multiple]')) {
321
+ module.set.multiple();
322
+ }
323
+ module.refresh();
324
+ },
325
+ menu: function(values) {
326
+ $menu.html( templates.menu( values ));
327
+ $item = $menu.find(selector.item);
328
+ },
329
+ reference: function() {
330
+ module.debug('Dropdown behavior was called on select, replacing with closest dropdown');
331
+ // replace module reference
332
+ $module = $module.parent(selector.dropdown);
167
333
  module.refresh();
334
+ module.setup.returnedObject();
335
+ // invoke method in context of current instance
336
+ if(methodInvoked) {
337
+ instance = module;
338
+ module.invoke(query);
339
+ }
340
+ },
341
+ returnedObject: function() {
342
+ var
343
+ $firstModules = $allModules.slice(0, elementIndex),
344
+ $lastModules = $allModules.slice(elementIndex + 1)
345
+ ;
346
+ // adjust all modules to use correct reference
347
+ $allModules = $firstModules.add($module).add($lastModules);
168
348
  }
169
349
  },
170
350
 
171
351
  refresh: function() {
352
+ module.refreshSelectors();
353
+ module.refreshData();
354
+ },
355
+
356
+ refreshSelectors: function() {
357
+ module.verbose('Refreshing selector cache');
172
358
  $text = $module.find(selector.text);
173
359
  $search = $module.find(selector.search);
174
360
  $input = $module.find(selector.input);
175
- $menu = $module.children(selector.menu);
176
- $item = $menu.find(selector.item);
361
+ $icon = $module.find(selector.icon);
362
+ $combo = ($module.prev().find(selector.text).length > 0)
363
+ ? $module.prev().find(selector.text)
364
+ : $module.prev()
365
+ ;
366
+ $menu = $module.children(selector.menu);
367
+ $item = $menu.find(selector.item);
368
+ },
369
+
370
+ refreshData: function() {
371
+ module.verbose('Refreshing cached metadata');
372
+ $item
373
+ .removeData(metadata.text)
374
+ .removeData(metadata.value)
375
+ ;
376
+ $module
377
+ .removeData(metadata.defaultText)
378
+ .removeData(metadata.defaultValue)
379
+ .removeData(metadata.placeholderText)
380
+ ;
177
381
  },
178
382
 
383
+
179
384
  toggle: function() {
180
385
  module.verbose('Toggling menu visibility');
181
386
  if( !module.is.active() ) {
@@ -186,26 +391,41 @@ $.fn.dropdown = function(parameters) {
186
391
  }
187
392
  },
188
393
 
189
- show: function() {
190
- module.debug('Checking if dropdown can show');
191
- if( !module.is.active() ) {
394
+ show: function(callback) {
395
+ callback = $.isFunction(callback)
396
+ ? callback
397
+ : function(){}
398
+ ;
399
+ if( module.can.show() && !module.is.active() ) {
400
+ module.debug('Showing dropdown');
401
+ if(module.is.multiple()) {
402
+ if(!module.has.search() && module.is.allFiltered()) {
403
+ return true;
404
+ }
405
+ }
192
406
  module.animate.show(function() {
193
407
  if( module.can.click() ) {
194
408
  module.bind.intent();
195
409
  }
196
410
  module.set.visible();
411
+ callback.call(element);
197
412
  });
198
- $.proxy(settings.onShow, element)();
413
+ settings.onShow.call(element);
199
414
  }
200
415
  },
201
416
 
202
- hide: function() {
417
+ hide: function(callback) {
418
+ callback = $.isFunction(callback)
419
+ ? callback
420
+ : function(){}
421
+ ;
203
422
  if( module.is.active() ) {
204
423
  module.debug('Hiding dropdown');
205
424
  module.animate.hide(function() {
206
425
  module.remove.visible();
426
+ callback.call(element);
207
427
  });
208
- $.proxy(settings.onHide, element)();
428
+ settings.onHide.call(element);
209
429
  }
210
430
  },
211
431
 
@@ -213,15 +433,23 @@ $.fn.dropdown = function(parameters) {
213
433
  module.verbose('Finding other dropdowns to hide');
214
434
  $allModules
215
435
  .not($module)
216
- .has(selector.menu + ':visible:not(.' + className.animating + ')')
436
+ .has(selector.menu + '.' + className.visible)
217
437
  .dropdown('hide')
218
438
  ;
219
439
  },
220
440
 
441
+ hideMenu: function() {
442
+ module.verbose('Hiding menu instantaneously');
443
+ module.remove.active();
444
+ module.remove.visible();
445
+ $menu.transition('hide');
446
+ },
447
+
221
448
  hideSubMenus: function() {
222
449
  var
223
- $subMenus = $menu.find(selector.menu)
450
+ $subMenus = $menu.children(selector.item).find(selector.menu)
224
451
  ;
452
+ module.verbose('Hiding sub menus', $subMenus);
225
453
  $subMenus.transition('hide');
226
454
  },
227
455
 
@@ -231,9 +459,14 @@ $.fn.dropdown = function(parameters) {
231
459
  $module
232
460
  .on('keydown' + eventNamespace, module.event.keydown)
233
461
  ;
234
- if( module.is.searchable() ) {
462
+ if( module.has.search() ) {
235
463
  $module
236
- .on(module.get.inputEvent(), selector.search, module.event.input)
464
+ .on(module.get.inputEvent() + eventNamespace, selector.search, module.event.input)
465
+ ;
466
+ }
467
+ if( module.is.multiple() ) {
468
+ $document
469
+ .on('keydown' + elementNamespace, module.event.document.keydown)
237
470
  ;
238
471
  }
239
472
  },
@@ -252,15 +485,27 @@ $.fn.dropdown = function(parameters) {
252
485
  ;
253
486
  },
254
487
  mouseEvents: function() {
255
- module.verbose('Mouse detected binding mouse events');
488
+ module.debug('Mouse detected binding mouse events');
489
+ if(module.is.multiple()) {
490
+ $module
491
+ .on('click' + eventNamespace, selector.label, module.event.label.click)
492
+ .on('click' + eventNamespace, selector.remove, module.event.remove.click)
493
+ ;
494
+ }
256
495
  if( module.is.searchSelection() ) {
257
496
  $module
258
- .on('mousedown' + eventNamespace, selector.menu, module.event.menu.activate)
259
- .on('mouseup' + eventNamespace, selector.menu, module.event.menu.deactivate)
260
- .on('focus' + eventNamespace, selector.search, module.event.searchFocus)
497
+ .on('mousedown' + eventNamespace, selector.menu, module.event.menu.mousedown)
498
+ .on('mouseup' + eventNamespace, selector.menu, module.event.menu.mouseup)
261
499
  .on('click' + eventNamespace, selector.search, module.show)
262
- .on('blur' + eventNamespace, selector.search, module.event.searchBlur)
500
+ .on('focus' + eventNamespace, selector.search, module.event.search.focus)
501
+ .on('blur' + eventNamespace, selector.search, module.event.search.blur)
502
+ .on('click' + eventNamespace, selector.text, module.event.text.focus)
263
503
  ;
504
+ if(module.is.multiple()) {
505
+ $module
506
+ .on('click' + eventNamespace, module.event.click)
507
+ ;
508
+ }
264
509
  }
265
510
  else {
266
511
  if(settings.on == 'click') {
@@ -296,12 +541,12 @@ $.fn.dropdown = function(parameters) {
296
541
  module.verbose('Binding hide intent event to document');
297
542
  if(hasTouch) {
298
543
  $document
299
- .on('touchstart' + eventNamespace, module.event.test.touch)
300
- .on('touchmove' + eventNamespace, module.event.test.touch)
544
+ .on('touchstart' + elementNamespace, module.event.test.touch)
545
+ .on('touchmove' + elementNamespace, module.event.test.touch)
301
546
  ;
302
547
  }
303
548
  $document
304
- .on('click' + eventNamespace, module.event.test.hide)
549
+ .on('click' + elementNamespace, module.event.test.hide)
305
550
  ;
306
551
  }
307
552
  },
@@ -311,202 +556,342 @@ $.fn.dropdown = function(parameters) {
311
556
  module.verbose('Removing hide intent event from document');
312
557
  if(hasTouch) {
313
558
  $document
314
- .off('touchstart' + eventNamespace)
315
- .off('touchmove' + eventNamespace)
559
+ .off('touchstart' + elementNamespace)
560
+ .off('touchmove' + elementNamespace)
316
561
  ;
317
562
  }
318
563
  $document
319
- .off('click' + eventNamespace)
564
+ .off('click' + elementNamespace)
320
565
  ;
321
566
  }
322
567
  },
323
568
 
324
- filter: function(searchTerm) {
569
+ filter: function(query) {
325
570
  var
326
- $results = $(),
327
- exactRegExp = new RegExp('(?:\s|^)' + searchTerm, 'i'),
328
- fullTextRegExp = new RegExp(searchTerm, 'i'),
329
- allItemsFiltered,
330
- $filteredItems
331
- ;
332
- $item
333
- .each(function(){
334
- var
335
- $choice = $(this),
336
- text = ( $choice.data(metadata.text) !== undefined )
337
- ? $choice.data(metadata.text)
338
- : (settings.preserveHTML)
339
- ? $choice.html()
340
- : $choice.text(),
341
- value = ( $choice.data(metadata.value) !== undefined)
342
- ? $choice.data(metadata.value)
343
- : (typeof text === 'string')
344
- ? text.toLowerCase()
345
- : text
346
- ;
347
- if( exactRegExp.test( text ) || exactRegExp.test( value ) ) {
348
- $results = $results.add($choice);
571
+ searchTerm = (query !== undefined)
572
+ ? query
573
+ : module.get.query(),
574
+ afterFiltered = function() {
575
+ if(module.is.multiple()) {
576
+ module.filterActive();
349
577
  }
350
- else if(settings.fullTextSearch) {
351
- if( fullTextRegExp.test( text ) || fullTextRegExp.test( value ) ) {
352
- $results = $results.add($choice);
578
+ module.select.firstUnfiltered();
579
+ if( module.has.allResultsFiltered() ) {
580
+ if( settings.onNoResults.call(element, searchTerm) ) {
581
+ if(!settings.allowAdditions) {
582
+ module.verbose('All items filtered, showing message', searchTerm);
583
+ module.add.message(message.noResults);
584
+ }
585
+ }
586
+ else {
587
+ module.verbose('All items filtered, hiding dropdown', searchTerm);
588
+ module.hideMenu();
353
589
  }
354
590
  }
355
- })
591
+ else {
592
+ module.remove.message();
593
+ }
594
+ if(settings.allowAdditions) {
595
+ module.add.userSuggestion(query);
596
+ }
597
+ if(module.is.searchSelection() && module.can.show() && module.is.focusedOnSearch() ) {
598
+ module.show();
599
+ }
600
+ }
601
+ ;
602
+ if(module.has.maxSelections()) {
603
+ return;
604
+ }
605
+ if(settings.apiSettings) {
606
+ if( module.can.useAPI() ) {
607
+ module.queryRemote(searchTerm, function() {
608
+ afterFiltered();
609
+ });
610
+ }
611
+ else {
612
+ module.error(error.noAPI);
613
+ }
614
+ }
615
+ else {
616
+ module.filterItems(searchTerm);
617
+ afterFiltered();
618
+ }
619
+ },
620
+
621
+ queryRemote: function(query, callback) {
622
+ var
623
+ apiSettings = {
624
+ errorDuration : false,
625
+ throttle : settings.throttle,
626
+ cache : 'local',
627
+ urlData : {
628
+ query: query
629
+ },
630
+ onError: function() {
631
+ module.add.message(message.serverError);
632
+ callback();
633
+ },
634
+ onFailure: function() {
635
+ module.add.message(message.serverError);
636
+ callback();
637
+ },
638
+ onSuccess : function(response) {
639
+ module.remove.message();
640
+ module.setup.menu({
641
+ values: response.results
642
+ });
643
+ callback();
644
+ }
645
+ }
646
+ ;
647
+ if( !$module.api('get request') ) {
648
+ module.setup.api();
649
+ }
650
+ apiSettings = $.extend(true, {}, apiSettings, settings.apiSettings);
651
+ $module
652
+ .api('setting', apiSettings)
653
+ .api('query')
654
+ ;
655
+ },
656
+
657
+ filterItems: function(query) {
658
+ var
659
+ searchTerm = (query !== undefined)
660
+ ? query
661
+ : module.get.query(),
662
+ $results = $(),
663
+ escapedTerm = module.escape.regExp(searchTerm),
664
+ beginsWithRegExp = new RegExp('^' + escapedTerm, 'igm')
356
665
  ;
357
- $filteredItems = $item.not($results);
358
- allItemsFiltered = ($filteredItems.size() == $item.size());
666
+ // avoid loop if we're matching nothing
667
+ if(searchTerm === '') {
668
+ $results = $item;
669
+ }
670
+ else {
671
+ module.verbose('Searching for matching values', searchTerm);
672
+ $item
673
+ .each(function(){
674
+ var
675
+ $choice = $(this),
676
+ text,
677
+ value
678
+ ;
679
+ if(settings.match == 'both' || settings.match == 'text') {
680
+ text = String(module.get.choiceText($choice, false));
681
+ if(text.search(beginsWithRegExp) !== -1) {
682
+ $results = $results.add($choice);
683
+ return true;
684
+ }
685
+ else if(settings.fullTextSearch && module.fuzzySearch(searchTerm, text)) {
686
+ $results = $results.add($choice);
687
+ return true;
688
+ }
689
+ }
690
+ if(settings.match == 'both' || settings.match == 'value') {
691
+ value = String(module.get.choiceValue($choice, text));
692
+
693
+ if(value.search(beginsWithRegExp) !== -1) {
694
+ $results = $results.add($choice);
695
+ return true;
696
+ }
697
+ else if(settings.fullTextSearch && module.fuzzySearch(searchTerm, value)) {
698
+ $results = $results.add($choice);
699
+ return true;
700
+ }
701
+ }
702
+ })
703
+ ;
704
+ }
359
705
 
706
+ module.debug('Showing only matched items', searchTerm);
360
707
  module.remove.filteredItem();
361
- module.remove.selectedItem();
362
- $filteredItems
708
+ $item
709
+ .not($results)
363
710
  .addClass(className.filtered)
364
711
  ;
365
- $item
366
- .not('.' + className.filtered)
367
- .eq(0)
368
- .addClass(className.selected)
712
+ },
713
+
714
+ fuzzySearch: function(query, term) {
715
+ var
716
+ termLength = term.length,
717
+ queryLength = query.length
369
718
  ;
370
- if(allItemsFiltered) {
371
- module.hide();
719
+ query = query.toLowerCase();
720
+ term = term.toLowerCase();
721
+ if(queryLength > termLength) {
722
+ return false;
723
+ }
724
+ if(queryLength === termLength) {
725
+ return (query === term);
372
726
  }
727
+ search: for (var characterIndex = 0, nextCharacterIndex = 0; characterIndex < queryLength; characterIndex++) {
728
+ var
729
+ queryCharacter = query.charCodeAt(characterIndex)
730
+ ;
731
+ while(nextCharacterIndex < termLength) {
732
+ if(term.charCodeAt(nextCharacterIndex++) === queryCharacter) {
733
+ continue search;
734
+ }
735
+ }
736
+ return false;
737
+ }
738
+ return true;
373
739
  },
374
740
 
375
- focusSearch: function() {
376
- if( module.is.search() ) {
377
- $search
378
- .focus()
741
+ filterActive: function() {
742
+ if(settings.useLabels) {
743
+ $item.filter('.' + className.active)
744
+ .addClass(className.filtered)
379
745
  ;
380
746
  }
381
747
  },
382
748
 
749
+ focusSearch: function() {
750
+ if( module.is.search() && !module.is.focusedOnSearch() ) {
751
+ $search[0].focus();
752
+ }
753
+ },
754
+
755
+ forceSelection: function() {
756
+ var
757
+ $currentlySelected = $item.not(className.filtered).filter('.' + className.selected).eq(0),
758
+ $activeItem = $item.not(className.filtered).filter('.' + className.active).eq(0),
759
+ $selectedItem = ($currentlySelected.length > 0)
760
+ ? $currentlySelected
761
+ : $activeItem,
762
+ hasSelected = ($selectedItem.size() > 0)
763
+ ;
764
+ if(hasSelected) {
765
+ module.debug('Forcing partial selection to selected item', $selectedItem);
766
+ module.event.item.click.call($selectedItem);
767
+ }
768
+ else {
769
+ module.hide();
770
+ }
771
+ },
772
+
383
773
  event: {
384
- // prevents focus callback from occuring on mousedown
385
- mousedown: function() {
386
- activated = true;
387
- },
388
- mouseup: function() {
389
- activated = false;
390
- },
391
774
  focus: function() {
392
- if(!activated && module.is.hidden()) {
775
+ if(settings.showOnFocus && !activated && module.is.hidden() && !pageLostFocus) {
393
776
  module.show();
394
777
  }
395
778
  },
779
+ click: function(event) {
780
+ var
781
+ $target = $(event.target)
782
+ ;
783
+ // focus search
784
+ if(($target.is($module) || $target.is($icon)) && !module.is.focusedOnSearch()) {
785
+ module.focusSearch();
786
+ }
787
+ },
396
788
  blur: function(event) {
397
- if(!activated) {
789
+ pageLostFocus = (document.activeElement === this);
790
+ if(!activated && !pageLostFocus) {
791
+ module.remove.activeLabel();
398
792
  module.hide();
399
793
  }
400
794
  },
401
- searchFocus: function() {
795
+ // prevents focus callback from occuring on mousedown
796
+ mousedown: function() {
402
797
  activated = true;
403
- module.show();
404
798
  },
405
- searchBlur: function(event) {
406
- if(!itemActivated) {
407
- module.hide();
408
- }
799
+ mouseup: function() {
800
+ activated = false;
409
801
  },
410
- input: function(event) {
411
- var
412
- query = $search.val()
413
- ;
414
- if(module.is.searchSelection()) {
415
- if( module.can.show() ) {
802
+ search: {
803
+ focus: function() {
804
+ activated = true;
805
+ if(module.is.multiple()) {
806
+ module.remove.activeLabel();
807
+ }
808
+ if(settings.showOnFocus) {
416
809
  module.show();
417
810
  }
418
- module.set.filtered();
811
+ },
812
+ blur: function(event) {
813
+ pageLostFocus = (document.activeElement === this);
814
+ if(!itemActivated && !pageLostFocus) {
815
+ if(module.is.multiple()) {
816
+ module.remove.activeLabel();
817
+ module.hide();
818
+ }
819
+ else if(settings.forceSelection) {
820
+ module.forceSelection();
821
+ }
822
+ else {
823
+ module.hide();
824
+ }
825
+ }
419
826
  }
420
- module.filter(query);
421
827
  },
422
- keydown: function(event) {
423
- var
424
- $selectedItem = $item.not(className.filtered).filter('.' + className.selected).eq(0),
425
- $visibleItems = $item.not('.' + className.filtered),
426
- pressedKey = event.which,
427
- keys = {
428
- enter : 13,
429
- escape : 27,
430
- upArrow : 38,
431
- downArrow : 40
432
- },
433
- selectedClass = className.selected,
434
- currentIndex = $visibleItems.index( $selectedItem ),
435
- hasSelectedItem = ($selectedItem.size() > 0),
436
- $nextItem,
437
- newIndex
438
- ;
439
- // default to activated choice if no selection present
440
- if(!hasSelectedItem) {
441
- $selectedItem = $item.filter('.' + className.active).eq(0);
442
- hasSelectedItem = ($selectedItem.size() > 0);
443
- }
444
- // close shortcuts
445
- if(pressedKey == keys.escape) {
446
- module.verbose('Escape key pressed, closing dropdown');
447
- module.hide();
828
+ text: {
829
+ focus: function(event) {
830
+ activated = true;
831
+ module.focusSearch();
448
832
  }
449
- // result shortcuts
450
- if(module.is.visible()) {
451
- if(pressedKey == keys.enter && hasSelectedItem) {
452
- module.verbose('Enter key pressed, choosing selected item');
453
- $.proxy(module.event.item.click, $selectedItem)(event);
454
- event.preventDefault();
455
- return false;
833
+ },
834
+ input: function(event) {
835
+ if(module.is.multiple() || module.is.searchSelection()) {
836
+ module.set.filtered();
837
+ }
838
+ clearTimeout(module.timer);
839
+ module.timer = setTimeout(module.search, settings.delay.search);
840
+ },
841
+ label: {
842
+ click: function(event) {
843
+ var
844
+ $label = $(this),
845
+ $labels = $module.find(selector.label),
846
+ $activeLabels = $labels.filter('.' + className.active),
847
+ $nextActive = $label.nextAll('.' + className.active),
848
+ $prevActive = $label.prevAll('.' + className.active),
849
+ $range = ($nextActive.length > 0)
850
+ ? $label.nextUntil($nextActive).add($activeLabels).add($label)
851
+ : $label.prevUntil($prevActive).add($activeLabels).add($label)
852
+ ;
853
+ if(event.shiftKey) {
854
+ $activeLabels.removeClass(className.active);
855
+ $range.addClass(className.active);
456
856
  }
457
- else if(pressedKey == keys.upArrow) {
458
- if(!hasSelectedItem) {
459
- $nextItem = $visibleItems.eq(0);
460
- }
461
- else {
462
- $nextItem = $selectedItem.prevAll(selector.item + ':not(.' + className.filtered + ')').eq(0);
463
- }
464
- if(currentIndex !== 0) {
465
- module.verbose('Up key pressed, changing active item');
466
- $item
467
- .removeClass(selectedClass)
468
- ;
469
- $nextItem
470
- .addClass(selectedClass)
471
- ;
472
- module.set.scrollPosition($nextItem);
473
- }
474
- event.preventDefault();
857
+ else if(event.ctrlKey) {
858
+ $label.toggleClass(className.active);
475
859
  }
476
- else if(pressedKey == keys.downArrow) {
477
- if(!hasSelectedItem) {
478
- $nextItem = $visibleItems.eq(0);
479
- }
480
- else {
481
- $nextItem = $selectedItem.nextAll(selector.item + ':not(.' + className.filtered + ')').eq(0);
482
- }
483
- if(currentIndex + 1 < $visibleItems.size() ) {
484
- module.verbose('Down key pressed, changing active item');
485
- $item
486
- .removeClass(selectedClass)
487
- ;
488
- $nextItem
489
- .addClass(selectedClass)
490
- ;
491
- module.set.scrollPosition($nextItem);
492
- }
493
- event.preventDefault();
860
+ else {
861
+ $activeLabels.removeClass(className.active);
862
+ $label.addClass(className.active);
494
863
  }
864
+ settings.onLabelSelect.apply(this, $labels.filter('.' + className.active));
495
865
  }
496
- else {
497
- if(pressedKey == keys.enter) {
498
- module.show();
866
+ },
867
+ remove: {
868
+ click: function() {
869
+ var
870
+ $label = $(this).parent()
871
+ ;
872
+ if( $label.hasClass(className.active) ) {
873
+ // remove all selected labels
874
+ module.remove.activeLabels();
875
+ }
876
+ else {
877
+ // remove this label only
878
+ module.remove.activeLabels( $label );
499
879
  }
500
880
  }
501
881
  },
502
882
  test: {
503
883
  toggle: function(event) {
504
- if( module.determine.eventInMenu(event, module.toggle) ) {
884
+ var
885
+ toggleBehavior = (module.is.multiple())
886
+ ? module.show
887
+ : module.toggle
888
+ ;
889
+ if( module.determine.eventOnElement(event, toggleBehavior) ) {
505
890
  event.preventDefault();
506
891
  }
507
892
  },
508
893
  touch: function(event) {
509
- module.determine.eventInMenu(event, function() {
894
+ module.determine.eventOnElement(event, function() {
510
895
  if(event.type == 'touchstart') {
511
896
  module.timer = setTimeout(module.hide, settings.delay.touch);
512
897
  }
@@ -520,78 +905,350 @@ $.fn.dropdown = function(parameters) {
520
905
  module.determine.eventInModule(event, module.hide);
521
906
  }
522
907
  },
523
-
524
908
  menu: {
525
- activate: function() {
909
+ mousedown: function() {
526
910
  itemActivated = true;
527
911
  },
528
- deactivate: function() {
912
+ mouseup: function() {
529
913
  itemActivated = false;
530
914
  }
531
915
  },
532
916
  item: {
533
917
  mouseenter: function(event) {
534
918
  var
535
- $currentMenu = $(this).children(selector.menu),
536
- $otherMenus = $(this).siblings(selector.item).children(selector.menu)
919
+ $subMenu = $(this).children(selector.menu),
920
+ $otherMenus = $(this).siblings(selector.item).children(selector.menu)
537
921
  ;
538
- if( $currentMenu.size() > 0 ) {
922
+ if( $subMenu.length > 0 ) {
539
923
  clearTimeout(module.itemTimer);
540
924
  module.itemTimer = setTimeout(function() {
925
+ module.verbose('Showing sub-menu', $subMenu);
541
926
  $.each($otherMenus, function() {
542
927
  module.animate.hide(false, $(this));
543
928
  });
544
- module.verbose('Showing sub-menu', $currentMenu);
545
- module.animate.show(false, $currentMenu);
929
+ module.animate.show(false, $subMenu);
546
930
  }, settings.delay.show);
547
931
  event.preventDefault();
548
932
  }
549
933
  },
550
-
551
934
  mouseleave: function(event) {
552
935
  var
553
- $currentMenu = $(this).children(selector.menu)
936
+ $subMenu = $(this).children(selector.menu)
554
937
  ;
555
- if($currentMenu.size() > 0) {
938
+ if($subMenu.length > 0) {
556
939
  clearTimeout(module.itemTimer);
557
940
  module.itemTimer = setTimeout(function() {
558
- module.verbose('Hiding sub-menu', $currentMenu);
559
- module.animate.hide(false, $currentMenu);
941
+ module.verbose('Hiding sub-menu', $subMenu);
942
+ module.animate.hide(false, $subMenu);
560
943
  }, settings.delay.hide);
561
944
  }
562
945
  },
563
-
564
946
  click: function (event) {
565
947
  var
566
- $choice = $(this),
567
- text = ( $choice.data(metadata.text) !== undefined )
568
- ? $choice.data(metadata.text)
569
- : (settings.preserveHTML)
570
- ? $choice.html()
571
- : $choice.text(),
572
- value = ( $choice.data(metadata.value) !== undefined)
573
- ? $choice.data(metadata.value)
574
- : (typeof text === 'string')
575
- ? text.toLowerCase()
576
- : text,
577
- callback = function() {
578
- module.remove.searchTerm();
579
- module.remove.filteredItem();
580
- module.determine.selectAction(text, value);
581
- },
582
- openingSubMenu = ($choice.find(selector.menu).size() > 0)
948
+ $choice = $(this),
949
+ $target = (event)
950
+ ? $(event.target)
951
+ : $(''),
952
+ $subMenu = $choice.find(selector.menu),
953
+ text = module.get.choiceText($choice),
954
+ value = module.get.choiceValue($choice, text),
955
+ hasSubMenu = ($subMenu.length > 0),
956
+ isBubbledEvent = ($subMenu.find($target).length > 0)
583
957
  ;
584
- if( !openingSubMenu ) {
585
- callback();
958
+ if(!isBubbledEvent && (!hasSubMenu || settings.allowCategorySelection)) {
959
+ if(!settings.useLabels) {
960
+ module.remove.searchTerm();
961
+ }
962
+ module.determine.selectAction.call(this, text, value);
586
963
  }
587
964
  }
588
-
589
965
  },
590
966
 
591
- resetStyle: function() {
592
- $(this).removeAttr('style');
593
- }
967
+ document: {
968
+ // label selection should occur even when element has no focus
969
+ keydown: function(event) {
970
+ var
971
+ pressedKey = event.which,
972
+ keys = module.get.shortcutKeys(),
973
+ isShortcutKey = module.is.inObject(pressedKey, keys)
974
+ ;
975
+ if(isShortcutKey) {
976
+ var
977
+ $label = $module.find(selector.label),
978
+ $activeLabel = $label.filter('.' + className.active),
979
+ activeValue = $activeLabel.data('value'),
980
+ labelIndex = $label.index($activeLabel),
981
+ labelCount = $label.length,
982
+ hasActiveLabel = ($activeLabel.length > 0),
983
+ hasMultipleActive = ($activeLabel.length > 1),
984
+ isFirstLabel = (labelIndex === 0),
985
+ isLastLabel = (labelIndex + 1 == labelCount),
986
+ isSearch = module.is.searchSelection(),
987
+ isFocusedOnSearch = module.is.focusedOnSearch(),
988
+ isFocused = module.is.focused(),
989
+ caretAtStart = (isFocusedOnSearch && module.get.caretPosition() === 0),
990
+ $nextLabel
991
+ ;
992
+ if(isSearch && !hasActiveLabel && !isFocusedOnSearch) {
993
+ return;
994
+ }
594
995
 
996
+ if(pressedKey == keys.leftArrow) {
997
+ // activate previous label
998
+ if((isFocused || caretAtStart) && !hasActiveLabel) {
999
+ module.verbose('Selecting previous label');
1000
+ $label.last().addClass(className.active);
1001
+ }
1002
+ else if(hasActiveLabel) {
1003
+ if(!event.shiftKey) {
1004
+ module.verbose('Selecting previous label');
1005
+ $label.removeClass(className.active);
1006
+ }
1007
+ else {
1008
+ module.verbose('Adding previous label to selection');
1009
+ }
1010
+ if(isFirstLabel && !hasMultipleActive) {
1011
+ $activeLabel.addClass(className.active);
1012
+ }
1013
+ else {
1014
+ $activeLabel.prev(selector.siblingLabel)
1015
+ .addClass(className.active)
1016
+ .end()
1017
+ ;
1018
+ }
1019
+ event.preventDefault();
1020
+ }
1021
+ }
1022
+ else if(pressedKey == keys.rightArrow) {
1023
+ // activate first label
1024
+ if(isFocused && !hasActiveLabel) {
1025
+ $label.first().addClass(className.active);
1026
+ }
1027
+ // activate next label
1028
+ if(hasActiveLabel) {
1029
+ if(!event.shiftKey) {
1030
+ module.verbose('Selecting next label');
1031
+ $label.removeClass(className.active);
1032
+ }
1033
+ else {
1034
+ module.verbose('Adding next label to selection');
1035
+ }
1036
+ if(isLastLabel) {
1037
+ if(isSearch) {
1038
+ if(!isFocusedOnSearch) {
1039
+ module.focusSearch();
1040
+ }
1041
+ else {
1042
+ $label.removeClass(className.active);
1043
+ }
1044
+ }
1045
+ else if(hasMultipleActive) {
1046
+ $activeLabel.next(selector.siblingLabel).addClass(className.active);
1047
+ }
1048
+ else {
1049
+ $activeLabel.addClass(className.active);
1050
+ }
1051
+ }
1052
+ else {
1053
+ $activeLabel.next(selector.siblingLabel).addClass(className.active);
1054
+ }
1055
+ event.preventDefault();
1056
+ }
1057
+ }
1058
+ else if(pressedKey == keys.deleteKey || pressedKey == keys.backspace) {
1059
+ if(hasActiveLabel) {
1060
+ module.verbose('Removing active labels');
1061
+ if(isLastLabel) {
1062
+ if(isSearch && !isFocusedOnSearch) {
1063
+ module.focusSearch();
1064
+ }
1065
+ }
1066
+ $activeLabel.last().next(selector.siblingLabel).addClass(className.active);
1067
+ module.remove.activeLabels($activeLabel);
1068
+ event.preventDefault();
1069
+ }
1070
+ else if(caretAtStart && !hasActiveLabel && pressedKey == keys.backspace) {
1071
+ module.verbose('Removing last label on input backspace');
1072
+ $activeLabel = $label.last().addClass(className.active);
1073
+ module.remove.activeLabels($activeLabel);
1074
+ }
1075
+ }
1076
+ else {
1077
+ $activeLabel.removeClass(className.active);
1078
+ }
1079
+ }
1080
+ }
1081
+ },
1082
+
1083
+ keydown: function(event) {
1084
+ var
1085
+ pressedKey = event.which,
1086
+ keys = module.get.shortcutKeys(),
1087
+ isShortcutKey = module.is.inObject(pressedKey, keys)
1088
+ ;
1089
+ if(isShortcutKey) {
1090
+ var
1091
+ $currentlySelected = $item.not(selector.unselectable).filter('.' + className.selected).eq(0),
1092
+ $activeItem = $menu.children('.' + className.active).eq(0),
1093
+ $selectedItem = ($currentlySelected.length > 0)
1094
+ ? $currentlySelected
1095
+ : $activeItem,
1096
+ $visibleItems = ($selectedItem.length > 0)
1097
+ ? $selectedItem.siblings(':not(.' + className.filtered +')').andSelf()
1098
+ : $menu.children(':not(.' + className.filtered +')'),
1099
+ $subMenu = $selectedItem.children(selector.menu),
1100
+ $parentMenu = $selectedItem.closest(selector.menu),
1101
+ inVisibleMenu = ($parentMenu.hasClass(className.visible) || $parentMenu.hasClass(className.animating) || $parentMenu.parent(selector.menu).length > 0),
1102
+ hasSubMenu = ($subMenu.length> 0),
1103
+ hasSelectedItem = ($selectedItem.length > 0),
1104
+ selectedIsVisible = ($selectedItem.not(selector.unselectable).length > 0),
1105
+ $nextItem,
1106
+ isSubMenuItem,
1107
+ newIndex
1108
+ ;
1109
+
1110
+ // visible menu keyboard shortcuts
1111
+ if( module.is.visible() ) {
1112
+
1113
+ // enter (select or open sub-menu)
1114
+ if(pressedKey == keys.enter || pressedKey == keys.delimiter) {
1115
+
1116
+ if(pressedKey == keys.enter && hasSelectedItem && hasSubMenu && !settings.allowCategorySelection) {
1117
+ module.verbose('Pressed enter on unselectable category, opening sub menu');
1118
+ pressedKey = keys.rightArrow;
1119
+ }
1120
+ else if(selectedIsVisible) {
1121
+ module.verbose('Selecting item from keyboard shortcut', $selectedItem);
1122
+ module.event.item.click.call($selectedItem, event);
1123
+ if(settings.useLabels && module.is.searchSelection()) {
1124
+ module.hideAndClear();
1125
+ }
1126
+ else {
1127
+ module.remove.searchTerm();
1128
+ }
1129
+ }
1130
+ event.preventDefault();
1131
+ }
1132
+
1133
+ // left arrow (hide sub-menu)
1134
+ if(pressedKey == keys.leftArrow) {
1135
+
1136
+ isSubMenuItem = ($parentMenu[0] !== $menu[0]);
1137
+
1138
+ if(isSubMenuItem) {
1139
+ module.verbose('Left key pressed, closing sub-menu');
1140
+ module.animate.hide(false, $parentMenu);
1141
+ $selectedItem
1142
+ .removeClass(className.selected)
1143
+ ;
1144
+ $parentMenu
1145
+ .closest(selector.item)
1146
+ .addClass(className.selected)
1147
+ ;
1148
+ event.preventDefault();
1149
+ }
1150
+ }
1151
+
1152
+ // right arrow (show sub-menu)
1153
+ if(pressedKey == keys.rightArrow) {
1154
+ if(hasSubMenu) {
1155
+ module.verbose('Right key pressed, opening sub-menu');
1156
+ module.animate.show(false, $subMenu);
1157
+ $selectedItem
1158
+ .removeClass(className.selected)
1159
+ ;
1160
+ $subMenu
1161
+ .find(selector.item).eq(0)
1162
+ .addClass(className.selected)
1163
+ ;
1164
+ event.preventDefault();
1165
+ }
1166
+ }
1167
+
1168
+ // up arrow (traverse menu up)
1169
+ if(pressedKey == keys.upArrow) {
1170
+ $nextItem = (hasSelectedItem && inVisibleMenu)
1171
+ ? $selectedItem.prevAll(selector.item + ':not(' + selector.unselectable + ')').eq(0)
1172
+ : $item.eq(0)
1173
+ ;
1174
+ if($visibleItems.index( $nextItem ) < 0) {
1175
+ module.verbose('Up key pressed but reached top of current menu');
1176
+ event.preventDefault();
1177
+ return;
1178
+ }
1179
+ else {
1180
+ module.verbose('Up key pressed, changing active item');
1181
+ $selectedItem
1182
+ .removeClass(className.selected)
1183
+ ;
1184
+ $nextItem
1185
+ .addClass(className.selected)
1186
+ ;
1187
+ module.set.scrollPosition($nextItem);
1188
+ }
1189
+ event.preventDefault();
1190
+ }
1191
+
1192
+ // down arrow (traverse menu down)
1193
+ if(pressedKey == keys.downArrow) {
1194
+ $nextItem = (hasSelectedItem && inVisibleMenu)
1195
+ ? $nextItem = $selectedItem.nextAll(selector.item + ':not(' + selector.unselectable + ')').eq(0)
1196
+ : $item.eq(0)
1197
+ ;
1198
+ if($nextItem.length === 0) {
1199
+ module.verbose('Down key pressed but reached bottom of current menu');
1200
+ event.preventDefault();
1201
+ return;
1202
+ }
1203
+ else {
1204
+ module.verbose('Down key pressed, changing active item');
1205
+ $item
1206
+ .removeClass(className.selected)
1207
+ ;
1208
+ $nextItem
1209
+ .addClass(className.selected)
1210
+ ;
1211
+ module.set.scrollPosition($nextItem);
1212
+ }
1213
+ event.preventDefault();
1214
+ }
1215
+
1216
+ // page down (show next page)
1217
+ if(pressedKey == keys.pageUp) {
1218
+ module.scrollPage('up');
1219
+ event.preventDefault();
1220
+ }
1221
+ if(pressedKey == keys.pageDown) {
1222
+ module.scrollPage('down');
1223
+ event.preventDefault();
1224
+ }
1225
+
1226
+ // escape (close menu)
1227
+ if(pressedKey == keys.escape) {
1228
+ module.verbose('Escape key pressed, closing dropdown');
1229
+ module.hide();
1230
+ }
1231
+
1232
+ }
1233
+ else {
1234
+ // delimiter key
1235
+ if(pressedKey == keys.delimiter) {
1236
+ event.preventDefault();
1237
+ }
1238
+ // down arrow (open menu)
1239
+ if(pressedKey == keys.downArrow) {
1240
+ module.verbose('Down key pressed, showing dropdown');
1241
+ module.show();
1242
+ event.preventDefault();
1243
+ }
1244
+ }
1245
+ }
1246
+ else {
1247
+ if( module.is.selection() && !module.is.search() ) {
1248
+ module.set.selectedLetter( String.fromCharCode(pressedKey) );
1249
+ }
1250
+ }
1251
+ }
595
1252
  },
596
1253
 
597
1254
  determine: {
@@ -599,19 +1256,22 @@ $.fn.dropdown = function(parameters) {
599
1256
  module.verbose('Determining action', settings.action);
600
1257
  if( $.isFunction( module.action[settings.action] ) ) {
601
1258
  module.verbose('Triggering preset action', settings.action, text, value);
602
- module.action[ settings.action ](text, value);
1259
+ module.action[ settings.action ].call(this, text, value);
603
1260
  }
604
1261
  else if( $.isFunction(settings.action) ) {
605
1262
  module.verbose('Triggering user action', settings.action, text, value);
606
- settings.action(text, value);
1263
+ settings.action.call(this, text, value);
607
1264
  }
608
1265
  else {
609
1266
  module.error(error.action, settings.action);
610
1267
  }
611
1268
  },
612
1269
  eventInModule: function(event, callback) {
613
- callback = callback || function(){};
614
- if( $(event.target).closest($module).size() === 0 ) {
1270
+ callback = $.isFunction(callback)
1271
+ ? callback
1272
+ : function(){}
1273
+ ;
1274
+ if( $(event.target).closest($module).length === 0 ) {
615
1275
  module.verbose('Triggering event', callback);
616
1276
  callback();
617
1277
  return true;
@@ -621,9 +1281,15 @@ $.fn.dropdown = function(parameters) {
621
1281
  return false;
622
1282
  }
623
1283
  },
624
- eventInMenu: function(event, callback) {
625
- callback = callback || function(){};
626
- if( $(event.target).closest($menu).size() === 0 ) {
1284
+ eventOnElement: function(event, callback) {
1285
+ var
1286
+ $target = $(event.target)
1287
+ ;
1288
+ callback = $.isFunction(callback)
1289
+ ? callback
1290
+ : function(){}
1291
+ ;
1292
+ if($target.closest($menu).length === 0) {
627
1293
  module.verbose('Triggering event', callback);
628
1294
  callback();
629
1295
  return true;
@@ -639,28 +1305,23 @@ $.fn.dropdown = function(parameters) {
639
1305
 
640
1306
  nothing: function() {},
641
1307
 
642
- hide: function() {
643
- module.hide();
644
- },
645
-
646
- select: function(text, value) {
1308
+ activate: function(text, value) {
647
1309
  value = (value !== undefined)
648
1310
  ? value
649
1311
  : text
650
1312
  ;
651
- module.set.selected(value);
652
- module.set.value(value);
653
- module.hide();
1313
+ module.set.selected(value, $(this));
1314
+ if(module.is.multiple() && !module.is.allFiltered()) {
1315
+ return;
1316
+ }
1317
+ else {
1318
+ module.hideAndClear();
1319
+ }
654
1320
  },
655
1321
 
656
- activate: function(text, value) {
657
- value = (value !== undefined)
658
- ? value
659
- : text
660
- ;
661
- module.set.selected(value);
662
- module.set.value(value);
663
- module.hide();
1322
+ select: function(text, value) {
1323
+ // mimics action.activate but does not select text
1324
+ module.action.activate.call(this);
664
1325
  },
665
1326
 
666
1327
  combo: function(text, value) {
@@ -668,23 +1329,177 @@ $.fn.dropdown = function(parameters) {
668
1329
  ? value
669
1330
  : text
670
1331
  ;
671
- module.set.selected(value);
672
- module.set.value(value);
673
- module.hide();
1332
+ module.set.selected(value, $(this));
1333
+ module.hideAndClear();
1334
+ },
1335
+
1336
+ hide: function() {
1337
+ module.hideAndClear();
674
1338
  }
675
1339
 
676
1340
  },
677
1341
 
678
1342
  get: {
1343
+ id: function() {
1344
+ return id;
1345
+ },
679
1346
  text: function() {
680
1347
  return $text.text();
681
1348
  },
1349
+ query: function() {
1350
+ return $.trim($search.val());
1351
+ },
1352
+ searchWidth: function(characterCount) {
1353
+ return (characterCount * settings.glyphWidth) + 'em';
1354
+ },
1355
+ selectionCount: function() {
1356
+ var
1357
+ values = module.get.values()
1358
+ ;
1359
+ return ( module.is.multiple() )
1360
+ ? $.isArray(values)
1361
+ ? values.length
1362
+ : 0
1363
+ : (module.get.value() !== '')
1364
+ ? 1
1365
+ : 0
1366
+ ;
1367
+ },
1368
+ transition: function($subMenu) {
1369
+ return (settings.transition == 'auto')
1370
+ ? module.is.upward($subMenu)
1371
+ ? 'slide up'
1372
+ : 'slide down'
1373
+ : settings.transition
1374
+ ;
1375
+ },
1376
+ userValues: function() {
1377
+ var
1378
+ values = module.get.values()
1379
+ ;
1380
+ if(!values) {
1381
+ return false;
1382
+ }
1383
+ values = $.isArray(values)
1384
+ ? values
1385
+ : [values]
1386
+ ;
1387
+ return $.grep(values, function(value) {
1388
+ return (module.get.item(value) === false);
1389
+ });
1390
+ },
1391
+ uniqueArray: function(array) {
1392
+ return $.grep(array, function (value, index) {
1393
+ return $.inArray(value, array) === index;
1394
+ });
1395
+ },
1396
+ caretPosition: function() {
1397
+ var
1398
+ input = $search.get(0),
1399
+ range,
1400
+ rangeLength
1401
+ ;
1402
+ if('selectionStart' in input) {
1403
+ return input.selectionStart;
1404
+ }
1405
+ else if (document.selection) {
1406
+ input.focus();
1407
+ range = document.selection.createRange();
1408
+ rangeLength = range.text.length;
1409
+ range.moveStart('character', -input.value.length);
1410
+ return range.text.length - rangeLength;
1411
+ }
1412
+ },
1413
+ shortcutKeys: function() {
1414
+ return {
1415
+ backspace : 8,
1416
+ delimiter : 188, // comma
1417
+ deleteKey : 46,
1418
+ enter : 13,
1419
+ escape : 27,
1420
+ pageUp : 33,
1421
+ pageDown : 34,
1422
+ leftArrow : 37,
1423
+ upArrow : 38,
1424
+ rightArrow : 39,
1425
+ downArrow : 40
1426
+ };
1427
+ },
682
1428
  value: function() {
683
- return ($input.size() > 0)
1429
+ return ($input.length > 0)
684
1430
  ? $input.val()
685
1431
  : $module.data(metadata.value)
686
1432
  ;
687
1433
  },
1434
+ values: function() {
1435
+ var
1436
+ value = module.get.value()
1437
+ ;
1438
+ if(value === '') {
1439
+ return '';
1440
+ }
1441
+ return (!$input.is('select') && module.is.multiple())
1442
+ ? typeof value == 'string'
1443
+ ? value.split(settings.delimiter)
1444
+ : ''
1445
+ : value
1446
+ ;
1447
+ },
1448
+ remoteValues: function() {
1449
+ var
1450
+ values = module.get.values(),
1451
+ remoteValues = false
1452
+ ;
1453
+ if(values) {
1454
+ if(typeof values == 'string') {
1455
+ values = [values];
1456
+ }
1457
+ remoteValues = {};
1458
+ $.each(values, function(index, value) {
1459
+ var
1460
+ name = module.read.remoteData(value)
1461
+ ;
1462
+ module.verbose('Restoring value from session data', name, value);
1463
+ remoteValues[value] = (name)
1464
+ ? name
1465
+ : value
1466
+ ;
1467
+ });
1468
+ }
1469
+ return remoteValues;
1470
+ },
1471
+ choiceText: function($choice, preserveHTML) {
1472
+ preserveHTML = (preserveHTML !== undefined)
1473
+ ? preserveHTML
1474
+ : settings.preserveHTML
1475
+ ;
1476
+ if($choice) {
1477
+ if($choice.find(selector.menu).length > 0) {
1478
+ module.verbose('Retreiving text of element with sub-menu');
1479
+ $choice = $choice.clone();
1480
+ $choice.find(selector.menu).remove();
1481
+ $choice.find(selector.menuIcon).remove();
1482
+ }
1483
+ return ($choice.data(metadata.text) !== undefined)
1484
+ ? $choice.data(metadata.text)
1485
+ : (preserveHTML)
1486
+ ? $choice.html().trim()
1487
+ : $choice.text().trim()
1488
+ ;
1489
+ }
1490
+ },
1491
+ choiceValue: function($choice, choiceText) {
1492
+ choiceText = choiceText || module.get.choiceText($choice);
1493
+ if(!$choice) {
1494
+ return false;
1495
+ }
1496
+ return ($choice.data(metadata.value) !== undefined)
1497
+ ? $choice.data(metadata.value)
1498
+ : (typeof choiceText === 'string')
1499
+ ? choiceText.toLowerCase().trim()
1500
+ : choiceText
1501
+ ;
1502
+ },
688
1503
  inputEvent: function() {
689
1504
  var
690
1505
  input = $search[0]
@@ -701,86 +1516,162 @@ $.fn.dropdown = function(parameters) {
701
1516
  },
702
1517
  selectValues: function() {
703
1518
  var
704
- select = {
705
- values : {}
706
- }
1519
+ select = {}
707
1520
  ;
1521
+ select.values = [];
708
1522
  $module
709
1523
  .find('option')
710
1524
  .each(function() {
711
1525
  var
712
- name = $(this).html(),
713
- value = ( $(this).attr('value') !== undefined )
714
- ? $(this).attr('value')
1526
+ $option = $(this),
1527
+ name = $option.html(),
1528
+ disabled = $option.attr('disabled'),
1529
+ value = ( $option.attr('value') !== undefined )
1530
+ ? $option.attr('value')
715
1531
  : name
716
1532
  ;
717
- if(value === '') {
1533
+ if(settings.placeholder === 'auto' && value === '') {
718
1534
  select.placeholder = name;
719
1535
  }
720
1536
  else {
721
- select.values[value] = name;
1537
+ select.values.push({
1538
+ name : name,
1539
+ value : value,
1540
+ disabled : disabled
1541
+ });
722
1542
  }
723
1543
  })
724
1544
  ;
725
- module.debug('Retrieved values from select', select);
1545
+ if(settings.placeholder && settings.placeholder !== 'auto') {
1546
+ module.debug('Setting placeholder value to', settings.placeholder);
1547
+ select.placeholder = settings.placeholder;
1548
+ }
1549
+ if(settings.sortSelect) {
1550
+ select.values.sort(function(a, b) {
1551
+ return (a.name > b.name)
1552
+ ? 1
1553
+ : -1
1554
+ ;
1555
+ });
1556
+ module.debug('Retrieved and sorted values from select', select);
1557
+ }
1558
+ else {
1559
+ module.debug('Retreived values from select', select);
1560
+ }
726
1561
  return select;
727
1562
  },
1563
+ activeItem: function() {
1564
+ return $item.filter('.' + className.active);
1565
+ },
1566
+ selectedItem: function() {
1567
+ var
1568
+ $selectedItem = $item.not(selector.unselectable).filter('.' + className.selected)
1569
+ ;
1570
+ return ($selectedItem.length > 0)
1571
+ ? $selectedItem
1572
+ : $item.eq(0)
1573
+ ;
1574
+ },
1575
+ itemWithAdditions: function(value) {
1576
+ var
1577
+ $items = module.get.item(value),
1578
+ $userItems = module.create.userChoice(value),
1579
+ hasUserItems = ($userItems && $userItems.length > 0)
1580
+ ;
1581
+ if(hasUserItems) {
1582
+ $items = ($items.length > 0)
1583
+ ? $items.add($userItems)
1584
+ : $userItems
1585
+ ;
1586
+ }
1587
+ return $items;
1588
+ },
728
1589
  item: function(value, strict) {
729
1590
  var
730
- $selectedItem = false
1591
+ $selectedItem = false,
1592
+ shouldSearch,
1593
+ isMultiple
731
1594
  ;
732
1595
  value = (value !== undefined)
733
1596
  ? value
734
- : ( module.get.value() !== undefined)
735
- ? module.get.value()
1597
+ : ( module.get.values() !== undefined)
1598
+ ? module.get.values()
736
1599
  : module.get.text()
737
1600
  ;
738
- strict = (value === '' || value === 0)
1601
+ shouldSearch = (isMultiple)
1602
+ ? (value.length > 0)
1603
+ : (value !== undefined && value !== '' && value !== null)
1604
+ ;
1605
+ isMultiple = (module.is.multiple() && $.isArray(value));
1606
+ strict = (value === '' || value === 0)
739
1607
  ? true
740
1608
  : strict || false
741
1609
  ;
742
- if(value !== undefined) {
1610
+ if(shouldSearch) {
743
1611
  $item
744
1612
  .each(function() {
745
1613
  var
746
1614
  $choice = $(this),
747
- optionText = ( $choice.data(metadata.text) !== undefined )
748
- ? $choice.data(metadata.text)
749
- : (settings.preserveHTML)
750
- ? $choice.html()
751
- : $choice.text(),
752
- optionValue = ( $choice.data(metadata.value) !== undefined )
753
- ? $choice.data(metadata.value)
754
- : (typeof optionText === 'string')
755
- ? optionText.toLowerCase()
756
- : optionText
1615
+ optionText = module.get.choiceText($choice),
1616
+ optionValue = module.get.choiceValue($choice, optionText)
757
1617
  ;
758
- if(strict) {
759
- module.verbose('Ambiguous dropdown value using strict type check', $choice, value);
760
- if( optionValue === value ) {
761
- $selectedItem = $(this);
1618
+ // safe early exit
1619
+ if(optionValue === null || optionValue === undefined) {
1620
+ return;
1621
+ }
1622
+ if(isMultiple) {
1623
+ if($.inArray(optionValue.toString(), value) !== -1 || $.inArray(optionText, value) !== -1) {
1624
+ $selectedItem = ($selectedItem)
1625
+ ? $selectedItem.add($choice)
1626
+ : $choice
1627
+ ;
762
1628
  }
763
- else if( !$selectedItem && optionText === value ) {
764
- $selectedItem = $(this);
1629
+ }
1630
+ else if(strict) {
1631
+ module.verbose('Ambiguous dropdown value using strict type check', $choice, value);
1632
+ if( optionValue === value || optionText === value) {
1633
+ $selectedItem = $choice;
1634
+ return true;
765
1635
  }
766
1636
  }
767
1637
  else {
768
- if( optionValue == value ) {
1638
+ if( optionValue.toString() == value.toString() || optionText == value) {
769
1639
  module.verbose('Found select item by value', optionValue, value);
770
- $selectedItem = $(this);
771
- }
772
- else if( !$selectedItem && optionText == value ) {
773
- module.verbose('Found select item by text', optionText, value);
774
- $selectedItem = $(this);
1640
+ $selectedItem = $choice;
1641
+ return true;
775
1642
  }
776
1643
  }
777
1644
  })
778
1645
  ;
779
1646
  }
780
- else {
781
- value = module.get.text();
1647
+ return $selectedItem;
1648
+ }
1649
+ },
1650
+
1651
+ check: {
1652
+ maxSelections: function(selectionCount) {
1653
+ if(settings.maxSelections) {
1654
+ selectionCount = (selectionCount !== undefined)
1655
+ ? selectionCount
1656
+ : module.get.selectionCount()
1657
+ ;
1658
+ if(selectionCount >= settings.maxSelections) {
1659
+ module.debug('Maximum selection count reached');
1660
+ $item.addClass(className.filtered);
1661
+ module.add.message(message.maxSelections);
1662
+ return true;
1663
+ }
1664
+ else {
1665
+ module.verbose('No longer at maximum selection count');
1666
+ module.remove.message();
1667
+ module.remove.filteredItem();
1668
+ if(module.is.searchSelection()) {
1669
+ module.filterItems();
1670
+ }
1671
+ return false;
1672
+ }
782
1673
  }
783
- return $selectedItem || false;
1674
+ return true;
784
1675
  }
785
1676
  },
786
1677
 
@@ -795,6 +1686,7 @@ $.fn.dropdown = function(parameters) {
795
1686
  ;
796
1687
  module.debug('Restoring default text', defaultText);
797
1688
  module.set.text(defaultText);
1689
+ $text.addClass(className.placeholder);
798
1690
  },
799
1691
  defaultValue: function() {
800
1692
  var
@@ -802,57 +1694,260 @@ $.fn.dropdown = function(parameters) {
802
1694
  ;
803
1695
  if(defaultValue !== undefined) {
804
1696
  module.debug('Restoring default value', defaultValue);
805
- module.set.selected(defaultValue);
806
- module.set.value(defaultValue);
1697
+ if(defaultValue !== '') {
1698
+ module.set.value(defaultValue);
1699
+ module.set.selected();
1700
+ }
1701
+ else {
1702
+ module.remove.activeItem();
1703
+ module.remove.selectedItem();
1704
+ }
1705
+ }
1706
+ },
1707
+ labels: function() {
1708
+ if(settings.allowAdditions) {
1709
+ if(!settings.useLabels) {
1710
+ module.error(error.labels);
1711
+ settings.useLabels = true;
1712
+ }
1713
+ module.debug('Restoring selected values');
1714
+ module.create.userLabels();
1715
+ }
1716
+ module.check.maxSelections();
1717
+ },
1718
+ selected: function() {
1719
+ module.restore.values();
1720
+ if(module.is.multiple()) {
1721
+ module.debug('Restoring previously selected values and labels');
1722
+ module.restore.labels();
1723
+ }
1724
+ else {
1725
+ module.debug('Restoring previously selected values');
1726
+ }
1727
+ },
1728
+ values: function() {
1729
+ // prevents callbacks from occuring on initial load
1730
+ module.set.initialLoad();
1731
+ if(settings.apiSettings) {
1732
+ if(settings.saveRemoteData) {
1733
+ module.restore.remoteValues();
1734
+ }
1735
+ else {
1736
+ module.clearValue();
1737
+ }
1738
+ }
1739
+ else {
1740
+ module.set.selected();
1741
+ }
1742
+ module.remove.initialLoad();
1743
+ },
1744
+ remoteValues: function() {
1745
+ var
1746
+ values = module.get.remoteValues()
1747
+ ;
1748
+ module.debug('Recreating selected from session data', values);
1749
+ if(values) {
1750
+ if( module.is.single() ) {
1751
+ $.each(values, function(value, name) {
1752
+ module.set.text(name);
1753
+ });
1754
+ }
1755
+ else {
1756
+ $.each(values, function(value, name) {
1757
+ module.add.label(value, name);
1758
+ });
1759
+ }
807
1760
  }
808
1761
  }
809
1762
  },
810
1763
 
1764
+ read: {
1765
+ remoteData: function(value) {
1766
+ var
1767
+ name
1768
+ ;
1769
+ if(window.Storage === undefined) {
1770
+ module.error(error.noStorage);
1771
+ return;
1772
+ }
1773
+ name = sessionStorage.getItem(value);
1774
+ return (name !== undefined)
1775
+ ? name
1776
+ : false
1777
+ ;
1778
+ }
1779
+ },
1780
+
811
1781
  save: {
812
1782
  defaults: function() {
813
1783
  module.save.defaultText();
1784
+ module.save.placeholderText();
814
1785
  module.save.defaultValue();
815
1786
  },
816
1787
  defaultValue: function() {
817
- $module.data(metadata.defaultValue, module.get.value() );
1788
+ var
1789
+ value = module.get.value()
1790
+ ;
1791
+ module.verbose('Saving default value as', value);
1792
+ $module.data(metadata.defaultValue, value);
818
1793
  },
819
1794
  defaultText: function() {
820
- $module.data(metadata.defaultText, $text.text() );
1795
+ var
1796
+ text = module.get.text()
1797
+ ;
1798
+ module.verbose('Saving default text as', text);
1799
+ $module.data(metadata.defaultText, text);
1800
+ },
1801
+ placeholderText: function() {
1802
+ var
1803
+ text
1804
+ ;
1805
+ if($text.hasClass(className.placeholder)) {
1806
+ text = module.get.text();
1807
+ module.verbose('Saving placeholder text as', text);
1808
+ $module.data(metadata.placeholderText, text);
1809
+ }
1810
+ },
1811
+ remoteData: function(name, value) {
1812
+ if(window.Storage === undefined) {
1813
+ module.error(error.noStorage);
1814
+ return;
1815
+ }
1816
+ module.verbose('Saving remote data to session storage', value, name);
1817
+ sessionStorage.setItem(value, name);
1818
+ }
1819
+ },
1820
+
1821
+ clear: function() {
1822
+ if(module.is.multiple()) {
1823
+ module.remove.labels();
1824
+ }
1825
+ else {
1826
+ module.remove.activeItem();
1827
+ module.remove.selectedItem();
1828
+ }
1829
+ module.set.placeholderText();
1830
+ module.clearValue();
1831
+ },
1832
+
1833
+ clearValue: function() {
1834
+ module.set.value('');
1835
+ },
1836
+
1837
+ scrollPage: function(direction, $selectedItem) {
1838
+ var
1839
+ $selectedItem = $selectedItem || module.get.selectedItem(),
1840
+ $menu = $selectedItem.closest(selector.menu),
1841
+ menuHeight = $menu.outerHeight(),
1842
+ currentScroll = $menu.scrollTop(),
1843
+ itemHeight = $item.eq(0).outerHeight(),
1844
+ itemsPerPage = Math.floor(menuHeight / itemHeight),
1845
+ maxScroll = $menu.prop('scrollHeight'),
1846
+ newScroll = (direction == 'up')
1847
+ ? currentScroll - (itemHeight * itemsPerPage)
1848
+ : currentScroll + (itemHeight * itemsPerPage),
1849
+ $selectableItem = $item.not(selector.unselectable),
1850
+ isWithinRange,
1851
+ $nextSelectedItem,
1852
+ elementIndex
1853
+ ;
1854
+ elementIndex = (direction == 'up')
1855
+ ? $selectableItem.index($selectedItem) - itemsPerPage
1856
+ : $selectableItem.index($selectedItem) + itemsPerPage
1857
+ ;
1858
+ isWithinRange = (direction == 'up')
1859
+ ? (elementIndex >= 0)
1860
+ : (elementIndex < $selectableItem.length)
1861
+ ;
1862
+ $nextSelectedItem = (isWithinRange)
1863
+ ? $selectableItem.eq(elementIndex)
1864
+ : (direction == 'up')
1865
+ ? $selectableItem.first()
1866
+ : $selectableItem.last()
1867
+ ;
1868
+ if($nextSelectedItem.length > 0) {
1869
+ module.debug('Scrolling page', direction, $nextSelectedItem);
1870
+ $selectedItem
1871
+ .removeClass(className.selected)
1872
+ ;
1873
+ $nextSelectedItem
1874
+ .addClass(className.selected)
1875
+ ;
1876
+ $menu
1877
+ .scrollTop(newScroll)
1878
+ ;
821
1879
  }
822
1880
  },
823
1881
 
824
1882
  set: {
825
1883
  filtered: function() {
826
- $text.addClass(className.filtered);
1884
+ var
1885
+ isMultiple = module.is.multiple(),
1886
+ isSearch = module.is.searchSelection(),
1887
+ isSearchMultiple = (isMultiple && isSearch),
1888
+ searchValue = (isSearch)
1889
+ ? module.get.query()
1890
+ : '',
1891
+ hasSearchValue = (typeof searchValue === 'string' && searchValue.length > 0),
1892
+ searchWidth = module.get.searchWidth(searchValue.length),
1893
+ valueIsSet = searchValue !== ''
1894
+ ;
1895
+ if(isMultiple && hasSearchValue) {
1896
+ module.verbose('Adjusting input width', searchWidth, settings.glyphWidth);
1897
+ $search.css('width', searchWidth);
1898
+ }
1899
+ if(hasSearchValue || (isSearchMultiple && valueIsSet)) {
1900
+ module.verbose('Hiding placeholder text');
1901
+ $text.addClass(className.filtered);
1902
+ }
1903
+ else if(!isMultiple || (isSearchMultiple && !valueIsSet)) {
1904
+ module.verbose('Showing placeholder text');
1905
+ $text.removeClass(className.filtered);
1906
+ }
1907
+ },
1908
+ loading: function() {
1909
+ $module.addClass(className.loading);
1910
+ },
1911
+ placeholderText: function(text) {
1912
+ text = text || $module.data(metadata.placeholderText);
1913
+ if(text) {
1914
+ module.debug('Restoring placeholder text');
1915
+ module.set.text(text);
1916
+ $text.addClass(className.placeholder);
1917
+ }
827
1918
  },
828
1919
  tabbable: function() {
829
- if( module.is.searchable() ) {
830
- module.debug('Searchable dropdown initialized');
1920
+ if( module.has.search() ) {
1921
+ module.debug('Added tabindex to searchable dropdown');
831
1922
  $search
832
1923
  .val('')
833
1924
  .attr('tabindex', 0)
834
1925
  ;
835
1926
  $menu
836
- .attr('tabindex', '-1')
1927
+ .attr('tabindex', -1)
837
1928
  ;
838
1929
  }
839
1930
  else {
840
- module.debug('Simple selection dropdown initialized');
1931
+ module.debug('Added tabindex to dropdown');
841
1932
  if(!$module.attr('tabindex') ) {
842
1933
  $module
843
1934
  .attr('tabindex', 0)
844
1935
  ;
845
1936
  $menu
846
- .attr('tabindex', '-1')
1937
+ .attr('tabindex', -1)
847
1938
  ;
848
1939
  }
849
1940
  }
850
1941
  },
851
- scrollPosition: function($item) {
1942
+ initialLoad: function() {
1943
+ module.verbose('Setting initial load');
1944
+ initialLoad = true;
1945
+ },
1946
+ scrollPosition: function($item, forceScroll) {
852
1947
  var
853
- $item = $item || module.get.item(),
854
- hasActive = ($item && $item.size() > 0),
855
1948
  edgeTolerance = 5,
1949
+ $menu,
1950
+ hasActive,
856
1951
  offset,
857
1952
  itemHeight,
858
1953
  itemOffset,
@@ -862,89 +1957,400 @@ $.fn.dropdown = function(parameters) {
862
1957
  abovePage,
863
1958
  belowPage
864
1959
  ;
865
- if($item && hasActive) {
866
- menuHeight = $menu.height();
867
- itemHeight = $item.height();
1960
+
1961
+ $item = $item || module.get.selectedItem();
1962
+ $menu = $item.closest(selector.menu);
1963
+ hasActive = ($item && $item.length > 0);
1964
+ forceScroll = (forceScroll !== undefined)
1965
+ ? forceScroll
1966
+ : false
1967
+ ;
1968
+ if($item && $menu.length > 0 && hasActive) {
1969
+ itemOffset = $item.position().top;
1970
+
1971
+ $menu.addClass(className.loading);
868
1972
  menuScroll = $menu.scrollTop();
869
1973
  menuOffset = $menu.offset().top;
870
1974
  itemOffset = $item.offset().top;
871
1975
  offset = menuScroll - menuOffset + itemOffset;
872
- belowPage = menuScroll + menuHeight < (offset + edgeTolerance);
873
- abovePage = ((offset - edgeTolerance) < menuScroll);
874
- if(abovePage || belowPage) {
875
- module.debug('Scrolling to active item');
876
- $menu
877
- .scrollTop(offset)
878
- ;
1976
+ if(!forceScroll) {
1977
+ menuHeight = $menu.height();
1978
+ belowPage = menuScroll + menuHeight < (offset + edgeTolerance);
1979
+ abovePage = ((offset - edgeTolerance) < menuScroll);
1980
+ }
1981
+ module.debug('Scrolling to active item', offset);
1982
+ if(forceScroll || abovePage || belowPage) {
1983
+ $menu.scrollTop(offset);
879
1984
  }
1985
+ $menu.removeClass(className.loading);
880
1986
  }
881
1987
  },
882
1988
  text: function(text) {
883
- if(settings.action == 'combo') {
884
- module.debug('Changing combo button text', text, $combo);
885
- if(settings.preserveHTML) {
886
- $combo.html(text);
1989
+ if(settings.action !== 'select') {
1990
+ if(settings.action == 'combo') {
1991
+ module.debug('Changing combo button text', text, $combo);
1992
+ if(settings.preserveHTML) {
1993
+ $combo.html(text);
1994
+ }
1995
+ else {
1996
+ $combo.text(text);
1997
+ }
1998
+ }
1999
+ else {
2000
+ module.debug('Changing text', text, $text);
2001
+ $text
2002
+ .removeClass(className.filtered)
2003
+ .removeClass(className.placeholder)
2004
+ ;
2005
+ if(settings.preserveHTML) {
2006
+ $text.html(text);
2007
+ }
2008
+ else {
2009
+ $text.text(text);
2010
+ }
2011
+ }
2012
+ }
2013
+ },
2014
+ selectedLetter: function(letter) {
2015
+ var
2016
+ $selectedItem = $item.filter('.' + className.selected),
2017
+ $nextValue = false
2018
+ ;
2019
+ $item
2020
+ .each(function(){
2021
+ var
2022
+ $choice = $(this),
2023
+ text = module.get.choiceText($choice, false),
2024
+ firstLetter = String(text).charAt(0).toLowerCase(),
2025
+ matchedLetter = letter.toLowerCase()
2026
+ ;
2027
+ if(firstLetter == matchedLetter) {
2028
+ $nextValue = $choice;
2029
+ return false;
2030
+ }
2031
+ })
2032
+ ;
2033
+ if($nextValue) {
2034
+ module.verbose('Scrolling to next value with letter', letter);
2035
+ module.set.scrollPosition($nextValue);
2036
+ $selectedItem.removeClass(className.selected);
2037
+ $nextValue.addClass(className.selected);
2038
+ }
2039
+ },
2040
+ direction: function($menu) {
2041
+ if(settings.direction == 'auto') {
2042
+ if(module.is.onScreen($menu)) {
2043
+ module.remove.upward($menu);
887
2044
  }
888
2045
  else {
889
- $combo.text(text);
2046
+ module.set.upward($menu);
2047
+ }
2048
+ }
2049
+ else if(settings.direction == 'upward') {
2050
+ module.set.upward($menu);
2051
+ }
2052
+ },
2053
+ upward: function($menu) {
2054
+ var $element = $menu || $module;
2055
+ $element.addClass(className.upward);
2056
+ },
2057
+ value: function(value, text, $selected) {
2058
+ var
2059
+ hasInput = ($input.length > 0),
2060
+ isAddition = !module.has.value(value),
2061
+ currentValue = module.get.values(),
2062
+ stringValue = (typeof value == 'number')
2063
+ ? value.toString()
2064
+ : value,
2065
+ newValue
2066
+ ;
2067
+ if(hasInput) {
2068
+ if(stringValue == currentValue) {
2069
+ module.verbose('Skipping value update already same value', value, currentValue);
2070
+ if(!module.is.initialLoad()) {
2071
+ return;
2072
+ }
2073
+ }
2074
+ module.debug('Updating input value', value, currentValue);
2075
+ $input
2076
+ .val(value)
2077
+ .trigger('change')
2078
+ ;
2079
+ }
2080
+ else {
2081
+ module.verbose('Storing value in metadata', value, $input);
2082
+ if(value !== currentValue) {
2083
+ $module.data(metadata.value, value);
890
2084
  }
891
2085
  }
892
- else if(settings.action !== 'select') {
893
- module.debug('Changing text', text, $text);
894
- $text
895
- .removeClass(className.filtered)
896
- .removeClass(className.placeholder)
2086
+ if(settings.fireOnInit === false && module.is.initialLoad()) {
2087
+ module.verbose('No callback on initial load', settings.onChange);
2088
+ }
2089
+ else {
2090
+ settings.onChange.call(element, value, text, $selected);
2091
+ }
2092
+ },
2093
+ active: function() {
2094
+ $module
2095
+ .addClass(className.active)
2096
+ ;
2097
+ },
2098
+ multiple: function() {
2099
+ $module.addClass(className.multiple);
2100
+ },
2101
+ visible: function() {
2102
+ $module.addClass(className.visible);
2103
+ },
2104
+ selected: function(value, $selectedItem) {
2105
+ var
2106
+ isMultiple = module.is.multiple(),
2107
+ $userSelectedItem
2108
+ ;
2109
+ $selectedItem = (settings.allowAdditions)
2110
+ ? $selectedItem || module.get.itemWithAdditions(value)
2111
+ : $selectedItem || module.get.item(value)
2112
+ ;
2113
+ if(!$selectedItem) {
2114
+ return;
2115
+ }
2116
+ module.debug('Setting selected menu item to', $selectedItem);
2117
+ if(module.is.single()) {
2118
+ module.remove.activeItem();
2119
+ module.remove.selectedItem();
2120
+ }
2121
+ else if(settings.useLabels) {
2122
+ module.remove.selectedItem();
2123
+ }
2124
+ // select each item
2125
+ $selectedItem
2126
+ .each(function() {
2127
+ var
2128
+ $selected = $(this),
2129
+ selectedText = module.get.choiceText($selected),
2130
+ selectedValue = module.get.choiceValue($selected, selectedText),
2131
+
2132
+ isFiltered = $selected.hasClass(className.filtered),
2133
+ isActive = $selected.hasClass(className.active),
2134
+ isUserValue = $selected.hasClass(className.addition),
2135
+ shouldAnimate = (isMultiple && $selectedItem.length == 1)
2136
+ ;
2137
+ if(isMultiple) {
2138
+ if(!isActive || isUserValue) {
2139
+ if(settings.apiSettings && settings.saveRemoteData) {
2140
+ module.save.remoteData(selectedText, selectedValue);
2141
+ }
2142
+ if(settings.useLabels) {
2143
+ module.add.value(selectedValue, selectedText, $selected);
2144
+ module.add.label(selectedValue, selectedText, shouldAnimate);
2145
+ $selected.addClass(className.active);
2146
+ module.filterActive();
2147
+ module.select.nextAvailable($selectedItem);
2148
+ }
2149
+ else {
2150
+ module.add.value(selectedValue, selectedText, $selected);
2151
+ module.set.text(module.add.variables(message.count));
2152
+ $selected.addClass(className.active);
2153
+ }
2154
+ }
2155
+ else if(!isFiltered) {
2156
+ module.debug('Selected active value, removing label');
2157
+ module.remove.selected(selectedValue);
2158
+ }
2159
+ }
2160
+ else {
2161
+ if(settings.apiSettings && settings.saveRemoteData) {
2162
+ module.save.remoteData(selectedText, selectedValue);
2163
+ }
2164
+ module.set.value(selectedValue, selectedText, $selected);
2165
+ module.set.text(selectedText);
2166
+ $selected
2167
+ .addClass(className.active)
2168
+ .addClass(className.selected)
2169
+ ;
2170
+ }
2171
+ })
2172
+ ;
2173
+ }
2174
+ },
2175
+
2176
+ add: {
2177
+ label: function(value, text, shouldAnimate) {
2178
+ var
2179
+ $next = module.is.searchSelection()
2180
+ ? $search
2181
+ : $text,
2182
+ $label
2183
+ ;
2184
+ $label = $('<a />')
2185
+ .addClass(className.label)
2186
+ .attr('data-value', value)
2187
+ .html(templates.label(value, text))
2188
+ ;
2189
+ $label = settings.onLabelCreate.call($label, value, text);
2190
+
2191
+ if(module.has.label(value)) {
2192
+ module.debug('Label already exists, skipping', value);
2193
+ return;
2194
+ }
2195
+ if(settings.label.variation) {
2196
+ $label.addClass(settings.label.variation);
2197
+ }
2198
+ if(shouldAnimate === true) {
2199
+ module.debug('Animating in label', $label);
2200
+ $label
2201
+ .addClass(className.hidden)
2202
+ .insertBefore($next)
2203
+ .transition(settings.label.transition, settings.label.duration)
2204
+ ;
2205
+ }
2206
+ else {
2207
+ module.debug('Adding selection label', $label);
2208
+ $label
2209
+ .insertBefore($next)
897
2210
  ;
898
- if(settings.preserveHTML) {
899
- $text.html(text);
900
- }
901
- else {
902
- $text.text(text);
903
- }
904
2211
  }
905
2212
  },
906
- value: function(value) {
907
- module.debug('Adding selected value to hidden input', value, $input);
908
- if($input.size() > 0) {
909
- $input
910
- .val(value)
911
- .trigger('change')
2213
+ message: function(message) {
2214
+ var
2215
+ $message = $menu.children(selector.message),
2216
+ html = settings.templates.message(module.add.variables(message))
2217
+ ;
2218
+ if($message.length > 0) {
2219
+ $message
2220
+ .html(html)
912
2221
  ;
913
2222
  }
914
2223
  else {
915
- $module.data(metadata.value, value);
2224
+ $message = $('<div/>')
2225
+ .html(html)
2226
+ .addClass(className.message)
2227
+ .appendTo($menu)
2228
+ ;
916
2229
  }
917
2230
  },
918
- active: function() {
919
- $module
920
- .addClass(className.active)
2231
+ optionValue: function(value) {
2232
+ var
2233
+ $option = $input.find('option[value="' + value + '"]'),
2234
+ hasOption = ($option.length > 0)
921
2235
  ;
2236
+ if(hasOption) {
2237
+ return;
2238
+ }
2239
+ // temporarily disconnect observer
2240
+ if(selectObserver) {
2241
+ selectObserver.disconnect();
2242
+ module.verbose('Temporarily disconnecting mutation observer', value);
2243
+ }
2244
+ $('<option/>')
2245
+ .prop('value', value)
2246
+ .html(value)
2247
+ .appendTo($input)
2248
+ ;
2249
+ module.verbose('Adding user addition as an <option>', value);
2250
+ if(selectObserver) {
2251
+ selectObserver.observe($input[0], {
2252
+ childList : true,
2253
+ subtree : true
2254
+ });
2255
+ }
922
2256
  },
923
- visible: function() {
924
- $module.addClass(className.visible);
925
- },
926
- selected: function(value) {
2257
+ userSuggestion: function(value) {
927
2258
  var
928
- $selectedItem = module.get.item(value),
929
- selectedText
930
- ;
931
- if($selectedItem) {
932
- module.debug('Setting selected menu item to', $selectedItem);
933
- selectedText = ($selectedItem.data(metadata.text) !== undefined)
934
- ? $selectedItem.data(metadata.text)
935
- : (settings.preserveHTML)
936
- ? $selectedItem.html()
937
- : $selectedItem.text()
2259
+ $addition = $menu.children(selector.addition),
2260
+ alreadyHasValue = module.get.item(value),
2261
+ hasUserSuggestion = $addition.length > 0,
2262
+ html
2263
+ ;
2264
+ if(module.has.maxSelections()) {
2265
+ return;
2266
+ }
2267
+ if(value === '' || alreadyHasValue) {
2268
+ $addition.remove();
2269
+ return;
2270
+ }
2271
+ $item
2272
+ .removeClass(className.selected)
2273
+ ;
2274
+ if(hasUserSuggestion) {
2275
+ html = settings.templates.addition(value);
2276
+ $addition
2277
+ .html(html)
2278
+ .data(metadata.value, value)
2279
+ .removeClass(className.filtered)
2280
+ .addClass(className.selected)
938
2281
  ;
939
- module.remove.activeItem();
940
- module.remove.selectedItem();
941
- $selectedItem
942
- .addClass(className.active)
2282
+ module.verbose('Replacing user suggestion with new value', $addition);
2283
+ }
2284
+ else {
2285
+ $addition = module.create.userChoice(value);
2286
+ $addition
2287
+ .prependTo($menu)
943
2288
  .addClass(className.selected)
944
2289
  ;
945
- module.set.text(selectedText);
946
- $.proxy(settings.onChange, element)(value, selectedText, $selectedItem);
2290
+ module.verbose('Adding item choice to menu corresponding with user choice addition', $addition);
2291
+ }
2292
+ },
2293
+ variables: function(message) {
2294
+ var
2295
+ hasCount = (message.search('{count}') !== -1),
2296
+ hasMaxCount = (message.search('{maxCount}') !== -1),
2297
+ hasTerm = (message.search('{term}') !== -1),
2298
+ values,
2299
+ count,
2300
+ query
2301
+ ;
2302
+ module.verbose('Adding templated variables to message', message);
2303
+ if(hasCount) {
2304
+ count = module.get.selectionCount();
2305
+ message = message.replace('{count}', count);
2306
+ }
2307
+ if(hasMaxCount) {
2308
+ count = module.get.selectionCount();
2309
+ message = message.replace('{maxCount}', settings.maxSelections);
2310
+ }
2311
+ if(hasTerm) {
2312
+ query = module.get.query();
2313
+ message = message.replace('{term}', query);
2314
+ }
2315
+ return message;
2316
+ },
2317
+ value: function(addedValue, addedText, $selectedItem) {
2318
+ var
2319
+ currentValue = module.get.values(),
2320
+ newValue
2321
+ ;
2322
+ if(addedValue === '') {
2323
+ module.debug('Cannot select blank values from multiselect');
2324
+ return;
947
2325
  }
2326
+ // extend currently array
2327
+ if($.isArray(currentValue)) {
2328
+ newValue = currentValue.concat([addedValue]);
2329
+ newValue = module.get.uniqueArray(newValue);
2330
+ }
2331
+ else {
2332
+ newValue = [addedValue];
2333
+ }
2334
+ // add values
2335
+ if( $input.is('select')) {
2336
+ if(settings.allowAdditions) {
2337
+ module.add.optionValue(addedValue);
2338
+ module.debug('Adding value to select', addedValue, newValue, $input);
2339
+ }
2340
+ }
2341
+ else {
2342
+ newValue = newValue.join(settings.delimiter);
2343
+ module.debug('Setting hidden input to delimited value', newValue, $input);
2344
+ }
2345
+
2346
+ if(settings.fireOnInit === false && module.is.initialLoad()) {
2347
+ module.verbose('No callback on initial load', settings.onAdd);
2348
+ }
2349
+ else {
2350
+ settings.onAdd.call(element, addedValue, addedText, $selectedItem);
2351
+ }
2352
+ module.set.value(newValue, addedValue, addedText, $selectedItem);
2353
+ module.check.maxSelections();
948
2354
  }
949
2355
  },
950
2356
 
@@ -952,6 +2358,19 @@ $.fn.dropdown = function(parameters) {
952
2358
  active: function() {
953
2359
  $module.removeClass(className.active);
954
2360
  },
2361
+ activeLabel: function() {
2362
+ $module.find(selector.label).removeClass(className.active);
2363
+ },
2364
+ loading: function() {
2365
+ $module.removeClass(className.loading);
2366
+ },
2367
+ initialLoad: function() {
2368
+ initialLoad = false;
2369
+ },
2370
+ upward: function($menu) {
2371
+ var $element = $menu || $module;
2372
+ $element.removeClass(className.upward);
2373
+ },
955
2374
  visible: function() {
956
2375
  $module.removeClass(className.visible);
957
2376
  },
@@ -959,16 +2378,146 @@ $.fn.dropdown = function(parameters) {
959
2378
  $item.removeClass(className.active);
960
2379
  },
961
2380
  filteredItem: function() {
962
- $item.removeClass(className.filtered);
2381
+ if( module.has.maxSelections() ) {
2382
+ return;
2383
+ }
2384
+ if(settings.useLabels) {
2385
+ $item.not('.' + className.active).removeClass(className.filtered);
2386
+ }
2387
+ else {
2388
+ $item.removeClass(className.filtered);
2389
+ }
2390
+ },
2391
+ message: function() {
2392
+ $menu.children(selector.message).remove();
963
2393
  },
964
2394
  searchTerm: function() {
2395
+ module.verbose('Cleared search term');
965
2396
  $search.val('');
2397
+ module.set.filtered();
2398
+ },
2399
+ selected: function(value, $selectedItem) {
2400
+ $selectedItem = (settings.allowAdditions)
2401
+ ? $selectedItem || module.get.itemWithAdditions(value)
2402
+ : $selectedItem || module.get.item(value)
2403
+ ;
2404
+
2405
+ if(!$selectedItem) {
2406
+ return false;
2407
+ }
2408
+
2409
+ $selectedItem
2410
+ .each(function() {
2411
+ var
2412
+ $selected = $(this),
2413
+ selectedText = module.get.choiceText($selected),
2414
+ selectedValue = module.get.choiceValue($selected, selectedText)
2415
+ ;
2416
+ if(module.is.multiple()) {
2417
+ if(settings.useLabels) {
2418
+ module.remove.value(selectedValue, selectedText, $selected);
2419
+ module.remove.label(selectedValue);
2420
+ }
2421
+ else {
2422
+ module.remove.value(selectedValue, selectedText, $selected);
2423
+ module.set.text(module.add.variables(message.count));
2424
+ }
2425
+ }
2426
+ else {
2427
+ module.remove.value(selectedValue, selectedText, $selected);
2428
+ }
2429
+ $selected
2430
+ .removeClass(className.filtered)
2431
+ .removeClass(className.active)
2432
+ ;
2433
+ if(settings.useLabels) {
2434
+ $selected.removeClass(className.selected);
2435
+ }
2436
+ })
2437
+ ;
966
2438
  },
967
2439
  selectedItem: function() {
968
2440
  $item.removeClass(className.selected);
969
2441
  },
2442
+ value: function(removedValue, removedText, $removedItem) {
2443
+ var
2444
+ values = $input.val(),
2445
+ newValue
2446
+ ;
2447
+ if( $input.is('select') ) {
2448
+ module.verbose('Input is <select> removing selected option', removedValue);
2449
+ newValue = module.remove.arrayValue(removedValue, values);
2450
+ }
2451
+ else {
2452
+ module.verbose('Removing from delimited values', removedValue);
2453
+ values = values.split(settings.delimiter);
2454
+ newValue = module.remove.arrayValue(removedValue, values);
2455
+ newValue = newValue.join(settings.delimiter);
2456
+ }
2457
+ if(settings.fireOnInit === false && module.is.initialLoad()) {
2458
+ module.verbose('No callback on initial load', settings.onRemove);
2459
+ }
2460
+ else {
2461
+ settings.onRemove.call(element, removedValue, removedText, $removedItem);
2462
+ }
2463
+ module.set.value(newValue, removedText, $removedItem);
2464
+ module.check.maxSelections();
2465
+ },
2466
+ arrayValue: function(removedValue, values) {
2467
+ values = $.grep(values, function(value){
2468
+ return (removedValue != value);
2469
+ });
2470
+ module.verbose('Removed value from delimited string', removedValue, values);
2471
+ return values;
2472
+ },
2473
+ label: function(value) {
2474
+ var
2475
+ $labels = $module.find(selector.label),
2476
+ $removedLabel = $labels.filter('[data-value="' + value +'"]'),
2477
+ labelCount = $labels.length,
2478
+ isLastLabel = ($labels.index($removedLabel) + 1 == labelCount),
2479
+ shouldAnimate = ( (!module.is.searchSelection() || !module.is.focusedOnSearch()) && isLastLabel)
2480
+ ;
2481
+ if(shouldAnimate) {
2482
+ module.verbose('Animating and removing label', $removedLabel);
2483
+ $removedLabel
2484
+ .transition(settings.label.transition, settings.label.duration, function() {
2485
+ $removedLabel.remove();
2486
+ })
2487
+ ;
2488
+ }
2489
+ else {
2490
+ module.verbose('Removing label', $removedLabel);
2491
+ $removedLabel.remove();
2492
+ }
2493
+ },
2494
+ activeLabels: function($activeLabels) {
2495
+ $activeLabels = $activeLabels || $module.find(selector.label).filter('.' + className.active);
2496
+ module.verbose('Removing active label selections', $activeLabels);
2497
+ module.remove.labels($activeLabels);
2498
+ },
2499
+ labels: function($labels) {
2500
+ $labels = $labels || $module.find(selector.label);
2501
+ module.verbose('Removing labels', $labels);
2502
+ $labels
2503
+ .each(function(){
2504
+ var
2505
+ value = $(this).data('value'),
2506
+ isUserValue = module.is.userValue(value)
2507
+ ;
2508
+ if(isUserValue) {
2509
+ module.remove.value(value);
2510
+ module.remove.label(value);
2511
+ }
2512
+ else {
2513
+ // selected will also remove label
2514
+ module.remove.selected(value);
2515
+ }
2516
+ })
2517
+ ;
2518
+ },
970
2519
  tabbable: function() {
971
- if( module.is.searchable() ) {
2520
+ if( module.has.search() ) {
972
2521
  module.debug('Searchable dropdown initialized');
973
2522
  $search
974
2523
  .attr('tabindex', '-1')
@@ -989,38 +2538,160 @@ $.fn.dropdown = function(parameters) {
989
2538
  }
990
2539
  },
991
2540
 
992
- is: {
2541
+ has: {
993
2542
  search: function() {
994
- return $module.hasClass(className.search);
2543
+ return ($search.length > 0);
995
2544
  },
996
- searchable: function() {
997
- return ($search.size() > 0);
2545
+ input: function() {
2546
+ return ($input.length > 0);
998
2547
  },
999
- searchSelection: function() {
1000
- return ( module.is.searchable() && $search.parent().is($module) );
2548
+ menu: function() {
2549
+ return ($menu.length > 0);
1001
2550
  },
1002
- selection: function() {
1003
- return $module.hasClass(className.selection);
2551
+ message: function() {
2552
+ return ($menu.children(selector.message).length !== 0);
1004
2553
  },
1005
- animating: function($subMenu) {
1006
- return ($subMenu)
1007
- ? $subMenu.is(':animated') || $subMenu.transition && $subMenu.transition('is animating')
1008
- : $menu.is(':animated') || $menu.transition && $menu.transition('is animating')
2554
+ label: function(value) {
2555
+ var
2556
+ $labels = $module.find(selector.label)
1009
2557
  ;
2558
+ return ($labels.filter('[data-value="' + value +'"]').length > 0);
2559
+ },
2560
+ maxSelections: function() {
2561
+ return (settings.maxSelections && module.get.selectionCount() >= settings.maxSelections);
2562
+ },
2563
+ allResultsFiltered: function() {
2564
+ return ($item.filter(selector.unselectable).length === $item.length);
1010
2565
  },
2566
+ value: function(value) {
2567
+ var
2568
+ values = module.get.values(),
2569
+ hasValue = $.isArray(values)
2570
+ ? values && ($.inArray(value, values) !== -1)
2571
+ : (values == value)
2572
+ ;
2573
+ return (hasValue)
2574
+ ? true
2575
+ : false
2576
+ ;
2577
+ }
2578
+ },
2579
+
2580
+ is: {
1011
2581
  active: function() {
1012
2582
  return $module.hasClass(className.active);
1013
2583
  },
1014
- visible: function($subMenu) {
2584
+ alreadySetup: function() {
2585
+ return ($module.is('select') && $module.parent(selector.dropdown).length > 0 && $module.prev().length === 0);
2586
+ },
2587
+ animating: function($subMenu) {
1015
2588
  return ($subMenu)
1016
- ? $subMenu.is(':visible')
1017
- : $menu.is(':visible')
2589
+ ? $subMenu.transition && $subMenu.transition('is animating')
2590
+ : $menu.transition && $menu.transition('is animating')
1018
2591
  ;
1019
2592
  },
2593
+ focused: function() {
2594
+ return (document.activeElement === $module[0]);
2595
+ },
2596
+ focusedOnSearch: function() {
2597
+ return (document.activeElement === $search[0]);
2598
+ },
2599
+ allFiltered: function() {
2600
+ return( (module.is.multiple() || module.has.search()) && !module.has.message() && module.has.allResultsFiltered() );
2601
+ },
1020
2602
  hidden: function($subMenu) {
2603
+ return !module.is.visible($subMenu);
2604
+ },
2605
+ initialLoad: function() {
2606
+ return initialLoad;
2607
+ },
2608
+ onScreen: function($subMenu) {
2609
+ var
2610
+ $currentMenu = $subMenu || $menu,
2611
+ canOpenDownward = true,
2612
+ onScreen = {},
2613
+ calculations
2614
+ ;
2615
+ $currentMenu.addClass(className.loading);
2616
+ calculations = {
2617
+ context: {
2618
+ scrollTop : $context.scrollTop(),
2619
+ height : $context.outerHeight()
2620
+ },
2621
+ menu : {
2622
+ offset: $currentMenu.offset(),
2623
+ height: $currentMenu.outerHeight()
2624
+ }
2625
+ };
2626
+ onScreen = {
2627
+ above : (calculations.context.scrollTop) <= calculations.menu.offset.top - calculations.menu.height,
2628
+ below : (calculations.context.scrollTop + calculations.context.height) >= calculations.menu.offset.top + calculations.menu.height
2629
+ };
2630
+ if(onScreen.below) {
2631
+ module.verbose('Dropdown can fit in context downward', onScreen);
2632
+ canOpenDownward = true;
2633
+ }
2634
+ else if(!onScreen.below && !onScreen.above) {
2635
+ module.verbose('Dropdown cannot fit in either direction, favoring downward', onScreen);
2636
+ canOpenDownward = true;
2637
+ }
2638
+ else {
2639
+ module.verbose('Dropdown cannot fit below, opening upward', onScreen);
2640
+ canOpenDownward = false;
2641
+ }
2642
+ $currentMenu.removeClass(className.loading);
2643
+ return canOpenDownward;
2644
+ },
2645
+ inObject: function(needle, object) {
2646
+ var
2647
+ found = false
2648
+ ;
2649
+ $.each(object, function(index, property) {
2650
+ if(property == needle) {
2651
+ found = true;
2652
+ return true;
2653
+ }
2654
+ });
2655
+ return found;
2656
+ },
2657
+ multiple: function() {
2658
+ return $module.hasClass(className.multiple);
2659
+ },
2660
+ single: function() {
2661
+ return !module.is.multiple();
2662
+ },
2663
+ selectMutation: function(mutations) {
2664
+ var
2665
+ selectChanged = false
2666
+ ;
2667
+ $.each(mutations, function(index, mutation) {
2668
+ if(mutation.target && $(mutation.target).is('select')) {
2669
+ selectChanged = true;
2670
+ return true;
2671
+ }
2672
+ });
2673
+ return selectChanged;
2674
+ },
2675
+ search: function() {
2676
+ return $module.hasClass(className.search);
2677
+ },
2678
+ searchSelection: function() {
2679
+ return ( module.has.search() && $search.closest(selector.menu).length === 0 );
2680
+ },
2681
+ selection: function() {
2682
+ return $module.hasClass(className.selection);
2683
+ },
2684
+ userValue: function(value) {
2685
+ return ($.inArray(value, module.get.userValues()) !== -1);
2686
+ },
2687
+ upward: function($menu) {
2688
+ var $element = $menu || $module;
2689
+ return $element.hasClass(className.upward);
2690
+ },
2691
+ visible: function($subMenu) {
1021
2692
  return ($subMenu)
1022
- ? $subMenu.is(':hidden')
1023
- : $menu.is(':hidden')
2693
+ ? $subMenu.hasClass(className.visible)
2694
+ : $menu.hasClass(className.visible)
1024
2695
  ;
1025
2696
  }
1026
2697
  },
@@ -1030,7 +2701,10 @@ $.fn.dropdown = function(parameters) {
1030
2701
  return (hasTouch || settings.on == 'click');
1031
2702
  },
1032
2703
  show: function() {
1033
- return !$module.hasClass(className.disabled);
2704
+ return !$module.hasClass(className.disabled) && $item.length > 0;
2705
+ },
2706
+ useAPI: function() {
2707
+ return $.fn.api !== undefined;
1034
2708
  }
1035
2709
  },
1036
2710
 
@@ -1044,62 +2718,42 @@ $.fn.dropdown = function(parameters) {
1044
2718
  module.hideSubMenus();
1045
2719
  module.hideOthers();
1046
2720
  module.set.active();
1047
- module.set.scrollPosition();
1048
- }
2721
+ },
2722
+ transition
2723
+ ;
2724
+ callback = $.isFunction(callback)
2725
+ ? callback
2726
+ : function(){}
1049
2727
  ;
1050
- callback = callback || function(){};
1051
2728
  module.verbose('Doing menu show animation', $currentMenu);
2729
+ module.set.direction($subMenu);
2730
+ transition = module.get.transition($subMenu);
2731
+ if( module.is.selection() ) {
2732
+ module.set.scrollPosition(module.get.selectedItem(), true);
2733
+ }
1052
2734
  if( module.is.hidden($currentMenu) || module.is.animating($currentMenu) ) {
1053
- if(settings.transition == 'none') {
1054
- $.proxy(callback, element)();
2735
+ if(transition == 'none') {
2736
+ start();
2737
+ $currentMenu.transition('show');
2738
+ callback.call(element);
1055
2739
  }
1056
2740
  else if($.fn.transition !== undefined && $module.transition('is supported')) {
1057
2741
  $currentMenu
1058
2742
  .transition({
1059
- animation : settings.transition + ' in',
2743
+ animation : transition + ' in',
1060
2744
  debug : settings.debug,
1061
2745
  verbose : settings.verbose,
1062
2746
  duration : settings.duration,
1063
2747
  queue : true,
1064
2748
  onStart : start,
1065
2749
  onComplete : function() {
1066
- $.proxy(callback, element)();
2750
+ callback.call(element);
1067
2751
  }
1068
2752
  })
1069
2753
  ;
1070
2754
  }
1071
- else if(settings.transition == 'slide down') {
1072
- start();
1073
- $currentMenu
1074
- .hide()
1075
- .clearQueue()
1076
- .children()
1077
- .clearQueue()
1078
- .css('opacity', 0)
1079
- .delay(50)
1080
- .animate({
1081
- opacity : 1
1082
- }, settings.duration, 'easeOutQuad', module.event.resetStyle)
1083
- .end()
1084
- .slideDown(100, 'easeOutQuad', function() {
1085
- $.proxy(module.event.resetStyle, this)();
1086
- $.proxy(callback, element)();
1087
- })
1088
- ;
1089
- }
1090
- else if(settings.transition == 'fade') {
1091
- start();
1092
- $currentMenu
1093
- .hide()
1094
- .clearQueue()
1095
- .fadeIn(settings.duration, function() {
1096
- $.proxy(module.event.resetStyle, this)();
1097
- $.proxy(callback, element)();
1098
- })
1099
- ;
1100
- }
1101
2755
  else {
1102
- module.error(error.transition, settings.transition);
2756
+ module.error(error.noTransition, transition);
1103
2757
  }
1104
2758
  }
1105
2759
  },
@@ -1115,62 +2769,40 @@ $.fn.dropdown = function(parameters) {
1115
2769
  if( module.can.click() ) {
1116
2770
  module.unbind.intent();
1117
2771
  }
1118
- module.focusSearch();
1119
2772
  module.remove.active();
1120
- }
2773
+ },
2774
+ transition = module.get.transition($subMenu)
2775
+ ;
2776
+ callback = $.isFunction(callback)
2777
+ ? callback
2778
+ : function(){}
1121
2779
  ;
1122
- callback = callback || function(){};
1123
2780
  if( module.is.visible($currentMenu) || module.is.animating($currentMenu) ) {
1124
2781
  module.verbose('Doing menu hide animation', $currentMenu);
1125
2782
 
1126
- if(settings.transition == 'none') {
1127
- $.proxy(callback, element)();
2783
+ if(transition == 'none') {
2784
+ start();
2785
+ $currentMenu.transition('hide');
2786
+ callback.call(element);
1128
2787
  }
1129
2788
  else if($.fn.transition !== undefined && $module.transition('is supported')) {
1130
2789
  $currentMenu
1131
2790
  .transition({
1132
- animation : settings.transition + ' out',
2791
+ animation : transition + ' out',
1133
2792
  duration : settings.duration,
1134
2793
  debug : settings.debug,
1135
2794
  verbose : settings.verbose,
1136
2795
  queue : true,
1137
2796
  onStart : start,
1138
2797
  onComplete : function() {
1139
- $.proxy(callback, element)();
2798
+ if(settings.direction == 'auto') {
2799
+ module.remove.upward($subMenu);
2800
+ }
2801
+ callback.call(element);
1140
2802
  }
1141
2803
  })
1142
2804
  ;
1143
2805
  }
1144
- else if(settings.transition == 'slide down') {
1145
- start();
1146
- $currentMenu
1147
- .show()
1148
- .clearQueue()
1149
- .children()
1150
- .clearQueue()
1151
- .css('opacity', 1)
1152
- .animate({
1153
- opacity : 0
1154
- }, 100, 'easeOutQuad', module.event.resetStyle)
1155
- .end()
1156
- .delay(50)
1157
- .slideUp(100, 'easeOutQuad', function() {
1158
- $.proxy(module.event.resetStyle, this)();
1159
- $.proxy(callback, element)();
1160
- })
1161
- ;
1162
- }
1163
- else if(settings.transition == 'fade') {
1164
- start();
1165
- $currentMenu
1166
- .show()
1167
- .clearQueue()
1168
- .fadeOut(150, function() {
1169
- $.proxy(module.event.resetStyle, this)();
1170
- $.proxy(callback, element)();
1171
- })
1172
- ;
1173
- }
1174
2806
  else {
1175
2807
  module.error(error.transition);
1176
2808
  }
@@ -1178,6 +2810,18 @@ $.fn.dropdown = function(parameters) {
1178
2810
  }
1179
2811
  },
1180
2812
 
2813
+ hideAndClear: function() {
2814
+ if(module.has.search()) {
2815
+ module.remove.searchTerm();
2816
+ module.hide(function() {
2817
+ module.remove.filteredItem();
2818
+ });
2819
+ }
2820
+ else {
2821
+ module.hide();
2822
+ }
2823
+ },
2824
+
1181
2825
  delay: {
1182
2826
  show: function() {
1183
2827
  module.verbose('Delaying show event to ensure user intent');
@@ -1191,6 +2835,13 @@ $.fn.dropdown = function(parameters) {
1191
2835
  }
1192
2836
  },
1193
2837
 
2838
+ escape: {
2839
+ regExp: function(text) {
2840
+ text = String(text);
2841
+ return text.replace(regExp.escape, '\\$&');
2842
+ }
2843
+ },
2844
+
1194
2845
  setting: function(name, value) {
1195
2846
  module.debug('Changing setting', name, value);
1196
2847
  if( $.isPlainObject(name) ) {
@@ -1260,7 +2911,7 @@ $.fn.dropdown = function(parameters) {
1260
2911
  });
1261
2912
  }
1262
2913
  clearTimeout(module.performance.timer);
1263
- module.performance.timer = setTimeout(module.performance.display, 100);
2914
+ module.performance.timer = setTimeout(module.performance.display, 500);
1264
2915
  },
1265
2916
  display: function() {
1266
2917
  var
@@ -1355,85 +3006,157 @@ $.fn.dropdown = function(parameters) {
1355
3006
  }
1356
3007
  else {
1357
3008
  if(instance !== undefined) {
1358
- module.destroy();
3009
+ instance.invoke('destroy');
1359
3010
  }
1360
3011
  module.initialize();
1361
3012
  }
1362
3013
  })
1363
3014
  ;
1364
-
1365
3015
  return (returnedValue !== undefined)
1366
3016
  ? returnedValue
1367
- : this
3017
+ : $allModules
1368
3018
  ;
1369
3019
  };
1370
3020
 
1371
3021
  $.fn.dropdown.settings = {
1372
3022
 
1373
- debug : false,
1374
- verbose : true,
1375
- performance : true,
3023
+ debug : false,
3024
+ verbose : false,
3025
+ performance : true,
3026
+
3027
+ on : 'click', // what event should show menu action on item selection
3028
+ action : 'activate', // action on item selection (nothing, activate, select, combo, hide, function(){})
3029
+
3030
+
3031
+ apiSettings : false,
3032
+ saveRemoteData : true, // Whether remote name/value pairs should be stored in sessionStorage to allow remote data to be restored on page refresh
3033
+ throttle : 200, // How long to wait after last user input to search remotely
3034
+
3035
+ context : window, // Context to use when determining if on screen
3036
+ direction : 'auto', // Whether dropdown should always open in one direction
3037
+ keepOnScreen : true, // Whether dropdown should check whether it is on screen before showing
3038
+
3039
+ match : 'both', // what to match against with search selection (both, text, or label)
3040
+ fullTextSearch : false, // search anywhere in value
3041
+
3042
+ placeholder : 'auto', // whether to convert blank <select> values to placeholder text
3043
+ preserveHTML : true, // preserve html when selecting value
3044
+ sortSelect : false, // sort selection on init
1376
3045
 
1377
- on : 'click',
1378
- action : 'activate',
3046
+ forceSelection : true, // force a choice on blur with search selection
3047
+ allowAdditions : false, // whether multiple select should allow user added values
1379
3048
 
1380
- allowTab : true,
1381
- fullTextSearch : true,
1382
- preserveHTML : true,
3049
+ maxSelections : false, // When set to a number limits the number of selections to this count
3050
+ useLabels : true, // whether multiple select should filter currently active selections from choices
3051
+ delimiter : ',', // when multiselect uses normal <input> the values will be delmited with this character
1383
3052
 
1384
- delay : {
1385
- show : 200,
1386
- hide : 300,
1387
- touch : 50
3053
+ showOnFocus : true, // show menu on focus
3054
+ allowTab : true, // add tabindex to element
3055
+ allowCategorySelection : false, // allow elements with sub-menus to be selected
3056
+
3057
+ fireOnInit : false, // Whether callbacks should fire when initializing dropdown values
3058
+
3059
+ transition : 'auto', // auto transition will slide down or up based on direction
3060
+ duration : 200, // duration of transition
3061
+
3062
+ glyphWidth : 1.0714, // widest glyph width in em (W is 1.0714 em) used to calculate multiselect input width
3063
+
3064
+ // label settings on multi-select
3065
+ label: {
3066
+ transition : 'scale',
3067
+ duration : 200,
3068
+ variation : false
1388
3069
  },
1389
3070
 
1390
- transition : 'slide down',
1391
- duration : 250,
3071
+ // delay before event
3072
+ delay : {
3073
+ hide : 300,
3074
+ show : 200,
3075
+ search : 20,
3076
+ touch : 50
3077
+ },
1392
3078
 
1393
3079
  /* Callbacks */
3080
+ onChange : function(value, text, $selected){},
3081
+ onAdd : function(value, text, $selected){},
3082
+ onRemove : function(value, text, $selected){},
1394
3083
 
1395
- onChange : function(value, text){},
1396
- onShow : function(){},
1397
- onHide : function(){},
3084
+ onLabelSelect : function($selectedLabels){},
3085
+ onLabelCreate : function(value, text) { return $(this); },
3086
+ onNoResults : function(searchTerm) { return true; },
3087
+ onShow : function(){},
3088
+ onHide : function(){},
1398
3089
 
1399
3090
  /* Component */
1400
-
1401
3091
  name : 'Dropdown',
1402
3092
  namespace : 'dropdown',
1403
3093
 
1404
- error : {
1405
- action : 'You called a dropdown action that was not defined',
1406
- method : 'The method you called is not defined.',
1407
- transition : 'The requested transition was not found'
3094
+ message: {
3095
+ addResult : 'Add <b>{term}</b>',
3096
+ count : '{count} selected',
3097
+ maxSelections : 'Max {maxCount} selections',
3098
+ noResults : 'No results found.',
3099
+ serverError : 'There was an error contacting the server'
3100
+ },
3101
+
3102
+ error : {
3103
+ action : 'You called a dropdown action that was not defined',
3104
+ alreadySetup : 'Once a select has been initialized behaviors must be called on the created ui dropdown',
3105
+ labels : 'Allowing user additions currently requires the use of labels.',
3106
+ method : 'The method you called is not defined.',
3107
+ noAPI : 'The API module is required to load resources remotely',
3108
+ noStorage : 'Saving remote data requires session storage',
3109
+ noTransition : 'This module requires ui transitions <https://github.com/Semantic-Org/UI-Transition>'
1408
3110
  },
1409
3111
 
1410
- metadata: {
1411
- defaultText : 'defaultText',
1412
- defaultValue : 'defaultValue',
1413
- text : 'text',
1414
- value : 'value'
3112
+ regExp : {
3113
+ escape : /[-[\]{}()*+?.,\\^$|#\s]/g,
3114
+ },
3115
+
3116
+ metadata : {
3117
+ defaultText : 'defaultText',
3118
+ defaultValue : 'defaultValue',
3119
+ placeholderText : 'placeholder',
3120
+ text : 'text',
3121
+ value : 'value'
1415
3122
  },
1416
3123
 
1417
3124
  selector : {
1418
- dropdown : '.ui.dropdown',
1419
- text : '> .text:not(.icon)',
1420
- input : '> input[type="hidden"], > select',
1421
- search : '> input.search, .menu > .search > input, .menu > input.search',
1422
- menu : '.menu',
1423
- item : '.item'
3125
+ addition : '.addition',
3126
+ dropdown : '.ui.dropdown',
3127
+ icon : '> .dropdown.icon',
3128
+ input : '> input[type="hidden"], > select',
3129
+ item : '.item',
3130
+ label : '> .label',
3131
+ remove : '> .label > .delete.icon',
3132
+ siblingLabel : '.label',
3133
+ menu : '.menu',
3134
+ message : '.message',
3135
+ menuIcon : '.dropdown.icon',
3136
+ search : 'input.search, .menu > .search > input',
3137
+ text : '> .text:not(.icon)',
3138
+ unselectable : '.disabled, .filtered'
1424
3139
  },
1425
3140
 
1426
3141
  className : {
1427
3142
  active : 'active',
3143
+ addition : 'addition',
1428
3144
  animating : 'animating',
1429
3145
  disabled : 'disabled',
1430
3146
  dropdown : 'ui dropdown',
1431
3147
  filtered : 'filtered',
3148
+ hidden : 'hidden transition',
3149
+ item : 'item',
3150
+ label : 'ui label',
3151
+ loading : 'loading',
1432
3152
  menu : 'menu',
3153
+ message : 'message',
3154
+ multiple : 'multiple',
1433
3155
  placeholder : 'default',
1434
3156
  search : 'search',
1435
3157
  selected : 'selected',
1436
3158
  selection : 'selection',
3159
+ upward : 'upward',
1437
3160
  visible : 'visible'
1438
3161
  }
1439
3162
 
@@ -1441,22 +3164,8 @@ $.fn.dropdown.settings = {
1441
3164
 
1442
3165
  /* Templates */
1443
3166
  $.fn.dropdown.settings.templates = {
1444
- menu: function(select) {
1445
- var
1446
- placeholder = select.placeholder || false,
1447
- values = select.values || {},
1448
- html = ''
1449
- ;
1450
- $.each(select.values, function(value, name) {
1451
- if(value === name) {
1452
- html += '<div class="item">' + name + '</div>';
1453
- }
1454
- else {
1455
- html += '<div class="item" data-value="' + value + '">' + name + '</div>';
1456
- }
1457
- });
1458
- return html;
1459
- },
3167
+
3168
+ // generates dropdown from select values
1460
3169
  dropdown: function(select) {
1461
3170
  var
1462
3171
  placeholder = select.placeholder || false,
@@ -1471,26 +3180,44 @@ $.fn.dropdown.settings.templates = {
1471
3180
  html += '<div class="text"></div>';
1472
3181
  }
1473
3182
  html += '<div class="menu">';
1474
- $.each(select.values, function(value, name) {
1475
- if(value === name) {
1476
- html += '<div class="item">' + name + '</div>';
1477
- }
1478
- else {
1479
- html += '<div class="item" data-value="' + value + '">' + name + '</div>';
1480
- }
3183
+ $.each(select.values, function(index, option) {
3184
+ html += (option.disabled)
3185
+ ? '<div class="disabled item" data-value="' + option.value + '">' + option.name + '</div>'
3186
+ : '<div class="item" data-value="' + option.value + '">' + option.name + '</div>'
3187
+ ;
1481
3188
  });
1482
3189
  html += '</div>';
1483
3190
  return html;
1484
- }
1485
- };
3191
+ },
3192
+
3193
+ // generates just menu from select
3194
+ menu: function(response) {
3195
+ var
3196
+ values = response.values || {},
3197
+ html = ''
3198
+ ;
3199
+ $.each(response.values, function(index, option) {
3200
+ html += '<div class="item" data-value="' + option.value + '">' + option.name + '</div>';
3201
+ });
3202
+ return html;
3203
+ },
3204
+
3205
+ // generates label for multiselect
3206
+ label: function(value, text) {
3207
+ return text + '<i class="delete icon"></i>';
3208
+ },
1486
3209
 
1487
3210
 
1488
- /* Dependencies */
1489
- $.extend( $.easing, {
1490
- easeOutQuad: function (x, t, b, c, d) {
1491
- return -c *(t/=d)*(t-2) + b;
3211
+ // generates messages like "No results"
3212
+ message: function(message) {
3213
+ return message;
1492
3214
  },
1493
- });
1494
3215
 
3216
+ // generates user addition to selection menu
3217
+ addition: function(choice) {
3218
+ return choice;
3219
+ }
3220
+
3221
+ };
1495
3222
 
1496
- })( jQuery, window , document );
3223
+ })( jQuery, window , document );