rbbt-rest 1.8.42 → 1.8.43

Sign up to get free protection for your applications and to get access to all the features.
Files changed (421) hide show
  1. checksums.yaml +4 -4
  2. data/share/views/compass/old/base/backgrounds.sass +41 -0
  3. data/share/views/compass/old/base/blocks.sass +92 -0
  4. data/share/views/compass/old/base/color.sass +66 -0
  5. data/share/views/compass/old/base/colors.sass +66 -0
  6. data/share/views/compass/old/base/font-scale.sass +20 -0
  7. data/share/views/compass/old/base/fonts.sass +56 -0
  8. data/share/views/compass/old/base/hide.sass +95 -0
  9. data/share/views/compass/old/base/icon_content.scss +569 -0
  10. data/share/views/compass/old/base/icons.sass +75 -0
  11. data/share/views/compass/old/base/material.sass +223 -0
  12. data/share/views/compass/old/base/misc.sass +2 -0
  13. data/share/views/compass/old/base/screen_sizes.sass +16 -0
  14. data/share/views/compass/old/base/text.sass +70 -0
  15. data/share/views/compass/old/base/util.sass +6 -0
  16. data/share/views/compass/old/base/variables.sass +68 -0
  17. data/share/views/compass/old/base/variables/color.sass +27 -0
  18. data/share/views/compass/old/blocks.sass +0 -0
  19. data/share/views/compass/old/cards.sass +131 -0
  20. data/share/views/compass/old/color.sass +10 -0
  21. data/share/views/compass/old/color/blocks.sass +0 -0
  22. data/share/views/compass/old/color/buttons.sass +36 -0
  23. data/share/views/compass/old/color/elements.sass +2 -0
  24. data/share/views/compass/old/color/font.sass +13 -0
  25. data/share/views/compass/old/color/top_bar.sass +18 -0
  26. data/share/views/compass/old/elements.sass +218 -0
  27. data/share/views/compass/old/elements/buttons.sass +18 -0
  28. data/share/views/compass/old/elements/forms.sass +197 -0
  29. data/share/views/compass/old/elements/lists.sass +14 -0
  30. data/share/views/compass/old/elements/materials.sass +1 -0
  31. data/share/views/compass/old/elements/movement.sass +84 -0
  32. data/share/views/compass/old/elements/positions.sass +18 -0
  33. data/share/views/compass/old/elements/table.sass +176 -0
  34. data/share/views/compass/old/elements/tool.sass +60 -0
  35. data/share/views/compass/old/grid.sass +3 -0
  36. data/share/views/compass/old/init.sass +9 -0
  37. data/share/views/compass/old/layout.sass +5 -0
  38. data/share/views/compass/old/layout/body.sass +23 -0
  39. data/share/views/compass/old/layout/footer.sass +44 -0
  40. data/share/views/compass/old/layout/result.sass +6 -0
  41. data/share/views/compass/old/layout/reveal.sass +50 -0
  42. data/share/views/compass/old/layout/top_bar.sass +99 -0
  43. data/share/views/compass/old/layout/top_menu.sass +87 -0
  44. data/share/views/compass/old/menu.sass +43 -0
  45. data/share/views/compass/old/menu/accordion_menu.sass +30 -0
  46. data/share/views/compass/old/menu/actionable.sass +1 -0
  47. data/share/views/compass/old/menu/dropdown_menu.sass +31 -0
  48. data/share/views/compass/old/menu/hide.sass +14 -0
  49. data/share/views/compass/old/menu/menu.sass +98 -0
  50. data/share/views/compass/old/menu/tab_menu.sass +14 -0
  51. data/share/views/compass/old/menu/top_bar.sass +105 -0
  52. data/share/views/compass/old/menu/vertical_menu.sass +21 -0
  53. data/share/views/compass/old/mixins/_all.sass +24 -0
  54. data/share/views/compass/old/mixins/_blocks.sass +79 -0
  55. data/share/views/compass/old/mixins/_compass.sass +0 -0
  56. data/share/views/compass/old/mixins/_deps.sass +5 -0
  57. data/share/views/compass/old/mixins/_hide.sass +76 -0
  58. data/share/views/compass/old/mixins/_keyframes.scss +4 -0
  59. data/share/views/compass/old/mixins/_semantic-ui.sass +2 -0
  60. data/share/views/compass/old/new.sass +1 -0
  61. data/share/views/compass/old/offcanvas.sass +52 -0
  62. data/share/views/compass/old/position/basic.sass +0 -0
  63. data/share/views/compass/old/responsive.sass +53 -0
  64. data/share/views/compass/old/semantic-ui.css +1 -0
  65. data/share/views/compass/old/semantic-ui/semantic-ui.css +19776 -0
  66. data/share/views/compass/old/space/button.sass +74 -0
  67. data/share/views/compass/old/table.sass +142 -0
  68. data/share/views/compass/old/text.sass +48 -0
  69. data/share/views/compass/old/variables/colors.sass +7 -0
  70. data/share/views/compass/old/variables/sizes.sass +5 -0
  71. data/share/views/layout/header.haml +1 -1
  72. data/share/views/public/js/helpers/helpers.js +25 -0
  73. data/share/views/public/js/rbbt.views.js +78 -18
  74. data/share/views/public/js/rbbt/table.js +0 -1
  75. data/share/views/public/plugins/FileSaver/js/FileSaver.js +74 -134
  76. data/share/views/public/plugins/jquery/js/jquery-3.1.1.js +10220 -0
  77. data/share/views/public/plugins/semantic-ui/CONTRIBUTING.md +48 -6
  78. data/share/views/public/plugins/semantic-ui/README.md +40 -15
  79. data/share/views/public/plugins/semantic-ui/RELEASE-NOTES.md +669 -14
  80. data/share/views/public/plugins/semantic-ui/bower.json +1 -3
  81. data/share/views/public/plugins/semantic-ui/dist/components/accordion.css +7 -10
  82. data/share/views/public/plugins/semantic-ui/dist/components/accordion.js +39 -21
  83. data/share/views/public/plugins/semantic-ui/dist/components/accordion.min.css +2 -3
  84. data/share/views/public/plugins/semantic-ui/dist/components/accordion.min.js +2 -3
  85. data/share/views/public/plugins/semantic-ui/dist/components/ad.css +2 -3
  86. data/share/views/public/plugins/semantic-ui/dist/components/ad.min.css +2 -2
  87. data/share/views/public/plugins/semantic-ui/dist/components/api.js +161 -71
  88. data/share/views/public/plugins/semantic-ui/dist/components/api.min.js +2 -3
  89. data/share/views/public/plugins/semantic-ui/dist/components/breadcrumb.css +5 -6
  90. data/share/views/public/plugins/semantic-ui/dist/components/breadcrumb.min.css +2 -3
  91. data/share/views/public/plugins/semantic-ui/dist/components/button.css +658 -432
  92. data/share/views/public/plugins/semantic-ui/dist/components/button.min.css +2 -3
  93. data/share/views/public/plugins/semantic-ui/dist/components/card.css +68 -44
  94. data/share/views/public/plugins/semantic-ui/dist/components/card.min.css +2 -3
  95. data/share/views/public/plugins/semantic-ui/dist/components/checkbox.css +126 -89
  96. data/share/views/public/plugins/semantic-ui/dist/components/checkbox.js +216 -91
  97. data/share/views/public/plugins/semantic-ui/dist/components/checkbox.min.css +2 -3
  98. data/share/views/public/plugins/semantic-ui/dist/components/checkbox.min.js +2 -3
  99. data/share/views/public/plugins/semantic-ui/dist/components/colorize.js +1 -1
  100. data/share/views/public/plugins/semantic-ui/dist/components/comment.css +17 -6
  101. data/share/views/public/plugins/semantic-ui/dist/components/comment.min.css +2 -3
  102. data/share/views/public/plugins/semantic-ui/dist/components/container.css +29 -7
  103. data/share/views/public/plugins/semantic-ui/dist/components/container.min.css +2 -3
  104. data/share/views/public/plugins/semantic-ui/dist/components/dimmer.css +7 -9
  105. data/share/views/public/plugins/semantic-ui/dist/components/dimmer.js +80 -39
  106. data/share/views/public/plugins/semantic-ui/dist/components/dimmer.min.css +2 -3
  107. data/share/views/public/plugins/semantic-ui/dist/components/dimmer.min.js +2 -3
  108. data/share/views/public/plugins/semantic-ui/dist/components/divider.css +8 -8
  109. data/share/views/public/plugins/semantic-ui/dist/components/divider.min.css +2 -3
  110. data/share/views/public/plugins/semantic-ui/dist/components/dropdown.css +127 -98
  111. data/share/views/public/plugins/semantic-ui/dist/components/dropdown.js +918 -400
  112. data/share/views/public/plugins/semantic-ui/dist/components/dropdown.min.css +2 -3
  113. data/share/views/public/plugins/semantic-ui/dist/components/dropdown.min.js +3 -5
  114. data/share/views/public/plugins/semantic-ui/dist/components/embed.css +12 -8
  115. data/share/views/public/plugins/semantic-ui/dist/components/embed.js +51 -17
  116. data/share/views/public/plugins/semantic-ui/dist/components/embed.min.css +2 -3
  117. data/share/views/public/plugins/semantic-ui/dist/components/embed.min.js +2 -3
  118. data/share/views/public/plugins/semantic-ui/dist/components/feed.css +5 -6
  119. data/share/views/public/plugins/semantic-ui/dist/components/feed.min.css +2 -3
  120. data/share/views/public/plugins/semantic-ui/dist/components/flag.css +10 -3
  121. data/share/views/public/plugins/semantic-ui/dist/components/flag.min.css +2 -3
  122. data/share/views/public/plugins/semantic-ui/dist/components/form.css +208 -121
  123. data/share/views/public/plugins/semantic-ui/dist/components/form.js +469 -167
  124. data/share/views/public/plugins/semantic-ui/dist/components/form.min.css +2 -3
  125. data/share/views/public/plugins/semantic-ui/dist/components/form.min.js +2 -3
  126. data/share/views/public/plugins/semantic-ui/dist/components/grid.css +222 -71
  127. data/share/views/public/plugins/semantic-ui/dist/components/grid.min.css +2 -3
  128. data/share/views/public/plugins/semantic-ui/dist/components/header.css +47 -48
  129. data/share/views/public/plugins/semantic-ui/dist/components/header.min.css +2 -3
  130. data/share/views/public/plugins/semantic-ui/dist/components/icon.css +839 -280
  131. data/share/views/public/plugins/semantic-ui/dist/components/icon.min.css +2 -3
  132. data/share/views/public/plugins/semantic-ui/dist/components/image.css +7 -3
  133. data/share/views/public/plugins/semantic-ui/dist/components/image.min.css +2 -3
  134. data/share/views/public/plugins/semantic-ui/dist/components/input.css +91 -61
  135. data/share/views/public/plugins/semantic-ui/dist/components/input.min.css +2 -3
  136. data/share/views/public/plugins/semantic-ui/dist/components/item.css +17 -18
  137. data/share/views/public/plugins/semantic-ui/dist/components/item.min.css +2 -3
  138. data/share/views/public/plugins/semantic-ui/dist/components/label.css +497 -304
  139. data/share/views/public/plugins/semantic-ui/dist/components/label.min.css +2 -3
  140. data/share/views/public/plugins/semantic-ui/dist/components/list.css +56 -27
  141. data/share/views/public/plugins/semantic-ui/dist/components/list.min.css +2 -3
  142. data/share/views/public/plugins/semantic-ui/dist/components/loader.css +101 -40
  143. data/share/views/public/plugins/semantic-ui/dist/components/loader.min.css +2 -3
  144. data/share/views/public/plugins/semantic-ui/dist/components/menu.css +335 -179
  145. data/share/views/public/plugins/semantic-ui/dist/components/menu.min.css +1 -1
  146. data/share/views/public/plugins/semantic-ui/dist/components/message.css +83 -65
  147. data/share/views/public/plugins/semantic-ui/dist/components/message.min.css +2 -3
  148. data/share/views/public/plugins/semantic-ui/dist/components/modal.css +16 -18
  149. data/share/views/public/plugins/semantic-ui/dist/components/modal.js +68 -42
  150. data/share/views/public/plugins/semantic-ui/dist/components/modal.min.css +2 -3
  151. data/share/views/public/plugins/semantic-ui/dist/components/modal.min.js +2 -3
  152. data/share/views/public/plugins/semantic-ui/dist/components/nag.css +6 -7
  153. data/share/views/public/plugins/semantic-ui/dist/components/nag.js +41 -10
  154. data/share/views/public/plugins/semantic-ui/dist/components/nag.min.css +2 -3
  155. data/share/views/public/plugins/semantic-ui/dist/components/nag.min.js +2 -3
  156. data/share/views/public/plugins/semantic-ui/dist/components/popup.css +423 -39
  157. data/share/views/public/plugins/semantic-ui/dist/components/popup.js +275 -153
  158. data/share/views/public/plugins/semantic-ui/dist/components/popup.min.css +2 -3
  159. data/share/views/public/plugins/semantic-ui/dist/components/popup.min.js +2 -3
  160. data/share/views/public/plugins/semantic-ui/dist/components/progress.css +47 -48
  161. data/share/views/public/plugins/semantic-ui/dist/components/progress.js +202 -64
  162. data/share/views/public/plugins/semantic-ui/dist/components/progress.min.css +2 -3
  163. data/share/views/public/plugins/semantic-ui/dist/components/progress.min.js +2 -3
  164. data/share/views/public/plugins/semantic-ui/dist/components/rail.css +24 -4
  165. data/share/views/public/plugins/semantic-ui/dist/components/rail.min.css +2 -3
  166. data/share/views/public/plugins/semantic-ui/dist/components/rating.css +12 -13
  167. data/share/views/public/plugins/semantic-ui/dist/components/rating.js +43 -10
  168. data/share/views/public/plugins/semantic-ui/dist/components/rating.min.css +2 -3
  169. data/share/views/public/plugins/semantic-ui/dist/components/rating.min.js +2 -3
  170. data/share/views/public/plugins/semantic-ui/dist/components/reset.css +1 -6
  171. data/share/views/public/plugins/semantic-ui/dist/components/reset.min.css +2 -3
  172. data/share/views/public/plugins/semantic-ui/dist/components/reveal.css +13 -41
  173. data/share/views/public/plugins/semantic-ui/dist/components/reveal.min.css +2 -3
  174. data/share/views/public/plugins/semantic-ui/dist/components/search.css +53 -21
  175. data/share/views/public/plugins/semantic-ui/dist/components/search.js +261 -132
  176. data/share/views/public/plugins/semantic-ui/dist/components/search.min.css +2 -3
  177. data/share/views/public/plugins/semantic-ui/dist/components/search.min.js +2 -3
  178. data/share/views/public/plugins/semantic-ui/dist/components/segment.css +124 -72
  179. data/share/views/public/plugins/semantic-ui/dist/components/segment.min.css +2 -3
  180. data/share/views/public/plugins/semantic-ui/dist/components/shape.css +11 -8
  181. data/share/views/public/plugins/semantic-ui/dist/components/shape.js +68 -23
  182. data/share/views/public/plugins/semantic-ui/dist/components/shape.min.css +2 -3
  183. data/share/views/public/plugins/semantic-ui/dist/components/shape.min.js +2 -3
  184. data/share/views/public/plugins/semantic-ui/dist/components/sidebar.css +45 -36
  185. data/share/views/public/plugins/semantic-ui/dist/components/sidebar.js +23 -10
  186. data/share/views/public/plugins/semantic-ui/dist/components/sidebar.min.css +2 -3
  187. data/share/views/public/plugins/semantic-ui/dist/components/sidebar.min.js +2 -3
  188. data/share/views/public/plugins/semantic-ui/dist/components/site.css +6 -7
  189. data/share/views/public/plugins/semantic-ui/dist/components/site.js +5 -5
  190. data/share/views/public/plugins/semantic-ui/dist/components/site.min.css +2 -3
  191. data/share/views/public/plugins/semantic-ui/dist/components/site.min.js +2 -3
  192. data/share/views/public/plugins/semantic-ui/dist/components/state.js +22 -9
  193. data/share/views/public/plugins/semantic-ui/dist/components/state.min.js +2 -3
  194. data/share/views/public/plugins/semantic-ui/dist/components/statistic.css +46 -45
  195. data/share/views/public/plugins/semantic-ui/dist/components/statistic.min.css +2 -3
  196. data/share/views/public/plugins/semantic-ui/dist/components/step.css +83 -44
  197. data/share/views/public/plugins/semantic-ui/dist/components/step.min.css +2 -3
  198. data/share/views/public/plugins/semantic-ui/dist/components/sticky.css +2 -3
  199. data/share/views/public/plugins/semantic-ui/dist/components/sticky.js +138 -78
  200. data/share/views/public/plugins/semantic-ui/dist/components/sticky.min.css +1 -2
  201. data/share/views/public/plugins/semantic-ui/dist/components/sticky.min.js +2 -3
  202. data/share/views/public/plugins/semantic-ui/dist/components/tab.css +1 -2
  203. data/share/views/public/plugins/semantic-ui/dist/components/tab.js +95 -46
  204. data/share/views/public/plugins/semantic-ui/dist/components/tab.min.css +1 -2
  205. data/share/views/public/plugins/semantic-ui/dist/components/tab.min.js +2 -3
  206. data/share/views/public/plugins/semantic-ui/dist/components/table.css +136 -77
  207. data/share/views/public/plugins/semantic-ui/dist/components/table.min.css +2 -3
  208. data/share/views/public/plugins/semantic-ui/dist/components/transition.css +1 -19
  209. data/share/views/public/plugins/semantic-ui/dist/components/transition.js +58 -32
  210. data/share/views/public/plugins/semantic-ui/dist/components/transition.min.css +2 -3
  211. data/share/views/public/plugins/semantic-ui/dist/components/transition.min.js +2 -3
  212. data/share/views/public/plugins/semantic-ui/dist/components/video.js +1 -1
  213. data/share/views/public/plugins/semantic-ui/dist/components/visibility.js +99 -29
  214. data/share/views/public/plugins/semantic-ui/dist/components/visibility.min.js +2 -3
  215. data/share/views/public/plugins/semantic-ui/dist/semantic.css +5051 -3645
  216. data/share/views/public/plugins/semantic-ui/dist/semantic.js +3345 -1456
  217. data/share/views/public/plugins/semantic-ui/dist/semantic.min.css +2 -2
  218. data/share/views/public/plugins/semantic-ui/dist/semantic.min.js +10 -10
  219. data/share/views/public/plugins/semantic-ui/dist/themes/default/assets/fonts/icons.eot +0 -0
  220. data/share/views/public/plugins/semantic-ui/dist/themes/default/assets/fonts/icons.svg +146 -26
  221. data/share/views/public/plugins/semantic-ui/dist/themes/default/assets/fonts/icons.ttf +0 -0
  222. data/share/views/public/plugins/semantic-ui/dist/themes/default/assets/fonts/icons.woff +0 -0
  223. data/share/views/public/plugins/semantic-ui/dist/themes/default/assets/fonts/icons.woff2 +0 -0
  224. data/share/views/public/plugins/semantic-ui/dist/themes/github/assets/fonts/octicons-local.ttf +0 -0
  225. data/share/views/public/plugins/semantic-ui/dist/themes/github/assets/fonts/octicons.svg +200 -0
  226. data/share/views/public/plugins/semantic-ui/dist/themes/github/assets/fonts/octicons.ttf +0 -0
  227. data/share/views/public/plugins/semantic-ui/dist/themes/github/assets/fonts/octicons.woff +0 -0
  228. data/share/views/public/plugins/semantic-ui/dist/themes/material/assets/fonts/icons.eot +0 -0
  229. data/share/views/public/plugins/semantic-ui/dist/themes/material/assets/fonts/icons.svg +2373 -0
  230. data/share/views/public/plugins/semantic-ui/dist/themes/material/assets/fonts/icons.ttf +0 -0
  231. data/share/views/public/plugins/semantic-ui/dist/themes/material/assets/fonts/icons.woff +0 -0
  232. data/share/views/public/plugins/semantic-ui/examples/assets/library/iframe-content.js +8 -8
  233. data/share/views/public/plugins/semantic-ui/examples/assets/library/iframe.js +1 -1
  234. data/share/views/public/plugins/semantic-ui/examples/attached.html +381 -0
  235. data/share/views/public/plugins/semantic-ui/examples/bootstrap.html +4 -4
  236. data/share/views/public/plugins/semantic-ui/examples/components/site.html +1 -1
  237. data/share/views/public/plugins/semantic-ui/examples/fixed.html +10 -10
  238. data/share/views/public/plugins/semantic-ui/examples/grid.html +1 -1
  239. data/share/views/public/plugins/semantic-ui/examples/homepage.html +3 -3
  240. data/share/views/public/plugins/semantic-ui/examples/login.html +1 -1
  241. data/share/views/public/plugins/semantic-ui/examples/responsive.html +5 -5
  242. data/share/views/public/plugins/semantic-ui/examples/sticky.html +1 -1
  243. data/share/views/public/plugins/semantic-ui/examples/theming.html +1 -1
  244. data/share/views/public/plugins/semantic-ui/gulpfile.js +3 -3
  245. data/share/views/public/plugins/semantic-ui/package.json +36 -31
  246. data/share/views/public/plugins/semantic-ui/semantic.json.example +1 -0
  247. data/share/views/public/plugins/semantic-ui/src/_site/collections/message.overrides +1 -1
  248. data/share/views/public/plugins/semantic-ui/src/definitions/behaviors/api.js +160 -70
  249. data/share/views/public/plugins/semantic-ui/src/definitions/behaviors/colorize.js +235 -229
  250. data/share/views/public/plugins/semantic-ui/src/definitions/behaviors/form.js +468 -166
  251. data/share/views/public/plugins/semantic-ui/src/definitions/behaviors/state.js +21 -8
  252. data/share/views/public/plugins/semantic-ui/src/definitions/behaviors/visibility.js +98 -28
  253. data/share/views/public/plugins/semantic-ui/src/definitions/behaviors/visit.js +14 -6
  254. data/share/views/public/plugins/semantic-ui/src/definitions/collections/breadcrumb.less +2 -3
  255. data/share/views/public/plugins/semantic-ui/src/definitions/collections/form.less +154 -74
  256. data/share/views/public/plugins/semantic-ui/src/definitions/collections/grid.less +171 -41
  257. data/share/views/public/plugins/semantic-ui/src/definitions/collections/menu.less +235 -99
  258. data/share/views/public/plugins/semantic-ui/src/definitions/collections/message.less +28 -10
  259. data/share/views/public/plugins/semantic-ui/src/definitions/collections/table.less +77 -16
  260. data/share/views/public/plugins/semantic-ui/src/definitions/elements/button.less +326 -109
  261. data/share/views/public/plugins/semantic-ui/src/definitions/elements/container.less +25 -7
  262. data/share/views/public/plugins/semantic-ui/src/definitions/elements/divider.less +7 -7
  263. data/share/views/public/plugins/semantic-ui/src/definitions/elements/flag.less +2 -3
  264. data/share/views/public/plugins/semantic-ui/src/definitions/elements/header.less +3 -4
  265. data/share/views/public/plugins/semantic-ui/src/definitions/elements/icon.less +37 -6
  266. data/share/views/public/plugins/semantic-ui/src/definitions/elements/image.less +324 -319
  267. data/share/views/public/plugins/semantic-ui/src/definitions/elements/input.less +70 -39
  268. data/share/views/public/plugins/semantic-ui/src/definitions/elements/label.less +363 -245
  269. data/share/views/public/plugins/semantic-ui/src/definitions/elements/list.less +49 -19
  270. data/share/views/public/plugins/semantic-ui/src/definitions/elements/loader.less +72 -9
  271. data/share/views/public/plugins/semantic-ui/src/definitions/elements/rail.less +21 -2
  272. data/share/views/public/plugins/semantic-ui/src/definitions/elements/reveal.less +6 -14
  273. data/share/views/public/plugins/semantic-ui/src/definitions/elements/segment.less +72 -21
  274. data/share/views/public/plugins/semantic-ui/src/definitions/elements/step.less +68 -34
  275. data/share/views/public/plugins/semantic-ui/src/definitions/globals/reset.less +1 -2
  276. data/share/views/public/plugins/semantic-ui/src/definitions/globals/site.js +4 -4
  277. data/share/views/public/plugins/semantic-ui/src/definitions/globals/site.less +3 -1
  278. data/share/views/public/plugins/semantic-ui/src/definitions/modules/accordion.js +38 -20
  279. data/share/views/public/plugins/semantic-ui/src/definitions/modules/accordion.less +2 -2
  280. data/share/views/public/plugins/semantic-ui/src/definitions/modules/checkbox.js +215 -90
  281. data/share/views/public/plugins/semantic-ui/src/definitions/modules/checkbox.less +105 -69
  282. data/share/views/public/plugins/semantic-ui/src/definitions/modules/dimmer.js +79 -38
  283. data/share/views/public/plugins/semantic-ui/src/definitions/modules/dimmer.less +1 -2
  284. data/share/views/public/plugins/semantic-ui/src/definitions/modules/dropdown.js +917 -399
  285. data/share/views/public/plugins/semantic-ui/src/definitions/modules/dropdown.less +62 -25
  286. data/share/views/public/plugins/semantic-ui/src/definitions/modules/embed.js +51 -17
  287. data/share/views/public/plugins/semantic-ui/src/definitions/modules/embed.less +163 -164
  288. data/share/views/public/plugins/semantic-ui/src/definitions/modules/modal.js +67 -41
  289. data/share/views/public/plugins/semantic-ui/src/definitions/modules/modal.less +7 -8
  290. data/share/views/public/plugins/semantic-ui/src/definitions/modules/nag.js +40 -9
  291. data/share/views/public/plugins/semantic-ui/src/definitions/modules/nag.less +158 -159
  292. data/share/views/public/plugins/semantic-ui/src/definitions/modules/popup.js +274 -152
  293. data/share/views/public/plugins/semantic-ui/src/definitions/modules/popup.less +712 -332
  294. data/share/views/public/plugins/semantic-ui/src/definitions/modules/progress.js +201 -63
  295. data/share/views/public/plugins/semantic-ui/src/definitions/modules/progress.less +0 -1
  296. data/share/views/public/plugins/semantic-ui/src/definitions/modules/rating.js +42 -9
  297. data/share/views/public/plugins/semantic-ui/src/definitions/modules/rating.less +0 -1
  298. data/share/views/public/plugins/semantic-ui/src/definitions/modules/search.js +260 -131
  299. data/share/views/public/plugins/semantic-ui/src/definitions/modules/search.less +35 -2
  300. data/share/views/public/plugins/semantic-ui/src/definitions/modules/shape.js +67 -22
  301. data/share/views/public/plugins/semantic-ui/src/definitions/modules/shape.less +1 -2
  302. data/share/views/public/plugins/semantic-ui/src/definitions/modules/sidebar.js +22 -9
  303. data/share/views/public/plugins/semantic-ui/src/definitions/modules/sidebar.less +13 -15
  304. data/share/views/public/plugins/semantic-ui/src/definitions/modules/sticky.js +137 -77
  305. data/share/views/public/plugins/semantic-ui/src/definitions/modules/sticky.less +1 -2
  306. data/share/views/public/plugins/semantic-ui/src/definitions/modules/tab.js +94 -45
  307. data/share/views/public/plugins/semantic-ui/src/definitions/modules/tab.less +1 -2
  308. data/share/views/public/plugins/semantic-ui/src/definitions/modules/transition.js +57 -31
  309. data/share/views/public/plugins/semantic-ui/src/definitions/modules/transition.less +1 -2
  310. data/share/views/public/plugins/semantic-ui/src/definitions/views/ad.less +1 -1
  311. data/share/views/public/plugins/semantic-ui/src/definitions/views/card.less +23 -2
  312. data/share/views/public/plugins/semantic-ui/src/definitions/views/comment.less +18 -5
  313. data/share/views/public/plugins/semantic-ui/src/definitions/views/feed.less +0 -1
  314. data/share/views/public/plugins/semantic-ui/src/definitions/views/item.less +3 -4
  315. data/share/views/public/plugins/semantic-ui/src/definitions/views/statistic.less +18 -19
  316. data/share/views/public/plugins/semantic-ui/src/theme.less +13 -7
  317. data/share/views/public/plugins/semantic-ui/src/themes/amazon/globals/site.variables +43 -0
  318. data/share/views/public/plugins/semantic-ui/src/themes/basic/elements/step.overrides +3 -0
  319. data/share/views/public/plugins/semantic-ui/src/themes/basic/elements/step.variables +12 -4
  320. data/share/views/public/plugins/semantic-ui/src/themes/basic/globals/reset.overrides +1 -1
  321. data/share/views/public/plugins/semantic-ui/src/themes/bookish/elements/header.variables +5 -5
  322. data/share/views/public/plugins/semantic-ui/src/themes/chubby/elements/header.variables +5 -5
  323. data/share/views/public/plugins/semantic-ui/src/themes/colored/modules/checkbox.variables +15 -3
  324. data/share/views/public/plugins/semantic-ui/src/themes/default/assets/fonts/icons.eot +0 -0
  325. data/share/views/public/plugins/semantic-ui/src/themes/default/assets/fonts/icons.svg +146 -26
  326. data/share/views/public/plugins/semantic-ui/src/themes/default/assets/fonts/icons.ttf +0 -0
  327. data/share/views/public/plugins/semantic-ui/src/themes/default/assets/fonts/icons.woff +0 -0
  328. data/share/views/public/plugins/semantic-ui/src/themes/default/assets/fonts/icons.woff2 +0 -0
  329. data/share/views/public/plugins/semantic-ui/src/themes/default/collections/breadcrumb.variables +1 -1
  330. data/share/views/public/plugins/semantic-ui/src/themes/default/collections/form.variables +20 -14
  331. data/share/views/public/plugins/semantic-ui/src/themes/default/collections/grid.variables +5 -0
  332. data/share/views/public/plugins/semantic-ui/src/themes/default/collections/menu.variables +57 -28
  333. data/share/views/public/plugins/semantic-ui/src/themes/default/collections/message.variables +48 -1
  334. data/share/views/public/plugins/semantic-ui/src/themes/default/collections/table.variables +18 -4
  335. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/button.variables +28 -4
  336. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/container.variables +14 -1
  337. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/flag.overrides +8 -0
  338. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/icon.overrides +263 -86
  339. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/icon.variables +3 -1
  340. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/input.variables +7 -10
  341. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/label.variables +37 -10
  342. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/list.variables +2 -1
  343. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/loader.variables +17 -5
  344. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/rail.variables +2 -2
  345. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/segment.variables +6 -5
  346. data/share/views/public/plugins/semantic-ui/src/themes/default/elements/step.variables +7 -4
  347. data/share/views/public/plugins/semantic-ui/src/themes/default/globals/reset.overrides +1 -6
  348. data/share/views/public/plugins/semantic-ui/src/themes/default/globals/site.variables +216 -67
  349. data/share/views/public/plugins/semantic-ui/src/themes/default/modules/checkbox.variables +36 -11
  350. data/share/views/public/plugins/semantic-ui/src/themes/default/modules/dropdown.variables +27 -18
  351. data/share/views/public/plugins/semantic-ui/src/themes/default/modules/popup.variables +52 -4
  352. data/share/views/public/plugins/semantic-ui/src/themes/default/modules/rating.overrides +2 -2
  353. data/share/views/public/plugins/semantic-ui/src/themes/default/modules/search.variables +16 -0
  354. data/share/views/public/plugins/semantic-ui/src/themes/default/modules/sticky.variables +1 -1
  355. data/share/views/public/plugins/semantic-ui/src/themes/default/views/card.variables +11 -0
  356. data/share/views/public/plugins/semantic-ui/src/themes/flat/collections/form.variables +1 -0
  357. data/share/views/public/plugins/semantic-ui/src/themes/github/assets/fonts/octicons-local.ttf +0 -0
  358. data/share/views/public/plugins/semantic-ui/src/themes/github/assets/fonts/octicons.svg +200 -0
  359. data/share/views/public/plugins/semantic-ui/src/themes/github/assets/fonts/octicons.ttf +0 -0
  360. data/share/views/public/plugins/semantic-ui/src/themes/github/assets/fonts/octicons.woff +0 -0
  361. data/share/views/public/plugins/semantic-ui/src/themes/github/collections/breadcrumb.variables +11 -0
  362. data/share/views/public/plugins/semantic-ui/src/themes/github/collections/grid.variables +2 -0
  363. data/share/views/public/plugins/semantic-ui/src/themes/github/collections/table.variables +8 -0
  364. data/share/views/public/plugins/semantic-ui/src/themes/github/elements/header.variables +9 -0
  365. data/share/views/public/plugins/semantic-ui/src/themes/github/elements/icon.overrides +208 -0
  366. data/share/views/public/plugins/semantic-ui/src/themes/github/elements/icon.variables +13 -0
  367. data/share/views/public/plugins/semantic-ui/src/themes/github/elements/image.variables +5 -0
  368. data/share/views/public/plugins/semantic-ui/src/themes/github/elements/input.overrides +32 -0
  369. data/share/views/public/plugins/semantic-ui/src/themes/github/elements/input.variables +16 -0
  370. data/share/views/public/plugins/semantic-ui/src/themes/github/elements/label.overrides +9 -0
  371. data/share/views/public/plugins/semantic-ui/src/themes/github/elements/label.variables +4 -0
  372. data/share/views/public/plugins/semantic-ui/src/themes/github/elements/segment.variables +0 -1
  373. data/share/views/public/plugins/semantic-ui/src/themes/github/elements/step.variables +7 -1
  374. data/share/views/public/plugins/semantic-ui/src/themes/github/globals/site.variables +47 -0
  375. data/share/views/public/plugins/semantic-ui/src/themes/github/modules/dropdown.overrides +53 -0
  376. data/share/views/public/plugins/semantic-ui/src/themes/github/modules/dropdown.variables +35 -0
  377. data/share/views/public/plugins/semantic-ui/src/themes/github/modules/popup.variables +12 -0
  378. data/share/views/public/plugins/semantic-ui/src/themes/material/assets/fonts/icons.eot +0 -0
  379. data/share/views/public/plugins/semantic-ui/src/themes/material/assets/fonts/icons.svg +2373 -0
  380. data/share/views/public/plugins/semantic-ui/src/themes/material/assets/fonts/icons.ttf +0 -0
  381. data/share/views/public/plugins/semantic-ui/src/themes/material/assets/fonts/icons.woff +0 -0
  382. data/share/views/public/plugins/semantic-ui/src/themes/material/collections/menu.overrides +1 -1
  383. data/share/views/public/plugins/semantic-ui/src/themes/material/collections/menu.variables +1 -1
  384. data/share/views/public/plugins/semantic-ui/src/themes/material/elements/button.overrides +2 -10
  385. data/share/views/public/plugins/semantic-ui/src/themes/material/elements/button.variables +4 -2
  386. data/share/views/public/plugins/semantic-ui/src/themes/material/elements/header.overrides +2 -2
  387. data/share/views/public/plugins/semantic-ui/src/themes/material/elements/icon.overrides +934 -0
  388. data/share/views/public/plugins/semantic-ui/src/themes/material/elements/icon.variables +11 -0
  389. data/share/views/public/plugins/semantic-ui/src/themes/material/globals/site.variables +8 -0
  390. data/share/views/public/plugins/semantic-ui/src/themes/material/modules/dropdown.overrides +2 -2
  391. data/share/views/public/plugins/semantic-ui/src/themes/material/modules/modal.overrides +2 -2
  392. data/share/views/public/plugins/semantic-ui/src/themes/twitter/elements/button.variables +1 -2
  393. data/share/views/public/plugins/semantic-ui/tasks/README.md +2 -2
  394. data/share/views/public/plugins/semantic-ui/tasks/admin/components/create.js +8 -8
  395. data/share/views/public/plugins/semantic-ui/tasks/admin/distributions/create.js +6 -6
  396. data/share/views/public/plugins/semantic-ui/tasks/admin/distributions/init.js +11 -12
  397. data/share/views/public/plugins/semantic-ui/tasks/admin/distributions/update.js +0 -3
  398. data/share/views/public/plugins/semantic-ui/tasks/build.js +22 -9
  399. data/share/views/public/plugins/semantic-ui/tasks/build/css.js +13 -5
  400. data/share/views/public/plugins/semantic-ui/tasks/collections/build.js +19 -0
  401. data/share/views/public/plugins/semantic-ui/tasks/collections/internal.js +23 -10
  402. data/share/views/public/plugins/semantic-ui/tasks/collections/rtl.js +16 -0
  403. data/share/views/public/plugins/semantic-ui/tasks/config/admin/github.js +1 -2
  404. data/share/views/public/plugins/semantic-ui/tasks/config/admin/oauth.example.js +4 -3
  405. data/share/views/public/plugins/semantic-ui/tasks/config/admin/release.js +1 -0
  406. data/share/views/public/plugins/semantic-ui/tasks/config/admin/templates/README.md +3 -0
  407. data/share/views/public/plugins/semantic-ui/tasks/config/npm/gulpfile.js +3 -3
  408. data/share/views/public/plugins/semantic-ui/tasks/config/project/config.js +3 -4
  409. data/share/views/public/plugins/semantic-ui/tasks/config/project/install.js +13 -6
  410. data/share/views/public/plugins/semantic-ui/tasks/config/project/release.js +16 -12
  411. data/share/views/public/plugins/semantic-ui/tasks/config/tasks.js +11 -5
  412. data/share/views/public/plugins/semantic-ui/tasks/docs/build.js +1 -1
  413. data/share/views/public/plugins/semantic-ui/tasks/docs/metadata.js +6 -5
  414. data/share/views/public/plugins/semantic-ui/tasks/docs/serve.js +2 -2
  415. data/share/views/public/plugins/semantic-ui/tasks/install.js +332 -272
  416. data/share/views/public/plugins/semantic-ui/tasks/rtl/build.js +2 -2
  417. data/share/views/public/plugins/semantic-ui/tasks/rtl/watch.js +2 -2
  418. data/share/views/public/plugins/semantic-ui/tasks/watch.js +7 -4
  419. data/share/views/public/plugins/semantic-ui/test/helpers/sinon.js +11 -11
  420. data/share/views/public/plugins/semantic-ui/test/modules/module.spec.js +1 -1
  421. metadata +109 -2
