kms 0.9.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (409) hide show
  1. checksums.yaml +4 -4
  2. data/{vendor/assets/bower_components/Responsive-Dashboard/src/img → app/assets/images}/avatar.jpg +0 -0
  3. data/app/assets/javascripts/kms/application.js +3 -0
  4. data/app/assets/javascripts/kms/application/controllers/assets_controller.coffee.erb +14 -7
  5. data/app/assets/javascripts/kms/application/controllers/pages_controller.coffee.erb +11 -3
  6. data/app/assets/javascripts/kms/application/controllers/snippets_controller.coffee.erb +3 -0
  7. data/app/assets/javascripts/kms/application/controllers/templates_controller.coffee.erb +3 -0
  8. data/app/assets/javascripts/kms/application/controllers/users_controller.coffee +4 -4
  9. data/app/assets/javascripts/kms/application/routes.coffee.erb +1 -1
  10. data/app/assets/javascripts/kms/application/services/transliteration_service.js +160 -0
  11. data/app/assets/javascripts/templates/assets/edit.html.slim +24 -2
  12. data/app/assets/javascripts/templates/assets/form.html.slim +23 -0
  13. data/app/assets/javascripts/templates/assets/index.html.slim +13 -12
  14. data/app/assets/javascripts/templates/assets/new.html.slim +1 -15
  15. data/app/assets/javascripts/templates/help.html.slim +1 -1
  16. data/app/assets/javascripts/templates/pages/index.html.slim +16 -5
  17. data/app/assets/javascripts/templates/snippets/index.html.slim +16 -5
  18. data/app/assets/javascripts/templates/templates/index.html.slim +16 -6
  19. data/app/assets/stylesheets/kms/application.css +2 -2
  20. data/app/assets/stylesheets/kms/custom.css.scss +38 -0
  21. data/app/controllers/kms/assets_controller.rb +8 -9
  22. data/app/controllers/kms/pages_controller.rb +10 -11
  23. data/app/controllers/kms/public/pages_controller.rb +5 -4
  24. data/app/controllers/kms/public/search_controller.rb +2 -0
  25. data/app/controllers/kms/settings_controller.rb +1 -1
  26. data/app/controllers/kms/snippets_controller.rb +2 -1
  27. data/app/controllers/kms/templates_controller.rb +6 -5
  28. data/app/controllers/kms/users_controller.rb +11 -8
  29. data/app/models/ability.rb +1 -0
  30. data/app/models/concerns/kms/permalinkable.rb +1 -1
  31. data/app/models/kms/page.rb +13 -4
  32. data/app/serializers/kms/asset_serializer.rb +6 -0
  33. data/app/serializers/kms/page_serializer.rb +5 -0
  34. data/app/serializers/kms/template_serializer.rb +5 -0
  35. data/app/serializers/kms/user_serializer.rb +5 -0
  36. data/app/services/kms/page_fetcher.rb +30 -0
  37. data/app/services/kms/search_service.rb +28 -3
  38. data/app/services/kms/template_processor.rb +19 -0
  39. data/app/views/devise/passwords/edit.html.erb +1 -1
  40. data/app/views/devise/passwords/new.html.erb +1 -1
  41. data/app/views/devise/registrations/new.html.erb +1 -1
  42. data/app/views/devise/sessions/new.html.erb +1 -1
  43. data/app/views/layouts/kms/devise.html.erb +1 -1
  44. data/app/views/layouts/kms/kms.html.erb +47 -18
  45. data/config/initializers/externals.rb +6 -32
  46. data/config/initializers/search.rb +1 -0
  47. data/config/locales/en.yml +17 -1
  48. data/config/locales/ru.yml +17 -1
  49. data/config/routes.rb +7 -6
  50. data/lib/kms/dependencies.rb +1 -4
  51. data/lib/kms/engine.rb +1 -2
  52. data/lib/kms/search_item.rb +18 -0
  53. data/lib/kms/version.rb +1 -1
  54. data/spec/controllers/kms/assets_controller_spec.rb +51 -0
  55. data/spec/controllers/kms/pages_controller_spec.rb +82 -0
  56. data/spec/controllers/kms/public/pages_controller_spec.rb +30 -0
  57. data/spec/controllers/kms/snippets_controller_spec.rb +61 -47
  58. data/spec/controllers/kms/templates_controller_spec.rb +51 -0
  59. data/spec/controllers/kms/users_controller_spec.rb +56 -0
  60. data/spec/factories/assets.rb +8 -0
  61. data/spec/factories/pages.rb +33 -0
  62. data/spec/factories/templates.rb +20 -0
  63. data/spec/factories/users.rb +9 -4
  64. data/spec/internal/config/routes.rb +12 -1
  65. data/spec/internal/log/test.log +81239 -0
  66. data/spec/internal/public/404.html +67 -0
  67. data/spec/internal/public/avatar.jpg +0 -0
  68. data/spec/internal/public/style.css +1 -0
  69. data/spec/internal/public/uploads/kms/asset/file/1/avatar.jpg +0 -0
  70. data/spec/internal/public/uploads/kms/asset/file/2/avatar.jpg +0 -0
  71. data/spec/internal/public/uploads/kms/asset/file/2/style.css +1 -0
  72. data/spec/internal/public/uploads/kms/asset/file/3/style.css +1 -0
  73. data/spec/internal/public/uploads/kms/asset/file/4/style.css +1 -0
  74. data/spec/internal/public/uploads/tmp/1500976987-41025-0002-0883/style.css +1 -0
  75. data/spec/internal/public/uploads/tmp/1500977082-41195-0002-6495/style.css +1 -0
  76. data/spec/internal/public/uploads/tmp/1500977109-41364-0002-4518/style.css +1 -0
  77. data/spec/internal/public/uploads/tmp/1500977152-41405-0002-2345/style.css +1 -0
  78. data/spec/internal/public/uploads/tmp/1500977327-41694-0002-5448/style.css +1 -0
  79. data/spec/internal/public/uploads/tmp/1500977376-41732-0002-7916/style.css +1 -0
  80. data/spec/internal/public/uploads/tmp/1500977392-41759-0002-7593/style.css +1 -0
  81. data/spec/internal/public/uploads/tmp/1500977410-42259-0002-7527/style.css +1 -0
  82. data/spec/internal/public/uploads/tmp/1500977429-42306-0002-5937/style.css +1 -0
  83. data/spec/internal/public/uploads/tmp/1500977437-42324-0002-5880/style.css +1 -0
  84. data/spec/internal/public/uploads/tmp/1500983228-53594-0002-4559/style.css +1 -0
  85. data/spec/internal/public/uploads/tmp/1500983284-53632-0002-6590/style.css +1 -0
  86. data/spec/internal/public/uploads/tmp/1500983360-53784-0002-7289/style.css +1 -0
  87. data/spec/internal/public/uploads/tmp/1500983469-54321-0002-0386/avatar.jpg +0 -0
  88. data/spec/internal/public/uploads/tmp/1500983469-54321-0004-5691/style.css +1 -0
  89. data/spec/internal/public/uploads/tmp/1500983511-54352-0002-5720/avatar.jpg +0 -0
  90. data/spec/internal/public/uploads/tmp/1500983511-54352-0004-1399/style.css +1 -0
  91. data/spec/internal/public/uploads/tmp/1500983610-54507-0002-4280/avatar.jpg +0 -0
  92. data/spec/internal/public/uploads/tmp/1500983610-54507-0004-9758/style.css +1 -0
  93. data/spec/internal/public/uploads/tmp/1500984466-57012-0002-4146/avatar.jpg +0 -0
  94. data/spec/internal/public/uploads/tmp/1500984466-57012-0004-5895/style.css +1 -0
  95. data/spec/internal/public/uploads/tmp/1500984509-57158-0002-9657/avatar.jpg +0 -0
  96. data/spec/internal/public/uploads/tmp/1500984509-57158-0004-5003/style.css +1 -0
  97. data/spec/internal/public/uploads/tmp/1500984616-57697-0002-7201/avatar.jpg +0 -0
  98. data/spec/internal/public/uploads/tmp/1500984616-57697-0004-6255/style.css +1 -0
  99. data/spec/internal/public/uploads/tmp/1500985257-58947-0002-3629/avatar.jpg +0 -0
  100. data/spec/internal/public/uploads/tmp/1500985257-58947-0004-5338/style.css +1 -0
  101. data/spec/internal/public/uploads/tmp/1500985407-58947-0006-5929/style.css +1 -0
  102. data/spec/internal/public/uploads/tmp/1500985473-59264-0002-0397/avatar.jpg +0 -0
  103. data/spec/internal/public/uploads/tmp/1500985473-59264-0004-6493/style.css +1 -0
  104. data/spec/internal/public/uploads/tmp/1500985475-59264-0007-8674/style.css +1 -0
  105. data/spec/internal/public/uploads/tmp/1500985538-59468-0002-9206/avatar.jpg +0 -0
  106. data/spec/internal/public/uploads/tmp/1500985538-59468-0004-2586/style.css +1 -0
  107. data/spec/internal/public/uploads/tmp/1500985538-59468-0007-6200/style.css +1 -0
  108. data/spec/internal/public/uploads/tmp/1500988358-65877-0002-4528/avatar.jpg +0 -0
  109. data/spec/internal/public/uploads/tmp/1500988358-65877-0004-5904/style.css +1 -0
  110. data/spec/internal/public/uploads/tmp/1500988358-65877-0007-7320/style.css +1 -0
  111. data/spec/internal/public/uploads/tmp/1500988407-65916-0002-3138/avatar.jpg +0 -0
  112. data/spec/internal/public/uploads/tmp/1500988407-65916-0004-5400/style.css +1 -0
  113. data/spec/internal/public/uploads/tmp/1500988407-65916-0007-1655/style.css +1 -0
  114. data/spec/internal/public/uploads/tmp/1500988421-65950-0002-9415/avatar.jpg +0 -0
  115. data/spec/internal/public/uploads/tmp/1500988421-65950-0004-7130/style.css +1 -0
  116. data/spec/internal/public/uploads/tmp/1500988421-65950-0007-9886/style.css +1 -0
  117. data/spec/internal/public/uploads/tmp/1500988435-65981-0002-3228/avatar.jpg +0 -0
  118. data/spec/internal/public/uploads/tmp/1500988435-65981-0004-3682/style.css +1 -0
  119. data/spec/internal/public/uploads/tmp/1500988435-65981-0007-1582/style.css +1 -0
  120. data/spec/internal/public/uploads/tmp/1500988475-66122-0002-9516/avatar.jpg +0 -0
  121. data/spec/internal/public/uploads/tmp/1500988475-66122-0004-5634/style.css +1 -0
  122. data/spec/internal/public/uploads/tmp/1500988530-66122-0007-2272/style.css +1 -0
  123. data/spec/internal/public/uploads/tmp/1500988554-66315-0002-6262/avatar.jpg +0 -0
  124. data/spec/internal/public/uploads/tmp/1500988554-66315-0004-6099/style.css +1 -0
  125. data/spec/internal/public/uploads/tmp/1500988554-66315-0007-1632/style.css +1 -0
  126. data/spec/internal/public/uploads/tmp/1500991751-73722-0002-9937/avatar.jpg +0 -0
  127. data/spec/internal/public/uploads/tmp/1500991751-73722-0004-8034/style.css +1 -0
  128. data/spec/internal/public/uploads/tmp/1500991751-73722-0007-7763/style.css +1 -0
  129. data/spec/internal/public/uploads/tmp/1501233238-34385-0002-3210/avatar.jpg +0 -0
  130. data/spec/internal/public/uploads/tmp/1501233238-34385-0004-5881/style.css +1 -0
  131. data/spec/internal/public/uploads/tmp/1501233238-34385-0007-6280/style.css +1 -0
  132. data/spec/models/kms/page_spec.rb +31 -0
  133. data/spec/models/kms/template_spec.rb +15 -0
  134. data/spec/services/kms/page_fetcher_spec.rb +36 -0
  135. data/spec/services/kms/search_service_spec.rb +53 -0
  136. data/spec/services/kms/template_processor_spec.rb +20 -0
  137. data/spec/support/controller_macros.rb +9 -1
  138. data/vendor/assets/bower.json +3 -2
  139. data/vendor/assets/bower_components/angular-ui-select/CHANGELOG.md +169 -0
  140. data/vendor/assets/bower_components/angular-ui-select/CONTRIBUTING.md +161 -0
  141. data/vendor/assets/bower_components/angular-ui-select/README.md +27 -13
  142. data/vendor/assets/bower_components/angular-ui-select/bower.json +6 -3
  143. data/vendor/assets/bower_components/angular-ui-select/composer.json +29 -0
  144. data/vendor/assets/bower_components/angular-ui-select/deploy-docs.sh +31 -0
  145. data/vendor/assets/bower_components/angular-ui-select/dist/select.css +48 -2
  146. data/vendor/assets/bower_components/angular-ui-select/dist/select.js +454 -111
  147. data/vendor/assets/bower_components/angular-ui-select/dist/select.min.css +2 -2
  148. data/vendor/assets/bower_components/angular-ui-select/dist/select.min.js +2 -2
  149. data/vendor/assets/bower_components/angular-ui-select/docs/assets/app.js +1 -0
  150. data/vendor/assets/bower_components/angular-ui-select/docs/assets/demo.js +461 -0
  151. data/vendor/assets/bower_components/angular-ui-select/docs/assets/docs.css +339 -0
  152. data/vendor/assets/bower_components/angular-ui-select/docs/assets/plunkr.js +110 -0
  153. data/vendor/assets/bower_components/angular-ui-select/docs/index.html +191 -0
  154. data/vendor/assets/bower_components/angular-ui-select/docs/partials/_footer.html +2 -0
  155. data/vendor/assets/bower_components/angular-ui-select/docs/partials/_header.html +64 -0
  156. data/vendor/assets/bower_components/angular-ui-select/index.js +2 -0
  157. data/vendor/assets/bower_components/angular-ui-select/package.json +36 -15
  158. data/vendor/assets/bower_components/bootstrap/CHANGELOG.md +5 -0
  159. data/vendor/assets/bower_components/bootstrap/Gemfile +6 -0
  160. data/vendor/assets/bower_components/bootstrap/Gemfile.lock +43 -0
  161. data/vendor/assets/bower_components/bootstrap/Gruntfile.js +176 -145
  162. data/vendor/assets/bower_components/bootstrap/ISSUE_TEMPLATE.md +22 -0
  163. data/vendor/assets/bower_components/bootstrap/LICENSE +1 -1
  164. data/vendor/assets/bower_components/bootstrap/README.md +55 -40
  165. data/vendor/assets/bower_components/bootstrap/bower.json +5 -9
  166. data/vendor/assets/bower_components/bootstrap/dist/css/bootstrap-theme.css +204 -59
  167. data/vendor/assets/bower_components/bootstrap/dist/css/bootstrap-theme.css.map +1 -1
  168. data/vendor/assets/bower_components/bootstrap/dist/css/bootstrap-theme.min.css +4 -3
  169. data/vendor/assets/bower_components/bootstrap/dist/css/bootstrap-theme.min.css.map +1 -0
  170. data/vendor/assets/bower_components/bootstrap/dist/css/{bootstrap.less → bootstrap.css} +881 -327
  171. data/vendor/assets/bower_components/bootstrap/dist/css/bootstrap.css.map +1 -1
  172. data/vendor/assets/bower_components/bootstrap/dist/css/bootstrap.min.css +6 -0
  173. data/vendor/assets/bower_components/bootstrap/dist/css/bootstrap.min.css.map +1 -0
  174. data/vendor/assets/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.eot +0 -0
  175. data/vendor/assets/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.svg +272 -213
  176. data/vendor/assets/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf +0 -0
  177. data/vendor/assets/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.woff +0 -0
  178. data/vendor/assets/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2 +0 -0
  179. data/vendor/assets/bower_components/bootstrap/dist/js/bootstrap.js +549 -286
  180. data/vendor/assets/bower_components/bootstrap/dist/js/bootstrap.min.js +5 -4
  181. data/vendor/assets/bower_components/bootstrap/dist/js/npm.js +13 -0
  182. data/vendor/assets/bower_components/bootstrap/fonts/glyphicons-halflings-regular.eot +0 -0
  183. data/vendor/assets/bower_components/bootstrap/fonts/glyphicons-halflings-regular.svg +272 -213
  184. data/vendor/assets/bower_components/bootstrap/fonts/glyphicons-halflings-regular.ttf +0 -0
  185. data/vendor/assets/bower_components/bootstrap/fonts/glyphicons-halflings-regular.woff +0 -0
  186. data/vendor/assets/bower_components/bootstrap/fonts/glyphicons-halflings-regular.woff2 +0 -0
  187. data/vendor/assets/bower_components/bootstrap/grunt/bs-commonjs-generator.js +30 -0
  188. data/vendor/assets/bower_components/bootstrap/grunt/bs-glyphicons-data-generator.js +5 -4
  189. data/vendor/assets/bower_components/bootstrap/grunt/bs-lessdoc-parser.js +13 -12
  190. data/vendor/assets/bower_components/bootstrap/grunt/bs-raw-files-generator.js +6 -8
  191. data/vendor/assets/bower_components/bootstrap/grunt/change-version.js +109 -0
  192. data/vendor/assets/bower_components/bootstrap/grunt/configBridge.json +46 -0
  193. data/vendor/assets/bower_components/bootstrap/grunt/npm-shrinkwrap.json +2679 -0
  194. data/vendor/assets/bower_components/bootstrap/grunt/sauce_browsers.yml +5 -5
  195. data/vendor/assets/bower_components/bootstrap/js/affix.js +46 -26
  196. data/vendor/assets/bower_components/bootstrap/js/alert.js +8 -6
  197. data/vendor/assets/bower_components/bootstrap/js/button.js +34 -19
  198. data/vendor/assets/bower_components/bootstrap/js/carousel.js +35 -21
  199. data/vendor/assets/bower_components/bootstrap/js/collapse.js +69 -27
  200. data/vendor/assets/bower_components/bootstrap/js/dropdown.js +55 -41
  201. data/vendor/assets/bower_components/bootstrap/js/modal.js +91 -32
  202. data/vendor/assets/bower_components/bootstrap/js/popover.js +5 -10
  203. data/vendor/assets/bower_components/bootstrap/js/scrollspy.js +28 -26
  204. data/vendor/assets/bower_components/bootstrap/js/tab.js +45 -18
  205. data/vendor/assets/bower_components/bootstrap/js/tooltip.js +117 -54
  206. data/vendor/assets/bower_components/bootstrap/js/transition.js +2 -2
  207. data/vendor/assets/bower_components/bootstrap/less/alerts.less +5 -0
  208. data/vendor/assets/bower_components/bootstrap/less/badges.less +14 -3
  209. data/vendor/assets/bower_components/bootstrap/less/bootstrap.less +6 -0
  210. data/vendor/assets/bower_components/bootstrap/less/button-groups.less +22 -18
  211. data/vendor/assets/bower_components/bootstrap/less/buttons.less +19 -10
  212. data/vendor/assets/bower_components/bootstrap/less/carousel.less +34 -7
  213. data/vendor/assets/bower_components/bootstrap/less/close.less +1 -0
  214. data/vendor/assets/bower_components/bootstrap/less/code.less +1 -0
  215. data/vendor/assets/bower_components/bootstrap/less/component-animations.less +3 -1
  216. data/vendor/assets/bower_components/bootstrap/less/dropdowns.less +9 -8
  217. data/vendor/assets/bower_components/bootstrap/less/forms.less +123 -50
  218. data/vendor/assets/bower_components/bootstrap/less/glyphicons.less +75 -3
  219. data/vendor/assets/bower_components/bootstrap/less/input-groups.less +8 -3
  220. data/vendor/assets/bower_components/bootstrap/less/jumbotron.less +10 -4
  221. data/vendor/assets/bower_components/bootstrap/less/list-group.less +10 -11
  222. data/vendor/assets/bower_components/bootstrap/less/media.less +40 -30
  223. data/vendor/assets/bower_components/bootstrap/less/mixins.less +1 -0
  224. data/vendor/assets/bower_components/bootstrap/less/mixins/background-variant.less +2 -1
  225. data/vendor/assets/bower_components/bootstrap/less/mixins/buttons.less +19 -4
  226. data/vendor/assets/bower_components/bootstrap/less/mixins/forms.less +5 -1
  227. data/vendor/assets/bower_components/bootstrap/less/mixins/grid-framework.less +4 -4
  228. data/vendor/assets/bower_components/bootstrap/less/mixins/grid.less +4 -4
  229. data/vendor/assets/bower_components/bootstrap/less/mixins/hide-text.less +2 -2
  230. data/vendor/assets/bower_components/bootstrap/less/mixins/image.less +0 -1
  231. data/vendor/assets/bower_components/bootstrap/less/mixins/labels.less +1 -1
  232. data/vendor/assets/bower_components/bootstrap/less/mixins/list-group.less +2 -1
  233. data/vendor/assets/bower_components/bootstrap/less/mixins/pagination.less +2 -1
  234. data/vendor/assets/bower_components/bootstrap/less/mixins/reset-text.less +18 -0
  235. data/vendor/assets/bower_components/bootstrap/less/mixins/responsive-visibility.less +1 -1
  236. data/vendor/assets/bower_components/bootstrap/less/mixins/tab-focus.less +3 -3
  237. data/vendor/assets/bower_components/bootstrap/less/mixins/text-emphasis.less +2 -1
  238. data/vendor/assets/bower_components/bootstrap/less/mixins/vendor-prefixes.less +8 -5
  239. data/vendor/assets/bower_components/bootstrap/less/modals.less +3 -3
  240. data/vendor/assets/bower_components/bootstrap/less/navbar.less +30 -25
  241. data/vendor/assets/bower_components/bootstrap/less/navs.less +1 -1
  242. data/vendor/assets/bower_components/bootstrap/less/normalize.less +12 -13
  243. data/vendor/assets/bower_components/bootstrap/less/pager.less +1 -2
  244. data/vendor/assets/bower_components/bootstrap/less/pagination.less +5 -4
  245. data/vendor/assets/bower_components/bootstrap/less/panels.less +33 -5
  246. data/vendor/assets/bower_components/bootstrap/less/popovers.less +5 -7
  247. data/vendor/assets/bower_components/bootstrap/less/print.less +96 -96
  248. data/vendor/assets/bower_components/bootstrap/less/progress-bars.less +1 -19
  249. data/vendor/assets/bower_components/bootstrap/less/responsive-embed.less +10 -9
  250. data/vendor/assets/bower_components/bootstrap/less/scaffolding.less +13 -2
  251. data/vendor/assets/bower_components/bootstrap/less/tables.less +14 -13
  252. data/vendor/assets/bower_components/bootstrap/less/theme.less +49 -16
  253. data/vendor/assets/bower_components/bootstrap/less/thumbnails.less +1 -1
  254. data/vendor/assets/bower_components/bootstrap/less/tooltip.less +13 -7
  255. data/vendor/assets/bower_components/bootstrap/less/type.less +2 -13
  256. data/vendor/assets/bower_components/bootstrap/less/utilities.less +0 -2
  257. data/vendor/assets/bower_components/bootstrap/less/variables.less +45 -22
  258. data/vendor/assets/bower_components/bootstrap/nuget/MyGet.ps1 +8 -0
  259. data/vendor/assets/bower_components/bootstrap/nuget/bootstrap.less.nuspec +28 -0
  260. data/vendor/assets/bower_components/bootstrap/nuget/bootstrap.nuspec +28 -0
  261. data/vendor/assets/bower_components/bootstrap/package.js +32 -0
  262. data/vendor/assets/bower_components/bootstrap/package.json +49 -41
  263. data/vendor/assets/bower_components/flow.js/README.md +79 -64
  264. data/vendor/assets/bower_components/flow.js/bower.json +6 -2
  265. data/vendor/assets/bower_components/flow.js/dist/flow.js +1635 -1532
  266. data/vendor/assets/bower_components/flow.js/dist/flow.min.js +2 -2
  267. data/vendor/assets/bower_components/flow.js/package.js +24 -0
  268. data/vendor/assets/bower_components/flow.js/travis.sh +19 -0
  269. data/vendor/assets/bower_components/font-awesome/scss/_path.scss +5 -5
  270. data/vendor/assets/bower_components/font-awesome/scss/_variables.scss +1 -2
  271. data/vendor/assets/bower_components/ng-flow/bower.json +1 -1
  272. data/vendor/assets/bower_components/ng-flow/dist/ng-flow-standalone.js +1655 -1542
  273. data/vendor/assets/bower_components/ng-flow/dist/ng-flow-standalone.min.js +2 -2
  274. data/vendor/assets/bower_components/ng-flow/dist/ng-flow.js +19 -9
  275. data/vendor/assets/bower_components/ng-flow/dist/ng-flow.min.js +2 -2
  276. data/vendor/assets/bower_components/ng-flow/index.js +3 -0
  277. data/vendor/assets/bower_components/ng-flow/package.js +25 -0
  278. data/vendor/assets/bower_components/ng-flow/src/directives/drag-events.js +2 -1
  279. data/vendor/assets/bower_components/ng-flow/src/directives/events.js +2 -1
  280. data/vendor/assets/bower_components/ng-flow/src/directives/init.js +7 -1
  281. data/vendor/assets/bower_components/ng-flow/travis.sh +19 -0
  282. data/vendor/assets/bower_components/{Responsive-Dashboard → rdash-ui}/LICENSE +21 -21
  283. data/vendor/assets/bower_components/rdash-ui/README.md +55 -0
  284. data/vendor/assets/bower_components/rdash-ui/bower.json +33 -0
  285. data/vendor/assets/bower_components/rdash-ui/dist/css/rdash.min.css +1 -0
  286. data/vendor/assets/bower_components/rdash-ui/dist/css/rdash.scss +489 -0
  287. data/vendor/assets/bower_components/{Responsive-Dashboard/src → rdash-ui/dist}/fonts/montserrat-regular-webfont.eot +0 -0
  288. data/vendor/assets/bower_components/{Responsive-Dashboard/src → rdash-ui/dist}/fonts/montserrat-regular-webfont.svg +1316 -1316
  289. data/vendor/assets/bower_components/{Responsive-Dashboard/src → rdash-ui/dist}/fonts/montserrat-regular-webfont.ttf +0 -0
  290. data/vendor/assets/bower_components/{Responsive-Dashboard/src → rdash-ui/dist}/fonts/montserrat-regular-webfont.woff +0 -0
  291. metadata +227 -180
  292. data/config/initializers/bower_rails.rb +0 -16
  293. data/vendor/assets/bower_components/Responsive-Dashboard/CONTRIBUTING.md +0 -21
  294. data/vendor/assets/bower_components/Responsive-Dashboard/README.md +0 -119
  295. data/vendor/assets/bower_components/Responsive-Dashboard/bower.json +0 -32
  296. data/vendor/assets/bower_components/Responsive-Dashboard/gulpfile.js +0 -81
  297. data/vendor/assets/bower_components/Responsive-Dashboard/package.json +0 -21
  298. data/vendor/assets/bower_components/Responsive-Dashboard/src/index.html +0 -413
  299. data/vendor/assets/bower_components/Responsive-Dashboard/src/js/dashboard/controllers/alerts-ctrl.js +0 -19
  300. data/vendor/assets/bower_components/Responsive-Dashboard/src/js/dashboard/controllers/master-ctrl.js +0 -51
  301. data/vendor/assets/bower_components/Responsive-Dashboard/src/js/dashboard/directives/loading.js +0 -13
  302. data/vendor/assets/bower_components/Responsive-Dashboard/src/js/dashboard/directives/widget-body.js +0 -16
  303. data/vendor/assets/bower_components/Responsive-Dashboard/src/js/dashboard/directives/widget-header.js +0 -17
  304. data/vendor/assets/bower_components/Responsive-Dashboard/src/js/dashboard/directives/widget.js +0 -16
  305. data/vendor/assets/bower_components/Responsive-Dashboard/src/js/dashboard/module.js +0 -1
  306. data/vendor/assets/bower_components/Responsive-Dashboard/src/js/dashboard/routes.js +0 -22
  307. data/vendor/assets/bower_components/Responsive-Dashboard/src/less/dashboard/content.less +0 -19
  308. data/vendor/assets/bower_components/Responsive-Dashboard/src/less/dashboard/hamburg.less +0 -29
  309. data/vendor/assets/bower_components/Responsive-Dashboard/src/less/dashboard/header.less +0 -92
  310. data/vendor/assets/bower_components/Responsive-Dashboard/src/less/dashboard/loading.less +0 -40
  311. data/vendor/assets/bower_components/Responsive-Dashboard/src/less/dashboard/main.less +0 -73
  312. data/vendor/assets/bower_components/Responsive-Dashboard/src/less/dashboard/mixins.less +0 -5
  313. data/vendor/assets/bower_components/Responsive-Dashboard/src/less/dashboard/sidebar.less +0 -122
  314. data/vendor/assets/bower_components/Responsive-Dashboard/src/less/dashboard/variables.less +0 -10
  315. data/vendor/assets/bower_components/Responsive-Dashboard/src/less/dashboard/widgets.less +0 -95
  316. data/vendor/assets/bower_components/bootstrap/dist/css/bootstrap.min.css.erb +0 -5
  317. data/vendor/assets/bower_components/flow.js/CHANGELOG.md +0 -37
  318. data/vendor/assets/bower_components/flow.js/Gruntfile.js +0 -132
  319. data/vendor/assets/bower_components/flow.js/karma.conf.js +0 -114
  320. data/vendor/assets/bower_components/flow.js/package.json +0 -50
  321. data/vendor/assets/bower_components/flow.js/src/flow.js +0 -1532
  322. data/vendor/assets/bower_components/jquery/MIT-LICENSE.txt +0 -21
  323. data/vendor/assets/bower_components/jquery/bower.json +0 -27
  324. data/vendor/assets/bower_components/jquery/dist/jquery.js +0 -9190
  325. data/vendor/assets/bower_components/jquery/dist/jquery.min.js +0 -5
  326. data/vendor/assets/bower_components/jquery/dist/jquery.min.map +0 -1
  327. data/vendor/assets/bower_components/jquery/src/ajax.js +0 -806
  328. data/vendor/assets/bower_components/jquery/src/ajax/jsonp.js +0 -89
  329. data/vendor/assets/bower_components/jquery/src/ajax/load.js +0 -75
  330. data/vendor/assets/bower_components/jquery/src/ajax/parseJSON.js +0 -13
  331. data/vendor/assets/bower_components/jquery/src/ajax/parseXML.js +0 -28
  332. data/vendor/assets/bower_components/jquery/src/ajax/script.js +0 -64
  333. data/vendor/assets/bower_components/jquery/src/ajax/var/nonce.js +0 -5
  334. data/vendor/assets/bower_components/jquery/src/ajax/var/rquery.js +0 -3
  335. data/vendor/assets/bower_components/jquery/src/ajax/xhr.js +0 -135
  336. data/vendor/assets/bower_components/jquery/src/attributes.js +0 -11
  337. data/vendor/assets/bower_components/jquery/src/attributes/attr.js +0 -143
  338. data/vendor/assets/bower_components/jquery/src/attributes/classes.js +0 -158
  339. data/vendor/assets/bower_components/jquery/src/attributes/prop.js +0 -96
  340. data/vendor/assets/bower_components/jquery/src/attributes/support.js +0 -35
  341. data/vendor/assets/bower_components/jquery/src/attributes/val.js +0 -163
  342. data/vendor/assets/bower_components/jquery/src/callbacks.js +0 -205
  343. data/vendor/assets/bower_components/jquery/src/core.js +0 -498
  344. data/vendor/assets/bower_components/jquery/src/core/access.js +0 -60
  345. data/vendor/assets/bower_components/jquery/src/core/init.js +0 -123
  346. data/vendor/assets/bower_components/jquery/src/core/parseHTML.js +0 -39
  347. data/vendor/assets/bower_components/jquery/src/core/ready.js +0 -97
  348. data/vendor/assets/bower_components/jquery/src/core/var/rsingleTag.js +0 -4
  349. data/vendor/assets/bower_components/jquery/src/css.js +0 -451
  350. data/vendor/assets/bower_components/jquery/src/css/addGetHookIf.js +0 -24
  351. data/vendor/assets/bower_components/jquery/src/css/curCSS.js +0 -57
  352. data/vendor/assets/bower_components/jquery/src/css/defaultDisplay.js +0 -70
  353. data/vendor/assets/bower_components/jquery/src/css/hiddenVisibleSelectors.js +0 -15
  354. data/vendor/assets/bower_components/jquery/src/css/support.js +0 -91
  355. data/vendor/assets/bower_components/jquery/src/css/swap.js +0 -28
  356. data/vendor/assets/bower_components/jquery/src/css/var/cssExpand.js +0 -3
  357. data/vendor/assets/bower_components/jquery/src/css/var/getStyles.js +0 -5
  358. data/vendor/assets/bower_components/jquery/src/css/var/isHidden.js +0 -13
  359. data/vendor/assets/bower_components/jquery/src/css/var/rmargin.js +0 -3
  360. data/vendor/assets/bower_components/jquery/src/css/var/rnumnonpx.js +0 -5
  361. data/vendor/assets/bower_components/jquery/src/data.js +0 -179
  362. data/vendor/assets/bower_components/jquery/src/data/Data.js +0 -181
  363. data/vendor/assets/bower_components/jquery/src/data/accepts.js +0 -20
  364. data/vendor/assets/bower_components/jquery/src/data/var/data_priv.js +0 -5
  365. data/vendor/assets/bower_components/jquery/src/data/var/data_user.js +0 -5
  366. data/vendor/assets/bower_components/jquery/src/deferred.js +0 -149
  367. data/vendor/assets/bower_components/jquery/src/deprecated.js +0 -13
  368. data/vendor/assets/bower_components/jquery/src/dimensions.js +0 -50
  369. data/vendor/assets/bower_components/jquery/src/effects.js +0 -649
  370. data/vendor/assets/bower_components/jquery/src/effects/Tween.js +0 -114
  371. data/vendor/assets/bower_components/jquery/src/effects/animatedSelector.js +0 -13
  372. data/vendor/assets/bower_components/jquery/src/event.js +0 -868
  373. data/vendor/assets/bower_components/jquery/src/event/alias.js +0 -39
  374. data/vendor/assets/bower_components/jquery/src/event/support.js +0 -9
  375. data/vendor/assets/bower_components/jquery/src/exports/amd.js +0 -24
  376. data/vendor/assets/bower_components/jquery/src/exports/global.js +0 -32
  377. data/vendor/assets/bower_components/jquery/src/intro.js +0 -44
  378. data/vendor/assets/bower_components/jquery/src/jquery.js +0 -36
  379. data/vendor/assets/bower_components/jquery/src/manipulation.js +0 -582
  380. data/vendor/assets/bower_components/jquery/src/manipulation/_evalUrl.js +0 -18
  381. data/vendor/assets/bower_components/jquery/src/manipulation/support.js +0 -31
  382. data/vendor/assets/bower_components/jquery/src/manipulation/var/rcheckableType.js +0 -3
  383. data/vendor/assets/bower_components/jquery/src/offset.js +0 -204
  384. data/vendor/assets/bower_components/jquery/src/outro.js +0 -1
  385. data/vendor/assets/bower_components/jquery/src/queue.js +0 -142
  386. data/vendor/assets/bower_components/jquery/src/queue/delay.js +0 -22
  387. data/vendor/assets/bower_components/jquery/src/selector-native.js +0 -172
  388. data/vendor/assets/bower_components/jquery/src/selector-sizzle.js +0 -14
  389. data/vendor/assets/bower_components/jquery/src/selector.js +0 -1
  390. data/vendor/assets/bower_components/jquery/src/serialize.js +0 -111
  391. data/vendor/assets/bower_components/jquery/src/sizzle/dist/sizzle.js +0 -2044
  392. data/vendor/assets/bower_components/jquery/src/sizzle/dist/sizzle.min.js +0 -3
  393. data/vendor/assets/bower_components/jquery/src/sizzle/dist/sizzle.min.map +0 -1
  394. data/vendor/assets/bower_components/jquery/src/traversing.js +0 -200
  395. data/vendor/assets/bower_components/jquery/src/traversing/findFilter.js +0 -100
  396. data/vendor/assets/bower_components/jquery/src/traversing/var/rneedsContext.js +0 -6
  397. data/vendor/assets/bower_components/jquery/src/var/arr.js +0 -3
  398. data/vendor/assets/bower_components/jquery/src/var/class2type.js +0 -4
  399. data/vendor/assets/bower_components/jquery/src/var/concat.js +0 -5
  400. data/vendor/assets/bower_components/jquery/src/var/hasOwn.js +0 -5
  401. data/vendor/assets/bower_components/jquery/src/var/indexOf.js +0 -5
  402. data/vendor/assets/bower_components/jquery/src/var/pnum.js +0 -3
  403. data/vendor/assets/bower_components/jquery/src/var/push.js +0 -5
  404. data/vendor/assets/bower_components/jquery/src/var/rnotwhite.js +0 -3
  405. data/vendor/assets/bower_components/jquery/src/var/slice.js +0 -5
  406. data/vendor/assets/bower_components/jquery/src/var/strundefined.js +0 -3
  407. data/vendor/assets/bower_components/jquery/src/var/support.js +0 -4
  408. data/vendor/assets/bower_components/jquery/src/var/toString.js +0 -5
  409. data/vendor/assets/bower_components/jquery/src/wrap.js +0 -78