@@ -3,7 +3,6 @@
3
3
  * http://github.com/semantic-org/semantic-ui/
4
4
  *
5
5
  *
6
- * Copyright 2015 Contributors
7
6
  * Released under the MIT license
8
7
  * http://opensource.org/licenses/MIT
9
8
  *
@@ -22,7 +21,7 @@
22
21
  Dimmer
23
22
  *******************************/
24
23
 
25
- .dimmable {
24
+ .dimmable:not(.body) {
26
25
  position: @dimmablePosition;
27
26
  }
28
27
 
@@ -3,16 +3,22 @@
3
3
  * http://github.com/semantic-org/semantic-ui/
4
4
  *
5
5
  *
6
- * Copyright 2015 Contributors
7
6
  * Released under the MIT license
8
7
  * http://opensource.org/licenses/MIT
9
8
  *
10
9
  */
11
10
 
12
- ;(function ( $, window, document, undefined ) {
11
+ ;(function ($, window, document, undefined) {
13
12
 
14
13
  "use strict";
15
14
 
15
+ window = (typeof window != 'undefined' && window.Math == Math)
16
+ ? window
17
+ : (typeof self != 'undefined' && self.Math == Math)
18
+ ? self
19
+ : Function('return this')()
20
+ ;
21
+
16
22
  $.fn.dropdown = function(parameters) {
17
23
  var
18
24
  $allModules = $(this),
@@ -39,6 +45,8 @@ $.fn.dropdown = function(parameters) {
39
45
 
40
46
  className = settings.className,
41
47
  message = settings.message,
48
+ fields = settings.fields,
49
+ keys = settings.keys,
42
50
  metadata = settings.metadata,
43
51
  namespace = settings.namespace,
44
52
  regExp = settings.regExp,
@@ -53,6 +61,7 @@ $.fn.dropdown = function(parameters) {
53
61
  $context = $(settings.context),
54
62
  $text = $module.find(selector.text),
55
63
  $search = $module.find(selector.search),
64
+ $sizer = $module.find(selector.sizer),
56
65
  $input = $module.find(selector.input),
57
66
  $icon = $module.find(selector.icon),
58
67
 
@@ -65,11 +74,13 @@ $.fn.dropdown = function(parameters) {
65
74
 
66
75
  activated = false,
67
76
  itemActivated = false,
77
+ internalChange = false,
68
78
  element = this,
69
79
  instance = $module.data(moduleNamespace),
70
80
 
71
81
  initialLoad,
72
82
  pageLostFocus,
83
+ willRefocus,
73
84
  elementNamespace,
74
85
  id,
75
86
  selectObserver,
@@ -93,11 +104,7 @@ $.fn.dropdown = function(parameters) {
93
104
  module.restore.selected();
94
105
 
95
106
  module.create.id();
96
- if(hasTouch) {
97
- module.bind.touchEvents();
98
- }
99
- module.bind.mouseEvents();
100
- module.bind.keyboardEvents();
107
+ module.bind.events();
101
108
 
102
109
  module.observeChanges();
103
110
  module.instantiate();
@@ -126,37 +133,48 @@ $.fn.dropdown = function(parameters) {
126
133
  $document
127
134
  .off(elementNamespace)
128
135
  ;
129
- if(selectObserver) {
130
- selectObserver.disconnect();
131
- }
132
- if(menuObserver) {
133
- menuObserver.disconnect();
134
- }
136
+ module.disconnect.menuObserver();
137
+ module.disconnect.selectObserver();
135
138
  },
136
139
 
137
140
  observeChanges: function() {
138
141
  if('MutationObserver' in window) {
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');
145
- module.refresh();
146
- });
142
+ selectObserver = new MutationObserver(module.event.select.mutation);
143
+ menuObserver = new MutationObserver(module.event.menu.mutation);
144
+ module.debug('Setting up mutation observer', selectObserver, menuObserver);
145
+ module.observe.select();
146
+ module.observe.menu();
147
+ }
148
+ },
149
+
150
+ disconnect: {
151
+ menuObserver: function() {
152
+ if(menuObserver) {
153
+ menuObserver.disconnect();
154
+ }
155
+ },
156
+ selectObserver: function() {
157
+ if(selectObserver) {
158
+ selectObserver.disconnect();
159
+ }
160
+ }
161
+ },
162
+ observe: {
163
+ select: function() {
147
164
  if(module.has.input()) {
148
165
  selectObserver.observe($input[0], {
149
166
  childList : true,
150
167
  subtree : true
151
168
  });
152
169
  }
170
+ },
171
+ menu: function() {
153
172
  if(module.has.menu()) {
154
173
  menuObserver.observe($menu[0], {
155
174
  childList : true,
156
175
  subtree : true
157
176
  });
158
177
  }
159
- module.debug('Setting up mutation observer', selectObserver, menuObserver);
160
178
  }
161
179
  },
162
180
 
@@ -183,13 +201,17 @@ $.fn.dropdown = function(parameters) {
183
201
  ;
184
202
  $.each(values, function(index, value) {
185
203
  if(module.get.item(value) === false) {
186
- html = settings.templates.addition(value);
204
+ html = settings.templates.addition( module.add.variables(message.addResult, value) );
187
205
  $userChoice = $('<div />')
188
206
  .html(html)
189
- .data(metadata.value, value)
207
+ .attr('data-' + metadata.value, value)
208
+ .attr('data-' + metadata.text, value)
190
209
  .addClass(className.addition)
191
210
  .addClass(className.item)
192
211
  ;
212
+ if(settings.hideAdditions) {
213
+ $userChoice.addClass(className.hidden);
214
+ }
193
215
  $userChoices = ($userChoices === undefined)
194
216
  ? $userChoice
195
217
  : $userChoices.add($userChoice)
@@ -211,6 +233,18 @@ $.fn.dropdown = function(parameters) {
211
233
  });
212
234
  }
213
235
  },
236
+ menu: function() {
237
+ $menu = $('<div />')
238
+ .addClass(className.menu)
239
+ .appendTo($module)
240
+ ;
241
+ },
242
+ sizer: function() {
243
+ $sizer = $('<span />')
244
+ .addClass(className.sizer)
245
+ .insertAfter($search)
246
+ ;
247
+ }
214
248
  },
215
249
 
216
250
  search: function(query) {
@@ -219,7 +253,12 @@ $.fn.dropdown = function(parameters) {
219
253
  : module.get.query()
220
254
  ;
221
255
  module.verbose('Searching for query', query);
222
- module.filter(query);
256
+ if(module.has.minCharacters(query)) {
257
+ module.filter(query);
258
+ }
259
+ else {
260
+ module.hide();
261
+ }
223
262
  },
224
263
 
225
264
  select: {
@@ -228,6 +267,7 @@ $.fn.dropdown = function(parameters) {
228
267
  module.remove.selectedItem();
229
268
  $item
230
269
  .not(selector.unselectable)
270
+ .not(selector.addition + selector.hidden)
231
271
  .eq(0)
232
272
  .addClass(className.selected)
233
273
  ;
@@ -254,7 +294,11 @@ $.fn.dropdown = function(parameters) {
254
294
  api: function() {
255
295
  var
256
296
  apiSettings = {
257
- debug : settings.debug,
297
+ debug : settings.debug,
298
+ urlData : {
299
+ value : module.get.value(),
300
+ query : module.get.query()
301
+ },
258
302
  on : false
259
303
  }
260
304
  ;
@@ -267,24 +311,24 @@ $.fn.dropdown = function(parameters) {
267
311
  if( $module.is('select') ) {
268
312
  module.setup.select();
269
313
  module.setup.returnedObject();
270
- console.log($module);
314
+ }
315
+ if( !module.has.menu() ) {
316
+ module.create.menu();
271
317
  }
272
318
  if( module.is.search() && !module.has.search() ) {
273
319
  module.verbose('Adding search input');
274
320
  $search = $('<input />')
275
321
  .addClass(className.search)
322
+ .prop('autocomplete', 'off')
276
323
  .insertBefore($text)
277
324
  ;
278
325
  }
326
+ if( module.is.multiple() && module.is.searchSelection() && !module.has.sizer()) {
327
+ module.create.sizer();
328
+ }
279
329
  if(settings.allowTab) {
280
330
  module.set.tabbable();
281
331
  }
282
- if($menu.length === 0) {
283
- $menu = $('<div />')
284
- .addClass(className.menu)
285
- .appendTo($module)
286
- ;
287
- }
288
332
  },
289
333
  select: function() {
290
334
  var
@@ -298,7 +342,10 @@ $.fn.dropdown = function(parameters) {
298
342
  if($input.parent(selector.dropdown).length > 0) {
299
343
  module.debug('UI dropdown already exists. Creating dropdown menu only');
300
344
  $module = $input.closest(selector.dropdown);
301
- $menu = $module.children(selector.menu);
345
+ if( !module.has.menu() ) {
346
+ module.create.menu();
347
+ }
348
+ $menu = $module.children(selector.menu);
302
349
  module.setup.menu(selectValues);
303
350
  }
304
351
  else {
@@ -310,20 +357,27 @@ $.fn.dropdown = function(parameters) {
310
357
  .html( templates.dropdown(selectValues) )
311
358
  .insertBefore($input)
312
359
  ;
360
+ if($input.hasClass(className.multiple) && $input.prop('multiple') === false) {
361
+ module.error(error.missingMultiple);
362
+ $input.prop('multiple', true);
363
+ }
364
+ if($input.is('[multiple]')) {
365
+ module.set.multiple();
366
+ }
367
+ if ($input.prop('disabled')) {
368
+ module.debug('Disabling dropdown');
369
+ $module.addClass(className.disabled);
370
+ }
313
371
  $input
314
372
  .removeAttr('class')
315
373
  .detach()
316
374
  .prependTo($module)
317
375
  ;
318
- console.log($module);
319
- }
320
- if($input.is('[multiple]')) {
321
- module.set.multiple();
322
376
  }
323
377
  module.refresh();
324
378
  },
325
379
  menu: function(values) {
326
- $menu.html( templates.menu( values ));
380
+ $menu.html( templates.menu(values, fields));
327
381
  $item = $menu.find(selector.item);
328
382
  },
329
383
  reference: function() {
@@ -353,6 +407,10 @@ $.fn.dropdown = function(parameters) {
353
407
  module.refreshData();
354
408
  },
355
409
 
410
+ refreshItems: function() {
411
+ $item = $menu.find(selector.item);
412
+ },
413
+
356
414
  refreshSelectors: function() {
357
415
  module.verbose('Refreshing selector cache');
358
416
  $text = $module.find(selector.text);
@@ -373,6 +431,14 @@ $.fn.dropdown = function(parameters) {
373
431
  .removeData(metadata.text)
374
432
  .removeData(metadata.value)
375
433
  ;
434
+ },
435
+
436
+ clearData: function() {
437
+ module.verbose('Clearing metadata');
438
+ $item
439
+ .removeData(metadata.text)
440
+ .removeData(metadata.value)
441
+ ;
376
442
  $module
377
443
  .removeData(metadata.defaultText)
378
444
  .removeData(metadata.defaultValue)
@@ -380,7 +446,6 @@ $.fn.dropdown = function(parameters) {
380
446
  ;
381
447
  },
382
448
 
383
-
384
449
  toggle: function() {
385
450
  module.verbose('Toggling menu visibility');
386
451
  if( !module.is.active() ) {
@@ -398,19 +463,24 @@ $.fn.dropdown = function(parameters) {
398
463
  ;
399
464
  if( module.can.show() && !module.is.active() ) {
400
465
  module.debug('Showing dropdown');
401
- if(module.is.multiple()) {
402
- if(!module.has.search() && module.is.allFiltered()) {
403
- return true;
404
- }
466
+ if(module.has.message() && !(module.has.maxSelections() || module.has.allResultsFiltered()) ) {
467
+ module.remove.message();
468
+ }
469
+ if(module.is.allFiltered()) {
470
+ return true;
471
+ }
472
+ if(settings.onShow.call(element) !== false) {
473
+ module.animate.show(function() {
474
+ if( module.can.click() ) {
475
+ module.bind.intent();
476
+ }
477
+ if(module.has.menuSearch()) {
478
+ module.focusSearch();
479
+ }
480
+ module.set.visible();
481
+ callback.call(element);
482
+ });
405
483
  }
406
- module.animate.show(function() {
407
- if( module.can.click() ) {
408
- module.bind.intent();
409
- }
410
- module.set.visible();
411
- callback.call(element);
412
- });
413
- settings.onShow.call(element);
414
484
  }
415
485
  },
416
486
 
@@ -421,11 +491,12 @@ $.fn.dropdown = function(parameters) {
421
491
  ;
422
492
  if( module.is.active() ) {
423
493
  module.debug('Hiding dropdown');
424
- module.animate.hide(function() {
425
- module.remove.visible();
426
- callback.call(element);
427
- });
428
- settings.onHide.call(element);
494
+ if(settings.onHide.call(element) !== false) {
495
+ module.animate.hide(function() {
496
+ module.remove.visible();
497
+ callback.call(element);
498
+ });
499
+ }
429
500
  }
430
501
  },
431
502
 
@@ -454,8 +525,30 @@ $.fn.dropdown = function(parameters) {
454
525
  },
455
526
 
456
527
  bind: {
528
+ events: function() {
529
+ if(hasTouch) {
530
+ module.bind.touchEvents();
531
+ }
532
+ module.bind.keyboardEvents();
533
+ module.bind.inputEvents();
534
+ module.bind.mouseEvents();
535
+ },
536
+ touchEvents: function() {
537
+ module.debug('Touch device detected binding additional touch events');
538
+ if( module.is.searchSelection() ) {
539
+ // do nothing special yet
540
+ }
541
+ else if( module.is.single() ) {
542
+ $module
543
+ .on('touchstart' + eventNamespace, module.event.test.toggle)
544
+ ;
545
+ }
546
+ $menu
547
+ .on('touchstart' + eventNamespace, selector.item, module.event.item.mouseenter)
548
+ ;
549
+ },
457
550
  keyboardEvents: function() {
458
- module.debug('Binding keyboard events');
551
+ module.verbose('Binding keyboard events');
459
552
  $module
460
553
  .on('keydown' + eventNamespace, module.event.keydown)
461
554
  ;
@@ -470,46 +563,42 @@ $.fn.dropdown = function(parameters) {
470
563
  ;
471
564
  }
472
565
  },
473
- touchEvents: function() {
474
- module.debug('Touch device detected binding additional touch events');
475
- if( module.is.searchSelection() ) {
476
- // do nothing special yet
477
- }
478
- else {
479
- $module
480
- .on('touchstart' + eventNamespace, module.event.test.toggle)
481
- ;
482
- }
483
- $menu
484
- .on('touchstart' + eventNamespace, selector.item, module.event.item.mouseenter)
566
+ inputEvents: function() {
567
+ module.verbose('Binding input change events');
568
+ $module
569
+ .on('change' + eventNamespace, selector.input, module.event.change)
485
570
  ;
486
571
  },
487
572
  mouseEvents: function() {
488
- module.debug('Mouse detected binding mouse events');
573
+ module.verbose('Binding mouse events');
489
574
  if(module.is.multiple()) {
490
575
  $module
491
- .on('click' + eventNamespace, selector.label, module.event.label.click)
576
+ .on('click' + eventNamespace, selector.label, module.event.label.click)
492
577
  .on('click' + eventNamespace, selector.remove, module.event.remove.click)
493
578
  ;
494
579
  }
495
580
  if( module.is.searchSelection() ) {
496
581
  $module
582
+ .on('mousedown' + eventNamespace, module.event.mousedown)
583
+ .on('mouseup' + eventNamespace, module.event.mouseup)
497
584
  .on('mousedown' + eventNamespace, selector.menu, module.event.menu.mousedown)
498
585
  .on('mouseup' + eventNamespace, selector.menu, module.event.menu.mouseup)
499
- .on('click' + eventNamespace, selector.search, module.show)
586
+ .on('click' + eventNamespace, selector.icon, module.event.icon.click)
500
587
  .on('focus' + eventNamespace, selector.search, module.event.search.focus)
588
+ .on('click' + eventNamespace, selector.search, module.event.search.focus)
501
589
  .on('blur' + eventNamespace, selector.search, module.event.search.blur)
502
590
  .on('click' + eventNamespace, selector.text, module.event.text.focus)
503
591
  ;
504
592
  if(module.is.multiple()) {
505
593
  $module
506
- .on('click' + eventNamespace, module.event.click)
594
+ .on('click' + eventNamespace, module.event.click)
507
595
  ;
508
596
  }
509
597
  }
510
598
  else {
511
599
  if(settings.on == 'click') {
512
600
  $module
601
+ .on('click' + eventNamespace, selector.icon, module.event.icon.click)
513
602
  .on('click' + eventNamespace, module.event.test.toggle)
514
603
  ;
515
604
  }
@@ -578,7 +667,14 @@ $.fn.dropdown = function(parameters) {
578
667
  module.select.firstUnfiltered();
579
668
  if( module.has.allResultsFiltered() ) {
580
669
  if( settings.onNoResults.call(element, searchTerm) ) {
581
- if(!settings.allowAdditions) {
670
+ if(settings.allowAdditions) {
671
+ if(settings.hideAdditions) {
672
+ module.verbose('User addition with no menu, setting empty style');
673
+ module.set.empty();
674
+ module.hideMenu();
675
+ }
676
+ }
677
+ else {
582
678
  module.verbose('All items filtered, showing message', searchTerm);
583
679
  module.add.message(message.noResults);
584
680
  }
@@ -589,6 +685,7 @@ $.fn.dropdown = function(parameters) {
589
685
  }
590
686
  }
591
687
  else {
688
+ module.remove.empty();
592
689
  module.remove.message();
593
690
  }
594
691
  if(settings.allowAdditions) {
@@ -599,7 +696,7 @@ $.fn.dropdown = function(parameters) {
599
696
  }
600
697
  }
601
698
  ;
602
- if(module.has.maxSelections()) {
699
+ if(settings.useLabels && module.has.maxSelections()) {
603
700
  return;
604
701
  }
605
702
  if(settings.apiSettings) {
@@ -621,10 +718,10 @@ $.fn.dropdown = function(parameters) {
621
718
  queryRemote: function(query, callback) {
622
719
  var
623
720
  apiSettings = {
624
- errorDuration : false,
625
- throttle : settings.throttle,
626
- cache : 'local',
627
- urlData : {
721
+ errorDuration : false,
722
+ cache : 'local',
723
+ throttle : settings.throttle,
724
+ urlData : {
628
725
  query: query
629
726
  },
630
727
  onError: function() {
@@ -638,7 +735,7 @@ $.fn.dropdown = function(parameters) {
638
735
  onSuccess : function(response) {
639
736
  module.remove.message();
640
737
  module.setup.menu({
641
- values: response.results
738
+ values: response[fields.remoteValues]
642
739
  });
643
740
  callback();
644
741
  }
@@ -659,15 +756,14 @@ $.fn.dropdown = function(parameters) {
659
756
  searchTerm = (query !== undefined)
660
757
  ? query
661
758
  : module.get.query(),
662
- $results = $(),
759
+ results = null,
663
760
  escapedTerm = module.escape.regExp(searchTerm),
664
761
  beginsWithRegExp = new RegExp('^' + escapedTerm, 'igm')
665
762
  ;
666
763
  // avoid loop if we're matching nothing
667
- if(searchTerm === '') {
668
- $results = $item;
669
- }
670
- else {
764
+ if( module.has.query() ) {
765
+ results = [];
766
+
671
767
  module.verbose('Searching for matching values', searchTerm);
672
768
  $item
673
769
  .each(function(){
@@ -679,11 +775,15 @@ $.fn.dropdown = function(parameters) {
679
775
  if(settings.match == 'both' || settings.match == 'text') {
680
776
  text = String(module.get.choiceText($choice, false));
681
777
  if(text.search(beginsWithRegExp) !== -1) {
682
- $results = $results.add($choice);
778
+ results.push(this);
779
+ return true;
780
+ }
781
+ else if (settings.fullTextSearch === 'exact' && module.exactSearch(searchTerm, text)) {
782
+ results.push(this);
683
783
  return true;
684
784
  }
685
- else if(settings.fullTextSearch && module.fuzzySearch(searchTerm, text)) {
686
- $results = $results.add($choice);
785
+ else if (settings.fullTextSearch === true && module.fuzzySearch(searchTerm, text)) {
786
+ results.push(this);
687
787
  return true;
688
788
  }
689
789
  }
@@ -691,24 +791,25 @@ $.fn.dropdown = function(parameters) {
691
791
  value = String(module.get.choiceValue($choice, text));
692
792
 
693
793
  if(value.search(beginsWithRegExp) !== -1) {
694
- $results = $results.add($choice);
794
+ results.push(this);
695
795
  return true;
696
796
  }
697
797
  else if(settings.fullTextSearch && module.fuzzySearch(searchTerm, value)) {
698
- $results = $results.add($choice);
798
+ results.push(this);
699
799
  return true;
700
800
  }
701
801
  }
702
802
  })
703
803
  ;
704
804
  }
705
-
706
805
  module.debug('Showing only matched items', searchTerm);
707
806
  module.remove.filteredItem();
708
- $item
709
- .not($results)
710
- .addClass(className.filtered)
711
- ;
807
+ if(results) {
808
+ $item
809
+ .not(results)
810
+ .addClass(className.filtered)
811
+ ;
812
+ }
712
813
  },
713
814
 
714
815
  fuzzySearch: function(query, term) {
@@ -737,7 +838,14 @@ $.fn.dropdown = function(parameters) {
737
838
  }
738
839
  return true;
739
840
  },
740
-
841
+ exactSearch: function (query, term) {
842
+ query = query.toLowerCase();
843
+ term = term.toLowerCase();
844
+ if(term.indexOf(query) > -1) {
845
+ return true;
846
+ }
847
+ return false;
848
+ },
741
849
  filterActive: function() {
742
850
  if(settings.useLabels) {
743
851
  $item.filter('.' + className.active)
@@ -746,9 +854,16 @@ $.fn.dropdown = function(parameters) {
746
854
  }
747
855
  },
748
856
 
749
- focusSearch: function() {
750
- if( module.is.search() && !module.is.focusedOnSearch() ) {
751
- $search[0].focus();
857
+ focusSearch: function(skipHandler) {
858
+ if( module.has.search() && !module.is.focusedOnSearch() ) {
859
+ if(skipHandler) {
860
+ $module.off('focus' + eventNamespace, selector.search);
861
+ $search.focus();
862
+ $module.on('focus' + eventNamespace, selector.search, module.event.search.focus);
863
+ }
864
+ else {
865
+ $search.focus();
866
+ }
752
867
  }
753
868
  },
754
869
 
@@ -759,32 +874,36 @@ $.fn.dropdown = function(parameters) {
759
874
  $selectedItem = ($currentlySelected.length > 0)
760
875
  ? $currentlySelected
761
876
  : $activeItem,
762
- hasSelected = ($selectedItem.size() > 0)
877
+ hasSelected = ($selectedItem.length > 0)
763
878
  ;
764
879
  if(hasSelected) {
765
880
  module.debug('Forcing partial selection to selected item', $selectedItem);
766
- module.event.item.click.call($selectedItem);
881
+ module.event.item.click.call($selectedItem, {}, true);
882
+ return;
767
883
  }
768
884
  else {
769
- module.hide();
885
+ if(settings.allowAdditions) {
886
+ module.set.selected(module.get.query());
887
+ module.remove.searchTerm();
888
+ }
889
+ else {
890
+ module.remove.searchTerm();
891
+ }
770
892
  }
771
893
  },
772
894
 
773
895
  event: {
896
+ change: function() {
897
+ if(!internalChange) {
898
+ module.debug('Input changed, updating selection');
899
+ module.set.selected();
900
+ }
901
+ },
774
902
  focus: function() {
775
903
  if(settings.showOnFocus && !activated && module.is.hidden() && !pageLostFocus) {
776
904
  module.show();
777
905
  }
778
906
  },
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
- },
788
907
  blur: function(event) {
789
908
  pageLostFocus = (document.activeElement === this);
790
909
  if(!activated && !pageLostFocus) {
@@ -792,12 +911,38 @@ $.fn.dropdown = function(parameters) {
792
911
  module.hide();
793
912
  }
794
913
  },
795
- // prevents focus callback from occuring on mousedown
796
914
  mousedown: function() {
797
- activated = true;
915
+ if(module.is.searchSelection()) {
916
+ // prevent menu hiding on immediate re-focus
917
+ willRefocus = true;
918
+ }
919
+ else {
920
+ // prevents focus callback from occurring on mousedown
921
+ activated = true;
922
+ }
798
923
  },
799
924
  mouseup: function() {
800
- activated = false;
925
+ if(module.is.searchSelection()) {
926
+ // prevent menu hiding on immediate re-focus
927
+ willRefocus = false;
928
+ }
929
+ else {
930
+ activated = false;
931
+ }
932
+ },
933
+ click: function(event) {
934
+ var
935
+ $target = $(event.target)
936
+ ;
937
+ // focus search
938
+ if($target.is($module)) {
939
+ if(!module.is.focusedOnSearch()) {
940
+ module.focusSearch();
941
+ }
942
+ else {
943
+ module.show();
944
+ }
945
+ }
801
946
  },
802
947
  search: {
803
948
  focus: function() {
@@ -806,23 +951,25 @@ $.fn.dropdown = function(parameters) {
806
951
  module.remove.activeLabel();
807
952
  }
808
953
  if(settings.showOnFocus) {
809
- module.show();
954
+ module.search();
810
955
  }
811
956
  },
812
957
  blur: function(event) {
813
958
  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 {
959
+ if(!willRefocus) {
960
+ if(!itemActivated && !pageLostFocus) {
961
+ if(settings.forceSelection) {
962
+ module.forceSelection();
963
+ }
823
964
  module.hide();
824
965
  }
825
966
  }
967
+ willRefocus = false;
968
+ }
969
+ },
970
+ icon: {
971
+ click: function(event) {
972
+ module.toggle();
826
973
  }
827
974
  },
828
975
  text: {
@@ -885,7 +1032,10 @@ $.fn.dropdown = function(parameters) {
885
1032
  toggleBehavior = (module.is.multiple())
886
1033
  ? module.show
887
1034
  : module.toggle
888
- ;
1035
+ ;
1036
+ if(module.is.bubbledLabelClick(event) || module.is.bubbledIconClick(event)) {
1037
+ return;
1038
+ }
889
1039
  if( module.determine.eventOnElement(event, toggleBehavior) ) {
890
1040
  event.preventDefault();
891
1041
  }
@@ -893,7 +1043,9 @@ $.fn.dropdown = function(parameters) {
893
1043
  touch: function(event) {
894
1044
  module.determine.eventOnElement(event, function() {
895
1045
  if(event.type == 'touchstart') {
896
- module.timer = setTimeout(module.hide, settings.delay.touch);
1046
+ module.timer = setTimeout(function() {
1047
+ module.hide();
1048
+ }, settings.delay.touch);
897
1049
  }
898
1050
  else if(event.type == 'touchmove') {
899
1051
  clearTimeout(module.timer);
@@ -905,7 +1057,35 @@ $.fn.dropdown = function(parameters) {
905
1057
  module.determine.eventInModule(event, module.hide);
906
1058
  }
907
1059
  },
1060
+ select: {
1061
+ mutation: function(mutations) {
1062
+ module.debug('<select> modified, recreating menu');
1063
+ module.setup.select();
1064
+ }
1065
+ },
908
1066
  menu: {
1067
+ mutation: function(mutations) {
1068
+ var
1069
+ mutation = mutations[0],
1070
+ $addedNode = mutation.addedNodes
1071
+ ? $(mutation.addedNodes[0])
1072
+ : $(false),
1073
+ $removedNode = mutation.removedNodes
1074
+ ? $(mutation.removedNodes[0])
1075
+ : $(false),
1076
+ $changedNodes = $addedNode.add($removedNode),
1077
+ isUserAddition = $changedNodes.is(selector.addition) || $changedNodes.closest(selector.addition).length > 0,
1078
+ isMessage = $changedNodes.is(selector.message) || $changedNodes.closest(selector.message).length > 0
1079
+ ;
1080
+ if(isUserAddition || isMessage) {
1081
+ module.debug('Updating item selector cache');
1082
+ module.refreshItems();
1083
+ }
1084
+ else {
1085
+ module.debug('Menu modified, updating selector cache');
1086
+ module.refresh();
1087
+ }
1088
+ },
909
1089
  mousedown: function() {
910
1090
  itemActivated = true;
911
1091
  },
@@ -916,17 +1096,21 @@ $.fn.dropdown = function(parameters) {
916
1096
  item: {
917
1097
  mouseenter: function(event) {
918
1098
  var
919
- $subMenu = $(this).children(selector.menu),
920
- $otherMenus = $(this).siblings(selector.item).children(selector.menu)
1099
+ $target = $(event.target),
1100
+ $item = $(this),
1101
+ $subMenu = $item.children(selector.menu),
1102
+ $otherMenus = $item.siblings(selector.item).children(selector.menu),
1103
+ hasSubMenu = ($subMenu.length > 0),
1104
+ isBubbledEvent = ($subMenu.find($target).length > 0)
921
1105
  ;
922
- if( $subMenu.length > 0 ) {
1106
+ if( !isBubbledEvent && hasSubMenu ) {
923
1107
  clearTimeout(module.itemTimer);
924
1108
  module.itemTimer = setTimeout(function() {
925
1109
  module.verbose('Showing sub-menu', $subMenu);
926
1110
  $.each($otherMenus, function() {
927
1111
  module.animate.hide(false, $(this));
928
1112
  });
929
- module.animate.show(false, $subMenu);
1113
+ module.animate.show(false, $subMenu);
930
1114
  }, settings.delay.show);
931
1115
  event.preventDefault();
932
1116
  }
@@ -939,25 +1123,35 @@ $.fn.dropdown = function(parameters) {
939
1123
  clearTimeout(module.itemTimer);
940
1124
  module.itemTimer = setTimeout(function() {
941
1125
  module.verbose('Hiding sub-menu', $subMenu);
942
- module.animate.hide(false, $subMenu);
1126
+ module.animate.hide(false, $subMenu);
943
1127
  }, settings.delay.hide);
944
1128
  }
945
1129
  },
946
- click: function (event) {
1130
+ click: function (event, skipRefocus) {
947
1131
  var
948
- $choice = $(this),
949
- $target = (event)
1132
+ $choice = $(this),
1133
+ $target = (event)
950
1134
  ? $(event.target)
951
1135
  : $(''),
952
- $subMenu = $choice.find(selector.menu),
953
- text = module.get.choiceText($choice),
954
- value = module.get.choiceValue($choice, text),
1136
+ $subMenu = $choice.find(selector.menu),
1137
+ text = module.get.choiceText($choice),
1138
+ value = module.get.choiceValue($choice, text),
955
1139
  hasSubMenu = ($subMenu.length > 0),
956
1140
  isBubbledEvent = ($subMenu.find($target).length > 0)
957
1141
  ;
958
1142
  if(!isBubbledEvent && (!hasSubMenu || settings.allowCategorySelection)) {
959
- if(!settings.useLabels) {
1143
+ if(module.is.searchSelection()) {
1144
+ if(settings.allowAdditions) {
1145
+ module.remove.userAddition();
1146
+ }
960
1147
  module.remove.searchTerm();
1148
+ if(!module.is.focusedOnSearch() && !(skipRefocus == true)) {
1149
+ module.focusSearch(true);
1150
+ }
1151
+ }
1152
+ if(!settings.useLabels) {
1153
+ module.remove.filteredItem();
1154
+ module.set.scrollPosition($choice);
961
1155
  }
962
1156
  module.determine.selectAction.call(this, text, value);
963
1157
  }
@@ -969,14 +1163,13 @@ $.fn.dropdown = function(parameters) {
969
1163
  keydown: function(event) {
970
1164
  var
971
1165
  pressedKey = event.which,
972
- keys = module.get.shortcutKeys(),
973
1166
  isShortcutKey = module.is.inObject(pressedKey, keys)
974
1167
  ;
975
1168
  if(isShortcutKey) {
976
1169
  var
977
1170
  $label = $module.find(selector.label),
978
1171
  $activeLabel = $label.filter('.' + className.active),
979
- activeValue = $activeLabel.data('value'),
1172
+ activeValue = $activeLabel.data(metadata.value),
980
1173
  labelIndex = $label.index($activeLabel),
981
1174
  labelCount = $label.length,
982
1175
  hasActiveLabel = ($activeLabel.length > 0),
@@ -1083,7 +1276,6 @@ $.fn.dropdown = function(parameters) {
1083
1276
  keydown: function(event) {
1084
1277
  var
1085
1278
  pressedKey = event.which,
1086
- keys = module.get.shortcutKeys(),
1087
1279
  isShortcutKey = module.is.inObject(pressedKey, keys)
1088
1280
  ;
1089
1281
  if(isShortcutKey) {
@@ -1094,74 +1286,83 @@ $.fn.dropdown = function(parameters) {
1094
1286
  ? $currentlySelected
1095
1287
  : $activeItem,
1096
1288
  $visibleItems = ($selectedItem.length > 0)
1097
- ? $selectedItem.siblings(':not(.' + className.filtered +')').andSelf()
1289
+ ? $selectedItem.siblings(':not(.' + className.filtered +')').addBack()
1098
1290
  : $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),
1291
+ $subMenu = $selectedItem.children(selector.menu),
1292
+ $parentMenu = $selectedItem.closest(selector.menu),
1293
+ inVisibleMenu = ($parentMenu.hasClass(className.visible) || $parentMenu.hasClass(className.animating) || $parentMenu.parent(selector.menu).length > 0),
1294
+ hasSubMenu = ($subMenu.length> 0),
1295
+ hasSelectedItem = ($selectedItem.length > 0),
1296
+ selectedIsSelectable = ($selectedItem.not(selector.unselectable).length > 0),
1297
+ delimiterPressed = (pressedKey == keys.delimiter && settings.allowAdditions && module.is.multiple()),
1298
+ isAdditionWithoutMenu = (settings.allowAdditions && settings.hideAdditions && (pressedKey == keys.enter || delimiterPressed) && selectedIsSelectable),
1105
1299
  $nextItem,
1106
1300
  isSubMenuItem,
1107
1301
  newIndex
1108
1302
  ;
1303
+ // allow selection with menu closed
1304
+ if(isAdditionWithoutMenu) {
1305
+ module.verbose('Selecting item from keyboard shortcut', $selectedItem);
1306
+ module.event.item.click.call($selectedItem, event);
1307
+ if(module.is.searchSelection()) {
1308
+ module.remove.searchTerm();
1309
+ }
1310
+ }
1109
1311
 
1110
1312
  // visible menu keyboard shortcuts
1111
1313
  if( module.is.visible() ) {
1112
1314
 
1113
1315
  // enter (select or open sub-menu)
1114
- if(pressedKey == keys.enter || pressedKey == keys.delimiter) {
1115
-
1316
+ if(pressedKey == keys.enter || delimiterPressed) {
1116
1317
  if(pressedKey == keys.enter && hasSelectedItem && hasSubMenu && !settings.allowCategorySelection) {
1117
1318
  module.verbose('Pressed enter on unselectable category, opening sub menu');
1118
1319
  pressedKey = keys.rightArrow;
1119
1320
  }
1120
- else if(selectedIsVisible) {
1321
+ else if(selectedIsSelectable) {
1121
1322
  module.verbose('Selecting item from keyboard shortcut', $selectedItem);
1122
1323
  module.event.item.click.call($selectedItem, event);
1123
- if(settings.useLabels && module.is.searchSelection()) {
1124
- module.hideAndClear();
1125
- }
1126
- else {
1324
+ if(module.is.searchSelection()) {
1127
1325
  module.remove.searchTerm();
1128
1326
  }
1129
1327
  }
1130
1328
  event.preventDefault();
1131
1329
  }
1132
1330
 
1133
- // left arrow (hide sub-menu)
1134
- if(pressedKey == keys.leftArrow) {
1331
+ // sub-menu actions
1332
+ if(hasSelectedItem) {
1135
1333
 
1136
- isSubMenuItem = ($parentMenu[0] !== $menu[0]);
1334
+ if(pressedKey == keys.leftArrow) {
1137
1335
 
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();
1336
+ isSubMenuItem = ($parentMenu[0] !== $menu[0]);
1337
+
1338
+ if(isSubMenuItem) {
1339
+ module.verbose('Left key pressed, closing sub-menu');
1340
+ module.animate.hide(false, $parentMenu);
1341
+ $selectedItem
1342
+ .removeClass(className.selected)
1343
+ ;
1344
+ $parentMenu
1345
+ .closest(selector.item)
1346
+ .addClass(className.selected)
1347
+ ;
1348
+ event.preventDefault();
1349
+ }
1149
1350
  }
1150
- }
1151
1351
 
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();
1352
+ // right arrow (show sub-menu)
1353
+ if(pressedKey == keys.rightArrow) {
1354
+ if(hasSubMenu) {
1355
+ module.verbose('Right key pressed, opening sub-menu');
1356
+ module.animate.show(false, $subMenu);
1357
+ $selectedItem
1358
+ .removeClass(className.selected)
1359
+ ;
1360
+ $subMenu
1361
+ .find(selector.item).eq(0)
1362
+ .addClass(className.selected)
1363
+ ;
1364
+ event.preventDefault();
1365
+ }
1165
1366
  }
1166
1367
  }
1167
1368
 
@@ -1185,6 +1386,9 @@ $.fn.dropdown = function(parameters) {
1185
1386
  .addClass(className.selected)
1186
1387
  ;
1187
1388
  module.set.scrollPosition($nextItem);
1389
+ if(settings.selectOnKeydown && module.is.single()) {
1390
+ module.set.selectedItem($nextItem);
1391
+ }
1188
1392
  }
1189
1393
  event.preventDefault();
1190
1394
  }
@@ -1209,6 +1413,9 @@ $.fn.dropdown = function(parameters) {
1209
1413
  .addClass(className.selected)
1210
1414
  ;
1211
1415
  module.set.scrollPosition($nextItem);
1416
+ if(settings.selectOnKeydown && module.is.single()) {
1417
+ module.set.selectedItem($nextItem);
1418
+ }
1212
1419
  }
1213
1420
  event.preventDefault();
1214
1421
  }
@@ -1232,46 +1439,66 @@ $.fn.dropdown = function(parameters) {
1232
1439
  }
1233
1440
  else {
1234
1441
  // delimiter key
1235
- if(pressedKey == keys.delimiter) {
1442
+ if(delimiterPressed) {
1236
1443
  event.preventDefault();
1237
1444
  }
1238
1445
  // down arrow (open menu)
1239
- if(pressedKey == keys.downArrow) {
1446
+ if(pressedKey == keys.downArrow && !module.is.visible()) {
1240
1447
  module.verbose('Down key pressed, showing dropdown');
1448
+ module.select.firstUnfiltered();
1241
1449
  module.show();
1242
1450
  event.preventDefault();
1243
1451
  }
1244
1452
  }
1245
1453
  }
1246
1454
  else {
1247
- if( module.is.selection() && !module.is.search() ) {
1455
+ if( !module.has.search() ) {
1248
1456
  module.set.selectedLetter( String.fromCharCode(pressedKey) );
1249
1457
  }
1250
1458
  }
1251
1459
  }
1252
1460
  },
1253
1461
 
1462
+ trigger: {
1463
+ change: function() {
1464
+ var
1465
+ events = document.createEvent('HTMLEvents'),
1466
+ inputElement = $input[0]
1467
+ ;
1468
+ if(inputElement) {
1469
+ module.verbose('Triggering native change event');
1470
+ events.initEvent('change', true, false);
1471
+ inputElement.dispatchEvent(events);
1472
+ }
1473
+ }
1474
+ },
1475
+
1254
1476
  determine: {
1255
1477
  selectAction: function(text, value) {
1256
1478
  module.verbose('Determining action', settings.action);
1257
1479
  if( $.isFunction( module.action[settings.action] ) ) {
1258
1480
  module.verbose('Triggering preset action', settings.action, text, value);
1259
- module.action[ settings.action ].call(this, text, value);
1481
+ module.action[ settings.action ].call(element, text, value, this);
1260
1482
  }
1261
1483
  else if( $.isFunction(settings.action) ) {
1262
1484
  module.verbose('Triggering user action', settings.action, text, value);
1263
- settings.action.call(this, text, value);
1485
+ settings.action.call(element, text, value, this);
1264
1486
  }
1265
1487
  else {
1266
1488
  module.error(error.action, settings.action);
1267
1489
  }
1268
1490
  },
1269
1491
  eventInModule: function(event, callback) {
1492
+ var
1493
+ $target = $(event.target),
1494
+ inDocument = ($target.closest(document.documentElement).length > 0),
1495
+ inModule = ($target.closest($module).length > 0)
1496
+ ;
1270
1497
  callback = $.isFunction(callback)
1271
1498
  ? callback
1272
1499
  : function(){}
1273
1500
  ;
1274
- if( $(event.target).closest($module).length === 0 ) {
1501
+ if(inDocument && !inModule) {
1275
1502
  module.verbose('Triggering event', callback);
1276
1503
  callback();
1277
1504
  return true;
@@ -1283,13 +1510,17 @@ $.fn.dropdown = function(parameters) {
1283
1510
  },
1284
1511
  eventOnElement: function(event, callback) {
1285
1512
  var
1286
- $target = $(event.target)
1513
+ $target = $(event.target),
1514
+ $label = $target.closest(selector.siblingLabel),
1515
+ inVisibleDOM = document.body.contains(event.target),
1516
+ notOnLabel = ($module.find($label).length === 0),
1517
+ notInMenu = ($target.closest($menu).length === 0)
1287
1518
  ;
1288
1519
  callback = $.isFunction(callback)
1289
1520
  ? callback
1290
1521
  : function(){}
1291
1522
  ;
1292
- if($target.closest($menu).length === 0) {
1523
+ if(inVisibleDOM && notOnLabel && notInMenu) {
1293
1524
  module.verbose('Triggering event', callback);
1294
1525
  callback();
1295
1526
  return true;
@@ -1305,35 +1536,49 @@ $.fn.dropdown = function(parameters) {
1305
1536
 
1306
1537
  nothing: function() {},
1307
1538
 
1308
- activate: function(text, value) {
1539
+ activate: function(text, value, element) {
1309
1540
  value = (value !== undefined)
1310
1541
  ? value
1311
1542
  : text
1312
1543
  ;
1313
- module.set.selected(value, $(this));
1314
- if(module.is.multiple() && !module.is.allFiltered()) {
1315
- return;
1316
- }
1317
- else {
1318
- module.hideAndClear();
1544
+ if( module.can.activate( $(element) ) ) {
1545
+ module.set.selected(value, $(element));
1546
+ if(module.is.multiple() && !module.is.allFiltered()) {
1547
+ return;
1548
+ }
1549
+ else {
1550
+ module.hideAndClear();
1551
+ }
1319
1552
  }
1320
1553
  },
1321
1554
 
1322
- select: function(text, value) {
1323
- // mimics action.activate but does not select text
1324
- module.action.activate.call(this);
1555
+ select: function(text, value, element) {
1556
+ value = (value !== undefined)
1557
+ ? value
1558
+ : text
1559
+ ;
1560
+ if( module.can.activate( $(element) ) ) {
1561
+ module.set.value(value, $(element));
1562
+ if(module.is.multiple() && !module.is.allFiltered()) {
1563
+ return;
1564
+ }
1565
+ else {
1566
+ module.hideAndClear();
1567
+ }
1568
+ }
1325
1569
  },
1326
1570
 
1327
- combo: function(text, value) {
1571
+ combo: function(text, value, element) {
1328
1572
  value = (value !== undefined)
1329
1573
  ? value
1330
1574
  : text
1331
1575
  ;
1332
- module.set.selected(value, $(this));
1576
+ module.set.selected(value, $(element));
1333
1577
  module.hideAndClear();
1334
1578
  },
1335
1579
 
1336
- hide: function() {
1580
+ hide: function(text, value, element) {
1581
+ module.set.value(value, text);
1337
1582
  module.hideAndClear();
1338
1583
  }
1339
1584
 
@@ -1343,20 +1588,36 @@ $.fn.dropdown = function(parameters) {
1343
1588
  id: function() {
1344
1589
  return id;
1345
1590
  },
1591
+ defaultText: function() {
1592
+ return $module.data(metadata.defaultText);
1593
+ },
1594
+ defaultValue: function() {
1595
+ return $module.data(metadata.defaultValue);
1596
+ },
1597
+ placeholderText: function() {
1598
+ return $module.data(metadata.placeholderText) || '';
1599
+ },
1346
1600
  text: function() {
1347
1601
  return $text.text();
1348
1602
  },
1349
1603
  query: function() {
1350
1604
  return $.trim($search.val());
1351
1605
  },
1352
- searchWidth: function(characterCount) {
1353
- return (characterCount * settings.glyphWidth) + 'em';
1606
+ searchWidth: function(value) {
1607
+ value = (value !== undefined)
1608
+ ? value
1609
+ : $search.val()
1610
+ ;
1611
+ $sizer.text(value);
1612
+ // prevent rounding issues
1613
+ return Math.ceil( $sizer.width() + 1);
1354
1614
  },
1355
1615
  selectionCount: function() {
1356
1616
  var
1357
- values = module.get.values()
1617
+ values = module.get.values(),
1618
+ count
1358
1619
  ;
1359
- return ( module.is.multiple() )
1620
+ count = ( module.is.multiple() )
1360
1621
  ? $.isArray(values)
1361
1622
  ? values.length
1362
1623
  : 0
@@ -1364,6 +1625,7 @@ $.fn.dropdown = function(parameters) {
1364
1625
  ? 1
1365
1626
  : 0
1366
1627
  ;
1628
+ return count;
1367
1629
  },
1368
1630
  transition: function($subMenu) {
1369
1631
  return (settings.transition == 'auto')
@@ -1410,25 +1672,17 @@ $.fn.dropdown = function(parameters) {
1410
1672
  return range.text.length - rangeLength;
1411
1673
  }
1412
1674
  },
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
- },
1428
1675
  value: function() {
1429
- return ($input.length > 0)
1430
- ? $input.val()
1431
- : $module.data(metadata.value)
1676
+ var
1677
+ value = ($input.length > 0)
1678
+ ? $input.val()
1679
+ : $module.data(metadata.value),
1680
+ isEmptyMultiselect = ($.isArray(value) && value.length === 1 && value[0] === '')
1681
+ ;
1682
+ // prevents placeholder element from being selected when multiple
1683
+ return (value === undefined || isEmptyMultiselect)
1684
+ ? ''
1685
+ : value
1432
1686
  ;
1433
1687
  },
1434
1688
  values: function() {
@@ -1438,8 +1692,8 @@ $.fn.dropdown = function(parameters) {
1438
1692
  if(value === '') {
1439
1693
  return '';
1440
1694
  }
1441
- return (!$input.is('select') && module.is.multiple())
1442
- ? typeof value == 'string'
1695
+ return ( !module.has.selectInput() && module.is.multiple() )
1696
+ ? (typeof value == 'string') // delimited string
1443
1697
  ? value.split(settings.delimiter)
1444
1698
  : ''
1445
1699
  : value
@@ -1454,16 +1708,17 @@ $.fn.dropdown = function(parameters) {
1454
1708
  if(typeof values == 'string') {
1455
1709
  values = [values];
1456
1710
  }
1457
- remoteValues = {};
1458
1711
  $.each(values, function(index, value) {
1459
1712
  var
1460
1713
  name = module.read.remoteData(value)
1461
1714
  ;
1462
1715
  module.verbose('Restoring value from session data', name, value);
1463
- remoteValues[value] = (name)
1464
- ? name
1465
- : value
1466
- ;
1716
+ if(name) {
1717
+ if(!remoteValues) {
1718
+ remoteValues = {};
1719
+ }
1720
+ remoteValues[value] = name;
1721
+ }
1467
1722
  });
1468
1723
  }
1469
1724
  return remoteValues;
@@ -1475,7 +1730,7 @@ $.fn.dropdown = function(parameters) {
1475
1730
  ;
1476
1731
  if($choice) {
1477
1732
  if($choice.find(selector.menu).length > 0) {
1478
- module.verbose('Retreiving text of element with sub-menu');
1733
+ module.verbose('Retrieving text of element with sub-menu');
1479
1734
  $choice = $choice.clone();
1480
1735
  $choice.find(selector.menu).remove();
1481
1736
  $choice.find(selector.menuIcon).remove();
@@ -1483,8 +1738,8 @@ $.fn.dropdown = function(parameters) {
1483
1738
  return ($choice.data(metadata.text) !== undefined)
1484
1739
  ? $choice.data(metadata.text)
1485
1740
  : (preserveHTML)
1486
- ? $choice.html().trim()
1487
- : $choice.text().trim()
1741
+ ? $.trim($choice.html())
1742
+ : $.trim($choice.text())
1488
1743
  ;
1489
1744
  }
1490
1745
  },
@@ -1494,10 +1749,10 @@ $.fn.dropdown = function(parameters) {
1494
1749
  return false;
1495
1750
  }
1496
1751
  return ($choice.data(metadata.value) !== undefined)
1497
- ? $choice.data(metadata.value)
1752
+ ? String( $choice.data(metadata.value) )
1498
1753
  : (typeof choiceText === 'string')
1499
- ? choiceText.toLowerCase().trim()
1500
- : choiceText
1754
+ ? $.trim(choiceText.toLowerCase())
1755
+ : String(choiceText)
1501
1756
  ;
1502
1757
  },
1503
1758
  inputEvent: function() {
@@ -1556,7 +1811,7 @@ $.fn.dropdown = function(parameters) {
1556
1811
  module.debug('Retrieved and sorted values from select', select);
1557
1812
  }
1558
1813
  else {
1559
- module.debug('Retreived values from select', select);
1814
+ module.debug('Retrieved values from select', select);
1560
1815
  }
1561
1816
  return select;
1562
1817
  },
@@ -1600,7 +1855,7 @@ $.fn.dropdown = function(parameters) {
1600
1855
  ;
1601
1856
  shouldSearch = (isMultiple)
1602
1857
  ? (value.length > 0)
1603
- : (value !== undefined && value !== '' && value !== null)
1858
+ : (value !== undefined && value !== null)
1604
1859
  ;
1605
1860
  isMultiple = (module.is.multiple() && $.isArray(value));
1606
1861
  strict = (value === '' || value === 0)
@@ -1620,7 +1875,7 @@ $.fn.dropdown = function(parameters) {
1620
1875
  return;
1621
1876
  }
1622
1877
  if(isMultiple) {
1623
- if($.inArray(optionValue.toString(), value) !== -1 || $.inArray(optionText, value) !== -1) {
1878
+ if($.inArray( String(optionValue), value) !== -1 || $.inArray(optionText, value) !== -1) {
1624
1879
  $selectedItem = ($selectedItem)
1625
1880
  ? $selectedItem.add($choice)
1626
1881
  : $choice
@@ -1635,7 +1890,7 @@ $.fn.dropdown = function(parameters) {
1635
1890
  }
1636
1891
  }
1637
1892
  else {
1638
- if( optionValue.toString() == value.toString() || optionText == value) {
1893
+ if( String(optionValue) == String(value) || optionText == value) {
1639
1894
  module.verbose('Found select item by value', optionValue, value);
1640
1895
  $selectedItem = $choice;
1641
1896
  return true;
@@ -1657,8 +1912,10 @@ $.fn.dropdown = function(parameters) {
1657
1912
  ;
1658
1913
  if(selectionCount >= settings.maxSelections) {
1659
1914
  module.debug('Maximum selection count reached');
1660
- $item.addClass(className.filtered);
1661
- module.add.message(message.maxSelections);
1915
+ if(settings.useLabels) {
1916
+ $item.addClass(className.filtered);
1917
+ module.add.message(message.maxSelections);
1918
+ }
1662
1919
  return true;
1663
1920
  }
1664
1921
  else {
@@ -1677,20 +1934,30 @@ $.fn.dropdown = function(parameters) {
1677
1934
 
1678
1935
  restore: {
1679
1936
  defaults: function() {
1937
+ module.clear();
1680
1938
  module.restore.defaultText();
1681
1939
  module.restore.defaultValue();
1682
1940
  },
1683
1941
  defaultText: function() {
1684
1942
  var
1685
- defaultText = $module.data(metadata.defaultText)
1943
+ defaultText = module.get.defaultText(),
1944
+ placeholderText = module.get.placeholderText
1686
1945
  ;
1687
- module.debug('Restoring default text', defaultText);
1688
- module.set.text(defaultText);
1689
- $text.addClass(className.placeholder);
1946
+ if(defaultText === placeholderText) {
1947
+ module.debug('Restoring default placeholder text', defaultText);
1948
+ module.set.placeholderText(defaultText);
1949
+ }
1950
+ else {
1951
+ module.debug('Restoring default text', defaultText);
1952
+ module.set.text(defaultText);
1953
+ }
1954
+ },
1955
+ placeholderText: function() {
1956
+ module.set.placeholderText();
1690
1957
  },
1691
1958
  defaultValue: function() {
1692
1959
  var
1693
- defaultValue = $module.data(metadata.defaultValue)
1960
+ defaultValue = module.get.defaultValue()
1694
1961
  ;
1695
1962
  if(defaultValue !== undefined) {
1696
1963
  module.debug('Restoring default value', defaultValue);
@@ -1726,15 +1993,10 @@ $.fn.dropdown = function(parameters) {
1726
1993
  }
1727
1994
  },
1728
1995
  values: function() {
1729
- // prevents callbacks from occuring on initial load
1996
+ // prevents callbacks from occurring on initial load
1730
1997
  module.set.initialLoad();
1731
- if(settings.apiSettings) {
1732
- if(settings.saveRemoteData) {
1733
- module.restore.remoteValues();
1734
- }
1735
- else {
1736
- module.clearValue();
1737
- }
1998
+ if(settings.apiSettings && settings.saveRemoteData && module.get.remoteValues()) {
1999
+ module.restore.remoteValues();
1738
2000
  }
1739
2001
  else {
1740
2002
  module.set.selected();
@@ -1802,7 +2064,7 @@ $.fn.dropdown = function(parameters) {
1802
2064
  var
1803
2065
  text
1804
2066
  ;
1805
- if($text.hasClass(className.placeholder)) {
2067
+ if(settings.placeholder !== false && $text.hasClass(className.placeholder)) {
1806
2068
  text = module.get.text();
1807
2069
  module.verbose('Saving placeholder text as', text);
1808
2070
  $module.data(metadata.placeholderText, text);
@@ -1819,7 +2081,7 @@ $.fn.dropdown = function(parameters) {
1819
2081
  },
1820
2082
 
1821
2083
  clear: function() {
1822
- if(module.is.multiple()) {
2084
+ if(module.is.multiple() && settings.useLabels) {
1823
2085
  module.remove.labels();
1824
2086
  }
1825
2087
  else {
@@ -1836,8 +2098,8 @@ $.fn.dropdown = function(parameters) {
1836
2098
 
1837
2099
  scrollPage: function(direction, $selectedItem) {
1838
2100
  var
1839
- $selectedItem = $selectedItem || module.get.selectedItem(),
1840
- $menu = $selectedItem.closest(selector.menu),
2101
+ $currentItem = $selectedItem || module.get.selectedItem(),
2102
+ $menu = $currentItem.closest(selector.menu),
1841
2103
  menuHeight = $menu.outerHeight(),
1842
2104
  currentScroll = $menu.scrollTop(),
1843
2105
  itemHeight = $item.eq(0).outerHeight(),
@@ -1852,8 +2114,8 @@ $.fn.dropdown = function(parameters) {
1852
2114
  elementIndex
1853
2115
  ;
1854
2116
  elementIndex = (direction == 'up')
1855
- ? $selectableItem.index($selectedItem) - itemsPerPage
1856
- : $selectableItem.index($selectedItem) + itemsPerPage
2117
+ ? $selectableItem.index($currentItem) - itemsPerPage
2118
+ : $selectableItem.index($currentItem) + itemsPerPage
1857
2119
  ;
1858
2120
  isWithinRange = (direction == 'up')
1859
2121
  ? (elementIndex >= 0)
@@ -1867,12 +2129,15 @@ $.fn.dropdown = function(parameters) {
1867
2129
  ;
1868
2130
  if($nextSelectedItem.length > 0) {
1869
2131
  module.debug('Scrolling page', direction, $nextSelectedItem);
1870
- $selectedItem
2132
+ $currentItem
1871
2133
  .removeClass(className.selected)
1872
2134
  ;
1873
2135
  $nextSelectedItem
1874
2136
  .addClass(className.selected)
1875
2137
  ;
2138
+ if(settings.selectOnKeydown && module.is.single()) {
2139
+ module.set.selectedItem($nextSelectedItem);
2140
+ }
1876
2141
  $menu
1877
2142
  .scrollTop(newScroll)
1878
2143
  ;
@@ -1889,7 +2154,7 @@ $.fn.dropdown = function(parameters) {
1889
2154
  ? module.get.query()
1890
2155
  : '',
1891
2156
  hasSearchValue = (typeof searchValue === 'string' && searchValue.length > 0),
1892
- searchWidth = module.get.searchWidth(searchValue.length),
2157
+ searchWidth = module.get.searchWidth(),
1893
2158
  valueIsSet = searchValue !== ''
1894
2159
  ;
1895
2160
  if(isMultiple && hasSearchValue) {
@@ -1905,16 +2170,17 @@ $.fn.dropdown = function(parameters) {
1905
2170
  $text.removeClass(className.filtered);
1906
2171
  }
1907
2172
  },
2173
+ empty: function() {
2174
+ $module.addClass(className.empty);
2175
+ },
1908
2176
  loading: function() {
1909
2177
  $module.addClass(className.loading);
1910
2178
  },
1911
2179
  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
- }
2180
+ text = text || module.get.placeholderText();
2181
+ module.debug('Setting placeholder text', text);
2182
+ module.set.text(text);
2183
+ $text.addClass(className.placeholder);
1918
2184
  },
1919
2185
  tabbable: function() {
1920
2186
  if( module.has.search() ) {
@@ -1929,7 +2195,7 @@ $.fn.dropdown = function(parameters) {
1929
2195
  }
1930
2196
  else {
1931
2197
  module.debug('Added tabindex to dropdown');
1932
- if(!$module.attr('tabindex') ) {
2198
+ if( $module.attr('tabindex') === undefined) {
1933
2199
  $module
1934
2200
  .attr('tabindex', 0)
1935
2201
  ;
@@ -1943,6 +2209,20 @@ $.fn.dropdown = function(parameters) {
1943
2209
  module.verbose('Setting initial load');
1944
2210
  initialLoad = true;
1945
2211
  },
2212
+ activeItem: function($item) {
2213
+ if( settings.allowAdditions && $item.filter(selector.addition).length > 0 ) {
2214
+ $item.addClass(className.filtered);
2215
+ }
2216
+ else {
2217
+ $item.addClass(className.active);
2218
+ }
2219
+ },
2220
+ partialSearch: function(text) {
2221
+ var
2222
+ length = module.get.query().length
2223
+ ;
2224
+ $search.val( text.substr(0 , length));
2225
+ },
1946
2226
  scrollPosition: function($item, forceScroll) {
1947
2227
  var
1948
2228
  edgeTolerance = 5,
@@ -1997,10 +2277,12 @@ $.fn.dropdown = function(parameters) {
1997
2277
  }
1998
2278
  }
1999
2279
  else {
2280
+ if(text !== module.get.placeholderText()) {
2281
+ $text.removeClass(className.placeholder);
2282
+ }
2000
2283
  module.debug('Changing text', text, $text);
2001
2284
  $text
2002
2285
  .removeClass(className.filtered)
2003
- .removeClass(className.placeholder)
2004
2286
  ;
2005
2287
  if(settings.preserveHTML) {
2006
2288
  $text.html(text);
@@ -2011,30 +2293,52 @@ $.fn.dropdown = function(parameters) {
2011
2293
  }
2012
2294
  }
2013
2295
  },
2014
- selectedLetter: function(letter) {
2296
+ selectedItem: function($item) {
2015
2297
  var
2016
- $selectedItem = $item.filter('.' + className.selected),
2017
- $nextValue = false
2298
+ value = module.get.choiceValue($item),
2299
+ text = module.get.choiceText($item, false)
2018
2300
  ;
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
- })
2301
+ module.debug('Setting user selection to item', $item);
2302
+ module.remove.activeItem();
2303
+ module.set.partialSearch(text);
2304
+ module.set.activeItem($item);
2305
+ module.set.selected(value, $item);
2306
+ module.set.text(text);
2307
+ },
2308
+ selectedLetter: function(letter) {
2309
+ var
2310
+ $selectedItem = $item.filter('.' + className.selected),
2311
+ alreadySelectedLetter = $selectedItem.length > 0 && module.has.firstLetter($selectedItem, letter),
2312
+ $nextValue = false,
2313
+ $nextItem
2032
2314
  ;
2315
+ // check next of same letter
2316
+ if(alreadySelectedLetter) {
2317
+ $nextItem = $selectedItem.nextAll($item).eq(0);
2318
+ if( module.has.firstLetter($nextItem, letter) ) {
2319
+ $nextValue = $nextItem;
2320
+ }
2321
+ }
2322
+ // check all values
2323
+ if(!$nextValue) {
2324
+ $item
2325
+ .each(function(){
2326
+ if(module.has.firstLetter($(this), letter)) {
2327
+ $nextValue = $(this);
2328
+ return false;
2329
+ }
2330
+ })
2331
+ ;
2332
+ }
2333
+ // set next value
2033
2334
  if($nextValue) {
2034
2335
  module.verbose('Scrolling to next value with letter', letter);
2035
2336
  module.set.scrollPosition($nextValue);
2036
2337
  $selectedItem.removeClass(className.selected);
2037
2338
  $nextValue.addClass(className.selected);
2339
+ if(settings.selectOnKeydown && module.is.single()) {
2340
+ module.set.selectedItem($nextValue);
2341
+ }
2038
2342
  }
2039
2343
  },
2040
2344
  direction: function($menu) {
@@ -2056,31 +2360,44 @@ $.fn.dropdown = function(parameters) {
2056
2360
  },
2057
2361
  value: function(value, text, $selected) {
2058
2362
  var
2363
+ escapedValue = module.escape.value(value),
2059
2364
  hasInput = ($input.length > 0),
2060
2365
  isAddition = !module.has.value(value),
2061
2366
  currentValue = module.get.values(),
2062
- stringValue = (typeof value == 'number')
2063
- ? value.toString()
2367
+ stringValue = (value !== undefined)
2368
+ ? String(value)
2064
2369
  : value,
2065
2370
  newValue
2066
2371
  ;
2067
2372
  if(hasInput) {
2068
- if(stringValue == currentValue) {
2373
+ if(!settings.allowReselection && stringValue == currentValue) {
2069
2374
  module.verbose('Skipping value update already same value', value, currentValue);
2070
2375
  if(!module.is.initialLoad()) {
2071
2376
  return;
2072
2377
  }
2073
2378
  }
2074
- module.debug('Updating input value', value, currentValue);
2379
+
2380
+ if( module.is.single() && module.has.selectInput() && module.can.extendSelect() ) {
2381
+ module.debug('Adding user option', value);
2382
+ module.add.optionValue(value);
2383
+ }
2384
+ module.debug('Updating input value', escapedValue, currentValue);
2385
+ internalChange = true;
2075
2386
  $input
2076
- .val(value)
2077
- .trigger('change')
2387
+ .val(escapedValue)
2078
2388
  ;
2389
+ if(settings.fireOnInit === false && module.is.initialLoad()) {
2390
+ module.debug('Input native change event ignored on initial load');
2391
+ }
2392
+ else {
2393
+ module.trigger.change();
2394
+ }
2395
+ internalChange = false;
2079
2396
  }
2080
2397
  else {
2081
- module.verbose('Storing value in metadata', value, $input);
2082
- if(value !== currentValue) {
2083
- $module.data(metadata.value, value);
2398
+ module.verbose('Storing value in metadata', escapedValue, $input);
2399
+ if(escapedValue !== currentValue) {
2400
+ $module.data(metadata.value, stringValue);
2084
2401
  }
2085
2402
  }
2086
2403
  if(settings.fireOnInit === false && module.is.initialLoad()) {
@@ -2101,6 +2418,11 @@ $.fn.dropdown = function(parameters) {
2101
2418
  visible: function() {
2102
2419
  $module.addClass(className.visible);
2103
2420
  },
2421
+ exactly: function(value, $selectedItem) {
2422
+ module.debug('Setting selected to exact values');
2423
+ module.clear();
2424
+ module.set.selected(value, $selectedItem);
2425
+ },
2104
2426
  selected: function(value, $selectedItem) {
2105
2427
  var
2106
2428
  isMultiple = module.is.multiple(),
@@ -2114,6 +2436,9 @@ $.fn.dropdown = function(parameters) {
2114
2436
  return;
2115
2437
  }
2116
2438
  module.debug('Setting selected menu item to', $selectedItem);
2439
+ if(module.is.multiple()) {
2440
+ module.remove.searchWidth();
2441
+ }
2117
2442
  if(module.is.single()) {
2118
2443
  module.remove.activeItem();
2119
2444
  module.remove.selectedItem();
@@ -2142,14 +2467,14 @@ $.fn.dropdown = function(parameters) {
2142
2467
  if(settings.useLabels) {
2143
2468
  module.add.value(selectedValue, selectedText, $selected);
2144
2469
  module.add.label(selectedValue, selectedText, shouldAnimate);
2145
- $selected.addClass(className.active);
2470
+ module.set.activeItem($selected);
2146
2471
  module.filterActive();
2147
2472
  module.select.nextAvailable($selectedItem);
2148
2473
  }
2149
2474
  else {
2150
2475
  module.add.value(selectedValue, selectedText, $selected);
2151
2476
  module.set.text(module.add.variables(message.count));
2152
- $selected.addClass(className.active);
2477
+ module.set.activeItem($selected);
2153
2478
  }
2154
2479
  }
2155
2480
  else if(!isFiltered) {
@@ -2161,8 +2486,8 @@ $.fn.dropdown = function(parameters) {
2161
2486
  if(settings.apiSettings && settings.saveRemoteData) {
2162
2487
  module.save.remoteData(selectedText, selectedValue);
2163
2488
  }
2164
- module.set.value(selectedValue, selectedText, $selected);
2165
2489
  module.set.text(selectedText);
2490
+ module.set.value(selectedValue, selectedText, $selected);
2166
2491
  $selected
2167
2492
  .addClass(className.active)
2168
2493
  .addClass(className.selected)
@@ -2179,17 +2504,18 @@ $.fn.dropdown = function(parameters) {
2179
2504
  $next = module.is.searchSelection()
2180
2505
  ? $search
2181
2506
  : $text,
2507
+ escapedValue = module.escape.value(value),
2182
2508
  $label
2183
2509
  ;
2184
2510
  $label = $('<a />')
2185
2511
  .addClass(className.label)
2186
- .attr('data-value', value)
2187
- .html(templates.label(value, text))
2512
+ .attr('data-value', escapedValue)
2513
+ .html(templates.label(escapedValue, text))
2188
2514
  ;
2189
- $label = settings.onLabelCreate.call($label, value, text);
2515
+ $label = settings.onLabelCreate.call($label, escapedValue, text);
2190
2516
 
2191
2517
  if(module.has.label(value)) {
2192
- module.debug('Label already exists, skipping', value);
2518
+ module.debug('Label already exists, skipping', escapedValue);
2193
2519
  return;
2194
2520
  }
2195
2521
  if(settings.label.variation) {
@@ -2230,67 +2556,76 @@ $.fn.dropdown = function(parameters) {
2230
2556
  },
2231
2557
  optionValue: function(value) {
2232
2558
  var
2233
- $option = $input.find('option[value="' + value + '"]'),
2234
- hasOption = ($option.length > 0)
2559
+ escapedValue = module.escape.value(value),
2560
+ $option = $input.find('option[value="' + escapedValue + '"]'),
2561
+ hasOption = ($option.length > 0)
2235
2562
  ;
2236
2563
  if(hasOption) {
2237
2564
  return;
2238
2565
  }
2239
2566
  // temporarily disconnect observer
2240
- if(selectObserver) {
2241
- selectObserver.disconnect();
2242
- module.verbose('Temporarily disconnecting mutation observer', value);
2567
+ module.disconnect.selectObserver();
2568
+ if( module.is.single() ) {
2569
+ module.verbose('Removing previous user addition');
2570
+ $input.find('option.' + className.addition).remove();
2243
2571
  }
2244
2572
  $('<option/>')
2245
- .prop('value', value)
2573
+ .prop('value', escapedValue)
2574
+ .addClass(className.addition)
2246
2575
  .html(value)
2247
2576
  .appendTo($input)
2248
2577
  ;
2249
2578
  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
- }
2579
+ module.observe.select();
2256
2580
  },
2257
2581
  userSuggestion: function(value) {
2258
2582
  var
2259
2583
  $addition = $menu.children(selector.addition),
2260
- alreadyHasValue = module.get.item(value),
2584
+ $existingItem = module.get.item(value),
2585
+ alreadyHasValue = $existingItem && $existingItem.not(selector.addition).length,
2261
2586
  hasUserSuggestion = $addition.length > 0,
2262
2587
  html
2263
2588
  ;
2264
- if(module.has.maxSelections()) {
2589
+ if(settings.useLabels && module.has.maxSelections()) {
2265
2590
  return;
2266
2591
  }
2267
2592
  if(value === '' || alreadyHasValue) {
2268
2593
  $addition.remove();
2269
2594
  return;
2270
2595
  }
2271
- $item
2272
- .removeClass(className.selected)
2273
- ;
2274
2596
  if(hasUserSuggestion) {
2275
- html = settings.templates.addition(value);
2276
2597
  $addition
2277
- .html(html)
2278
2598
  .data(metadata.value, value)
2599
+ .data(metadata.text, value)
2600
+ .attr('data-' + metadata.value, value)
2601
+ .attr('data-' + metadata.text, value)
2279
2602
  .removeClass(className.filtered)
2280
- .addClass(className.selected)
2281
2603
  ;
2604
+ if(!settings.hideAdditions) {
2605
+ html = settings.templates.addition( module.add.variables(message.addResult, value) );
2606
+ $addition
2607
+ .html(html)
2608
+ ;
2609
+ }
2282
2610
  module.verbose('Replacing user suggestion with new value', $addition);
2283
2611
  }
2284
2612
  else {
2285
2613
  $addition = module.create.userChoice(value);
2286
2614
  $addition
2287
2615
  .prependTo($menu)
2288
- .addClass(className.selected)
2289
2616
  ;
2290
2617
  module.verbose('Adding item choice to menu corresponding with user choice addition', $addition);
2291
2618
  }
2619
+ if(!settings.hideAdditions || module.is.allFiltered()) {
2620
+ $addition
2621
+ .addClass(className.selected)
2622
+ .siblings()
2623
+ .removeClass(className.selected)
2624
+ ;
2625
+ }
2626
+ module.refreshItems();
2292
2627
  },
2293
- variables: function(message) {
2628
+ variables: function(message, term) {
2294
2629
  var
2295
2630
  hasCount = (message.search('{count}') !== -1),
2296
2631
  hasMaxCount = (message.search('{maxCount}') !== -1),
@@ -2309,7 +2644,7 @@ $.fn.dropdown = function(parameters) {
2309
2644
  message = message.replace('{maxCount}', settings.maxSelections);
2310
2645
  }
2311
2646
  if(hasTerm) {
2312
- query = module.get.query();
2647
+ query = term || module.get.query();
2313
2648
  message = message.replace('{term}', query);
2314
2649
  }
2315
2650
  return message;
@@ -2323,7 +2658,7 @@ $.fn.dropdown = function(parameters) {
2323
2658
  module.debug('Cannot select blank values from multiselect');
2324
2659
  return;
2325
2660
  }
2326
- // extend currently array
2661
+ // extend current array
2327
2662
  if($.isArray(currentValue)) {
2328
2663
  newValue = currentValue.concat([addedValue]);
2329
2664
  newValue = module.get.uniqueArray(newValue);
@@ -2332,10 +2667,10 @@ $.fn.dropdown = function(parameters) {
2332
2667
  newValue = [addedValue];
2333
2668
  }
2334
2669
  // add values
2335
- if( $input.is('select')) {
2336
- if(settings.allowAdditions) {
2337
- module.add.optionValue(addedValue);
2670
+ if( module.has.selectInput() ) {
2671
+ if(module.can.extendSelect()) {
2338
2672
  module.debug('Adding value to select', addedValue, newValue, $input);
2673
+ module.add.optionValue(addedValue);
2339
2674
  }
2340
2675
  }
2341
2676
  else {
@@ -2344,7 +2679,7 @@ $.fn.dropdown = function(parameters) {
2344
2679
  }
2345
2680
 
2346
2681
  if(settings.fireOnInit === false && module.is.initialLoad()) {
2347
- module.verbose('No callback on initial load', settings.onAdd);
2682
+ module.verbose('Skipping onadd callback on initial load', settings.onAdd);
2348
2683
  }
2349
2684
  else {
2350
2685
  settings.onAdd.call(element, addedValue, addedText, $selectedItem);
@@ -2361,6 +2696,9 @@ $.fn.dropdown = function(parameters) {
2361
2696
  activeLabel: function() {
2362
2697
  $module.find(selector.label).removeClass(className.active);
2363
2698
  },
2699
+ empty: function() {
2700
+ $module.removeClass(className.empty);
2701
+ },
2364
2702
  loading: function() {
2365
2703
  $module.removeClass(className.loading);
2366
2704
  },
@@ -2378,24 +2716,54 @@ $.fn.dropdown = function(parameters) {
2378
2716
  $item.removeClass(className.active);
2379
2717
  },
2380
2718
  filteredItem: function() {
2381
- if( module.has.maxSelections() ) {
2719
+ if(settings.useLabels && module.has.maxSelections() ) {
2382
2720
  return;
2383
2721
  }
2384
- if(settings.useLabels) {
2722
+ if(settings.useLabels && module.is.multiple()) {
2385
2723
  $item.not('.' + className.active).removeClass(className.filtered);
2386
2724
  }
2387
2725
  else {
2388
2726
  $item.removeClass(className.filtered);
2389
2727
  }
2728
+ module.remove.empty();
2729
+ },
2730
+ optionValue: function(value) {
2731
+ var
2732
+ escapedValue = module.escape.value(value),
2733
+ $option = $input.find('option[value="' + escapedValue + '"]'),
2734
+ hasOption = ($option.length > 0)
2735
+ ;
2736
+ if(!hasOption || !$option.hasClass(className.addition)) {
2737
+ return;
2738
+ }
2739
+ // temporarily disconnect observer
2740
+ if(selectObserver) {
2741
+ selectObserver.disconnect();
2742
+ module.verbose('Temporarily disconnecting mutation observer');
2743
+ }
2744
+ $option.remove();
2745
+ module.verbose('Removing user addition as an <option>', escapedValue);
2746
+ if(selectObserver) {
2747
+ selectObserver.observe($input[0], {
2748
+ childList : true,
2749
+ subtree : true
2750
+ });
2751
+ }
2390
2752
  },
2391
2753
  message: function() {
2392
2754
  $menu.children(selector.message).remove();
2393
2755
  },
2756
+ searchWidth: function() {
2757
+ $search.css('width', '');
2758
+ },
2394
2759
  searchTerm: function() {
2395
2760
  module.verbose('Cleared search term');
2396
2761
  $search.val('');
2397
2762
  module.set.filtered();
2398
2763
  },
2764
+ userAddition: function() {
2765
+ $item.filter(selector.addition).remove();
2766
+ },
2399
2767
  selected: function(value, $selectedItem) {
2400
2768
  $selectedItem = (settings.allowAdditions)
2401
2769
  ? $selectedItem || module.get.itemWithAdditions(value)
@@ -2420,7 +2788,12 @@ $.fn.dropdown = function(parameters) {
2420
2788
  }
2421
2789
  else {
2422
2790
  module.remove.value(selectedValue, selectedText, $selected);
2423
- module.set.text(module.add.variables(message.count));
2791
+ if(module.get.selectionCount() === 0) {
2792
+ module.set.placeholderText();
2793
+ }
2794
+ else {
2795
+ module.set.text(module.add.variables(message.count));
2796
+ }
2424
2797
  }
2425
2798
  }
2426
2799
  else {
@@ -2441,16 +2814,16 @@ $.fn.dropdown = function(parameters) {
2441
2814
  },
2442
2815
  value: function(removedValue, removedText, $removedItem) {
2443
2816
  var
2444
- values = $input.val(),
2817
+ values = module.get.values(),
2445
2818
  newValue
2446
2819
  ;
2447
- if( $input.is('select') ) {
2820
+ if( module.has.selectInput() ) {
2448
2821
  module.verbose('Input is <select> removing selected option', removedValue);
2449
2822
  newValue = module.remove.arrayValue(removedValue, values);
2823
+ module.remove.optionValue(removedValue);
2450
2824
  }
2451
2825
  else {
2452
2826
  module.verbose('Removing from delimited values', removedValue);
2453
- values = values.split(settings.delimiter);
2454
2827
  newValue = module.remove.arrayValue(removedValue, values);
2455
2828
  newValue = newValue.join(settings.delimiter);
2456
2829
  }
@@ -2464,32 +2837,22 @@ $.fn.dropdown = function(parameters) {
2464
2837
  module.check.maxSelections();
2465
2838
  },
2466
2839
  arrayValue: function(removedValue, values) {
2840
+ if( !$.isArray(values) ) {
2841
+ values = [values];
2842
+ }
2467
2843
  values = $.grep(values, function(value){
2468
2844
  return (removedValue != value);
2469
2845
  });
2470
2846
  module.verbose('Removed value from delimited string', removedValue, values);
2471
2847
  return values;
2472
2848
  },
2473
- label: function(value) {
2849
+ label: function(value, shouldAnimate) {
2474
2850
  var
2475
2851
  $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
- }
2852
+ $removedLabel = $labels.filter('[data-value="' + value +'"]')
2853
+ ;
2854
+ module.verbose('Removing label', $removedLabel);
2855
+ $removedLabel.remove();
2493
2856
  },
2494
2857
  activeLabels: function($activeLabels) {
2495
2858
  $activeLabels = $activeLabels || $module.find(selector.label).filter('.' + className.active);
@@ -2502,16 +2865,25 @@ $.fn.dropdown = function(parameters) {
2502
2865
  $labels
2503
2866
  .each(function(){
2504
2867
  var
2505
- value = $(this).data('value'),
2506
- isUserValue = module.is.userValue(value)
2868
+ $label = $(this),
2869
+ value = $label.data(metadata.value),
2870
+ stringValue = (value !== undefined)
2871
+ ? String(value)
2872
+ : value,
2873
+ isUserValue = module.is.userValue(stringValue)
2507
2874
  ;
2875
+ if(settings.onLabelRemove.call($label, value) === false) {
2876
+ module.debug('Label remove callback cancelled removal');
2877
+ return;
2878
+ }
2879
+ module.remove.message();
2508
2880
  if(isUserValue) {
2509
- module.remove.value(value);
2510
- module.remove.label(value);
2881
+ module.remove.value(stringValue);
2882
+ module.remove.label(stringValue);
2511
2883
  }
2512
2884
  else {
2513
2885
  // selected will also remove label
2514
- module.remove.selected(value);
2886
+ module.remove.selected(stringValue);
2515
2887
  }
2516
2888
  })
2517
2889
  ;
@@ -2520,31 +2892,66 @@ $.fn.dropdown = function(parameters) {
2520
2892
  if( module.has.search() ) {
2521
2893
  module.debug('Searchable dropdown initialized');
2522
2894
  $search
2523
- .attr('tabindex', '-1')
2895
+ .removeAttr('tabindex')
2524
2896
  ;
2525
2897
  $menu
2526
- .attr('tabindex', '-1')
2898
+ .removeAttr('tabindex')
2527
2899
  ;
2528
2900
  }
2529
2901
  else {
2530
2902
  module.debug('Simple selection dropdown initialized');
2531
2903
  $module
2532
- .attr('tabindex', '-1')
2904
+ .removeAttr('tabindex')
2533
2905
  ;
2534
2906
  $menu
2535
- .attr('tabindex', '-1')
2907
+ .removeAttr('tabindex')
2536
2908
  ;
2537
2909
  }
2538
2910
  }
2539
2911
  },
2540
2912
 
2541
2913
  has: {
2914
+ menuSearch: function() {
2915
+ return (module.has.search() && $search.closest($menu).length > 0);
2916
+ },
2542
2917
  search: function() {
2543
2918
  return ($search.length > 0);
2544
2919
  },
2920
+ sizer: function() {
2921
+ return ($sizer.length > 0);
2922
+ },
2923
+ selectInput: function() {
2924
+ return ( $input.is('select') );
2925
+ },
2926
+ minCharacters: function(searchTerm) {
2927
+ if(settings.minCharacters) {
2928
+ searchTerm = (searchTerm !== undefined)
2929
+ ? String(searchTerm)
2930
+ : String(module.get.query())
2931
+ ;
2932
+ return (searchTerm.length >= settings.minCharacters);
2933
+ }
2934
+ return true;
2935
+ },
2936
+ firstLetter: function($item, letter) {
2937
+ var
2938
+ text,
2939
+ firstLetter
2940
+ ;
2941
+ if(!$item || $item.length === 0 || typeof letter !== 'string') {
2942
+ return false;
2943
+ }
2944
+ text = module.get.choiceText($item, false);
2945
+ letter = letter.toLowerCase();
2946
+ firstLetter = String(text).charAt(0).toLowerCase();
2947
+ return (letter == firstLetter);
2948
+ },
2545
2949
  input: function() {
2546
2950
  return ($input.length > 0);
2547
2951
  },
2952
+ items: function() {
2953
+ return ($item.length > 0);
2954
+ },
2548
2955
  menu: function() {
2549
2956
  return ($menu.length > 0);
2550
2957
  },
@@ -2553,15 +2960,25 @@ $.fn.dropdown = function(parameters) {
2553
2960
  },
2554
2961
  label: function(value) {
2555
2962
  var
2556
- $labels = $module.find(selector.label)
2963
+ escapedValue = module.escape.value(value),
2964
+ $labels = $module.find(selector.label)
2557
2965
  ;
2558
- return ($labels.filter('[data-value="' + value +'"]').length > 0);
2966
+ return ($labels.filter('[data-value="' + escapedValue +'"]').length > 0);
2559
2967
  },
2560
2968
  maxSelections: function() {
2561
2969
  return (settings.maxSelections && module.get.selectionCount() >= settings.maxSelections);
2562
2970
  },
2563
2971
  allResultsFiltered: function() {
2564
- return ($item.filter(selector.unselectable).length === $item.length);
2972
+ var
2973
+ $normalResults = $item.not(selector.addition)
2974
+ ;
2975
+ return ($normalResults.filter(selector.unselectable).length === $normalResults.length);
2976
+ },
2977
+ userSuggestion: function() {
2978
+ return ($menu.children(selector.addition).length > 0);
2979
+ },
2980
+ query: function() {
2981
+ return (module.get.query() !== '');
2565
2982
  },
2566
2983
  value: function(value) {
2567
2984
  var
@@ -2581,6 +2998,12 @@ $.fn.dropdown = function(parameters) {
2581
2998
  active: function() {
2582
2999
  return $module.hasClass(className.active);
2583
3000
  },
3001
+ bubbledLabelClick: function(event) {
3002
+ return $(event.target).is('select, input') && $module.closest('label').length > 0;
3003
+ },
3004
+ bubbledIconClick: function(event) {
3005
+ return $(event.target).closest($icon).length > 0;
3006
+ },
2584
3007
  alreadySetup: function() {
2585
3008
  return ($module.is('select') && $module.parent(selector.dropdown).length > 0 && $module.prev().length === 0);
2586
3009
  },
@@ -2590,6 +3013,9 @@ $.fn.dropdown = function(parameters) {
2590
3013
  : $menu.transition && $menu.transition('is animating')
2591
3014
  ;
2592
3015
  },
3016
+ disabled: function() {
3017
+ return $module.hasClass(className.disabled);
3018
+ },
2593
3019
  focused: function() {
2594
3020
  return (document.activeElement === $module[0]);
2595
3021
  },
@@ -2597,7 +3023,7 @@ $.fn.dropdown = function(parameters) {
2597
3023
  return (document.activeElement === $search[0]);
2598
3024
  },
2599
3025
  allFiltered: function() {
2600
- return( (module.is.multiple() || module.has.search()) && !module.has.message() && module.has.allResultsFiltered() );
3026
+ return( (module.is.multiple() || module.has.search()) && !(settings.hideAdditions == false && module.has.userSuggestion()) && !module.has.message() && module.has.allResultsFiltered() );
2601
3027
  },
2602
3028
  hidden: function($subMenu) {
2603
3029
  return !module.is.visible($subMenu);
@@ -2676,7 +3102,7 @@ $.fn.dropdown = function(parameters) {
2676
3102
  return $module.hasClass(className.search);
2677
3103
  },
2678
3104
  searchSelection: function() {
2679
- return ( module.has.search() && $search.closest(selector.menu).length === 0 );
3105
+ return ( module.has.search() && $search.parent(selector.dropdown).length === 1 );
2680
3106
  },
2681
3107
  selection: function() {
2682
3108
  return $module.hasClass(className.selection);
@@ -2697,11 +3123,26 @@ $.fn.dropdown = function(parameters) {
2697
3123
  },
2698
3124
 
2699
3125
  can: {
3126
+ activate: function($item) {
3127
+ if(settings.useLabels) {
3128
+ return true;
3129
+ }
3130
+ if(!module.has.maxSelections()) {
3131
+ return true;
3132
+ }
3133
+ if(module.has.maxSelections() && $item.hasClass(className.active)) {
3134
+ return true;
3135
+ }
3136
+ return false;
3137
+ },
2700
3138
  click: function() {
2701
3139
  return (hasTouch || settings.on == 'click');
2702
3140
  },
3141
+ extendSelect: function() {
3142
+ return settings.allowAdditions || settings.apiSettings;
3143
+ },
2703
3144
  show: function() {
2704
- return !$module.hasClass(className.disabled) && $item.length > 0;
3145
+ return !module.is.disabled() && (module.has.items() || module.has.message());
2705
3146
  },
2706
3147
  useAPI: function() {
2707
3148
  return $.fn.api !== undefined;
@@ -2811,8 +3252,11 @@ $.fn.dropdown = function(parameters) {
2811
3252
  },
2812
3253
 
2813
3254
  hideAndClear: function() {
3255
+ module.remove.searchTerm();
3256
+ if( module.has.maxSelections() ) {
3257
+ return;
3258
+ }
2814
3259
  if(module.has.search()) {
2815
- module.remove.searchTerm();
2816
3260
  module.hide(function() {
2817
3261
  module.remove.filteredItem();
2818
3262
  });
@@ -2836,6 +3280,26 @@ $.fn.dropdown = function(parameters) {
2836
3280
  },
2837
3281
 
2838
3282
  escape: {
3283
+ value: function(value) {
3284
+ var
3285
+ multipleValues = $.isArray(value),
3286
+ stringValue = (typeof value === 'string'),
3287
+ isUnparsable = (!stringValue && !multipleValues),
3288
+ hasQuotes = (stringValue && value.search(regExp.quote) !== -1),
3289
+ values = []
3290
+ ;
3291
+ if(!module.has.selectInput() || isUnparsable || !hasQuotes) {
3292
+ return value;
3293
+ }
3294
+ module.debug('Encoding quote values for use in select', value);
3295
+ if(multipleValues) {
3296
+ $.each(value, function(index, value){
3297
+ values.push(value.replace(regExp.quote, '&quot;'));
3298
+ });
3299
+ return values;
3300
+ }
3301
+ return value.replace(regExp.quote, '&quot;');
3302
+ },
2839
3303
  regExp: function(text) {
2840
3304
  text = String(text);
2841
3305
  return text.replace(regExp.escape, '\\$&');
@@ -2848,7 +3312,12 @@ $.fn.dropdown = function(parameters) {
2848
3312
  $.extend(true, settings, name);
2849
3313
  }
2850
3314
  else if(value !== undefined) {
2851
- settings[name] = value;
3315
+ if($.isPlainObject(settings[name])) {
3316
+ $.extend(true, settings[name], value);
3317
+ }
3318
+ else {
3319
+ settings[name] = value;
3320
+ }
2852
3321
  }
2853
3322
  else {
2854
3323
  return settings[name];
@@ -2866,7 +3335,7 @@ $.fn.dropdown = function(parameters) {
2866
3335
  }
2867
3336
  },
2868
3337
  debug: function() {
2869
- if(settings.debug) {
3338
+ if(!settings.silent && settings.debug) {
2870
3339
  if(settings.performance) {
2871
3340
  module.performance.log(arguments);
2872
3341
  }
@@ -2877,7 +3346,7 @@ $.fn.dropdown = function(parameters) {
2877
3346
  }
2878
3347
  },
2879
3348
  verbose: function() {
2880
- if(settings.verbose && settings.debug) {
3349
+ if(!settings.silent && settings.verbose && settings.debug) {
2881
3350
  if(settings.performance) {
2882
3351
  module.performance.log(arguments);
2883
3352
  }
@@ -2888,8 +3357,10 @@ $.fn.dropdown = function(parameters) {
2888
3357
  }
2889
3358
  },
2890
3359
  error: function() {
2891
- module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
2892
- module.error.apply(console, arguments);
3360
+ if(!settings.silent) {
3361
+ module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
3362
+ module.error.apply(console, arguments);
3363
+ }
2893
3364
  },
2894
3365
  performance: {
2895
3366
  log: function(message) {
@@ -3020,6 +3491,7 @@ $.fn.dropdown = function(parameters) {
3020
3491
 
3021
3492
  $.fn.dropdown.settings = {
3022
3493
 
3494
+ silent : false,
3023
3495
  debug : false,
3024
3496
  verbose : false,
3025
3497
  performance : true,
@@ -3029,28 +3501,33 @@ $.fn.dropdown.settings = {
3029
3501
 
3030
3502
 
3031
3503
  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
3504
+ selectOnKeydown : true, // Whether selection should occur automatically when keyboard shortcuts used
3505
+ minCharacters : 0, // Minimum characters required to trigger API call
3506
+ saveRemoteData : true, // Whether remote name/value pairs should be stored in sessionStorage to allow remote data to be restored on page refresh
3507
+ throttle : 200, // How long to wait after last user input to search remotely
3034
3508
 
3035
- context : window, // Context to use when determining if on screen
3509
+ context : window, // Context to use when determining if on screen
3036
3510
  direction : 'auto', // Whether dropdown should always open in one direction
3037
3511
  keepOnScreen : true, // Whether dropdown should check whether it is on screen before showing
3038
3512
 
3039
3513
  match : 'both', // what to match against with search selection (both, text, or label)
3040
- fullTextSearch : false, // search anywhere in value
3514
+ fullTextSearch : false, // search anywhere in value (set to 'exact' to require exact matches)
3041
3515
 
3042
3516
  placeholder : 'auto', // whether to convert blank <select> values to placeholder text
3043
3517
  preserveHTML : true, // preserve html when selecting value
3044
3518
  sortSelect : false, // sort selection on init
3045
3519
 
3046
3520
  forceSelection : true, // force a choice on blur with search selection
3521
+
3047
3522
  allowAdditions : false, // whether multiple select should allow user added values
3523
+ hideAdditions : true, // whether or not to hide special message prompting a user they can enter a value
3048
3524
 
3049
3525
  maxSelections : false, // When set to a number limits the number of selections to this count
3050
3526
  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
3527
+ delimiter : ',', // when multiselect uses normal <input> the values will be delimited with this character
3052
3528
 
3053
3529
  showOnFocus : true, // show menu on focus
3530
+ allowReselection : false, // whether current value should trigger callbacks when reselected
3054
3531
  allowTab : true, // add tabindex to element
3055
3532
  allowCategorySelection : false, // allow elements with sub-menus to be selected
3056
3533
 
@@ -3059,7 +3536,7 @@ $.fn.dropdown.settings = {
3059
3536
  transition : 'auto', // auto transition will slide down or up based on direction
3060
3537
  duration : 200, // duration of transition
3061
3538
 
3062
- glyphWidth : 1.0714, // widest glyph width in em (W is 1.0714 em) used to calculate multiselect input width
3539
+ glyphWidth : 1.037, // widest glyph width in em (W is 1.037 em) used to calculate multiselect input width
3063
3540
 
3064
3541
  // label settings on multi-select
3065
3542
  label: {
@@ -3083,6 +3560,7 @@ $.fn.dropdown.settings = {
3083
3560
 
3084
3561
  onLabelSelect : function($selectedLabels){},
3085
3562
  onLabelCreate : function(value, text) { return $(this); },
3563
+ onLabelRemove : function(value) { return true; },
3086
3564
  onNoResults : function(searchTerm) { return true; },
3087
3565
  onShow : function(){},
3088
3566
  onHide : function(){},
@@ -3100,17 +3578,19 @@ $.fn.dropdown.settings = {
3100
3578
  },
3101
3579
 
3102
3580
  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>'
3581
+ action : 'You called a dropdown action that was not defined',
3582
+ alreadySetup : 'Once a select has been initialized behaviors must be called on the created ui dropdown',
3583
+ labels : 'Allowing user additions currently requires the use of labels.',
3584
+ missingMultiple : '<select> requires multiple property to be set to correctly preserve multiple values',
3585
+ method : 'The method you called is not defined.',
3586
+ noAPI : 'The API module is required to load resources remotely',
3587
+ noStorage : 'Saving remote data requires session storage',
3588
+ noTransition : 'This module requires ui transitions <https://github.com/Semantic-Org/UI-Transition>'
3110
3589
  },
3111
3590
 
3112
3591
  regExp : {
3113
3592
  escape : /[-[\]{}()*+?.,\\^$|#\s]/g,
3593
+ quote : /"/g
3114
3594
  },
3115
3595
 
3116
3596
  metadata : {
@@ -3121,9 +3601,34 @@ $.fn.dropdown.settings = {
3121
3601
  value : 'value'
3122
3602
  },
3123
3603
 
3604
+ // property names for remote query
3605
+ fields: {
3606
+ remoteValues : 'results', // grouping for api results
3607
+ values : 'values', // grouping for all dropdown values
3608
+ disabled : 'disabled', // whether value should be disabled
3609
+ name : 'name', // displayed dropdown text
3610
+ value : 'value', // actual dropdown value
3611
+ text : 'text' // displayed text when selected
3612
+ },
3613
+
3614
+ keys : {
3615
+ backspace : 8,
3616
+ delimiter : 188, // comma
3617
+ deleteKey : 46,
3618
+ enter : 13,
3619
+ escape : 27,
3620
+ pageUp : 33,
3621
+ pageDown : 34,
3622
+ leftArrow : 37,
3623
+ upArrow : 38,
3624
+ rightArrow : 39,
3625
+ downArrow : 40
3626
+ },
3627
+
3124
3628
  selector : {
3125
3629
  addition : '.addition',
3126
3630
  dropdown : '.ui.dropdown',
3631
+ hidden : '.hidden',
3127
3632
  icon : '> .dropdown.icon',
3128
3633
  input : '> input[type="hidden"], > select',
3129
3634
  item : '.item',
@@ -3133,7 +3638,8 @@ $.fn.dropdown.settings = {
3133
3638
  menu : '.menu',
3134
3639
  message : '.message',
3135
3640
  menuIcon : '.dropdown.icon',
3136
- search : 'input.search, .menu > .search > input',
3641
+ search : 'input.search, .menu > .search > input, .menu input.search',
3642
+ sizer : '> input.sizer',
3137
3643
  text : '> .text:not(.icon)',
3138
3644
  unselectable : '.disabled, .filtered'
3139
3645
  },
@@ -3143,6 +3649,7 @@ $.fn.dropdown.settings = {
3143
3649
  addition : 'addition',
3144
3650
  animating : 'animating',
3145
3651
  disabled : 'disabled',
3652
+ empty : 'empty',
3146
3653
  dropdown : 'ui dropdown',
3147
3654
  filtered : 'filtered',
3148
3655
  hidden : 'hidden transition',
@@ -3153,6 +3660,7 @@ $.fn.dropdown.settings = {
3153
3660
  message : 'message',
3154
3661
  multiple : 'multiple',
3155
3662
  placeholder : 'default',
3663
+ sizer : 'sizer',
3156
3664
  search : 'search',
3157
3665
  selected : 'selected',
3158
3666
  selection : 'selection',
@@ -3191,13 +3699,23 @@ $.fn.dropdown.settings.templates = {
3191
3699
  },
3192
3700
 
3193
3701
  // generates just menu from select
3194
- menu: function(response) {
3702
+ menu: function(response, fields) {
3195
3703
  var
3196
- values = response.values || {},
3704
+ values = response[fields.values] || {},
3197
3705
  html = ''
3198
3706
  ;
3199
- $.each(response.values, function(index, option) {
3200
- html += '<div class="item" data-value="' + option.value + '">' + option.name + '</div>';
3707
+ $.each(values, function(index, option) {
3708
+ var
3709
+ maybeText = (option[fields.text])
3710
+ ? 'data-text="' + option[fields.text] + '"'
3711
+ : '',
3712
+ maybeDisabled = (option[fields.disabled])
3713
+ ? 'disabled '
3714
+ : ''
3715
+ ;
3716
+ html += '<div class="'+ maybeDisabled +'item" data-value="' + option[fields.value] + '"' + maybeText + '>'
3717
+ html += option[fields.name];
3718
+ html += '</div>';
3201
3719
  });
3202
3720
  return html;
3203
3721
  },
@@ -3220,4 +3738,4 @@ $.fn.dropdown.settings.templates = {
3220
3738
 
3221
3739
  };
3222
3740
 
3223
- })( jQuery, window , document );
3741
+ })( jQuery, window, document );