@@ -0,0 +1,161 @@
1
+ We are excited to have you working on the project and cordially request that you follow the Guidelines:
2
+
3
+ - [Got a question or problem?](#question)
4
+ - [You think you've found a bug?](#bug)
5
+ - [Code Style Guidelines](#rules)
6
+ - [Commit Message Guidelines](#commit)
7
+
8
+ ## <a name="question"></a> Got a question or problem?
9
+
10
+ Firstly, please go over our FAQ: https://github.com/angular-ui/ui-select/wiki/FAQs
11
+
12
+ Please, do not open issues for the general support questions as we want to keep GitHub issues for bug reports and feature requests. You've got much better chances of getting your question answered on [StackOverflow](http://stackoverflow.com/questions/tagged/angular-ui-select) where maintainers are looking at questions tagged with `angular-ui-select`.
13
+
14
+ StackOverflow is a much better place to ask questions since:
15
+ * there are hundreds of people willing to help on StackOverflow
16
+ * questions and answers stay available for public viewing so your question / answer might help someone else
17
+ * SO voting system assures that the best answers are prominently visible.
18
+
19
+ To save your and our time we will be systematically closing all the issues that are requests for general support and redirecting people to StackOverflow.
20
+
21
+ ## <a name="bug"></a> You think you've found a bug?
22
+
23
+ Oh, we are ashamed and want to fix it asap! But before fixing a bug we need to reproduce and confirm it. In order to reproduce bugs we will systematically ask you to provide a _minimal_ reproduce scenario using http://plnkr.co/. Having a live reproduce scenario gives us wealth of important information without going back & forth to you with additional questions like:
24
+ * version of AngularJS used
25
+ * version of this library that you are using
26
+ * 3rd-party libraries used, if any
27
+ * and most importantly - a use-case that fails
28
+
29
+ A minimal reproduce scenario using http://plnkr.co/ allows us to quickly confirm a bug (or point out coding problem) as well as confirm that we are fixing the right problem.
30
+
31
+ We will be insisting on a minimal reproduce scenario in order to save maintainers time and ultimately be able to fix more bugs. Interestingly, from our experience users often find coding problems themselves while preparing a minimal plunk. We understand that sometimes it might be hard to extract essentials bits of code from a larger code-base but we really need to isolate the problem before we can fix it.
32
+
33
+ The best part is that you don't need to create plunks from scratch - you can use one from our [demo page](http://plnkr.co/edit/a3KlK8dKH3wwiiksDSn2?p=preview).
34
+
35
+ Unfortunately we are not able to investigate / fix bugs without a minimal reproduce scenario using http://plnkr.co/, so if we don't hear back from you we are going to close an issue that don't have enough info to be reproduced.
36
+
37
+ ## <a name="rules"></a> Coding Rules
38
+ To ensure consistency throughout the source code, keep these rules in mind as you are working:
39
+
40
+ * All features or bug fixes **must pass all tests** (run `gulp` to jshint, build and test).
41
+ * All public API methods **must be documented** with ngdoc, an extended version of jsdoc (we added
42
+ support for markdown and templating via @ngdoc tag). To see how we document our APIs, please check
43
+ out the existing ngdocs and see [this wiki page][ngDocs].
44
+
45
+ ## <a name="commit"></a> Git Commit Guidelines
46
+
47
+ We have very precise rules over how our git commit messages can be formatted for maintenance of the changelog and semvar versioning. This leads to **more
48
+ readable messages** that are easy to follow when looking through the **project history**. But also,
49
+ we use the git commit messages to **generate the change log**.
50
+
51
+ ## Development
52
+
53
+ ### Prepare your environment
54
+ * Install [Node.js](http://nodejs.org/) and NPM (should come with)
55
+ * Install global dev dependencies: `npm install -g bower gulp`
56
+ * Install local dev dependencies: `npm install && bower install` in repository directory
57
+
58
+ ### Development Commands
59
+
60
+ * `gulp` to jshint, build and test
61
+ * `gulp build` to jshint and build
62
+ * `gulp test` for one-time test with karma (also build and jshint)
63
+ * `gulp watch` to watch src files to jshint, build and test when changed
64
+
65
+ ## Recommended workflow
66
+
67
+ 1. Make changes
68
+ 2. Run `gulp` or `gulp test` to run Karma tests and ensure they pass.
69
+ 3. Reset all `dist/*` files
70
+ 4. Commit changes using the commit message conventions below.
71
+ 5. Push
72
+ 6. Create PR
73
+
74
+ ### Commit Message Format
75
+ Each commit message consists of a **header**, a **body** and a **footer**. The header has a special
76
+ format that includes a **type**, a **scope** and a **subject**:
77
+
78
+ ```
79
+ <type>(<scope>): <subject>
80
+ <BLANK LINE>
81
+ <body>
82
+ <BLANK LINE>
83
+ <footer>
84
+ ```
85
+
86
+ The **header** is mandatory and the **scope** of the header is optional.
87
+
88
+ Any line of the commit message cannot be longer 100 characters! This allows the message to be easier
89
+ to read on GitHub as well as in various git tools.
90
+
91
+ ### Revert
92
+ If the commit reverts a previous commit, it should begin with `revert: `, followed by the header of the reverted commit. In the body it should say: `This reverts commit <hash>.`, where the hash is the SHA of the commit being reverted.
93
+
94
+ ### Type
95
+ Must be one of the following:
96
+
97
+ * **feat**: A new feature
98
+ * **fix**: A bug fix
99
+ * **docs**: Documentation only changes
100
+ * **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing
101
+ semi-colons, etc)
102
+ * **refactor**: A code change that neither fixes a bug nor adds a feature
103
+ * **perf**: A code change that improves performance
104
+ * **test**: Adding missing tests
105
+ * **chore**: Changes to the build process or auxiliary tools and libraries such as documentation
106
+ generation
107
+
108
+ ### Scope
109
+ The scope could be anything specifying place of the commit change. For example `$location`,
110
+ `$browser`, `$compile`, `$rootScope`, `ngHref`, `ngClick`, `ngView`, etc...
111
+
112
+ ### Subject
113
+ The subject contains succinct description of the change:
114
+
115
+ * use the imperative, present tense: "change" not "changed" nor "changes"
116
+ * don't capitalize first letter
117
+ * no dot (.) at the end
118
+
119
+ ### Body
120
+ Just as in the **subject**, use the imperative, present tense: "change" not "changed" nor "changes".
121
+ The body should include the motivation for the change and contrast this with previous behavior.
122
+
123
+ ### Footer
124
+ The footer should contain any information about **Breaking Changes** and is also the place to
125
+ reference github issues that this commit **Closes**.
126
+
127
+ **Breaking Changes** should start with the word `BREAKING CHANGE:` with a space or two newlines. The rest of the commit message is then used for this.
128
+
129
+ #### Examples
130
+
131
+ Appears under "Features" header, pencil subheader:
132
+
133
+ ```
134
+ feat(pencil): add 'graphiteWidth' option
135
+ ```
136
+
137
+ Appears under "Bug Fixes" header, graphite subheader, with a link to issue #GSNP-28:
138
+
139
+ ```
140
+ fix(graphite): stop graphite breaking when width < 0.1
141
+
142
+ Closes #123
143
+ ```
144
+
145
+ Appears under "Performance Improvements" header, and under "Breaking Changes" with the breaking change explanation:
146
+
147
+ ```
148
+ perf(pencil): remove graphiteWidth option
149
+
150
+ BREAKING CHANGE: The graphiteWidth option has been removed. The default graphite width of 10mm is always used for performance reason.
151
+ ```
152
+
153
+ The following commit and commit `667ecc1` do not appear in the changelog if they are under the same release. If not, the revert commit appears under the "Reverts" header.
154
+
155
+ ```
156
+ revert: feat(pencil): add 'graphiteWidth' option
157
+
158
+ This reverts commit 667ecc1654a317a13331b17617d973392f415f02.
159
+ ```
160
+
161
+ A detailed explanation can be found in this [document][https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit#].
@@ -1,43 +1,57 @@
1
- # AngularJS ui-select [![Build Status](https://travis-ci.org/angular-ui/ui-select.svg?branch=master)](https://travis-ci.org/angular-ui/ui-select)
1
+ # AngularJS ui-select [![Build Status](https://travis-ci.org/angular-ui/ui-select.svg?branch=master)](https://travis-ci.org/angular-ui/ui-select) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/angular-ui/ui-select?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
2
2
 
3
- [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/angular-ui/ui-select?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
3
+ AngularJS-native version of [Select2](http://ivaynberg.github.io/select2/) and [Selectize](http://brianreavis.github.io/selectize.js/). [http://angular-ui.github.io/ui-select/](http://angular-ui.github.io/ui-select/)
4
4
 
5
- AngularJS-native version of [Select2](http://ivaynberg.github.io/select2/) and [Selectize](http://brianreavis.github.io/selectize.js/).
5
+ [Getting Started](https://github.com/angular-ui/ui-select/wiki/Getting-Started)
6
6
 
7
- - [Demo](http://plnkr.co/edit/a3KlK8dKH3wwiiksDSn2?p=preview)
8
- - [Demo Multiselect](http://plnkr.co/edit/juqoNOt1z1Gb349XabQ2?p=preview)
9
- - [Examples](https://github.com/angular-ui/ui-select/blob/master/examples)
7
+ - [Examples](http://angular-ui.github.io/ui-select/#examples)
8
+ - [Examples Source](./docs/examples)
10
9
  - [Documentation](https://github.com/angular-ui/ui-select/wiki)
11
10
 
11
+ ## Latest Changes
12
+
13
+ - Check [CHANGELOG.md](/CHANGELOG.md)
12
14
 
13
15
  ## Features
14
16
 
15
- - Search, Select, and Multi-select
16
- - Themes: Bootstrap, Select2 and Selectize
17
+ - Search, Select, Multi-select and Tagging
18
+ - Multiple Themes: Bootstrap, Select2 and Selectize
17
19
  - Keyboard support
18
- - jQuery not required (except for old browsers)
20
+ - No jQuery required (except for old browsers)
19
21
  - Small code base: 4.57KB min/gzipped vs 20KB for select2
20
22
 
21
23
  For the roadmap, check [issue #3](https://github.com/angular-ui/ui-select/issues/3) and the [Wiki page](https://github.com/angular-ui/ui-select/wiki/Roadmap).
22
24
 
25
+ ## Installation Methods
26
+
27
+ ### npm
28
+ ```
29
+ $ npm install ui-select
30
+ ```
31
+ ### bower
32
+ ```
33
+ $ bower install angular-ui-select
34
+ ```
23
35
 
24
36
  ## Development
25
37
 
26
38
  ### Prepare your environment
27
39
  * Install [Node.js](http://nodejs.org/) and NPM (should come with)
28
- * Install global dev dependencies: `npm install -g bower gulp`
29
- * Install local dev dependencies: `npm install && bower install` in repository directory
40
+ * Install global dev dependencies: `npm install -g gulp`
41
+ * Install local dev dependencies: `npm install` in repository directory
30
42
 
31
43
  ### Development Commands
32
44
 
33
45
  * `gulp` to jshint, build and test
34
46
  * `gulp build` to jshint and build
35
47
  * `gulp test` for one-time test with karma (also build and jshint)
36
- * `gulp watch` to watch src files to jshin, build and test when changed
48
+ * `gulp watch` to watch src files to jshint, build and test when changed
49
+ * `gulp docs` build docs and examples
37
50
 
38
51
  ## Contributing
39
52
 
53
+ - Check [CONTRIBUTING.md](/CONTRIBUTING.md)
40
54
  - Run the tests
41
- - Try the [examples](https://github.com/angular-ui/ui-select/blob/master/examples)
55
+ - Try the [examples](./docs/examples)
42
56
 
43
57
  When issuing a pull request, please exclude changes from the "dist" folder to avoid merge conflicts.
@@ -1,12 +1,15 @@
1
1
  {
2
- "name": "ui-select",
3
- "version": "0.11.2",
2
+ "name": "angular-ui-select",
3
+ "version": "0.17.0",
4
4
  "homepage": "https://github.com/angular-ui/ui-select",
5
5
  "authors": [
6
6
  "AngularUI"
7
7
  ],
8
8
  "description": "AngularJS ui-select",
9
- "main": ["dist/select.js", "dist/select.css"],
9
+ "main": [
10
+ "dist/select.js",
11
+ "dist/select.css"
12
+ ],
10
13
  "license": "MIT",
11
14
  "ignore": [
12
15
  "**/.*",
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "components/ui-select",
3
+ "description": "AngularJS UI Select",
4
+ "keywords": ["angular", "angular-ui", "select", "select2", "angularjs"],
5
+ "type": "component",
6
+ "homepage": "https://github.com/angular-ui/ui-select",
7
+ "license": "MIT",
8
+ "support": {
9
+ "issues": "https://github.com/angular-ui/ui-select/issues",
10
+ "wiki": "https://github.com/angular-ui/ui-select/wiki",
11
+ "source": "https://github.com/angular-ui/ui-select"
12
+ },
13
+ "require": {
14
+ "robloach/component-installer": "*"
15
+ },
16
+ "extra": {
17
+ "component": {
18
+ "scripts": [
19
+ "dist/select.js"
20
+ ],
21
+ "files": [
22
+ "dist/select.js",
23
+ "dist/select.css",
24
+ "dist/select.min.js",
25
+ "dist/select.min.css"
26
+ ]
27
+ }
28
+ }
29
+ }
@@ -0,0 +1,31 @@
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ [[ $TRAVIS_SECURE_ENV_VARS == "true" ]] || { echo "No github key avaliable, aborting publishing"; exit 0; }
5
+
6
+ ID_REF="$(git rev-parse --short HEAD)"
7
+
8
+ git clone "https://${GH_KEY}@${GH_REF}" ./docs-out -b ${GH_PAGES_BRANCH} --single-branch --depth=1
9
+
10
+ cd docs-out
11
+
12
+ # clear out everything
13
+ git rm -rf .
14
+ git clean -fxd
15
+
16
+ # get new content
17
+ cp ../docs-built/* . -R
18
+
19
+ git add .
20
+
21
+ # inside this git repo we'll pretend to be a new user
22
+ git config user.name "Travis CI"
23
+ git config user.email "travisci@users.noreply.github.com"
24
+
25
+ # The first and only commit to this new Git repo contains all the
26
+ # files present with the commit message "Deploy to GitHub Pages".
27
+ git commit -m "docs(*): new deploy (angular-ui/ui-select@${ID_REF})"
28
+
29
+
30
+ git push origin --quiet
31
+ #> /dev/null 2>&1
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * ui-select
3
3
  * http://github.com/angular-ui/ui-select
4
- * Version: 0.11.2 - 2015-03-17T04:08:46.478Z
4
+ * Version: 0.16.0 - 2016-03-23T20:51:56.678Z
5
5
  * License: MIT
6
6
  */
7
7
 
@@ -25,6 +25,11 @@
25
25
  top: 0px !important;
26
26
  }
27
27
 
28
+
29
+ .ui-select-choices-row:hover {
30
+ background-color: #f5f5f5;
31
+ }
32
+
28
33
  /* Select2 theme */
29
34
 
30
35
  /* Mark invalid Select2 */
@@ -48,6 +53,31 @@ body > .select2-container.open {
48
53
  z-index: 9999; /* The z-index Select2 applies to the select2-drop */
49
54
  }
50
55
 
56
+ /* Handle up direction Select2 */
57
+ .ui-select-container[theme="select2"].direction-up .ui-select-match {
58
+ border-radius: 4px; /* FIXME hardcoded value :-/ */
59
+ border-top-left-radius: 0;
60
+ border-top-right-radius: 0;
61
+ }
62
+ .ui-select-container[theme="select2"].direction-up .ui-select-dropdown {
63
+ border-radius: 4px; /* FIXME hardcoded value :-/ */
64
+ border-bottom-left-radius: 0;
65
+ border-bottom-right-radius: 0;
66
+
67
+ border-top-width: 1px; /* FIXME hardcoded value :-/ */
68
+ border-top-style: solid;
69
+
70
+ box-shadow: 0 -4px 8px rgba(0, 0, 0, 0.25);
71
+
72
+ margin-top: -4px; /* FIXME hardcoded value :-/ */
73
+ }
74
+ .ui-select-container[theme="select2"].direction-up .ui-select-dropdown .select2-search {
75
+ margin-top: 4px; /* FIXME hardcoded value :-/ */
76
+ }
77
+ .ui-select-container[theme="select2"].direction-up.select2-dropdown-open .ui-select-match {
78
+ border-bottom-color: #5897fb;
79
+ }
80
+
51
81
  /* Selectize theme */
52
82
 
53
83
  /* Helper class to show styles when focus */
@@ -70,6 +100,12 @@ body > .select2-container.open {
70
100
  border-color: #D44950;
71
101
  }
72
102
 
103
+ /* Handle up direction Selectize */
104
+ .ui-select-container[theme="selectize"].direction-up .ui-select-dropdown {
105
+ box-shadow: 0 -4px 8px rgba(0, 0, 0, 0.25);
106
+
107
+ margin-top: -2px; /* FIXME hardcoded value :-/ */
108
+ }
73
109
 
74
110
  /* Bootstrap theme */
75
111
 
@@ -107,6 +143,11 @@ body > .select2-container.open {
107
143
  border-top-right-radius: 0;
108
144
  border-bottom-right-radius: 0;
109
145
  }
146
+ .input-group > .ui-select-bootstrap > input.ui-select-search.form-control.direction-up {
147
+ border-radius: 4px !important; /* FIXME hardcoded value :-/ */
148
+ border-top-right-radius: 0 !important;
149
+ border-bottom-right-radius: 0 !important;
150
+ }
110
151
 
111
152
  .ui-select-bootstrap > .ui-select-match > .btn{
112
153
  /* Instead of center because of .btn */
@@ -218,4 +259,9 @@ body > .ui-select-bootstrap.open {
218
259
  /* Mark invalid Bootstrap */
219
260
  .ui-select-bootstrap.ng-dirty.ng-invalid > button.btn.ui-select-match {
220
261
  border-color: #D44950;
221
- }
262
+ }
263
+
264
+ /* Handle up direction Bootstrap */
265
+ .ui-select-container[theme="bootstrap"].direction-up .ui-select-dropdown {
266
+ box-shadow: 0 -4px 8px rgba(0, 0, 0, 0.25);
267
+ }
@@ -1,14 +1,13 @@
1
1
  /*!
2
2
  * ui-select
3
3
  * http://github.com/angular-ui/ui-select
4
- * Version: 0.11.2 - 2015-03-17T04:08:46.474Z
4
+ * Version: 0.16.0 - 2016-03-23T20:51:56.609Z
5
5
  * License: MIT
6
6
  */
7
7
 
8
8
 
9
9
  (function () {
10
10
  "use strict";
11
-
12
11
  var KEY = {
13
12
  TAB: 9,
14
13
  ENTER: 13,
@@ -55,6 +54,13 @@ var KEY = {
55
54
  },
56
55
  isHorizontalMovement: function (k){
57
56
  return ~[KEY.LEFT,KEY.RIGHT,KEY.BACKSPACE,KEY.DELETE].indexOf(k);
57
+ },
58
+ toSeparator: function (k) {
59
+ var sep = {ENTER:"\n",TAB:"\t",SPACE:" "}[k];
60
+ if (sep) return sep;
61
+ // return undefined for special keys other than enter, tab or space.
62
+ // no way to use them to cut strings.
63
+ return KEY[k] ? undefined : k;
58
64
  }
59
65
  };
60
66
 
@@ -103,6 +109,8 @@ var uis = angular.module('ui.select', [])
103
109
  placeholder: '', // Empty by default, like HTML tag <select>
104
110
  refreshDelay: 1000, // In milliseconds
105
111
  closeOnSelect: true,
112
+ skipFocusser: false,
113
+ dropdownPosition: 'auto',
106
114
  generateId: function() {
107
115
  return latestId++;
108
116
  },
@@ -138,11 +146,11 @@ var uis = angular.module('ui.select', [])
138
146
  */
139
147
  .filter('highlight', function() {
140
148
  function escapeRegexp(queryToEscape) {
141
- return queryToEscape.replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1');
149
+ return ('' + queryToEscape).replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1');
142
150
  }
143
151
 
144
152
  return function(matchItem, query) {
145
- return query && matchItem ? matchItem.replace(new RegExp(escapeRegexp(query), 'gi'), '<span class="ui-select-highlight">$&</span>') : matchItem;
153
+ return query && matchItem ? ('' + matchItem).replace(new RegExp(escapeRegexp(query), 'gi'), '<span class="ui-select-highlight">$&</span>') : matchItem;
146
154
  };
147
155
  })
148
156
 
@@ -168,8 +176,8 @@ var uis = angular.module('ui.select', [])
168
176
  }]);
169
177
 
170
178
  uis.directive('uiSelectChoices',
171
- ['uiSelectConfig', 'uisRepeatParser', 'uiSelectMinErr', '$compile',
172
- function(uiSelectConfig, RepeatParser, uiSelectMinErr, $compile) {
179
+ ['uiSelectConfig', 'uisRepeatParser', 'uiSelectMinErr', '$compile', '$window',
180
+ function(uiSelectConfig, RepeatParser, uiSelectMinErr, $compile, $window) {
173
181
 
174
182
  return {
175
183
  restrict: 'EA',
@@ -177,6 +185,9 @@ uis.directive('uiSelectChoices',
177
185
  replace: true,
178
186
  transclude: true,
179
187
  templateUrl: function(tElement) {
188
+ // Needed so the uiSelect can detect the transcluded content
189
+ tElement.addClass('ui-select-choices');
190
+
180
191
  // Gets theme attribute from parent (ui-select)
181
192
  var theme = tElement.parent().attr('theme') || uiSelectConfig.theme;
182
193
  return theme + '/choices.tpl.html';
@@ -190,12 +201,15 @@ uis.directive('uiSelectChoices',
190
201
 
191
202
  // var repeat = RepeatParser.parse(attrs.repeat);
192
203
  var groupByExp = attrs.groupBy;
204
+ var groupFilterExp = attrs.groupFilter;
193
205
 
194
- $select.parseRepeatAttr(attrs.repeat, groupByExp); //Result ready at $select.parserResult
206
+ $select.parseRepeatAttr(attrs.repeat, groupByExp, groupFilterExp); //Result ready at $select.parserResult
195
207
 
196
208
  $select.disableChoiceExpression = attrs.uiDisableChoice;
197
209
  $select.onHighlightCallback = attrs.onHighlight;
198
210
 
211
+ $select.dropdownPosition = attrs.position ? attrs.position.toLowerCase() : uiSelectConfig.dropdownPosition;
212
+
199
213
  if(groupByExp) {
200
214
  var groups = element.querySelectorAll('.ui-select-choices-group');
201
215
  if (groups.length !== 1) throw uiSelectMinErr('rows', "Expected 1 .ui-select-choices-group but got '{0}'.", groups.length);
@@ -207,21 +221,31 @@ uis.directive('uiSelectChoices',
207
221
  throw uiSelectMinErr('rows', "Expected 1 .ui-select-choices-row but got '{0}'.", choices.length);
208
222
  }
209
223
 
210
- choices.attr('ng-repeat', RepeatParser.getNgRepeatExpression($select.parserResult.itemName, '$select.items', $select.parserResult.trackByExp, groupByExp))
211
- .attr('ng-if', '$select.open') //Prevent unnecessary watches when dropdown is closed
212
- .attr('ng-mouseenter', '$select.setActiveItem('+$select.parserResult.itemName +')')
213
- .attr('ng-click', '$select.select(' + $select.parserResult.itemName + ',false,$event)');
224
+ choices.attr('ng-repeat', $select.parserResult.repeatExpression(groupByExp))
225
+ .attr('ng-if', '$select.open'); //Prevent unnecessary watches when dropdown is closed
226
+ if ($window.document.addEventListener) { //crude way to exclude IE8, specifically, which also cannot capture events
227
+ choices.attr('ng-mouseenter', '$select.setActiveItem('+$select.parserResult.itemName +')')
228
+ .attr('ng-click', '$select.select(' + $select.parserResult.itemName + ',$select.skipFocusser,$event)');
229
+ }
214
230
 
215
231
  var rowsInner = element.querySelectorAll('.ui-select-choices-row-inner');
216
232
  if (rowsInner.length !== 1) throw uiSelectMinErr('rows', "Expected 1 .ui-select-choices-row-inner but got '{0}'.", rowsInner.length);
217
233
  rowsInner.attr('uis-transclude-append', ''); //Adding uisTranscludeAppend directive to row element after choices element has ngRepeat
234
+ if (!$window.document.addEventListener) { //crude way to target IE8, specifically, which also cannot capture events - so event bindings must be here
235
+ rowsInner.attr('ng-mouseenter', '$select.setActiveItem('+$select.parserResult.itemName +')')
236
+ .attr('ng-click', '$select.select(' + $select.parserResult.itemName + ',$select.skipFocusser,$event)');
237
+ }
218
238
 
219
239
  $compile(element, transcludeFn)(scope); //Passing current transcludeFn to be able to append elements correctly from uisTranscludeAppend
220
240
 
221
241
  scope.$watch('$select.search', function(newValue) {
222
242
  if(newValue && !$select.open && $select.multiple) $select.activate(false, true);
223
243
  $select.activeIndex = $select.tagging.isActivated ? -1 : 0;
224
- $select.refresh(attrs.refresh);
244
+ if (!attrs.minimumInputLength || $select.search.length >= attrs.minimumInputLength) {
245
+ $select.refresh(attrs.refresh);
246
+ } else {
247
+ $select.items = [];
248
+ }
225
249
  });
226
250
 
227
251
  attrs.$observe('refreshDelay', function() {
@@ -241,8 +265,8 @@ uis.directive('uiSelectChoices',
241
265
  * put as much logic in the controller (instead of the link functions) as possible so it can be easily tested.
242
266
  */
243
267
  uis.controller('uiSelectCtrl',
244
- ['$scope', '$element', '$timeout', '$filter', 'uisRepeatParser', 'uiSelectMinErr', 'uiSelectConfig',
245
- function($scope, $element, $timeout, $filter, RepeatParser, uiSelectMinErr, uiSelectConfig) {
268
+ ['$scope', '$element', '$timeout', '$filter', 'uisRepeatParser', 'uiSelectMinErr', 'uiSelectConfig', '$parse', '$injector', '$window',
269
+ function($scope, $element, $timeout, $filter, RepeatParser, uiSelectMinErr, uiSelectConfig, $parse, $injector, $window) {
246
270
 
247
271
  var ctrl = this;
248
272
 
@@ -252,9 +276,11 @@ uis.controller('uiSelectCtrl',
252
276
  ctrl.searchEnabled = uiSelectConfig.searchEnabled;
253
277
  ctrl.sortable = uiSelectConfig.sortable;
254
278
  ctrl.refreshDelay = uiSelectConfig.refreshDelay;
279
+ ctrl.paste = uiSelectConfig.paste;
255
280
 
256
281
  ctrl.removeSelected = false; //If selected item(s) should be removed from dropdown list
257
282
  ctrl.closeOnSelect = true; //Initialized inside uiSelect directive link function
283
+ ctrl.skipFocusser = false; //Set to true to avoid returning focus to ctrl when item is selected
258
284
  ctrl.search = EMPTY_SEARCH;
259
285
 
260
286
  ctrl.activeIndex = 0; //Dropdown of choices
@@ -265,6 +291,8 @@ uis.controller('uiSelectCtrl',
265
291
  ctrl.disabled = false;
266
292
  ctrl.selected = undefined;
267
293
 
294
+ ctrl.dropdownPosition = 'auto';
295
+
268
296
  ctrl.focusser = undefined; //Reference to input element used to handle focus events
269
297
  ctrl.resetSearchInput = true;
270
298
  ctrl.multiple = undefined; // Initialized inside uiSelect directive link function
@@ -275,26 +303,68 @@ uis.controller('uiSelectCtrl',
275
303
  ctrl.clickTriggeredSelect = false;
276
304
  ctrl.$filter = $filter;
277
305
 
306
+ // Use $injector to check for $animate and store a reference to it
307
+ ctrl.$animate = (function () {
308
+ try {
309
+ return $injector.get('$animate');
310
+ } catch (err) {
311
+ // $animate does not exist
312
+ return null;
313
+ }
314
+ })();
315
+
278
316
  ctrl.searchInput = $element.querySelectorAll('input.ui-select-search');
279
317
  if (ctrl.searchInput.length !== 1) {
280
318
  throw uiSelectMinErr('searchInput', "Expected 1 input.ui-select-search but got '{0}'.", ctrl.searchInput.length);
281
319
  }
282
-
320
+
283
321
  ctrl.isEmpty = function() {
284
- return angular.isUndefined(ctrl.selected) || ctrl.selected === null || ctrl.selected === '';
322
+ return angular.isUndefined(ctrl.selected) || ctrl.selected === null || ctrl.selected === '' || (ctrl.multiple && ctrl.selected.length === 0);
285
323
  };
286
324
 
325
+ function _findIndex(collection, predicate, thisArg){
326
+ if (collection.findIndex){
327
+ return collection.findIndex(predicate, thisArg);
328
+ } else {
329
+ var list = Object(collection);
330
+ var length = list.length >>> 0;
331
+ var value;
332
+
333
+ for (var i = 0; i < length; i++) {
334
+ value = list[i];
335
+ if (predicate.call(thisArg, value, i, list)) {
336
+ return i;
337
+ }
338
+ }
339
+ return -1;
340
+ }
341
+ }
342
+
287
343
  // Most of the time the user does not want to empty the search input when in typeahead mode
288
344
  function _resetSearchInput() {
289
345
  if (ctrl.resetSearchInput || (ctrl.resetSearchInput === undefined && uiSelectConfig.resetSearchInput)) {
290
346
  ctrl.search = EMPTY_SEARCH;
291
347
  //reset activeIndex
292
348
  if (ctrl.selected && ctrl.items.length && !ctrl.multiple) {
293
- ctrl.activeIndex = ctrl.items.indexOf(ctrl.selected);
349
+ ctrl.activeIndex = _findIndex(ctrl.items, function(item){
350
+ return angular.equals(this, item);
351
+ }, ctrl.selected);
294
352
  }
295
353
  }
296
354
  }
297
355
 
356
+ function _groupsFilter(groups, groupNames) {
357
+ var i, j, result = [];
358
+ for(i = 0; i < groupNames.length ;i++){
359
+ for(j = 0; j < groups.length ;j++){
360
+ if(groups[j].name == [groupNames[i]]){
361
+ result.push(groups[j]);
362
+ }
363
+ }
364
+ }
365
+ return result;
366
+ }
367
+
298
368
  // When the user clicks on ui-select, displays the dropdown list
299
369
  ctrl.activate = function(initSearchValue, avoidReset) {
300
370
  if (!ctrl.disabled && !ctrl.open) {
@@ -312,25 +382,43 @@ uis.controller('uiSelectCtrl',
312
382
  ctrl.activeIndex = 0;
313
383
  }
314
384
 
315
- // Give it time to appear before focus
316
- $timeout(function() {
317
- ctrl.search = initSearchValue || ctrl.search;
318
- ctrl.searchInput[0].focus();
319
- });
385
+ var container = $element.querySelectorAll('.ui-select-choices-content');
386
+ if (ctrl.$animate && ctrl.$animate.on && ctrl.$animate.enabled(container[0])) {
387
+ ctrl.$animate.on('enter', container[0], function (elem, phase) {
388
+ if (phase === 'close') {
389
+ // Only focus input after the animation has finished
390
+ $timeout(function () {
391
+ ctrl.focusSearchInput(initSearchValue);
392
+ });
393
+ }
394
+ });
395
+ } else {
396
+ $timeout(function () {
397
+ ctrl.focusSearchInput(initSearchValue);
398
+ if(!ctrl.tagging.isActivated && ctrl.items.length > 1) {
399
+ _ensureHighlightVisible();
400
+ }
401
+ });
402
+ }
320
403
  }
321
404
  };
322
405
 
406
+ ctrl.focusSearchInput = function (initSearchValue) {
407
+ ctrl.search = initSearchValue || ctrl.search;
408
+ ctrl.searchInput[0].focus();
409
+ };
410
+
323
411
  ctrl.findGroupByName = function(name) {
324
412
  return ctrl.groups && ctrl.groups.filter(function(group) {
325
413
  return group.name === name;
326
414
  })[0];
327
415
  };
328
416
 
329
- ctrl.parseRepeatAttr = function(repeatAttr, groupByExp) {
417
+ ctrl.parseRepeatAttr = function(repeatAttr, groupByExp, groupFilterExp) {
330
418
  function updateGroups(items) {
419
+ var groupFn = $scope.$eval(groupByExp);
331
420
  ctrl.groups = [];
332
421
  angular.forEach(items, function(item) {
333
- var groupFn = $scope.$eval(groupByExp);
334
422
  var groupName = angular.isFunction(groupFn) ? groupFn(item) : item[groupFn];
335
423
  var group = ctrl.findGroupByName(groupName);
336
424
  if(group) {
@@ -340,6 +428,14 @@ uis.controller('uiSelectCtrl',
340
428
  ctrl.groups.push({name: groupName, items: [item]});
341
429
  }
342
430
  });
431
+ if(groupFilterExp){
432
+ var groupFilterFn = $scope.$eval(groupFilterExp);
433
+ if( angular.isFunction(groupFilterFn)){
434
+ ctrl.groups = groupFilterFn(ctrl.groups);
435
+ } else if(angular.isArray(groupFilterFn)){
436
+ ctrl.groups = _groupsFilter(ctrl.groups, groupFilterFn);
437
+ }
438
+ }
343
439
  ctrl.items = [];
344
440
  ctrl.groups.forEach(function(group) {
345
441
  ctrl.items = ctrl.items.concat(group.items);
@@ -357,18 +453,48 @@ uis.controller('uiSelectCtrl',
357
453
  ctrl.isGrouped = !!groupByExp;
358
454
  ctrl.itemProperty = ctrl.parserResult.itemName;
359
455
 
456
+ //If collection is an Object, convert it to Array
457
+
458
+ var originalSource = ctrl.parserResult.source;
459
+
460
+ //When an object is used as source, we better create an array and use it as 'source'
461
+ var createArrayFromObject = function(){
462
+ var origSrc = originalSource($scope);
463
+ $scope.$uisSource = Object.keys(origSrc).map(function(v){
464
+ var result = {};
465
+ result[ctrl.parserResult.keyName] = v;
466
+ result.value = origSrc[v];
467
+ return result;
468
+ });
469
+ };
470
+
471
+ if (ctrl.parserResult.keyName){ // Check for (key,value) syntax
472
+ createArrayFromObject();
473
+ ctrl.parserResult.source = $parse('$uisSource' + ctrl.parserResult.filters);
474
+ $scope.$watch(originalSource, function(newVal, oldVal){
475
+ if (newVal !== oldVal) createArrayFromObject();
476
+ }, true);
477
+ }
478
+
360
479
  ctrl.refreshItems = function (data){
361
480
  data = data || ctrl.parserResult.source($scope);
362
481
  var selectedItems = ctrl.selected;
363
482
  //TODO should implement for single mode removeSelected
364
- if ((angular.isArray(selectedItems) && !selectedItems.length) || !ctrl.removeSelected) {
483
+ if (ctrl.isEmpty() || (angular.isArray(selectedItems) && !selectedItems.length) || !ctrl.removeSelected) {
365
484
  ctrl.setItemsFn(data);
366
485
  }else{
367
486
  if ( data !== undefined ) {
368
- var filteredItems = data.filter(function(i) {return selectedItems.indexOf(i) < 0;});
487
+ var filteredItems = data.filter(function(i) {
488
+ return selectedItems.every(function(selectedItem) {
489
+ return !angular.equals(i, selectedItem);
490
+ });
491
+ });
369
492
  ctrl.setItemsFn(filteredItems);
370
493
  }
371
494
  }
495
+ if (ctrl.dropdownPosition === 'auto' || ctrl.dropdownPosition === 'up'){
496
+ $scope.calculateDropdownPos();
497
+ }
372
498
  };
373
499
 
374
500
  // See https://github.com/angular/angular.js/blob/v1.2.15/src/ng/directive/ngRepeat.js#L259
@@ -414,16 +540,12 @@ uis.controller('uiSelectCtrl',
414
540
  }
415
541
  };
416
542
 
417
- ctrl.setActiveItem = function(item) {
418
- ctrl.activeIndex = ctrl.items.indexOf(item);
419
- };
420
-
421
543
  ctrl.isActive = function(itemScope) {
422
544
  if ( !ctrl.open ) {
423
545
  return false;
424
546
  }
425
547
  var itemIndex = ctrl.items.indexOf(itemScope[ctrl.itemProperty]);
426
- var isActive = itemIndex === ctrl.activeIndex;
548
+ var isActive = itemIndex == ctrl.activeIndex;
427
549
 
428
550
  if ( !isActive || ( itemIndex < 0 && ctrl.taggingLabel !== false ) ||( itemIndex < 0 && ctrl.taggingLabel === false) ) {
429
551
  return false;
@@ -458,7 +580,7 @@ uis.controller('uiSelectCtrl',
458
580
  ctrl.select = function(item, skipFocusser, $event) {
459
581
  if (item === undefined || !item._uiSelectChoiceDisabled) {
460
582
 
461
- if ( ! ctrl.items && ! ctrl.search ) return;
583
+ if ( ! ctrl.items && ! ctrl.search && ! ctrl.tagging.isActivated) return;
462
584
 
463
585
  if (!item || !item._uiSelectChoiceDisabled) {
464
586
  if(ctrl.tagging.isActivated) {
@@ -484,7 +606,7 @@ uis.controller('uiSelectCtrl',
484
606
  // create new item on the fly if we don't already have one;
485
607
  // use tagging function if we have one
486
608
  if ( ctrl.tagging.fct !== undefined && typeof item === 'string' ) {
487
- item = ctrl.tagging.fct(ctrl.search);
609
+ item = ctrl.tagging.fct(item);
488
610
  if (!item) return;
489
611
  // if item type is 'string', apply the tagging label
490
612
  } else if ( typeof item === 'string' ) {
@@ -540,7 +662,9 @@ uis.controller('uiSelectCtrl',
540
662
  ctrl.clear = function($event) {
541
663
  ctrl.select(undefined);
542
664
  $event.stopPropagation();
543
- ctrl.focusser[0].focus();
665
+ $timeout(function() {
666
+ ctrl.focusser[0].focus();
667
+ }, 0, false);
544
668
  };
545
669
 
546
670
  // Toggle dropdown
@@ -612,8 +736,8 @@ uis.controller('uiSelectCtrl',
612
736
  if (!ctrl.multiple || ctrl.open) ctrl.select(ctrl.items[ctrl.activeIndex], true);
613
737
  break;
614
738
  case KEY.ENTER:
615
- if(ctrl.open && ctrl.activeIndex >= 0){
616
- ctrl.select(ctrl.items[ctrl.activeIndex]); // Make sure at least one dropdown item is highlighted before adding.
739
+ if(ctrl.open && (ctrl.tagging.isActivated || ctrl.activeIndex >= 0)){
740
+ ctrl.select(ctrl.items[ctrl.activeIndex], ctrl.skipFocusser); // Make sure at least one dropdown item is highlighted before adding if not in tagging mode
617
741
  } else {
618
742
  ctrl.activate(false, true); //In case its the search input in 'multiple' mode
619
743
  }
@@ -632,6 +756,11 @@ uis.controller('uiSelectCtrl',
632
756
 
633
757
  var key = e.which;
634
758
 
759
+ if (~[KEY.ENTER,KEY.ESC].indexOf(key)){
760
+ e.preventDefault();
761
+ e.stopPropagation();
762
+ }
763
+
635
764
  // if(~[KEY.ESC,KEY.TAB].indexOf(key)){
636
765
  // //TODO: SEGURO?
637
766
  // ctrl.close();
@@ -671,20 +800,45 @@ uis.controller('uiSelectCtrl',
671
800
  _ensureHighlightVisible();
672
801
  }
673
802
 
803
+ if (key === KEY.ENTER || key === KEY.ESC) {
804
+ e.preventDefault();
805
+ e.stopPropagation();
806
+ }
807
+
674
808
  });
675
809
 
676
- // If tagging try to split by tokens and add items
677
810
  ctrl.searchInput.on('paste', function (e) {
678
- var data = e.originalEvent.clipboardData.getData('text/plain');
679
- if (data && data.length > 0 && ctrl.taggingTokens.isActivated && ctrl.tagging.fct) {
680
- var items = data.split(ctrl.taggingTokens.tokens[0]); // split by first token only
681
- if (items && items.length > 0) {
682
- angular.forEach(items, function (item) {
683
- var newItem = ctrl.tagging.fct(item);
684
- if (newItem) {
685
- ctrl.select(newItem, true);
686
- }
687
- });
811
+ var data;
812
+
813
+ if (window.clipboardData && window.clipboardData.getData) { // IE
814
+ data = window.clipboardData.getData('Text');
815
+ } else {
816
+ data = (e.originalEvent || e).clipboardData.getData('text/plain');
817
+ }
818
+
819
+ // Prepend the current input field text to the paste buffer.
820
+ data = ctrl.search + data;
821
+
822
+ if (data && data.length > 0) {
823
+ // If tagging try to split by tokens and add items
824
+ if (ctrl.taggingTokens.isActivated) {
825
+ var separator = KEY.toSeparator(ctrl.taggingTokens.tokens[0]);
826
+ var items = data.split(separator || ctrl.taggingTokens.tokens[0]); // split by first token only
827
+ if (items && items.length > 0) {
828
+ var oldsearch = ctrl.search;
829
+ angular.forEach(items, function (item) {
830
+ var newItem = ctrl.tagging.fct ? ctrl.tagging.fct(item) : item;
831
+ if (newItem) {
832
+ ctrl.select(newItem, true);
833
+ }
834
+ });
835
+ ctrl.search = oldsearch || EMPTY_SEARCH;
836
+ e.preventDefault();
837
+ e.stopPropagation();
838
+ }
839
+ } else if (ctrl.paste) {
840
+ ctrl.paste(data);
841
+ ctrl.search = EMPTY_SEARCH;
688
842
  e.preventDefault();
689
843
  e.stopPropagation();
690
844
  }
@@ -727,6 +881,10 @@ uis.controller('uiSelectCtrl',
727
881
  ctrl.searchInput.off('keyup keydown tagged blur paste');
728
882
  });
729
883
 
884
+ angular.element($window).bind('resize', function() {
885
+ ctrl.sizeSearchInput();
886
+ });
887
+
730
888
  }]);
731
889
 
732
890
  uis.directive('uiSelect',
@@ -748,11 +906,22 @@ uis.directive('uiSelect',
748
906
  controllerAs: '$select',
749
907
  compile: function(tElement, tAttrs) {
750
908
 
909
+ // Allow setting ngClass on uiSelect
910
+ var match = /{(.*)}\s*{(.*)}/.exec(tAttrs.ngClass);
911
+ if(match) {
912
+ var combined = '{'+ match[1] +', '+ match[2] +'}';
913
+ tAttrs.ngClass = combined;
914
+ tElement.attr('ng-class', combined);
915
+ }
916
+
751
917
  //Multiple or Single depending if multiple attribute presence
752
918
  if (angular.isDefined(tAttrs.multiple))
753
- tElement.append("<ui-select-multiple/>").removeAttr('multiple');
919
+ tElement.append('<ui-select-multiple/>').removeAttr('multiple');
754
920
  else
755
- tElement.append("<ui-select-single/>");
921
+ tElement.append('<ui-select-single/>');
922
+
923
+ if (tAttrs.inputId)
924
+ tElement.querySelectorAll('input.ui-select-search')[0].id = tAttrs.inputId;
756
925
 
757
926
  return function(scope, element, attrs, ctrls, transcludeFn) {
758
927
 
@@ -772,9 +941,17 @@ uis.directive('uiSelect',
772
941
  }
773
942
  }();
774
943
 
944
+ scope.$watch('skipFocusser', function() {
945
+ var skipFocusser = scope.$eval(attrs.skipFocusser);
946
+ $select.skipFocusser = skipFocusser !== undefined ? skipFocusser : uiSelectConfig.skipFocusser;
947
+ });
948
+
775
949
  $select.onSelectCallback = $parse(attrs.onSelect);
776
950
  $select.onRemoveCallback = $parse(attrs.onRemove);
777
-
951
+
952
+ //Limit the number of selections allowed
953
+ $select.limit = (angular.isDefined(attrs.limit)) ? parseInt(attrs.limit, 10) : undefined;
954
+
778
955
  //Set reference to ngModel from uiSelectCtrl
779
956
  $select.ngModel = ngModel;
780
957
 
@@ -784,8 +961,8 @@ uis.directive('uiSelect',
784
961
 
785
962
  if(attrs.tabindex){
786
963
  attrs.$observe('tabindex', function(value) {
787
- $select.focusInput.attr("tabindex", value);
788
- element.removeAttr("tabindex");
964
+ $select.focusInput.attr('tabindex', value);
965
+ element.removeAttr('tabindex');
789
966
  });
790
967
  }
791
968
 
@@ -810,6 +987,10 @@ uis.directive('uiSelect',
810
987
  $select.resetSearchInput = resetSearchInput !== undefined ? resetSearchInput : true;
811
988
  });
812
989
 
990
+ attrs.$observe('paste', function() {
991
+ $select.paste = scope.$eval(attrs.paste);
992
+ });
993
+
813
994
  attrs.$observe('tagging', function() {
814
995
  if(attrs.tagging !== undefined)
815
996
  {
@@ -875,11 +1056,16 @@ uis.directive('uiSelect',
875
1056
  }
876
1057
 
877
1058
  if (!contains && !$select.clickTriggeredSelect) {
878
- //Will lose focus only with certain targets
879
- var focusableControls = ['input','button','textarea'];
880
- var targetScope = angular.element(e.target).scope(); //To check if target is other ui-select
881
- var skipFocusser = targetScope && targetScope.$select && targetScope.$select !== $select; //To check if target is other ui-select
882
- if (!skipFocusser) skipFocusser = ~focusableControls.indexOf(e.target.tagName.toLowerCase()); //Check if target is input, button or textarea
1059
+ var skipFocusser;
1060
+ if (!$select.skipFocusser) {
1061
+ //Will lose focus only with certain targets
1062
+ var focusableControls = ['input','button','textarea','select'];
1063
+ var targetController = angular.element(e.target).controller('uiSelect'); //To check if target is other ui-select
1064
+ skipFocusser = targetController && targetController !== $select; //To check if target is other ui-select
1065
+ if (!skipFocusser) skipFocusser = ~focusableControls.indexOf(e.target.tagName.toLowerCase()); //Check if target is input, button or textarea
1066
+ } else {
1067
+ skipFocusser = true;
1068
+ }
883
1069
  $select.close(skipFocusser);
884
1070
  scope.$digest();
885
1071
  }
@@ -978,7 +1164,100 @@ uis.directive('uiSelect',
978
1164
  element[0].style.left = '';
979
1165
  element[0].style.top = '';
980
1166
  element[0].style.width = originalWidth;
1167
+
1168
+ // Set focus back on to the moved element
1169
+ $select.setFocus();
981
1170
  }
1171
+
1172
+ // Hold on to a reference to the .ui-select-dropdown element for direction support.
1173
+ var dropdown = null,
1174
+ directionUpClassName = 'direction-up';
1175
+
1176
+ // Support changing the direction of the dropdown if there isn't enough space to render it.
1177
+ scope.$watch('$select.open', function() {
1178
+
1179
+ if ($select.dropdownPosition === 'auto' || $select.dropdownPosition === 'up'){
1180
+ scope.calculateDropdownPos();
1181
+ }
1182
+
1183
+ });
1184
+
1185
+ var setDropdownPosUp = function(offset, offsetDropdown){
1186
+
1187
+ offset = offset || uisOffset(element);
1188
+ offsetDropdown = offsetDropdown || uisOffset(dropdown);
1189
+
1190
+ dropdown[0].style.position = 'absolute';
1191
+ dropdown[0].style.top = (offsetDropdown.height * -1) + 'px';
1192
+ element.addClass(directionUpClassName);
1193
+
1194
+ };
1195
+
1196
+ var setDropdownPosDown = function(offset, offsetDropdown){
1197
+
1198
+ element.removeClass(directionUpClassName);
1199
+
1200
+ offset = offset || uisOffset(element);
1201
+ offsetDropdown = offsetDropdown || uisOffset(dropdown);
1202
+
1203
+ dropdown[0].style.position = '';
1204
+ dropdown[0].style.top = '';
1205
+
1206
+ };
1207
+
1208
+ scope.calculateDropdownPos = function(){
1209
+
1210
+ if ($select.open) {
1211
+ dropdown = angular.element(element).querySelectorAll('.ui-select-dropdown');
1212
+ if (dropdown.length === 0) {
1213
+ return;
1214
+ }
1215
+
1216
+ // Hide the dropdown so there is no flicker until $timeout is done executing.
1217
+ dropdown[0].style.opacity = 0;
1218
+
1219
+ // Delay positioning the dropdown until all choices have been added so its height is correct.
1220
+ $timeout(function(){
1221
+
1222
+ if ($select.dropdownPosition === 'up'){
1223
+ //Go UP
1224
+ setDropdownPosUp();
1225
+
1226
+ }else{ //AUTO
1227
+
1228
+ element.removeClass(directionUpClassName);
1229
+
1230
+ var offset = uisOffset(element);
1231
+ var offsetDropdown = uisOffset(dropdown);
1232
+
1233
+ //https://code.google.com/p/chromium/issues/detail?id=342307#c4
1234
+ var scrollTop = $document[0].documentElement.scrollTop || $document[0].body.scrollTop; //To make it cross browser (blink, webkit, IE, Firefox).
1235
+
1236
+ // Determine if the direction of the dropdown needs to be changed.
1237
+ if (offset.top + offset.height + offsetDropdown.height > scrollTop + $document[0].documentElement.clientHeight) {
1238
+ //Go UP
1239
+ setDropdownPosUp(offset, offsetDropdown);
1240
+ }else{
1241
+ //Go DOWN
1242
+ setDropdownPosDown(offset, offsetDropdown);
1243
+ }
1244
+
1245
+ }
1246
+
1247
+ // Display the dropdown once it has been positioned.
1248
+ dropdown[0].style.opacity = 1;
1249
+ });
1250
+ } else {
1251
+ if (dropdown === null || dropdown.length === 0) {
1252
+ return;
1253
+ }
1254
+
1255
+ // Reset the position of the dropdown.
1256
+ dropdown[0].style.position = '';
1257
+ dropdown[0].style.top = '';
1258
+ element.removeClass(directionUpClassName);
1259
+ }
1260
+ };
982
1261
  };
983
1262
  }
984
1263
  };
@@ -991,6 +1270,9 @@ uis.directive('uiSelectMatch', ['uiSelectConfig', function(uiSelectConfig) {
991
1270
  replace: true,
992
1271
  transclude: true,
993
1272
  templateUrl: function(tElement) {
1273
+ // Needed so the uiSelect can detect the transcluded content
1274
+ tElement.addClass('ui-select-match');
1275
+
994
1276
  // Gets theme attribute from parent (ui-select)
995
1277
  var theme = tElement.parent().attr('theme') || uiSelectConfig.theme;
996
1278
  var multi = tElement.parent().attr('multiple');
@@ -1028,7 +1310,10 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
1028
1310
  $select = $scope.$select,
1029
1311
  ngModel;
1030
1312
 
1031
- //Wait for link fn to inject it
1313
+ if (angular.isUndefined($select.selected))
1314
+ $select.selected = [];
1315
+
1316
+ //Wait for link fn to inject it
1032
1317
  $scope.$evalAsync(function(){ ngModel = $scope.ngModel; });
1033
1318
 
1034
1319
  ctrl.activeMatchIndex = -1;
@@ -1040,7 +1325,7 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
1040
1325
 
1041
1326
  ctrl.refreshComponent = function(){
1042
1327
  //Remove already selected items
1043
- //e.g. When user clicks on a selection, the selected array changes and
1328
+ //e.g. When user clicks on a selection, the selected array changes and
1044
1329
  //the dropdown should remove that item
1045
1330
  $select.refreshItems();
1046
1331
  $select.sizeSearchInput();
@@ -1075,7 +1360,7 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
1075
1360
 
1076
1361
  ctrl.getPlaceholder = function(){
1077
1362
  //Refactor single?
1078
- if($select.selected.length) return;
1363
+ if($select.selected && $select.selected.length) return;
1079
1364
  return $select.placeholder;
1080
1365
  };
1081
1366
 
@@ -1097,6 +1382,11 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
1097
1382
  //Input that will handle focus
1098
1383
  $select.focusInput = $select.searchInput;
1099
1384
 
1385
+ //Properly check for empty if set to multiple
1386
+ ngModel.$isEmpty = function(value) {
1387
+ return !value || value.length === 0;
1388
+ };
1389
+
1100
1390
  //From view --> model
1101
1391
  ngModel.$parsers.unshift(function () {
1102
1392
  var locals = {},
@@ -1124,10 +1414,13 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
1124
1414
  locals[$select.parserResult.itemName] = list[p];
1125
1415
  result = $select.parserResult.modelMapper(scope, locals);
1126
1416
  if($select.parserResult.trackByExp){
1127
- var matches = /\.(.+)/.exec($select.parserResult.trackByExp);
1128
- if(matches.length>0 && result[matches[1]] == value[matches[1]]){
1129
- resultMultiple.unshift(list[p]);
1130
- return true;
1417
+ var propsItemNameMatches = /(\w*)\./.exec($select.parserResult.trackByExp);
1418
+ var matches = /\.([^\s]+)/.exec($select.parserResult.trackByExp);
1419
+ if(propsItemNameMatches && propsItemNameMatches.length > 0 && propsItemNameMatches[1] == $select.parserResult.itemName){
1420
+ if(matches && matches.length>0 && result[matches[1]] == value[matches[1]]){
1421
+ resultMultiple.unshift(list[p]);
1422
+ return true;
1423
+ }
1131
1424
  }
1132
1425
  }
1133
1426
  if (angular.equals(result,value)){
@@ -1139,7 +1432,7 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
1139
1432
  };
1140
1433
  if (!inputValue) return resultMultiple; //If ngModel was undefined
1141
1434
  for (var k = inputValue.length - 1; k >= 0; k--) {
1142
- //Check model array of currently selected items
1435
+ //Check model array of currently selected items
1143
1436
  if (!checkFnMultiple($select.selected, inputValue[k])){
1144
1437
  //Check model array of all items available
1145
1438
  if (!checkFnMultiple(data, inputValue[k])){
@@ -1150,8 +1443,8 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
1150
1443
  }
1151
1444
  return resultMultiple;
1152
1445
  });
1153
-
1154
- //Watch for external model changes
1446
+
1447
+ //Watch for external model changes
1155
1448
  scope.$watchCollection(function(){ return ngModel.$modelValue; }, function(newValue, oldValue) {
1156
1449
  if (oldValue != newValue){
1157
1450
  ngModel.$modelValue = null; //Force scope model value and ngModel value to be out of sync to re-run formatters
@@ -1170,10 +1463,14 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
1170
1463
  }
1171
1464
  }
1172
1465
  $select.selected = ngModel.$viewValue;
1466
+ $selectMultiple.refreshComponent();
1173
1467
  scope.$evalAsync(); //To force $digest
1174
1468
  };
1175
1469
 
1176
1470
  scope.$on('uis:select', function (event, item) {
1471
+ if($select.selected.length >= $select.limit) {
1472
+ return;
1473
+ }
1177
1474
  $select.selected.push(item);
1178
1475
  $selectMultiple.updateModel();
1179
1476
  });
@@ -1309,9 +1606,19 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
1309
1606
  stashArr = stashArr.slice(1,stashArr.length);
1310
1607
  }
1311
1608
  newItem = $select.tagging.fct($select.search);
1312
- newItem.isTag = true;
1313
- // verify the the tag doesn't match the value of an existing item
1314
- if ( stashArr.filter( function (origItem) { return angular.equals( origItem, $select.tagging.fct($select.search) ); } ).length > 0 ) {
1609
+ // verify the new tag doesn't match the value of a possible selection choice or an already selected item.
1610
+ if (
1611
+ stashArr.some(function (origItem) {
1612
+ return angular.equals(origItem, $select.tagging.fct($select.search));
1613
+ }) ||
1614
+ $select.selected.some(function (origItem) {
1615
+ return angular.equals(origItem, newItem);
1616
+ })
1617
+ ) {
1618
+ scope.$evalAsync(function () {
1619
+ $select.activeIndex = 0;
1620
+ $select.items = items;
1621
+ });
1315
1622
  return;
1316
1623
  }
1317
1624
  newItem.isTag = true;
@@ -1399,9 +1706,11 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
1399
1706
  // handle the object tagging implementation
1400
1707
  } else {
1401
1708
  var mockObj = tempArr[i];
1402
- mockObj.isTag = true;
1709
+ if (angular.isObject(mockObj)) {
1710
+ mockObj.isTag = true;
1711
+ }
1403
1712
  if ( angular.equals(mockObj, needle) ) {
1404
- dupeIndex = i;
1713
+ dupeIndex = i;
1405
1714
  }
1406
1715
  }
1407
1716
  }
@@ -1418,6 +1727,7 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
1418
1727
  }
1419
1728
  };
1420
1729
  }]);
1730
+
1421
1731
  uis.directive('uiSelectSingle', ['$timeout','$compile', function($timeout, $compile) {
1422
1732
  return {
1423
1733
  restrict: 'EA',
@@ -1545,10 +1855,10 @@ uis.directive('uiSelectSingle', ['$timeout','$compile', function($timeout, $comp
1545
1855
  // Make multiple matches sortable
1546
1856
  uis.directive('uiSelectSort', ['$timeout', 'uiSelectConfig', 'uiSelectMinErr', function($timeout, uiSelectConfig, uiSelectMinErr) {
1547
1857
  return {
1548
- require: '^uiSelect',
1858
+ require: '^^uiSelect',
1549
1859
  link: function(scope, element, attrs, $select) {
1550
1860
  if (scope[attrs.uiSelectSort] === null) {
1551
- throw uiSelectMinErr('sort', "Expected a list to sort");
1861
+ throw uiSelectMinErr('sort', 'Expected a list to sort');
1552
1862
  }
1553
1863
 
1554
1864
  var options = angular.extend({
@@ -1556,26 +1866,26 @@ uis.directive('uiSelectSort', ['$timeout', 'uiSelectConfig', 'uiSelectMinErr', f
1556
1866
  },
1557
1867
  scope.$eval(attrs.uiSelectSortOptions));
1558
1868
 
1559
- var axis = options.axis,
1560
- draggingClassName = 'dragging',
1561
- droppingClassName = 'dropping',
1562
- droppingBeforeClassName = 'dropping-before',
1563
- droppingAfterClassName = 'dropping-after';
1869
+ var axis = options.axis;
1870
+ var draggingClassName = 'dragging';
1871
+ var droppingClassName = 'dropping';
1872
+ var droppingBeforeClassName = 'dropping-before';
1873
+ var droppingAfterClassName = 'dropping-after';
1564
1874
 
1565
1875
  scope.$watch(function(){
1566
1876
  return $select.sortable;
1567
- }, function(n){
1568
- if (n) {
1877
+ }, function(newValue){
1878
+ if (newValue) {
1569
1879
  element.attr('draggable', true);
1570
1880
  } else {
1571
1881
  element.removeAttr('draggable');
1572
1882
  }
1573
1883
  });
1574
1884
 
1575
- element.on('dragstart', function(e) {
1885
+ element.on('dragstart', function(event) {
1576
1886
  element.addClass(draggingClassName);
1577
1887
 
1578
- (e.dataTransfer || e.originalEvent.dataTransfer).setData('text/plain', scope.$index);
1888
+ (event.dataTransfer || event.originalEvent.dataTransfer).setData('text', scope.$index.toString());
1579
1889
  });
1580
1890
 
1581
1891
  element.on('dragend', function() {
@@ -1587,10 +1897,10 @@ uis.directive('uiSelectSort', ['$timeout', 'uiSelectConfig', 'uiSelectMinErr', f
1587
1897
  this.splice(to, 0, this.splice(from, 1)[0]);
1588
1898
  };
1589
1899
 
1590
- var dragOverHandler = function(e) {
1591
- e.preventDefault();
1900
+ var dragOverHandler = function(event) {
1901
+ event.preventDefault();
1592
1902
 
1593
- var offset = axis === 'vertical' ? e.offsetY || e.layerY || (e.originalEvent ? e.originalEvent.offsetY : 0) : e.offsetX || e.layerX || (e.originalEvent ? e.originalEvent.offsetX : 0);
1903
+ var offset = axis === 'vertical' ? event.offsetY || event.layerY || (event.originalEvent ? event.originalEvent.offsetY : 0) : event.offsetX || event.layerX || (event.originalEvent ? event.originalEvent.offsetX : 0);
1594
1904
 
1595
1905
  if (offset < (this[axis === 'vertical' ? 'offsetHeight' : 'offsetWidth'] / 2)) {
1596
1906
  element.removeClass(droppingAfterClassName);
@@ -1604,10 +1914,10 @@ uis.directive('uiSelectSort', ['$timeout', 'uiSelectConfig', 'uiSelectMinErr', f
1604
1914
 
1605
1915
  var dropTimeout;
1606
1916
 
1607
- var dropHandler = function(e) {
1608
- e.preventDefault();
1917
+ var dropHandler = function(event) {
1918
+ event.preventDefault();
1609
1919
 
1610
- var droppedItemIndex = parseInt((e.dataTransfer || e.originalEvent.dataTransfer).getData('text/plain'), 10);
1920
+ var droppedItemIndex = parseInt((event.dataTransfer || event.originalEvent.dataTransfer).getData('text'), 10);
1611
1921
 
1612
1922
  // prevent event firing multiple times in firefox
1613
1923
  $timeout.cancel(dropTimeout);
@@ -1617,9 +1927,9 @@ uis.directive('uiSelectSort', ['$timeout', 'uiSelectConfig', 'uiSelectMinErr', f
1617
1927
  };
1618
1928
 
1619
1929
  var _dropHandler = function(droppedItemIndex) {
1620
- var theList = scope.$eval(attrs.uiSelectSort),
1621
- itemToMove = theList[droppedItemIndex],
1622
- newIndex = null;
1930
+ var theList = scope.$eval(attrs.uiSelectSort);
1931
+ var itemToMove = theList[droppedItemIndex];
1932
+ var newIndex = null;
1623
1933
 
1624
1934
  if (element.hasClass(droppingBeforeClassName)) {
1625
1935
  if (droppedItemIndex < scope.$index) {
@@ -1664,8 +1974,8 @@ uis.directive('uiSelectSort', ['$timeout', 'uiSelectConfig', 'uiSelectMinErr', f
1664
1974
  element.on('drop', dropHandler);
1665
1975
  });
1666
1976
 
1667
- element.on('dragleave', function(e) {
1668
- if (e.target != element) {
1977
+ element.on('dragleave', function(event) {
1978
+ if (event.target != element) {
1669
1979
  return;
1670
1980
  }
1671
1981
  element.removeClass(droppingClassName);
@@ -1701,18 +2011,58 @@ uis.service('uisRepeatParser', ['uiSelectMinErr','$parse', function(uiSelectMinE
1701
2011
  */
1702
2012
  self.parse = function(expression) {
1703
2013
 
1704
- var match = expression.match(/^\s*(?:([\s\S]+?)\s+as\s+)?([\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/);
2014
+
2015
+ var match;
2016
+ //var isObjectCollection = /\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)/.test(expression);
2017
+ // If an array is used as collection
2018
+
2019
+ // if (isObjectCollection){
2020
+ // 000000000000000000000000000000111111111000000000000000222222222222220033333333333333333333330000444444444444444444000000000000000055555555555000000000000000000000066666666600000000
2021
+ match = expression.match(/^\s*(?:([\s\S]+?)\s+as\s+)?(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+(\s*[\s\S]+?)?(?:\s+track\s+by\s+([\s\S]+?))?\s*$/);
2022
+
2023
+ // 1 Alias
2024
+ // 2 Item
2025
+ // 3 Key on (key,value)
2026
+ // 4 Value on (key,value)
2027
+ // 5 Source expression (including filters)
2028
+ // 6 Track by
1705
2029
 
1706
2030
  if (!match) {
1707
2031
  throw uiSelectMinErr('iexp', "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",
1708
2032
  expression);
1709
2033
  }
2034
+
2035
+ var source = match[5],
2036
+ filters = '';
2037
+
2038
+ // When using (key,value) ui-select requires filters to be extracted, since the object
2039
+ // is converted to an array for $select.items
2040
+ // (in which case the filters need to be reapplied)
2041
+ if (match[3]) {
2042
+ // Remove any enclosing parenthesis
2043
+ source = match[5].replace(/(^\()|(\)$)/g, '');
2044
+ // match all after | but not after ||
2045
+ var filterMatch = match[5].match(/^\s*(?:[\s\S]+?)(?:[^\|]|\|\|)+([\s\S]*)\s*$/);
2046
+ if(filterMatch && filterMatch[1].trim()) {
2047
+ filters = filterMatch[1];
2048
+ source = source.replace(filters, '');
2049
+ }
2050
+ }
1710
2051
 
1711
2052
  return {
1712
- itemName: match[2], // (lhs) Left-hand side,
1713
- source: $parse(match[3]),
1714
- trackByExp: match[4],
1715
- modelMapper: $parse(match[1] || match[2])
2053
+ itemName: match[4] || match[2], // (lhs) Left-hand side,
2054
+ keyName: match[3], //for (key, value) syntax
2055
+ source: $parse(source),
2056
+ filters: filters,
2057
+ trackByExp: match[6],
2058
+ modelMapper: $parse(match[1] || match[4] || match[2]),
2059
+ repeatExpression: function (grouped) {
2060
+ var expression = this.itemName + ' in ' + (grouped ? '$group.items' : '$select.items');
2061
+ if (this.trackByExp) {
2062
+ expression += ' track by ' + this.trackByExp;
2063
+ }
2064
+ return expression;
2065
+ }
1716
2066
  };
1717
2067
 
1718
2068
  };
@@ -1721,17 +2071,10 @@ uis.service('uisRepeatParser', ['uiSelectMinErr','$parse', function(uiSelectMinE
1721
2071
  return '$group in $select.groups';
1722
2072
  };
1723
2073
 
1724
- self.getNgRepeatExpression = function(itemName, source, trackByExp, grouped) {
1725
- var expression = itemName + ' in ' + (grouped ? '$group.items' : source);
1726
- if (trackByExp) {
1727
- expression += ' track by ' + trackByExp;
1728
- }
1729
- return expression;
1730
- };
1731
2074
  }]);
1732
2075
 
1733
2076
  }());
1734
- angular.module("ui.select").run(["$templateCache", function($templateCache) {$templateCache.put("bootstrap/choices.tpl.html","<ul class=\"ui-select-choices ui-select-choices-content dropdown-menu\" role=\"listbox\" ng-show=\"$select.items.length > 0\"><li class=\"ui-select-choices-group\" id=\"ui-select-choices-{{ $select.generatedId }}\"><div class=\"divider\" ng-show=\"$select.isGrouped && $index > 0\"></div><div ng-show=\"$select.isGrouped\" class=\"ui-select-choices-group-label dropdown-header\" ng-bind=\"$group.name\"></div><div id=\"ui-select-choices-row-{{ $select.generatedId }}-{{$index}}\" class=\"ui-select-choices-row\" ng-class=\"{active: $select.isActive(this), disabled: $select.isDisabled(this)}\" role=\"option\"><a href=\"javascript:void(0)\" class=\"ui-select-choices-row-inner\"></a></div></li></ul>");
2077
+ angular.module("ui.select").run(["$templateCache", function($templateCache) {$templateCache.put("bootstrap/choices.tpl.html","<ul class=\"ui-select-choices ui-select-choices-content ui-select-dropdown dropdown-menu\" role=\"listbox\" ng-show=\"$select.open\"><li class=\"ui-select-choices-group\" id=\"ui-select-choices-{{ $select.generatedId }}\"><div class=\"divider\" ng-show=\"$select.isGrouped && $index > 0\"></div><div ng-show=\"$select.isGrouped\" class=\"ui-select-choices-group-label dropdown-header\" ng-bind=\"$group.name\"></div><div id=\"ui-select-choices-row-{{ $select.generatedId }}-{{$index}}\" class=\"ui-select-choices-row\" ng-class=\"{active: $select.isActive(this), disabled: $select.isDisabled(this)}\" role=\"option\"><a href=\"\" class=\"ui-select-choices-row-inner\"></a></div></li></ul>");
1735
2078
  $templateCache.put("bootstrap/match-multiple.tpl.html","<span class=\"ui-select-match\"><span ng-repeat=\"$item in $select.selected\"><span class=\"ui-select-match-item btn btn-default btn-xs\" tabindex=\"-1\" type=\"button\" ng-disabled=\"$select.disabled\" ng-click=\"$selectMultiple.activeMatchIndex = $index;\" ng-class=\"{\'btn-primary\':$selectMultiple.activeMatchIndex === $index, \'select-locked\':$select.isLocked(this, $index)}\" ui-select-sort=\"$select.selected\"><span class=\"close ui-select-match-close\" ng-hide=\"$select.disabled\" ng-click=\"$selectMultiple.removeChoice($index)\">&nbsp;&times;</span> <span uis-transclude-append=\"\"></span></span></span></span>");
1736
2079
  $templateCache.put("bootstrap/match.tpl.html","<div class=\"ui-select-match\" ng-hide=\"$select.open\" ng-disabled=\"$select.disabled\" ng-class=\"{\'btn-default-focus\':$select.focus}\"><span tabindex=\"-1\" class=\"btn btn-default form-control ui-select-toggle\" aria-label=\"{{ $select.baseTitle }} activate\" ng-disabled=\"$select.disabled\" ng-click=\"$select.activate()\" style=\"outline: 0;\"><span ng-show=\"$select.isEmpty()\" class=\"ui-select-placeholder text-muted\">{{$select.placeholder}}</span> <span ng-hide=\"$select.isEmpty()\" class=\"ui-select-match-text pull-left\" ng-class=\"{\'ui-select-allow-clear\': $select.allowClear && !$select.isEmpty()}\" ng-transclude=\"\"></span> <i class=\"caret pull-right\" ng-click=\"$select.toggle($event)\"></i> <a ng-show=\"$select.allowClear && !$select.isEmpty()\" aria-label=\"{{ $select.baseTitle }} clear\" style=\"margin-right: 10px\" ng-click=\"$select.clear($event)\" class=\"btn btn-xs btn-link pull-right\"><i class=\"glyphicon glyphicon-remove\" aria-hidden=\"true\"></i></a></span></div>");
1737
2080
  $templateCache.put("bootstrap/select-multiple.tpl.html","<div class=\"ui-select-container ui-select-multiple ui-select-bootstrap dropdown form-control\" ng-class=\"{open: $select.open}\"><div><div class=\"ui-select-match\"></div><input type=\"text\" autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" class=\"ui-select-search input-xs\" placeholder=\"{{$selectMultiple.getPlaceholder()}}\" ng-disabled=\"$select.disabled\" ng-hide=\"$select.disabled\" ng-click=\"$select.activate()\" ng-model=\"$select.search\" role=\"combobox\" aria-label=\"{{ $select.baseTitle }}\" ondrop=\"return false;\"></div><div class=\"ui-select-choices\"></div></div>");
@@ -1739,8 +2082,8 @@ $templateCache.put("bootstrap/select.tpl.html","<div class=\"ui-select-container
1739
2082
  $templateCache.put("select2/choices.tpl.html","<ul class=\"ui-select-choices ui-select-choices-content select2-results\"><li class=\"ui-select-choices-group\" ng-class=\"{\'select2-result-with-children\': $select.choiceGrouped($group) }\"><div ng-show=\"$select.choiceGrouped($group)\" class=\"ui-select-choices-group-label select2-result-label\" ng-bind=\"$group.name\"></div><ul role=\"listbox\" id=\"ui-select-choices-{{ $select.generatedId }}\" ng-class=\"{\'select2-result-sub\': $select.choiceGrouped($group), \'select2-result-single\': !$select.choiceGrouped($group) }\"><li role=\"option\" id=\"ui-select-choices-row-{{ $select.generatedId }}-{{$index}}\" class=\"ui-select-choices-row\" ng-class=\"{\'select2-highlighted\': $select.isActive(this), \'select2-disabled\': $select.isDisabled(this)}\"><div class=\"select2-result-label ui-select-choices-row-inner\"></div></li></ul></li></ul>");
1740
2083
  $templateCache.put("select2/match-multiple.tpl.html","<span class=\"ui-select-match\"><li class=\"ui-select-match-item select2-search-choice\" ng-repeat=\"$item in $select.selected\" ng-class=\"{\'select2-search-choice-focus\':$selectMultiple.activeMatchIndex === $index, \'select2-locked\':$select.isLocked(this, $index)}\" ui-select-sort=\"$select.selected\"><span uis-transclude-append=\"\"></span> <a href=\"javascript:;\" class=\"ui-select-match-close select2-search-choice-close\" ng-click=\"$selectMultiple.removeChoice($index)\" tabindex=\"-1\"></a></li></span>");
1741
2084
  $templateCache.put("select2/match.tpl.html","<a class=\"select2-choice ui-select-match\" ng-class=\"{\'select2-default\': $select.isEmpty()}\" ng-click=\"$select.toggle($event)\" aria-label=\"{{ $select.baseTitle }} select\"><span ng-show=\"$select.isEmpty()\" class=\"select2-chosen\">{{$select.placeholder}}</span> <span ng-hide=\"$select.isEmpty()\" class=\"select2-chosen\" ng-transclude=\"\"></span> <abbr ng-if=\"$select.allowClear && !$select.isEmpty()\" class=\"select2-search-choice-close\" ng-click=\"$select.clear($event)\"></abbr> <span class=\"select2-arrow ui-select-toggle\"><b></b></span></a>");
1742
- $templateCache.put("select2/select-multiple.tpl.html","<div class=\"ui-select-container ui-select-multiple select2 select2-container select2-container-multi\" ng-class=\"{\'select2-container-active select2-dropdown-open open\': $select.open, \'select2-container-disabled\': $select.disabled}\"><ul class=\"select2-choices\"><span class=\"ui-select-match\"></span><li class=\"select2-search-field\"><input type=\"text\" autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" role=\"combobox\" aria-expanded=\"true\" aria-owns=\"ui-select-choices-{{ $select.generatedId }}\" aria-label=\"{{ $select.baseTitle }}\" aria-activedescendant=\"ui-select-choices-row-{{ $select.generatedId }}-{{ $select.activeIndex }}\" class=\"select2-input ui-select-search\" placeholder=\"{{$selectMultiple.getPlaceholder()}}\" ng-disabled=\"$select.disabled\" ng-hide=\"$select.disabled\" ng-model=\"$select.search\" ng-click=\"$select.activate()\" style=\"width: 34px;\" ondrop=\"return false;\"></li></ul><div class=\"select2-drop select2-with-searchbox select2-drop-active\" ng-class=\"{\'select2-display-none\': !$select.open}\"><div class=\"ui-select-choices\"></div></div></div>");
1743
- $templateCache.put("select2/select.tpl.html","<div class=\"ui-select-container select2 select2-container\" ng-class=\"{\'select2-container-active select2-dropdown-open open\': $select.open, \'select2-container-disabled\': $select.disabled, \'select2-container-active\': $select.focus, \'select2-allowclear\': $select.allowClear && !$select.isEmpty()}\"><div class=\"ui-select-match\"></div><div class=\"select2-drop select2-with-searchbox select2-drop-active\" ng-class=\"{\'select2-display-none\': !$select.open}\"><div class=\"select2-search\" ng-show=\"$select.searchEnabled\"><input type=\"text\" autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" role=\"combobox\" aria-expanded=\"true\" aria-owns=\"ui-select-choices-{{ $select.generatedId }}\" aria-label=\"{{ $select.baseTitle }}\" aria-activedescendant=\"ui-select-choices-row-{{ $select.generatedId }}-{{ $select.activeIndex }}\" class=\"ui-select-search select2-input\" ng-model=\"$select.search\"></div><div class=\"ui-select-choices\"></div></div></div>");
1744
- $templateCache.put("selectize/choices.tpl.html","<div ng-show=\"$select.open\" class=\"ui-select-choices selectize-dropdown single\"><div class=\"ui-select-choices-content selectize-dropdown-content\"><div class=\"ui-select-choices-group optgroup\" role=\"listbox\"><div ng-show=\"$select.isGrouped\" class=\"ui-select-choices-group-label optgroup-header\" ng-bind=\"$group.name\"></div><div role=\"option\" class=\"ui-select-choices-row\" ng-class=\"{active: $select.isActive(this), disabled: $select.isDisabled(this)}\"><div class=\"option ui-select-choices-row-inner\" data-selectable=\"\"></div></div></div></div></div>");
2085
+ $templateCache.put("select2/select-multiple.tpl.html","<div class=\"ui-select-container ui-select-multiple select2 select2-container select2-container-multi\" ng-class=\"{\'select2-container-active select2-dropdown-open open\': $select.open, \'select2-container-disabled\': $select.disabled}\"><ul class=\"select2-choices\"><span class=\"ui-select-match\"></span><li class=\"select2-search-field\"><input type=\"text\" autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" role=\"combobox\" aria-expanded=\"true\" aria-owns=\"ui-select-choices-{{ $select.generatedId }}\" aria-label=\"{{ $select.baseTitle }}\" aria-activedescendant=\"ui-select-choices-row-{{ $select.generatedId }}-{{ $select.activeIndex }}\" class=\"select2-input ui-select-search\" placeholder=\"{{$selectMultiple.getPlaceholder()}}\" ng-disabled=\"$select.disabled\" ng-hide=\"$select.disabled\" ng-model=\"$select.search\" ng-click=\"$select.activate()\" style=\"width: 34px;\" ondrop=\"return false;\"></li></ul><div class=\"ui-select-dropdown select2-drop select2-with-searchbox select2-drop-active\" ng-class=\"{\'select2-display-none\': !$select.open}\"><div class=\"ui-select-choices\"></div></div></div>");
2086
+ $templateCache.put("select2/select.tpl.html","<div class=\"ui-select-container select2 select2-container\" ng-class=\"{\'select2-container-active select2-dropdown-open open\': $select.open, \'select2-container-disabled\': $select.disabled, \'select2-container-active\': $select.focus, \'select2-allowclear\': $select.allowClear && !$select.isEmpty()}\"><div class=\"ui-select-match\"></div><div class=\"ui-select-dropdown select2-drop select2-with-searchbox select2-drop-active\" ng-class=\"{\'select2-display-none\': !$select.open}\"><div class=\"select2-search\" ng-show=\"$select.searchEnabled\"><input type=\"text\" autocomplete=\"off\" autocorrect=\"false\" autocapitalize=\"off\" spellcheck=\"false\" role=\"combobox\" aria-expanded=\"true\" aria-owns=\"ui-select-choices-{{ $select.generatedId }}\" aria-label=\"{{ $select.baseTitle }}\" aria-activedescendant=\"ui-select-choices-row-{{ $select.generatedId }}-{{ $select.activeIndex }}\" class=\"ui-select-search select2-input\" ng-model=\"$select.search\"></div><div class=\"ui-select-choices\"></div></div></div>");
2087
+ $templateCache.put("selectize/choices.tpl.html","<div ng-show=\"$select.open\" class=\"ui-select-choices ui-select-dropdown selectize-dropdown single\"><div class=\"ui-select-choices-content selectize-dropdown-content\"><div class=\"ui-select-choices-group optgroup\" role=\"listbox\"><div ng-show=\"$select.isGrouped\" class=\"ui-select-choices-group-label optgroup-header\" ng-bind=\"$group.name\"></div><div role=\"option\" class=\"ui-select-choices-row\" ng-class=\"{active: $select.isActive(this), disabled: $select.isDisabled(this)}\"><div class=\"option ui-select-choices-row-inner\" data-selectable=\"\"></div></div></div></div></div>");
1745
2088
  $templateCache.put("selectize/match.tpl.html","<div ng-hide=\"($select.open || $select.isEmpty())\" class=\"ui-select-match\" ng-transclude=\"\"></div>");
1746
- $templateCache.put("selectize/select.tpl.html","<div class=\"ui-select-container selectize-control single\" ng-class=\"{\'open\': $select.open}\"><div class=\"selectize-input\" ng-class=\"{\'focus\': $select.open, \'disabled\': $select.disabled, \'selectize-focus\' : $select.focus}\" ng-click=\"$select.activate()\"><div class=\"ui-select-match\"></div><input type=\"text\" autocomplete=\"off\" tabindex=\"-1\" class=\"ui-select-search ui-select-toggle\" ng-click=\"$select.toggle($event)\" placeholder=\"{{$select.placeholder}}\" ng-model=\"$select.search\" ng-hide=\"!$select.searchEnabled || ($select.selected && !$select.open)\" ng-disabled=\"$select.disabled\" aria-label=\"{{ $select.baseTitle }}\"></div><div class=\"ui-select-choices\"></div></div>");}]);
2089
+ $templateCache.put("selectize/select.tpl.html","<div class=\"ui-select-container selectize-control single\" ng-class=\"{\'open\': $select.open}\"><div class=\"selectize-input\" ng-class=\"{\'focus\': $select.open, \'disabled\': $select.disabled, \'selectize-focus\' : $select.focus}\" ng-click=\"$select.open && !$select.searchEnabled ? $select.toggle($event) : $select.activate()\"><div class=\"ui-select-match\"></div><input type=\"text\" autocomplete=\"off\" tabindex=\"-1\" class=\"ui-select-search ui-select-toggle\" ng-click=\"$select.toggle($event)\" placeholder=\"{{$select.placeholder}}\" ng-model=\"$select.search\" ng-hide=\"!$select.searchEnabled || ($select.selected && !$select.open)\" ng-disabled=\"$select.disabled\" aria-label=\"{{ $select.baseTitle }}\"></div><div class=\"ui-select-choices\"></div></div>");}]);