fanforce-plugin-factory 0.41.0 → 1.6.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (260) hide show
  1. data/.gitignore +1 -0
  2. data/.ruby-version +1 -0
  3. data/.yardopts +5 -0
  4. data/.yardopts.rb +1 -0
  5. data/Gemfile +9 -0
  6. data/README.md +40 -75
  7. data/Rakefile +61 -4
  8. data/fanforce-plugin-factory.gemspec +21 -21
  9. data/lib/fanforce/plugin_factory.rb +16 -58
  10. data/lib/fanforce/plugin_factory/Rakefile +51 -0
  11. data/lib/fanforce/plugin_factory/Routes.rb +33 -0
  12. data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/_bootstrap.scss +2 -0
  13. data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/_common.scss +1 -0
  14. data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/_directives.scss +7 -0
  15. data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/_font-awesome.scss +1 -0
  16. data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/_ui-select.scss +3 -0
  17. data/lib/fanforce/plugin_factory/{assets/lib/common → asset_framework/plugin_factory/bootstrap}/_bootstrap-overrides.scss +2 -0
  18. data/lib/fanforce/plugin_factory/{assets/lib/vendors/bootstrap/css → asset_framework/plugin_factory/bootstrap}/bootstrap.css +2 -2
  19. data/lib/fanforce/plugin_factory/{assets/lib/vendors/bootstrap/js → asset_framework/plugin_factory/bootstrap}/bootstrap.js +0 -0
  20. data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/bootstrap/bootstrap.min.css +7 -0
  21. data/lib/fanforce/plugin_factory/{assets/lib/vendors/bootstrap/js → asset_framework/plugin_factory/bootstrap}/bootstrap.min.js +0 -0
  22. data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/bootstrap/glyphicons-halflings-regular.eot +0 -0
  23. data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/bootstrap/glyphicons-halflings-regular.svg +229 -0
  24. data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/bootstrap/glyphicons-halflings-regular.ttf +0 -0
  25. data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/bootstrap/glyphicons-halflings-regular.woff +0 -0
  26. data/lib/fanforce/plugin_factory/{assets/lib → asset_framework/plugin_factory}/common/_mixins.scss +2 -1
  27. data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/directives.coffee +1 -0
  28. data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/directives/error/_error.scss +6 -0
  29. data/lib/fanforce/plugin_factory/{assets/lib/common/module-error → asset_framework/plugin_factory/directives/error}/arrow-left.png +0 -0
  30. data/lib/fanforce/plugin_factory/{assets/lib/common/module-error → asset_framework/plugin_factory/directives/error}/icon-error.png +0 -0
  31. data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/directives/initiative-footer/_initiative-footer.coffee +16 -0
  32. data/lib/fanforce/plugin_factory/{assets/lib/common/_module-add-initiative-footer.scss → asset_framework/plugin_factory/directives/initiative-footer/_initiative-footer.scss} +4 -1
  33. data/lib/fanforce/plugin_factory/{assets/lib/common/_module-initiative-searcher.scss → asset_framework/plugin_factory/directives/initiative-searcher/_initiative-searcher.scss} +14 -13
  34. data/lib/fanforce/plugin_factory/{assets/lib/common/module-initiative-searcher → asset_framework/plugin_factory/directives/initiative-searcher}/icon-search.png +0 -0
  35. data/lib/fanforce/plugin_factory/{assets/lib/common/module-initiative-searcher → asset_framework/plugin_factory/directives/initiative-searcher}/spinner.gif +0 -0
  36. data/lib/fanforce/plugin_factory/{assets/lib/common/module-initiative-searcher → asset_framework/plugin_factory/directives/initiative-searcher}/sprite-arrows.png +0 -0
  37. data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/directives/loading/_loading.coffee +4 -0
  38. data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/directives/loading/_loading.scss +4 -0
  39. data/lib/fanforce/plugin_factory/{assets/js/add_source_popup.js → asset_framework/plugin_factory/directives/saving-to-server/_saving-to-server.coffee} +0 -0
  40. data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/directives/saving-to-server/_saving-to-server.scss +6 -0
  41. data/lib/fanforce/plugin_factory/{assets/lib/common/module-saving-initiative → asset_framework/plugin_factory/directives/saving-to-server}/spinner.gif +0 -0
  42. data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/directives/start-arrow/_start-arrow.coffee +8 -0
  43. data/lib/fanforce/plugin_factory/{assets/lib/common/_module-start-here.scss → asset_framework/plugin_factory/directives/start-arrow/_start-arrow.scss} +5 -4
  44. data/lib/fanforce/plugin_factory/{assets/lib/common/module-start-here → asset_framework/plugin_factory/directives/start-arrow}/arrow.png +0 -0
  45. data/lib/fanforce/plugin_factory/{assets/lib/common/_module-video-thumbnail.scss → asset_framework/plugin_factory/directives/video-thumbnail/_video-thumbnail.scss} +4 -4
  46. data/lib/fanforce/plugin_factory/{assets/lib/common/module-video-thumbnail → asset_framework/plugin_factory/directives/video-thumbnail}/icon-play.png +0 -0
  47. data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/font-awesome.coffee +1 -0
  48. data/lib/fanforce/plugin_factory/{assets/lib/vendors/font-awesome/font → asset_framework/plugin_factory/font-awesome}/FontAwesome.otf +0 -0
  49. data/lib/fanforce/plugin_factory/{assets/lib/vendors/font-awesome/css → asset_framework/plugin_factory/font-awesome}/font-awesome.css +2 -2
  50. data/lib/fanforce/plugin_factory/{assets/lib/vendors/font-awesome/css → asset_framework/plugin_factory/font-awesome}/font-awesome.min.css +0 -0
  51. data/lib/fanforce/plugin_factory/{assets/lib/vendors/font-awesome/font → asset_framework/plugin_factory/font-awesome}/fontawesome-webfont.eot +0 -0
  52. data/lib/fanforce/plugin_factory/{assets/lib/vendors/font-awesome/font → asset_framework/plugin_factory/font-awesome}/fontawesome-webfont.svg +0 -0
  53. data/lib/fanforce/plugin_factory/{assets/lib/vendors/font-awesome/font → asset_framework/plugin_factory/font-awesome}/fontawesome-webfont.ttf +0 -0
  54. data/lib/fanforce/plugin_factory/{assets/lib/vendors/font-awesome/font → asset_framework/plugin_factory/font-awesome}/fontawesome-webfont.woff +0 -0
  55. data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/lib.coffee +1 -0
  56. data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/lib/ng-focus-blur.js +68 -0
  57. data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/lib/ng-visible.js +7 -0
  58. data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/ui-select.coffee +1 -0
  59. data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/ui-select/select.css +171 -0
  60. data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/ui-select/select.js +1281 -0
  61. data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/ui-select/select_override.scss +1 -0
  62. data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/ui-select/selectize.default.css +443 -0
  63. data/lib/fanforce/plugin_factory/cli.rb +5 -0
  64. data/lib/fanforce/plugin_factory/cli/lib/bitbucket.rb +77 -0
  65. data/lib/fanforce/plugin_factory/cli/lib/bundler.rb +21 -0
  66. data/lib/fanforce/plugin_factory/cli/lib/env.rb +96 -0
  67. data/lib/fanforce/plugin_factory/cli/lib/git.rb +59 -0
  68. data/lib/fanforce/plugin_factory/cli/lib/heroku.rb +94 -0
  69. data/lib/fanforce/plugin_factory/cli/lib/iron.rb +71 -0
  70. data/lib/fanforce/plugin_factory/cli/lib/pow.rb +46 -0
  71. data/lib/fanforce/plugin_factory/cli/lib/scaffolding.rb +74 -0
  72. data/lib/fanforce/plugin_factory/cli/lib/scaffolding_file.rb +510 -0
  73. data/lib/fanforce/plugin_factory/cli/lib/uranium.rb +77 -0
  74. data/lib/fanforce/plugin_factory/cli/lib/utils.rb +57 -0
  75. data/lib/fanforce/plugin_factory/cli/scripts/config.rb +9 -0
  76. data/lib/fanforce/plugin_factory/cli/scripts/create.rb +64 -0
  77. data/lib/fanforce/plugin_factory/cli/scripts/destroy.rb +61 -0
  78. data/lib/fanforce/plugin_factory/cli/scripts/diff.rb +156 -0
  79. data/lib/fanforce/plugin_factory/cli/scripts/push.rb +88 -0
  80. data/lib/fanforce/plugin_factory/cli/scripts/restart.rb +41 -0
  81. data/lib/fanforce/plugin_factory/cli/scripts/setup.rb +70 -0
  82. data/lib/fanforce/plugin_factory/cli/scripts/update.rb +132 -0
  83. data/lib/fanforce/plugin_factory/cli_directory_of_plugins.rb +51 -0
  84. data/lib/fanforce/plugin_factory/cli_single_plugin.rb +52 -0
  85. data/lib/fanforce/plugin_factory/controllers/base_controller.rb +15 -0
  86. data/lib/fanforce/plugin_factory/core_config.rb +94 -0
  87. data/lib/fanforce/plugin_factory/directive_views/initiative-footer.haml +8 -0
  88. data/lib/fanforce/plugin_factory/load.rb +7 -0
  89. data/lib/fanforce/plugin_factory/load_iron_worker.rb +2 -0
  90. data/lib/fanforce/plugin_factory/load_sprockets.rb +2 -0
  91. data/lib/fanforce/plugin_factory/plugin.rb +60 -0
  92. data/lib/fanforce/plugin_factory/scaffolding/._.gitignore.registry +1 -0
  93. data/lib/fanforce/plugin_factory/scaffolding/._Gemfile.registry +3 -0
  94. data/lib/fanforce/plugin_factory/scaffolding/._Rakefile.registry +3 -0
  95. data/lib/fanforce/plugin_factory/scaffolding/._config.json.registry +2 -0
  96. data/lib/fanforce/plugin_factory/scaffolding/._config.ru.registry +4 -0
  97. data/lib/fanforce/plugin_factory/scaffolding/._favicon.ico.registry +1 -0
  98. data/lib/fanforce/plugin_factory/scaffolding/._robots.txt.registry +3 -0
  99. data/lib/fanforce/plugin_factory/scaffolding/.gitignore +27 -0
  100. data/lib/fanforce/plugin_factory/scaffolding/Gemfile +9 -0
  101. data/lib/fanforce/plugin_factory/scaffolding/Rakefile +7 -0
  102. data/lib/fanforce/plugin_factory/scaffolding/Routes.rb +67 -0
  103. data/lib/fanforce/plugin_factory/scaffolding/assets/css/._fembedded.scss.registry +4 -0
  104. data/lib/fanforce/plugin_factory/scaffolding/assets/css/._promotional.scss.registry +4 -0
  105. data/lib/fanforce/plugin_factory/scaffolding/assets/css/._visitor.scss.registry +4 -0
  106. data/lib/fanforce/plugin_factory/scaffolding/assets/css/fembedded.scss +24 -0
  107. data/lib/fanforce/plugin_factory/scaffolding/assets/css/promotional.scss +33 -0
  108. data/lib/fanforce/plugin_factory/scaffolding/assets/css/visitor.scss +61 -0
  109. data/lib/fanforce/plugin_factory/scaffolding/assets/img/._icon-16.png.registry +1 -0
  110. data/lib/fanforce/plugin_factory/scaffolding/assets/img/._icon-32.png.registry +1 -0
  111. data/lib/fanforce/plugin_factory/scaffolding/assets/img/._icon-42.png.registry +1 -0
  112. data/lib/fanforce/plugin_factory/scaffolding/assets/img/._marketplace.png.registry +1 -0
  113. data/lib/fanforce/plugin_factory/{assets → scaffolding/assets}/img/icon-16.png +0 -0
  114. data/lib/fanforce/plugin_factory/{assets → scaffolding/assets}/img/icon-32.png +0 -0
  115. data/lib/fanforce/plugin_factory/{assets → scaffolding/assets}/img/icon-42.png +0 -0
  116. data/lib/fanforce/plugin_factory/scaffolding/assets/img/marketplace.png +0 -0
  117. data/lib/fanforce/plugin_factory/scaffolding/assets/img/promotional/._fanforce_bg.png.registry +1 -0
  118. data/lib/fanforce/plugin_factory/scaffolding/assets/img/promotional/._icon-42.png.registry +1 -0
  119. data/lib/fanforce/plugin_factory/scaffolding/assets/img/promotional/._icon-plus.png.registry +1 -0
  120. data/lib/fanforce/plugin_factory/{assets/lib → scaffolding/assets/img}/promotional/fanforce_bg.png +0 -0
  121. data/lib/fanforce/plugin_factory/{assets/lib → scaffolding/assets/img}/promotional/icon-42.png +0 -0
  122. data/lib/fanforce/plugin_factory/scaffolding/assets/img/promotional/icon-plus.png +0 -0
  123. data/lib/fanforce/plugin_factory/scaffolding/assets/js/._fembedded-app.coffee.registry +5 -0
  124. data/lib/fanforce/plugin_factory/scaffolding/assets/js/._fembedded.js.registry +3 -0
  125. data/lib/fanforce/plugin_factory/scaffolding/assets/js/._promotional.js.registry +3 -0
  126. data/lib/fanforce/plugin_factory/scaffolding/assets/js/fembedded-app.coffee +11 -0
  127. data/lib/fanforce/plugin_factory/scaffolding/assets/js/fembedded.js +12 -0
  128. data/lib/fanforce/plugin_factory/scaffolding/assets/js/lib/._cookie.coffee.registry +3 -0
  129. data/lib/fanforce/plugin_factory/scaffolding/assets/js/lib/._filters.coffee.registry +3 -0
  130. data/lib/fanforce/plugin_factory/scaffolding/assets/js/lib/._utils.coffee.registry +3 -0
  131. data/lib/fanforce/plugin_factory/scaffolding/assets/js/lib/cookie.coffee +24 -0
  132. data/lib/fanforce/plugin_factory/scaffolding/assets/js/lib/filters.coffee +9 -0
  133. data/lib/fanforce/plugin_factory/scaffolding/assets/js/lib/utils.coffee +40 -0
  134. data/lib/fanforce/plugin_factory/scaffolding/assets/js/promotional.js +4 -0
  135. data/lib/fanforce/plugin_factory/scaffolding/config.json +24 -0
  136. data/lib/fanforce/plugin_factory/scaffolding/config.ru +8 -0
  137. data/lib/fanforce/plugin_factory/{public → scaffolding}/favicon.ico +0 -0
  138. data/lib/fanforce/plugin_factory/scaffolding/layouts/._fembedded.haml.registry +4 -0
  139. data/lib/fanforce/plugin_factory/scaffolding/layouts/._promotional.haml.registry +2 -0
  140. data/lib/fanforce/plugin_factory/scaffolding/layouts/._visitor.haml.registry +6 -0
  141. data/lib/fanforce/plugin_factory/scaffolding/layouts/fembedded.haml +26 -0
  142. data/lib/fanforce/plugin_factory/{layouts → scaffolding/layouts}/promotional.haml +6 -6
  143. data/lib/fanforce/plugin_factory/{layouts/engage.haml → scaffolding/layouts/visitor.haml} +10 -7
  144. data/lib/fanforce/plugin_factory/scaffolding/robots.txt +7 -0
  145. data/lib/fanforce/plugin_factory/scaffolding/views/._index.haml.registry +3 -0
  146. data/lib/fanforce/plugin_factory/{views → scaffolding/views}/index.haml +13 -7
  147. data/lib/fanforce/plugin_factory/sinatra/_load.rb +87 -0
  148. data/lib/fanforce/plugin_factory/sinatra/error_handling.rb +48 -0
  149. data/lib/fanforce/plugin_factory/sinatra/helper_routes/com_behavior.rb +19 -0
  150. data/lib/fanforce/plugin_factory/sinatra/helper_routes/com_broadcaster.rb +7 -0
  151. data/lib/fanforce/plugin_factory/sinatra/helper_routes/com_connector.rb +11 -0
  152. data/lib/fanforce/plugin_factory/sinatra/helper_routes/com_identifier.rb +3 -0
  153. data/lib/fanforce/plugin_factory/sinatra/helper_routes/com_js_widget.rb +8 -0
  154. data/lib/fanforce/plugin_factory/sinatra/helper_routes/plugin.rb +50 -0
  155. data/lib/fanforce/plugin_factory/sinatra/helpers/assets.rb +23 -0
  156. data/lib/fanforce/plugin_factory/sinatra/helpers/css_frameworks.rb +70 -0
  157. data/lib/fanforce/plugin_factory/sinatra/helpers/fanforce.rb +18 -0
  158. data/lib/fanforce/plugin_factory/{config → sinatra}/helpers/json.rb +2 -2
  159. data/lib/fanforce/plugin_factory/sinatra/helpers/ractive.rb +45 -0
  160. data/lib/fanforce/plugin_factory/sprockets/compiler.rb +5 -11
  161. data/lib/fanforce/plugin_factory/sprockets/hacks.rb +2 -2
  162. data/lib/fanforce/plugin_factory/version.rb +2 -2
  163. metadata +201 -195
  164. data/.rbenv-gemsets +0 -1
  165. data/.rbenv-version +0 -1
  166. data/lib/fanforce/plugin_factory.rake +0 -72
  167. data/lib/fanforce/plugin_factory/_init_sinatra.rb +0 -54
  168. data/lib/fanforce/plugin_factory/assets/css/add_edit_initiative.scss +0 -1
  169. data/lib/fanforce/plugin_factory/assets/css/add_source.scss +0 -1
  170. data/lib/fanforce/plugin_factory/assets/css/convert_pending_initiative.scss +0 -1
  171. data/lib/fanforce/plugin_factory/assets/css/engage.scss +0 -1
  172. data/lib/fanforce/plugin_factory/assets/css/new_message.scss +0 -1
  173. data/lib/fanforce/plugin_factory/assets/css/promotional.scss +0 -1
  174. data/lib/fanforce/plugin_factory/assets/css/source_details.scss +0 -1
  175. data/lib/fanforce/plugin_factory/assets/js/add_edit_initiative.js +0 -1
  176. data/lib/fanforce/plugin_factory/assets/js/add_source.js +0 -1
  177. data/lib/fanforce/plugin_factory/assets/js/convert_pending_initiative.js +0 -1
  178. data/lib/fanforce/plugin_factory/assets/js/engage.js +0 -1
  179. data/lib/fanforce/plugin_factory/assets/js/new_message.js +0 -1
  180. data/lib/fanforce/plugin_factory/assets/js/promotional.js +0 -2
  181. data/lib/fanforce/plugin_factory/assets/js/source_details.js +0 -0
  182. data/lib/fanforce/plugin_factory/assets/lib/common/_module-error.scss +0 -11
  183. data/lib/fanforce/plugin_factory/assets/lib/common/_module-page-loading.scss +0 -1
  184. data/lib/fanforce/plugin_factory/assets/lib/common/_module-saving-initiative.scss +0 -6
  185. data/lib/fanforce/plugin_factory/assets/lib/common/_tags.scss +0 -1
  186. data/lib/fanforce/plugin_factory/assets/lib/common/_variables.scss +0 -27
  187. data/lib/fanforce/plugin_factory/assets/lib/common/broadcaster-divider-arrow.png +0 -0
  188. data/lib/fanforce/plugin_factory/assets/lib/common/icons/dropdown-arrow.png +0 -0
  189. data/lib/fanforce/plugin_factory/assets/lib/common/icons/initiative.png +0 -0
  190. data/lib/fanforce/plugin_factory/assets/lib/common/layouts/_add_edit_initiative.scss +0 -27
  191. data/lib/fanforce/plugin_factory/assets/lib/common/layouts/_add_source.scss +0 -18
  192. data/lib/fanforce/plugin_factory/assets/lib/common/layouts/_convert_pending_initiative.scss +0 -27
  193. data/lib/fanforce/plugin_factory/assets/lib/common/layouts/_engage.scss +0 -78
  194. data/lib/fanforce/plugin_factory/assets/lib/common/layouts/_new_message.scss +0 -24
  195. data/lib/fanforce/plugin_factory/assets/lib/common/layouts/_promotional.scss +0 -27
  196. data/lib/fanforce/plugin_factory/assets/lib/common/layouts/_source_details.scss +0 -17
  197. data/lib/fanforce/plugin_factory/assets/lib/common/layouts/add_edit_initiative.js +0 -6
  198. data/lib/fanforce/plugin_factory/assets/lib/common/layouts/add_source.js +0 -6
  199. data/lib/fanforce/plugin_factory/assets/lib/common/layouts/convert_pending_initiative.js +0 -6
  200. data/lib/fanforce/plugin_factory/assets/lib/common/layouts/engage.js +0 -0
  201. data/lib/fanforce/plugin_factory/assets/lib/common/layouts/new_message.js +0 -5
  202. data/lib/fanforce/plugin_factory/assets/lib/common/layouts/promotional.js +0 -1
  203. data/lib/fanforce/plugin_factory/assets/lib/common/layouts/source_details.js +0 -5
  204. data/lib/fanforce/plugin_factory/assets/lib/promotional/icon-behavior.png +0 -0
  205. data/lib/fanforce/plugin_factory/assets/lib/promotional/icon-broadcaster.png +0 -0
  206. data/lib/fanforce/plugin_factory/assets/lib/promotional/icon-data-connector.png +0 -0
  207. data/lib/fanforce/plugin_factory/assets/lib/promotional/icon-data-processor.png +0 -0
  208. data/lib/fanforce/plugin_factory/assets/lib/promotional/icon-identifier.png +0 -0
  209. data/lib/fanforce/plugin_factory/assets/lib/vendors/bootstrap-datepicker/datepicker.css +0 -7
  210. data/lib/fanforce/plugin_factory/assets/lib/vendors/bootstrap-datepicker/datepicker.js +0 -454
  211. data/lib/fanforce/plugin_factory/assets/lib/vendors/bootstrap-timepicker/timepicker.css +0 -82
  212. data/lib/fanforce/plugin_factory/assets/lib/vendors/bootstrap-timepicker/timepicker.js +0 -803
  213. data/lib/fanforce/plugin_factory/assets/lib/vendors/bootstrap/css/bootstrap.min.css +0 -7
  214. data/lib/fanforce/plugin_factory/assets/lib/vendors/bootstrap/img/glyphicons-halflings-regular.eot +0 -0
  215. data/lib/fanforce/plugin_factory/assets/lib/vendors/bootstrap/img/glyphicons-halflings-regular.svg +0 -0
  216. data/lib/fanforce/plugin_factory/assets/lib/vendors/bootstrap/img/glyphicons-halflings-regular.ttf +0 -0
  217. data/lib/fanforce/plugin_factory/assets/lib/vendors/bootstrap/img/glyphicons-halflings-regular.woff +0 -0
  218. data/lib/fanforce/plugin_factory/assets/lib/vendors/chosen/_chosen_override.scss +0 -6
  219. data/lib/fanforce/plugin_factory/assets/lib/vendors/chosen/chosen-sprite.png +0 -0
  220. data/lib/fanforce/plugin_factory/assets/lib/vendors/chosen/chosen-sprite@2x.png +0 -0
  221. data/lib/fanforce/plugin_factory/assets/lib/vendors/chosen/chosen.jquery.js +0 -1166
  222. data/lib/fanforce/plugin_factory/assets/lib/vendors/chosen/chosen.scss +0 -434
  223. data/lib/fanforce/plugin_factory/assets/lib/vendors/jquery/jquery-1.10.2.js +0 -9789
  224. data/lib/fanforce/plugin_factory/assets/lib/vendors/jquery/jquery.inputHint.js +0 -154
  225. data/lib/fanforce/plugin_factory/assets/lib/vendors/jquery/jquery.tmpl.debug.js +0 -484
  226. data/lib/fanforce/plugin_factory/assets/lib/vendors/knockout/knockout.custom-handlers.coffee +0 -155
  227. data/lib/fanforce/plugin_factory/assets/lib/vendors/knockout/knockout.debug.js +0 -4469
  228. data/lib/fanforce/plugin_factory/assets/lib/vendors/knockout/knockout.min.js +0 -96
  229. data/lib/fanforce/plugin_factory/assets/lib/vendors/select2/_select2_override.scss +0 -47
  230. data/lib/fanforce/plugin_factory/assets/lib/vendors/select2/select2-spinner.gif +0 -0
  231. data/lib/fanforce/plugin_factory/assets/lib/vendors/select2/select2.png +0 -0
  232. data/lib/fanforce/plugin_factory/assets/lib/vendors/select2/select2.scss +0 -617
  233. data/lib/fanforce/plugin_factory/assets/lib/vendors/select2/select2_modified.js +0 -3225
  234. data/lib/fanforce/plugin_factory/assets/lib/vendors/select2/select2x2.png +0 -0
  235. data/lib/fanforce/plugin_factory/assets/lib/vendors/underscore/underscore.debug.js +0 -999
  236. data/lib/fanforce/plugin_factory/config/_error_handling.rb +0 -27
  237. data/lib/fanforce/plugin_factory/config/core_config.rb +0 -92
  238. data/lib/fanforce/plugin_factory/config/helpers/assets.rb +0 -72
  239. data/lib/fanforce/plugin_factory/config/helpers/fanforce.rb +0 -19
  240. data/lib/fanforce/plugin_factory/layouts/add_edit_initiative.haml +0 -19
  241. data/lib/fanforce/plugin_factory/layouts/add_source.haml +0 -19
  242. data/lib/fanforce/plugin_factory/layouts/convert_pending_initiative.haml +0 -19
  243. data/lib/fanforce/plugin_factory/layouts/new_message.haml +0 -19
  244. data/lib/fanforce/plugin_factory/layouts/source_details.haml +0 -19
  245. data/lib/fanforce/plugin_factory/public/robots.txt +0 -2
  246. data/lib/fanforce/plugin_factory/routes.rb +0 -48
  247. data/lib/fanforce/plugin_factory/routes_behavior.rb +0 -34
  248. data/lib/fanforce/plugin_factory/routes_broadcaster.rb +0 -9
  249. data/lib/fanforce/plugin_factory/routes_data_connector.rb +0 -21
  250. data/lib/fanforce/plugin_factory/routes_identifier.rb +0 -3
  251. data/lib/fanforce/plugin_factory/views/add_initiative.haml +0 -1
  252. data/lib/fanforce/plugin_factory/views/add_source.haml +0 -1
  253. data/lib/fanforce/plugin_factory/views/close_popup.haml +0 -8
  254. data/lib/fanforce/plugin_factory/views/convert_pending_initiative.haml +0 -1
  255. data/lib/fanforce/plugin_factory/views/edit_initiative.haml +0 -1
  256. data/lib/fanforce/plugin_factory/views/engage.haml +0 -1
  257. data/lib/fanforce/plugin_factory/views/new_message.haml +0 -1
  258. data/lib/fanforce/plugin_factory/views/source_details.haml +0 -1
  259. data/lib/fanforce/plugin_factory/views/widget_tmpls.haml +0 -1
  260. data/lib/fanforce/plugin_factory_workers.rb +0 -2
@@ -0,0 +1,4 @@
1
+ App.directive('pageLoading', [() ->
2
+ restrict: 'E',
3
+ link: (($scope, $element, attrs) ->)
4
+ ])
@@ -0,0 +1,4 @@
1
+ $module_path: '/assets/plugin_factory/directives/loading';
2
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3
+
4
+ loading { display:block; color:#cccccc; font-size:15px; text-align: center; padding-top:45px; }
@@ -0,0 +1,6 @@
1
+ $module_path: '/assets/plugin_factory/directives/saving-to-server';
2
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3
+
4
+ saving-to-server { text-align: center; height:100px; position:absolute; left:0; margin-top:80px; width:100%; color:#b9cddc; text-shadow:#ffffff 1px 1px 0; display:none; text-align:center;
5
+ .spinner { width:64px; height:64px; background:url(#{$module_path}/spinner.gif) 0 0 no-repeat; margin:0 auto 20px; }
6
+ }
@@ -0,0 +1,8 @@
1
+ App.directive('startArrow', [() ->
2
+ restrict: 'E',
3
+ transclude: true,
4
+ template: '<div class="arrow"></div><div class="text" ng-transclude></div>'
5
+ link: (($scope, $element, attrs) ->
6
+
7
+ )
8
+ ])
@@ -1,6 +1,7 @@
1
- $module_path: '/assets/common/module-start-here';
2
- /////////////////////////////////////////////////////////////////////////////////////////
3
- .module-start-here { padding: 10px 0 0 30px; position:relative;
1
+ $module_path: '/assets/plugin_factory/directives/start-arrow';
2
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3
+
4
+ start-arrow { padding: 10px 0 0 30px; position:relative;
4
5
  .arrow { width: 114px; height: 61px; background:url(#{$module_path}/arrow.png) 6px center no-repeat;}
5
- .text { color: #afb7c8; font-weight: bold; position:absolute; top: 60px; left: 155px; }
6
+ .text { color: #afb7c8; font-weight: bold; position:absolute; top: 78px; left: 125px; white-space: nowrap; }
6
7
  }
@@ -1,7 +1,7 @@
1
- $module_path: '/assets/common/module-video-thumbnail';
2
- /////////////////////////////////////////////////////////////////////////////////////////
1
+ $module_path: '/assets/plugin_factory/directives/video-thumbnail';
2
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3
3
 
4
- .module-video-thumbnail { display:inline-block; position:relative;
4
+ video-thumbnail { display:inline-block; position:relative;
5
5
  .video-thumb { vertical-align:bottom; height:77px; width:138px; overflow:hidden; @include border-radius(2px); display:inline-block; position:relative;
6
6
  img { top:0; min-height:77px; min-width:138px; display:block; position:absolute; left:0; }
7
7
  }
@@ -12,4 +12,4 @@ $module_path: '/assets/common/module-video-thumbnail';
12
12
  &:hover {
13
13
  .play { display:block; cursor:pointer; cursor:hand; }
14
14
  }
15
- }
15
+ }
@@ -0,0 +1 @@
1
+ #=require_tree ./font-awesome
@@ -27,8 +27,8 @@
27
27
  * -------------------------- */
28
28
  @font-face {
29
29
  font-family: 'FontAwesome';
30
- src: url('/assets/vendors/font-awesome/font/fontawesome-webfont.eot?v=3.2.1');
31
- src: url('/assets/vendors/font-awesome/font/fontawesome-webfont.eot?#iefix&v=3.2.1') format('embedded-opentype'), url('/assets/vendors/font-awesome/font/fontawesome-webfont.woff?v=3.2.1') format('woff'), url('/assets/vendors/font-awesome/font/fontawesome-webfont.ttf?v=3.2.1') format('truetype'), url('/assets/vendors/font-awesome/font/fontawesome-webfont.svg#fontawesomeregular?v=3.2.1') format('svg');
30
+ src: url('/assets/plugin_factory/font-awesome/fontawesome-webfont.eot?v=3.2.1');
31
+ src: url('/assets/plugin_factory/font-awesome/fontawesome-webfont.eot?#iefix&v=3.2.1') format('embedded-opentype'), url('/assets/plugin_factory/font-awesome/fontawesome-webfont.woff?v=3.2.1') format('woff'), url('/assets/plugin_factory/font-awesome/fontawesome-webfont.ttf?v=3.2.1') format('truetype'), url('/assets/plugin_factory/font-awesome/fontawesome-webfont.svg#fontawesomeregular?v=3.2.1') format('svg');
32
32
  font-weight: normal;
33
33
  font-style: normal;
34
34
  }
@@ -0,0 +1,68 @@
1
+ App.directive('ngFocus',function($parse,$timeout){
2
+ return function(scope,element,attrs){
3
+ var ngFocusGet = $parse(attrs.ngFocus);
4
+ var ngFocusSet = ngFocusGet.assign;
5
+ if (!ngFocusSet) {
6
+ throw Error("Non assignable expression");
7
+ }
8
+
9
+ var digesting = false;
10
+
11
+ var abortFocusing = false;
12
+ var unwatch = scope.$watch(attrs.ngFocus,function(newVal){
13
+ if(newVal){
14
+ $timeout(function(){
15
+ element[0].focus();
16
+ },0)
17
+ }
18
+ else {
19
+ $timeout(function(){
20
+ element[0].blur();
21
+ },0);
22
+ }
23
+ });
24
+
25
+
26
+ element.bind("blur",function(){
27
+
28
+ if(abortFocusing) return;
29
+
30
+ $timeout(function(){
31
+ ngFocusSet(scope,false);
32
+ },0);
33
+
34
+ });
35
+
36
+
37
+ var timerStarted = false;
38
+ var focusCount = 0;
39
+
40
+ function startTimer(){
41
+ $timeout(function(){
42
+ timerStarted = false;
43
+ if(focusCount > 3){
44
+ unwatch();
45
+ abortFocusing = true;
46
+ throw new Error("Aborting : ngFocus cannot be assigned to the same variable with multiple elements");
47
+ }
48
+ },200);
49
+ }
50
+
51
+ element.bind("focus",function(){
52
+
53
+ if(abortFocusing) return;
54
+
55
+ if(!timerStarted){
56
+ timerStarted = true;
57
+ focusCount = 0;
58
+ startTimer();
59
+ }
60
+ focusCount++;
61
+
62
+ $timeout(function(){
63
+ ngFocusSet(scope,true);
64
+ },0);
65
+
66
+ });
67
+ };
68
+ });
@@ -0,0 +1,7 @@
1
+ App.directive('ngVisible', function() {
2
+ return function(scope, element, attr) {
3
+ scope.$watch(attr.ngVisible, function(visible) {
4
+ element.css('display', visible ? '' : 'none');
5
+ });
6
+ };
7
+ });
@@ -0,0 +1 @@
1
+ #=require_tree ./ui-select
@@ -0,0 +1,171 @@
1
+ /*!
2
+ * ui-select
3
+ * http://github.com/angular-ui/ui-select
4
+ * Version: 0.8.3 - 2014-11-25T22:50:54.099Z
5
+ * License: MIT
6
+ */
7
+
8
+
9
+ /* Style when highlighting a search. */
10
+ .ui-select-highlight {
11
+ font-weight: bold;
12
+ }
13
+
14
+ .ui-select-offscreen {
15
+ clip: rect(0 0 0 0) !important;
16
+ width: 1px !important;
17
+ height: 1px !important;
18
+ border: 0 !important;
19
+ margin: 0 !important;
20
+ padding: 0 !important;
21
+ overflow: hidden !important;
22
+ position: absolute !important;
23
+ outline: 0 !important;
24
+ left: 0px !important;
25
+ top: 0px !important;
26
+ }
27
+
28
+ /* Select2 theme */
29
+
30
+ /* Mark invalid Select2 */
31
+ .ng-dirty.ng-invalid > a.select2-choice {
32
+ border-color: #D44950;
33
+ }
34
+
35
+ .select2-result-single {
36
+ padding-left: 0;
37
+ }
38
+
39
+ .select2-locked > .select2-search-choice-close{
40
+ display:none;
41
+ }
42
+
43
+ /* Selectize theme */
44
+
45
+ /* Helper class to show styles when focus */
46
+ .selectize-input.selectize-focus{
47
+ border-color: #007FBB !important;
48
+ }
49
+
50
+ /* Fix input width for Selectize theme */
51
+ .selectize-control > .selectize-input > input {
52
+ width: 100%;
53
+ }
54
+
55
+ /* Fix dropdown width for Selectize theme */
56
+ .selectize-control > .selectize-dropdown {
57
+ width: 100%;
58
+ }
59
+
60
+ /* Mark invalid Selectize */
61
+ .ng-dirty.ng-invalid > div.selectize-input {
62
+ border-color: #D44950;
63
+ }
64
+
65
+
66
+ /* Bootstrap theme */
67
+
68
+ /* Helper class to show styles when focus */
69
+ .btn-default-focus {
70
+ color: #333;
71
+ background-color: #EBEBEB;
72
+ border-color: #ADADAD;
73
+ text-decoration: none;
74
+ outline: 5px auto -webkit-focus-ring-color;
75
+ outline-offset: -2px;
76
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6);
77
+ }
78
+
79
+
80
+ /* Fix Bootstrap dropdown position when inside a input-group */
81
+ .input-group > .ui-select-bootstrap.dropdown {
82
+ /* Instead of relative */
83
+ position: static;
84
+ }
85
+
86
+ .input-group > .ui-select-bootstrap > input.ui-select-search.form-control {
87
+ border-radius: 4px; /* FIXME hardcoded value :-/ */
88
+ border-top-right-radius: 0;
89
+ border-bottom-right-radius: 0;
90
+ }
91
+
92
+ .ui-select-bootstrap > .ui-select-match {
93
+ /* Instead of center because of .btn */
94
+ text-align: left;
95
+ }
96
+
97
+ .ui-select-bootstrap > .ui-select-match > .caret {
98
+ position: absolute;
99
+ top: 45%;
100
+ right: 15px;
101
+ }
102
+
103
+ /* See Scrollable Menu with Bootstrap 3 http://stackoverflow.com/questions/19227496 */
104
+ .ui-select-bootstrap > .ui-select-choices {
105
+ width: 100%;
106
+ height: auto;
107
+ max-height: 200px;
108
+ overflow-x: hidden;
109
+ }
110
+
111
+ .ui-select-multiple.ui-select-bootstrap {
112
+ height: auto;
113
+ padding: .3em;
114
+ }
115
+
116
+ .ui-select-multiple.ui-select-bootstrap input.ui-select-search {
117
+ background-color: transparent !important; /* To prevent double background when disabled */
118
+ border: none;
119
+ outline: none;
120
+ height: 1.666666em;
121
+ }
122
+
123
+ .ui-select-multiple.ui-select-bootstrap .ui-select-match .close {
124
+ font-size: 1.6em;
125
+ line-height: 0.75;
126
+ }
127
+
128
+ .ui-select-multiple.ui-select-bootstrap .ui-select-match-item{
129
+ outline: 0;
130
+ }
131
+
132
+ .ui-select-bootstrap .ui-select-choices-row>a {
133
+ display: block;
134
+ padding: 3px 20px;
135
+ clear: both;
136
+ font-weight: 400;
137
+ line-height: 1.42857143;
138
+ color: #333;
139
+ white-space: nowrap;
140
+ }
141
+
142
+ .ui-select-bootstrap .ui-select-choices-row>a:hover, .ui-select-bootstrap .ui-select-choices-row>a:focus {
143
+ text-decoration: none;
144
+ color: #262626;
145
+ background-color: #f5f5f5;
146
+ }
147
+
148
+ .ui-select-bootstrap .ui-select-choices-row.active>a {
149
+ color: #fff;
150
+ text-decoration: none;
151
+ outline: 0;
152
+ background-color: #428bca;
153
+ }
154
+
155
+ .ui-select-bootstrap .ui-select-choices-row.disabled>a,
156
+ .ui-select-bootstrap .ui-select-choices-row.active.disabled>a {
157
+ color: #777;
158
+ cursor: not-allowed;
159
+ background-color: #fff;
160
+ }
161
+
162
+ /* fix hide/show angular animation */
163
+ .ui-select-match.ng-hide-add,
164
+ .ui-select-search.ng-hide-add {
165
+ display: none !important;
166
+ }
167
+
168
+ /* Mark invalid Bootstrap */
169
+ .ui-select-bootstrap.ng-dirty.ng-invalid > button.btn.ui-select-match {
170
+ border-color: #D44950;
171
+ }
@@ -0,0 +1,1281 @@
1
+ /*!
2
+ * ui-select
3
+ * http://github.com/angular-ui/ui-select
4
+ * Version: 0.8.3 - 2014-11-30T19:28:47.691Z
5
+ * License: MIT
6
+ */
7
+
8
+
9
+ (function () {
10
+ "use strict";
11
+
12
+ var KEY = {
13
+ TAB: 9,
14
+ ENTER: 13,
15
+ ESC: 27,
16
+ SPACE: 32,
17
+ LEFT: 37,
18
+ UP: 38,
19
+ RIGHT: 39,
20
+ DOWN: 40,
21
+ SHIFT: 16,
22
+ CTRL: 17,
23
+ ALT: 18,
24
+ PAGE_UP: 33,
25
+ PAGE_DOWN: 34,
26
+ HOME: 36,
27
+ END: 35,
28
+ BACKSPACE: 8,
29
+ DELETE: 46,
30
+ COMMAND: 91,
31
+
32
+ MAP: { 91 : "COMMAND", 8 : "BACKSPACE" , 9 : "TAB" , 13 : "ENTER" , 16 : "SHIFT" , 17 : "CTRL" , 18 : "ALT" , 19 : "PAUSEBREAK" , 20 : "CAPSLOCK" , 27 : "ESC" , 32 : "SPACE" , 33 : "PAGE_UP", 34 : "PAGE_DOWN" , 35 : "END" , 36 : "HOME" , 37 : "LEFT" , 38 : "UP" , 39 : "RIGHT" , 40 : "DOWN" , 43 : "+" , 44 : "PRINTSCREEN" , 45 : "INSERT" , 46 : "DELETE", 48 : "0" , 49 : "1" , 50 : "2" , 51 : "3" , 52 : "4" , 53 : "5" , 54 : "6" , 55 : "7" , 56 : "8" , 57 : "9" , 59 : ";", 61 : "=" , 65 : "A" , 66 : "B" , 67 : "C" , 68 : "D" , 69 : "E" , 70 : "F" , 71 : "G" , 72 : "H" , 73 : "I" , 74 : "J" , 75 : "K" , 76 : "L", 77 : "M" , 78 : "N" , 79 : "O" , 80 : "P" , 81 : "Q" , 82 : "R" , 83 : "S" , 84 : "T" , 85 : "U" , 86 : "V" , 87 : "W" , 88 : "X" , 89 : "Y" , 90 : "Z", 96 : "0" , 97 : "1" , 98 : "2" , 99 : "3" , 100 : "4" , 101 : "5" , 102 : "6" , 103 : "7" , 104 : "8" , 105 : "9", 106 : "*" , 107 : "+" , 109 : "-" , 110 : "." , 111 : "/", 112 : "F1" , 113 : "F2" , 114 : "F3" , 115 : "F4" , 116 : "F5" , 117 : "F6" , 118 : "F7" , 119 : "F8" , 120 : "F9" , 121 : "F10" , 122 : "F11" , 123 : "F12", 144 : "NUMLOCK" , 145 : "SCROLLLOCK" , 186 : ";" , 187 : "=" , 188 : "SPACE" , 189 : "-" , 190 : "." , 191 : "/" , 192 : "`" , 219 : "[" , 220 : "\\" , 221 : "]" , 222 : "'"
33
+ },
34
+
35
+ isControl: function (e) {
36
+ var k = e.which;
37
+ switch (k) {
38
+ case KEY.COMMAND:
39
+ case KEY.SHIFT:
40
+ case KEY.CTRL:
41
+ case KEY.ALT:
42
+ return true;
43
+ }
44
+
45
+ if (e.metaKey) return true;
46
+
47
+ return false;
48
+ },
49
+ isFunctionKey: function (k) {
50
+ k = k.which ? k.which : k;
51
+ return k >= 112 && k <= 123;
52
+ },
53
+ isVerticalMovement: function (k){
54
+ return ~[KEY.UP, KEY.DOWN].indexOf(k);
55
+ },
56
+ isHorizontalMovement: function (k){
57
+ return ~[KEY.LEFT,KEY.RIGHT,KEY.BACKSPACE,KEY.DELETE].indexOf(k);
58
+ }
59
+ };
60
+
61
+ /**
62
+ * Add querySelectorAll() to jqLite.
63
+ *
64
+ * jqLite find() is limited to lookups by tag name.
65
+ * TODO This will change with future versions of AngularJS, to be removed when this happens
66
+ *
67
+ * See jqLite.find - why not use querySelectorAll? https://github.com/angular/angular.js/issues/3586
68
+ * See feat(jqLite): use querySelectorAll instead of getElementsByTagName in jqLite.find https://github.com/angular/angular.js/pull/3598
69
+ */
70
+ if (angular.element.prototype.querySelectorAll === undefined) {
71
+ angular.element.prototype.querySelectorAll = function(selector) {
72
+ return angular.element(this[0].querySelectorAll(selector));
73
+ };
74
+ }
75
+
76
+ angular.module('ui.select', [])
77
+
78
+ .constant('uiSelectConfig', {
79
+ theme: 'bootstrap',
80
+ searchEnabled: true,
81
+ placeholder: '', // Empty by default, like HTML tag <select>
82
+ refreshDelay: 1000, // In milliseconds
83
+ closeOnSelect: true
84
+ })
85
+
86
+ // See Rename minErr and make it accessible from outside https://github.com/angular/angular.js/issues/6913
87
+ .service('uiSelectMinErr', function() {
88
+ var minErr = angular.$$minErr('ui.select');
89
+ return function() {
90
+ var error = minErr.apply(this, arguments);
91
+ var message = error.message.replace(new RegExp('\nhttp://errors.angularjs.org/.*'), '');
92
+ return new Error(message);
93
+ };
94
+ })
95
+
96
+ /**
97
+ * Parses "repeat" attribute.
98
+ *
99
+ * Taken from AngularJS ngRepeat source code
100
+ * See https://github.com/angular/angular.js/blob/v1.2.15/src/ng/directive/ngRepeat.js#L211
101
+ *
102
+ * Original discussion about parsing "repeat" attribute instead of fully relying on ng-repeat:
103
+ * https://github.com/angular-ui/ui-select/commit/5dd63ad#commitcomment-5504697
104
+ */
105
+ .service('RepeatParser', ['uiSelectMinErr','$parse', function(uiSelectMinErr, $parse) {
106
+ var self = this;
107
+
108
+ /**
109
+ * Example:
110
+ * expression = "address in addresses | filter: {street: $select.search} track by $index"
111
+ * itemName = "address",
112
+ * source = "addresses | filter: {street: $select.search}",
113
+ * trackByExp = "$index",
114
+ */
115
+ self.parse = function(expression) {
116
+
117
+ var match = expression.match(/^\s*(?:([\s\S]+?)\s+as\s+)?([\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/);
118
+
119
+ if (!match) {
120
+ throw uiSelectMinErr('iexp', "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",
121
+ expression);
122
+ }
123
+
124
+ return {
125
+ itemName: match[2], // (lhs) Left-hand side,
126
+ source: $parse(match[3]),
127
+ trackByExp: match[4],
128
+ modelMapper: $parse(match[1] || match[2])
129
+ };
130
+
131
+ };
132
+
133
+ self.getGroupNgRepeatExpression = function() {
134
+ return '$group in $select.groups';
135
+ };
136
+
137
+ self.getNgRepeatExpression = function(itemName, source, trackByExp, grouped) {
138
+ var expression = itemName + ' in ' + (grouped ? '$group.items' : source);
139
+ if (trackByExp) {
140
+ expression += ' track by ' + trackByExp;
141
+ }
142
+ return expression;
143
+ };
144
+ }])
145
+
146
+ /**
147
+ * Contains ui-select "intelligence".
148
+ *
149
+ * The goal is to limit dependency on the DOM whenever possible and
150
+ * put as much logic in the controller (instead of the link functions) as possible so it can be easily tested.
151
+ */
152
+ .controller('uiSelectCtrl',
153
+ ['$scope', '$element', '$timeout', '$filter', 'RepeatParser', 'uiSelectMinErr', 'uiSelectConfig',
154
+ function($scope, $element, $timeout, $filter, RepeatParser, uiSelectMinErr, uiSelectConfig) {
155
+
156
+ var ctrl = this;
157
+
158
+ var EMPTY_SEARCH = '';
159
+
160
+ ctrl.placeholder = undefined;
161
+ ctrl.search = EMPTY_SEARCH;
162
+ ctrl.activeIndex = 0;
163
+ ctrl.activeMatchIndex = -1;
164
+ ctrl.items = [];
165
+ ctrl.selected = undefined;
166
+ ctrl.open = false;
167
+ ctrl.focus = false;
168
+ ctrl.focusser = undefined; //Reference to input element used to handle focus events
169
+ ctrl.disabled = undefined; // Initialized inside uiSelect directive link function
170
+ ctrl.searchEnabled = undefined; // Initialized inside uiSelect directive link function
171
+ ctrl.resetSearchInput = undefined; // Initialized inside uiSelect directive link function
172
+ ctrl.refreshDelay = undefined; // Initialized inside uiSelectChoices directive link function
173
+ ctrl.multiple = false; // Initialized inside uiSelect directive link function
174
+ ctrl.disableChoiceExpression = undefined; // Initialized inside uiSelect directive link function
175
+ ctrl.tagging = {isActivated: false, fct: undefined};
176
+ ctrl.taggingTokens = {isActivated: false, tokens: undefined};
177
+ ctrl.lockChoiceExpression = undefined; // Initialized inside uiSelect directive link function
178
+ ctrl.closeOnSelect = true; // Initialized inside uiSelect directive link function
179
+ ctrl.clickTriggeredSelect = false;
180
+ ctrl.$filter = $filter;
181
+
182
+ ctrl.isEmpty = function() {
183
+ return angular.isUndefined(ctrl.selected) || ctrl.selected === null || ctrl.selected === '';
184
+ };
185
+
186
+ var _searchInput = $element.querySelectorAll('input.ui-select-search');
187
+ if (_searchInput.length !== 1) {
188
+ throw uiSelectMinErr('searchInput', "Expected 1 input.ui-select-search but got '{0}'.", _searchInput.length);
189
+ }
190
+
191
+ // Most of the time the user does not want to empty the search input when in typeahead mode
192
+ function _resetSearchInput() {
193
+ if (ctrl.resetSearchInput || (ctrl.resetSearchInput === undefined && uiSelectConfig.resetSearchInput)) {
194
+ ctrl.search = EMPTY_SEARCH;
195
+ //reset activeIndex
196
+ if (ctrl.selected && ctrl.items.length && !ctrl.multiple) {
197
+ ctrl.activeIndex = ctrl.items.indexOf(ctrl.selected);
198
+ }
199
+ }
200
+ }
201
+
202
+ // When the user clicks on ui-select, displays the dropdown list
203
+ ctrl.activate = function(initSearchValue, avoidReset) {
204
+ if (!ctrl.disabled && !ctrl.open) {
205
+ if(!avoidReset) _resetSearchInput();
206
+ ctrl.focusser.prop('disabled', true); //Will reactivate it on .close()
207
+ ctrl.open = true;
208
+ ctrl.activeMatchIndex = -1;
209
+
210
+ ctrl.activeIndex = ctrl.activeIndex >= ctrl.items.length ? 0 : ctrl.activeIndex;
211
+
212
+ // ensure that the index is set to zero for tagging variants
213
+ // that where first option is auto-selected
214
+ if ( ctrl.activeIndex === -1 && ctrl.taggingLabel !== false ) {
215
+ ctrl.activeIndex = 0;
216
+ }
217
+
218
+ // Give it time to appear before focus
219
+ $timeout(function() {
220
+ ctrl.search = initSearchValue || ctrl.search;
221
+ _searchInput[0].focus();
222
+ });
223
+ }
224
+ };
225
+
226
+ ctrl.findGroupByName = function(name) {
227
+ return ctrl.groups && ctrl.groups.filter(function(group) {
228
+ return group.name === name;
229
+ })[0];
230
+ };
231
+
232
+ ctrl.parseRepeatAttr = function(repeatAttr, groupByExp) {
233
+ function updateGroups(items) {
234
+ ctrl.groups = [];
235
+ angular.forEach(items, function(item) {
236
+ var groupFn = $scope.$eval(groupByExp);
237
+ var groupName = angular.isFunction(groupFn) ? groupFn(item) : item[groupFn];
238
+ var group = ctrl.findGroupByName(groupName);
239
+ if(group) {
240
+ group.items.push(item);
241
+ }
242
+ else {
243
+ ctrl.groups.push({name: groupName, items: [item]});
244
+ }
245
+ });
246
+ ctrl.items = [];
247
+ ctrl.groups.forEach(function(group) {
248
+ ctrl.items = ctrl.items.concat(group.items);
249
+ });
250
+ }
251
+
252
+ function setPlainItems(items) {
253
+ ctrl.items = items;
254
+ }
255
+
256
+ var setItemsFn = groupByExp ? updateGroups : setPlainItems;
257
+
258
+ ctrl.parserResult = RepeatParser.parse(repeatAttr);
259
+
260
+ ctrl.isGrouped = !!groupByExp;
261
+ ctrl.itemProperty = ctrl.parserResult.itemName;
262
+
263
+ // See https://github.com/angular/angular.js/blob/v1.2.15/src/ng/directive/ngRepeat.js#L259
264
+ $scope.$watchCollection(ctrl.parserResult.source, function(items) {
265
+
266
+ if (items === undefined || items === null) {
267
+ // If the user specifies undefined or null => reset the collection
268
+ // Special case: items can be undefined if the user did not initialized the collection on the scope
269
+ // i.e $scope.addresses = [] is missing
270
+ ctrl.items = [];
271
+ } else {
272
+ if (!angular.isArray(items)) {
273
+ throw uiSelectMinErr('items', "Expected an array but got '{0}'.", items);
274
+ } else {
275
+ if (ctrl.multiple){
276
+ //Remove already selected items (ex: while searching)
277
+ var filteredItems = items.filter(function(i) {return ctrl.selected.indexOf(i) < 0;});
278
+ setItemsFn(filteredItems);
279
+ }else{
280
+ setItemsFn(items);
281
+ }
282
+ ctrl.ngModel.$modelValue = null; //Force scope model value and ngModel value to be out of sync to re-run formatters
283
+
284
+ }
285
+ }
286
+
287
+ });
288
+
289
+ if (ctrl.multiple){
290
+ //Remove already selected items
291
+ $scope.$watchCollection('$select.selected', function(selectedItems){
292
+ var data = ctrl.parserResult.source($scope);
293
+ if (!selectedItems.length) {
294
+ setItemsFn(data);
295
+ }else{
296
+ if ( data !== undefined ) {
297
+ var filteredItems = data.filter(function(i) {return selectedItems.indexOf(i) < 0;});
298
+ setItemsFn(filteredItems);
299
+ }
300
+ }
301
+ ctrl.sizeSearchInput();
302
+ });
303
+ }
304
+
305
+ };
306
+
307
+ var _refreshDelayPromise;
308
+
309
+ /**
310
+ * Typeahead mode: lets the user refresh the collection using his own function.
311
+ *
312
+ * See Expose $select.search for external / remote filtering https://github.com/angular-ui/ui-select/pull/31
313
+ */
314
+ ctrl.refresh = function(refreshAttr) {
315
+ if (refreshAttr !== undefined) {
316
+
317
+ // Debounce
318
+ // See https://github.com/angular-ui/bootstrap/blob/0.10.0/src/typeahead/typeahead.js#L155
319
+ // FYI AngularStrap typeahead does not have debouncing: https://github.com/mgcrea/angular-strap/blob/v2.0.0-rc.4/src/typeahead/typeahead.js#L177
320
+ if (_refreshDelayPromise) {
321
+ $timeout.cancel(_refreshDelayPromise);
322
+ }
323
+ _refreshDelayPromise = $timeout(function() {
324
+ $scope.$eval(refreshAttr);
325
+ }, ctrl.refreshDelay);
326
+ }
327
+ };
328
+
329
+ ctrl.setActiveItem = function(item) {
330
+ ctrl.activeIndex = ctrl.items.indexOf(item);
331
+ };
332
+
333
+ ctrl.isActive = function(itemScope) {
334
+ if ( !ctrl.open ) {
335
+ return false;
336
+ }
337
+ var itemIndex = ctrl.items.indexOf(itemScope[ctrl.itemProperty]);
338
+ var isActive = itemIndex === ctrl.activeIndex;
339
+
340
+ if ( !isActive || ( itemIndex < 0 && ctrl.taggingLabel !== false ) ||( itemIndex < 0 && ctrl.taggingLabel === false) ) {
341
+ return false;
342
+ }
343
+
344
+ if (isActive && !angular.isUndefined(ctrl.onHighlightCallback)) {
345
+ itemScope.$eval(ctrl.onHighlightCallback);
346
+ }
347
+
348
+ return isActive;
349
+ };
350
+
351
+ ctrl.isDisabled = function(itemScope) {
352
+
353
+ if (!ctrl.open) return;
354
+
355
+ var itemIndex = ctrl.items.indexOf(itemScope[ctrl.itemProperty]);
356
+ var isDisabled = false;
357
+ var item;
358
+
359
+ if (itemIndex >= 0 && !angular.isUndefined(ctrl.disableChoiceExpression)) {
360
+ item = ctrl.items[itemIndex];
361
+ isDisabled = !!(itemScope.$eval(ctrl.disableChoiceExpression)); // force the boolean value
362
+ item._uiSelectChoiceDisabled = isDisabled; // store this for later reference
363
+ }
364
+
365
+ return isDisabled;
366
+ };
367
+
368
+
369
+ // When the user selects an item with ENTER or clicks the dropdown
370
+ ctrl.select = function(item, skipFocusser, $event) {
371
+ if (item === undefined || !item._uiSelectChoiceDisabled) {
372
+
373
+ if ( ! ctrl.items && ! ctrl.search ) return;
374
+
375
+ if (!item || !item._uiSelectChoiceDisabled) {
376
+ if(ctrl.tagging.isActivated) {
377
+ // if taggingLabel is disabled, we pull from ctrl.search val
378
+ if ( ctrl.taggingLabel === false ) {
379
+ if ( ctrl.activeIndex < 0 ) {
380
+ item = ctrl.tagging.fct !== undefined ? ctrl.tagging.fct(ctrl.search) : ctrl.search;
381
+ if ( angular.equals( ctrl.items[0], item ) ) {
382
+ return;
383
+ }
384
+ } else {
385
+ // keyboard nav happened first, user selected from dropdown
386
+ item = ctrl.items[ctrl.activeIndex];
387
+ }
388
+ } else {
389
+ // tagging always operates at index zero, taggingLabel === false pushes
390
+ // the ctrl.search value without having it injected
391
+ if ( ctrl.activeIndex === 0 ) {
392
+ // ctrl.tagging pushes items to ctrl.items, so we only have empty val
393
+ // for `item` if it is a detected duplicate
394
+ if ( item === undefined ) return;
395
+ // create new item on the fly
396
+ item = ctrl.tagging.fct !== undefined ? ctrl.tagging.fct(ctrl.search) : item.replace(ctrl.taggingLabel,'');
397
+ }
398
+ }
399
+ // search ctrl.selected for dupes potentially caused by tagging and return early if found
400
+ if ( ctrl.selected && ctrl.selected.filter( function (selection) { return angular.equals(selection, item); }).length > 0 ) {
401
+ ctrl.close(skipFocusser);
402
+ return;
403
+ }
404
+ }
405
+
406
+ var locals = {};
407
+ locals[ctrl.parserResult.itemName] = item;
408
+
409
+ ctrl.onSelectCallback($scope, {
410
+ $item: item,
411
+ $model: ctrl.parserResult.modelMapper($scope, locals)
412
+ });
413
+
414
+ if(ctrl.multiple) {
415
+ ctrl.selected.push(item);
416
+ ctrl.sizeSearchInput();
417
+ } else {
418
+ ctrl.selected = item;
419
+ }
420
+ if (!ctrl.multiple || ctrl.closeOnSelect) {
421
+ ctrl.close(skipFocusser);
422
+ }
423
+ if ($event && $event.type === 'click') {
424
+ ctrl.clickTriggeredSelect = true;
425
+ }
426
+ }
427
+ }
428
+ };
429
+
430
+ // Closes the dropdown
431
+ ctrl.close = function(skipFocusser) {
432
+ if (!ctrl.open) return;
433
+ _resetSearchInput();
434
+ ctrl.open = false;
435
+ if (!ctrl.multiple){
436
+ $timeout(function(){
437
+ ctrl.focusser.prop('disabled', false);
438
+ if (!skipFocusser) ctrl.focusser[0].focus();
439
+ },0,false);
440
+ }
441
+ };
442
+
443
+ // Toggle dropdown
444
+ ctrl.toggle = function(e) {
445
+ if (ctrl.open) ctrl.close(); else ctrl.activate();
446
+ e.preventDefault();
447
+ e.stopPropagation();
448
+ };
449
+
450
+ ctrl.isLocked = function(itemScope, itemIndex) {
451
+ var isLocked, item = ctrl.selected[itemIndex];
452
+
453
+ if (item && !angular.isUndefined(ctrl.lockChoiceExpression)) {
454
+ isLocked = !!(itemScope.$eval(ctrl.lockChoiceExpression)); // force the boolean value
455
+ item._uiSelectChoiceLocked = isLocked; // store this for later reference
456
+ }
457
+
458
+ return isLocked;
459
+ };
460
+
461
+ // Remove item from multiple select
462
+ ctrl.removeChoice = function(index){
463
+ var removedChoice = ctrl.selected[index];
464
+
465
+ // if the choice is locked, can't remove it
466
+ if(removedChoice._uiSelectChoiceLocked) return;
467
+
468
+ var locals = {};
469
+ locals[ctrl.parserResult.itemName] = removedChoice;
470
+
471
+ ctrl.selected.splice(index, 1);
472
+ ctrl.activeMatchIndex = -1;
473
+ ctrl.sizeSearchInput();
474
+
475
+ ctrl.onRemoveCallback($scope, {
476
+ $item: removedChoice,
477
+ $model: ctrl.parserResult.modelMapper($scope, locals)
478
+ });
479
+ };
480
+
481
+ ctrl.getPlaceholder = function(){
482
+ //Refactor single?
483
+ if(ctrl.multiple && ctrl.selected.length) return;
484
+ return ctrl.placeholder;
485
+ };
486
+
487
+ var containerSizeWatch;
488
+ ctrl.sizeSearchInput = function(){
489
+ var input = _searchInput[0],
490
+ container = _searchInput.parent().parent()[0];
491
+ _searchInput.css('width','10px');
492
+ var calculate = function(){
493
+ var newWidth = container.clientWidth - input.offsetLeft - 10;
494
+ if(newWidth < 50) newWidth = container.clientWidth;
495
+ _searchInput.css('width',newWidth+'px');
496
+ };
497
+ $timeout(function(){ //Give tags time to render correctly
498
+ if (container.clientWidth === 0 && !containerSizeWatch){
499
+ containerSizeWatch = $scope.$watch(function(){ return container.clientWidth;}, function(newValue){
500
+ if (newValue !== 0){
501
+ calculate();
502
+ containerSizeWatch();
503
+ containerSizeWatch = null;
504
+ }
505
+ });
506
+ }else if (!containerSizeWatch) {
507
+ calculate();
508
+ }
509
+ }, 0, false);
510
+ };
511
+
512
+ function _handleDropDownSelection(key) {
513
+ var processed = true;
514
+ switch (key) {
515
+ case KEY.DOWN:
516
+ if (!ctrl.open && ctrl.multiple) ctrl.activate(false, true); //In case its the search input in 'multiple' mode
517
+ else if (ctrl.activeIndex < ctrl.items.length - 1) { ctrl.activeIndex++; }
518
+ break;
519
+ case KEY.UP:
520
+ if (!ctrl.open && ctrl.multiple) ctrl.activate(false, true); //In case its the search input in 'multiple' mode
521
+ else if (ctrl.activeIndex > 0 || (ctrl.search.length === 0 && ctrl.tagging.isActivated)) { ctrl.activeIndex--; }
522
+ break;
523
+ case KEY.TAB:
524
+ if (!ctrl.multiple || ctrl.open) ctrl.select(ctrl.items[ctrl.activeIndex], true);
525
+ break;
526
+ case KEY.ENTER:
527
+ if(ctrl.open){
528
+ ctrl.select(ctrl.items[ctrl.activeIndex]);
529
+ } else {
530
+ ctrl.activate(false, true); //In case its the search input in 'multiple' mode
531
+ }
532
+ break;
533
+ case KEY.ESC:
534
+ ctrl.close();
535
+ break;
536
+ default:
537
+ processed = false;
538
+ }
539
+ return processed;
540
+ }
541
+
542
+ // Handles selected options in "multiple" mode
543
+ function _handleMatchSelection(key){
544
+ var caretPosition = _getCaretPosition(_searchInput[0]),
545
+ length = ctrl.selected.length,
546
+ // none = -1,
547
+ first = 0,
548
+ last = length-1,
549
+ curr = ctrl.activeMatchIndex,
550
+ next = ctrl.activeMatchIndex+1,
551
+ prev = ctrl.activeMatchIndex-1,
552
+ newIndex = curr;
553
+
554
+ if(caretPosition > 0 || (ctrl.search.length && key == KEY.RIGHT)) return false;
555
+
556
+ ctrl.close();
557
+
558
+ function getNewActiveMatchIndex(){
559
+ switch(key){
560
+ case KEY.LEFT:
561
+ // Select previous/first item
562
+ if(~ctrl.activeMatchIndex) return prev;
563
+ // Select last item
564
+ else return last;
565
+ break;
566
+ case KEY.RIGHT:
567
+ // Open drop-down
568
+ if(!~ctrl.activeMatchIndex || curr === last){
569
+ ctrl.activate();
570
+ return false;
571
+ }
572
+ // Select next/last item
573
+ else return next;
574
+ break;
575
+ case KEY.BACKSPACE:
576
+ // Remove selected item and select previous/first
577
+ if(~ctrl.activeMatchIndex){
578
+ ctrl.removeChoice(curr);
579
+ return prev;
580
+ }
581
+ // Select last item
582
+ else return last;
583
+ break;
584
+ case KEY.DELETE:
585
+ // Remove selected item and select next item
586
+ if(~ctrl.activeMatchIndex){
587
+ ctrl.removeChoice(ctrl.activeMatchIndex);
588
+ return curr;
589
+ }
590
+ else return false;
591
+ }
592
+ }
593
+
594
+ newIndex = getNewActiveMatchIndex();
595
+
596
+ if(!ctrl.selected.length || newIndex === false) ctrl.activeMatchIndex = -1;
597
+ else ctrl.activeMatchIndex = Math.min(last,Math.max(first,newIndex));
598
+
599
+ return true;
600
+ }
601
+
602
+ // Bind to keyboard shortcuts
603
+ _searchInput.on('keydown', function(e) {
604
+
605
+ var key = e.which;
606
+
607
+ // if(~[KEY.ESC,KEY.TAB].indexOf(key)){
608
+ // //TODO: SEGURO?
609
+ // ctrl.close();
610
+ // }
611
+
612
+ $scope.$apply(function() {
613
+ var processed = false;
614
+
615
+ if(ctrl.multiple && KEY.isHorizontalMovement(key)){
616
+ processed = _handleMatchSelection(key);
617
+ }
618
+
619
+ if (!processed && (ctrl.items.length > 0 || ctrl.tagging.isActivated)) {
620
+ processed = _handleDropDownSelection(key);
621
+ if ( ctrl.taggingTokens.isActivated ) {
622
+ for (var i = 0; i < ctrl.taggingTokens.tokens.length; i++) {
623
+ if ( ctrl.taggingTokens.tokens[i] === KEY.MAP[e.keyCode] ) {
624
+ // make sure there is a new value to push via tagging
625
+ if ( ctrl.search.length > 0 ) {
626
+ ctrl.select(null, true);
627
+ _searchInput.triggerHandler('tagged');
628
+ }
629
+ }
630
+ }
631
+ }
632
+ }
633
+
634
+ if (processed && key != KEY.TAB) {
635
+ //TODO Check si el tab selecciona aun correctamente
636
+ //Crear test
637
+ e.preventDefault();
638
+ e.stopPropagation();
639
+ }
640
+ });
641
+
642
+ if(KEY.isVerticalMovement(key) && ctrl.items.length > 0){
643
+ _ensureHighlightVisible();
644
+ }
645
+
646
+ });
647
+
648
+ _searchInput.on('keyup', function(e) {
649
+ if ( ! KEY.isVerticalMovement(e.which) ) {
650
+ $scope.$evalAsync( function () {
651
+ ctrl.activeIndex = ctrl.taggingLabel === false ? -1 : 0;
652
+ });
653
+ }
654
+ // Push a "create new" item into array if there is a search string
655
+ if ( ctrl.tagging.isActivated && ctrl.search.length > 0 ) {
656
+
657
+ // return early with these keys
658
+ if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.ESC || KEY.isVerticalMovement(e.which) ) {
659
+ return;
660
+ }
661
+ // always reset the activeIndex to the first item when tagging
662
+ ctrl.activeIndex = ctrl.taggingLabel === false ? -1 : 0;
663
+ // taggingLabel === false bypasses all of this
664
+ if (ctrl.taggingLabel === false) return;
665
+
666
+ var items = angular.copy( ctrl.items );
667
+ var stashArr = angular.copy( ctrl.items );
668
+ var newItem;
669
+ var item;
670
+ var hasTag = false;
671
+ var dupeIndex = -1;
672
+ var tagItems;
673
+ var tagItem;
674
+
675
+ // case for object tagging via transform `ctrl.tagging.fct` function
676
+ if ( ctrl.tagging.fct !== undefined) {
677
+ tagItems = ctrl.$filter('filter')(items,{'isTag': true});
678
+ if ( tagItems.length > 0 ) {
679
+ tagItem = tagItems[0];
680
+ }
681
+ // remove the first element, if it has the `isTag` prop we generate a new one with each keyup, shaving the previous
682
+ if ( items.length > 0 && tagItem ) {
683
+ hasTag = true;
684
+ items = items.slice(1,items.length);
685
+ stashArr = stashArr.slice(1,stashArr.length);
686
+ }
687
+ newItem = ctrl.tagging.fct(ctrl.search);
688
+ newItem.isTag = true;
689
+ // verify the the tag doesn't match the value of an existing item
690
+ if ( stashArr.filter( function (origItem) { return angular.equals( origItem, ctrl.tagging.fct(ctrl.search) ); } ).length > 0 ) {
691
+ return;
692
+ }
693
+ // handle newItem string and stripping dupes in tagging string context
694
+ } else {
695
+ // find any tagging items already in the ctrl.items array and store them
696
+ tagItems = ctrl.$filter('filter')(items,function (item) {
697
+ return item.match(ctrl.taggingLabel);
698
+ });
699
+ if ( tagItems.length > 0 ) {
700
+ tagItem = tagItems[0];
701
+ }
702
+ item = items[0];
703
+ // remove existing tag item if found (should only ever be one tag item)
704
+ if ( item !== undefined && items.length > 0 && tagItem ) {
705
+ hasTag = true;
706
+ items = items.slice(1,items.length);
707
+ stashArr = stashArr.slice(1,stashArr.length);
708
+ }
709
+ newItem = ctrl.search+' '+ctrl.taggingLabel;
710
+ if ( _findApproxDupe(ctrl.selected, ctrl.search) > -1 ) {
711
+ return;
712
+ }
713
+ // verify the the tag doesn't match the value of an existing item from
714
+ // the searched data set
715
+ if ( stashArr.filter( function (origItem) { return origItem.toUpperCase() === ctrl.search.toUpperCase(); }).length > 0 ) {
716
+ // if there is a tag from prev iteration, strip it / queue the change
717
+ // and return early
718
+ if ( hasTag ) {
719
+ items = stashArr;
720
+ $scope.$evalAsync( function () {
721
+ ctrl.activeIndex = 0;
722
+ ctrl.items = items;
723
+ });
724
+ }
725
+ return;
726
+ }
727
+ if ( ctrl.selected.filter( function (selection) { return selection.toUpperCase() === ctrl.search.toUpperCase(); } ).length > 0 ) {
728
+ // if there is a tag from prev iteration, strip it
729
+ if ( hasTag ) {
730
+ ctrl.items = stashArr.slice(1,stashArr.length);
731
+ }
732
+ return;
733
+ }
734
+ }
735
+ if ( hasTag ) dupeIndex = _findApproxDupe(ctrl.selected, newItem);
736
+ // dupe found, shave the first item
737
+ if ( dupeIndex > -1 ) {
738
+ items = items.slice(dupeIndex+1,items.length-1);
739
+ } else {
740
+ items = [];
741
+ items.push(newItem);
742
+ items = items.concat(stashArr);
743
+ }
744
+ $scope.$evalAsync( function () {
745
+ ctrl.activeIndex = 0;
746
+ ctrl.items = items;
747
+ });
748
+ }
749
+ });
750
+
751
+ _searchInput.on('tagged', function() {
752
+ $timeout(function() {
753
+ _resetSearchInput();
754
+ });
755
+ });
756
+
757
+ _searchInput.on('blur', function() {
758
+ $timeout(function() {
759
+ ctrl.activeMatchIndex = -1;
760
+ });
761
+ });
762
+
763
+ function _findApproxDupe(haystack, needle) {
764
+ var tempArr = angular.copy(haystack);
765
+ var dupeIndex = -1;
766
+ for (var i = 0; i <tempArr.length; i++) {
767
+ // handle the simple string version of tagging
768
+ if ( ctrl.tagging.fct === undefined ) {
769
+ // search the array for the match
770
+ if ( tempArr[i]+' '+ctrl.taggingLabel === needle ) {
771
+ dupeIndex = i;
772
+ }
773
+ // handle the object tagging implementation
774
+ } else {
775
+ var mockObj = tempArr[i];
776
+ mockObj.isTag = true;
777
+ if ( angular.equals(mockObj, needle) ) {
778
+ dupeIndex = i;
779
+ }
780
+ }
781
+ }
782
+ return dupeIndex;
783
+ }
784
+
785
+ function _getCaretPosition(el) {
786
+ if(angular.isNumber(el.selectionStart)) return el.selectionStart;
787
+ // selectionStart is not supported in IE8 and we don't want hacky workarounds so we compromise
788
+ else return el.value.length;
789
+ }
790
+
791
+ // See https://github.com/ivaynberg/select2/blob/3.4.6/select2.js#L1431
792
+ function _ensureHighlightVisible() {
793
+ var container = $element.querySelectorAll('.ui-select-choices-content');
794
+ var choices = container.querySelectorAll('.ui-select-choices-row');
795
+ if (choices.length < 1) {
796
+ throw uiSelectMinErr('choices', "Expected multiple .ui-select-choices-row but got '{0}'.", choices.length);
797
+ }
798
+
799
+ var highlighted = choices[ctrl.activeIndex];
800
+ var posY = highlighted.offsetTop + highlighted.clientHeight - container[0].scrollTop;
801
+ var height = container[0].offsetHeight;
802
+
803
+ if (posY > height) {
804
+ container[0].scrollTop += posY - height;
805
+ } else if (posY < highlighted.clientHeight) {
806
+ if (ctrl.isGrouped && ctrl.activeIndex === 0)
807
+ container[0].scrollTop = 0; //To make group header visible when going all the way up
808
+ else
809
+ container[0].scrollTop -= highlighted.clientHeight - posY;
810
+ }
811
+ }
812
+
813
+ $scope.$on('$destroy', function() {
814
+ _searchInput.off('keyup keydown tagged blur');
815
+ });
816
+ }])
817
+
818
+ .directive('uiSelect',
819
+ ['$document', 'uiSelectConfig', 'uiSelectMinErr', '$compile', '$parse',
820
+ function($document, uiSelectConfig, uiSelectMinErr, $compile, $parse) {
821
+
822
+ return {
823
+ restrict: 'EA',
824
+ templateUrl: function(tElement, tAttrs) {
825
+ var theme = tAttrs.theme || uiSelectConfig.theme;
826
+ return theme + (angular.isDefined(tAttrs.multiple) ? '/select-multiple.tpl.html' : '/select.tpl.html');
827
+ },
828
+ replace: true,
829
+ transclude: true,
830
+ require: ['uiSelect', 'ngModel'],
831
+ scope: true,
832
+
833
+ controller: 'uiSelectCtrl',
834
+ controllerAs: '$select',
835
+
836
+ link: function(scope, element, attrs, ctrls, transcludeFn) {
837
+ var $select = ctrls[0];
838
+ var ngModel = ctrls[1];
839
+
840
+ var searchInput = element.querySelectorAll('input.ui-select-search');
841
+
842
+ $select.multiple = angular.isDefined(attrs.multiple) && (
843
+ attrs.multiple === '' ||
844
+ attrs.multiple.toLowerCase() === 'multiple' ||
845
+ attrs.multiple.toLowerCase() === 'true'
846
+ );
847
+
848
+ $select.closeOnSelect = (angular.isDefined(attrs.closeOnSelect) && attrs.closeOnSelect.toLowerCase() === 'false') ? false : uiSelectConfig.closeOnSelect;
849
+ $select.onSelectCallback = $parse(attrs.onSelect);
850
+ $select.onRemoveCallback = $parse(attrs.onRemove);
851
+
852
+ //From view --> model
853
+ ngModel.$parsers.unshift(function (inputValue) {
854
+ var locals = {},
855
+ result;
856
+ if ($select.multiple){
857
+ var resultMultiple = [];
858
+ for (var j = $select.selected.length - 1; j >= 0; j--) {
859
+ locals = {};
860
+ locals[$select.parserResult.itemName] = $select.selected[j];
861
+ result = $select.parserResult.modelMapper(scope, locals);
862
+ resultMultiple.unshift(result);
863
+ }
864
+ return resultMultiple;
865
+ }else{
866
+ locals = {};
867
+ locals[$select.parserResult.itemName] = inputValue;
868
+ result = $select.parserResult.modelMapper(scope, locals);
869
+ return result;
870
+ }
871
+ });
872
+
873
+ //From model --> view
874
+ ngModel.$formatters.unshift(function (inputValue) {
875
+ var data = $select.parserResult.source (scope, { $select : {search:''}}), //Overwrite $search
876
+ locals = {},
877
+ result;
878
+ if (data){
879
+ if ($select.multiple){
880
+ var resultMultiple = [];
881
+ var checkFnMultiple = function(list, value){
882
+ if (!list || !list.length) return;
883
+ for (var p = list.length - 1; p >= 0; p--) {
884
+ locals[$select.parserResult.itemName] = list[p];
885
+ result = $select.parserResult.modelMapper(scope, locals);
886
+ if (result == value){
887
+ resultMultiple.unshift(list[p]);
888
+ return true;
889
+ }
890
+ }
891
+ return false;
892
+ };
893
+ if (!inputValue) return resultMultiple; //If ngModel was undefined
894
+ for (var k = inputValue.length - 1; k >= 0; k--) {
895
+ if (!checkFnMultiple($select.selected, inputValue[k])){
896
+ checkFnMultiple(data, inputValue[k]);
897
+ }
898
+ }
899
+ return resultMultiple;
900
+ }else{
901
+ var checkFnSingle = function(d){
902
+ locals[$select.parserResult.itemName] = d;
903
+ result = $select.parserResult.modelMapper(scope, locals);
904
+ return result == inputValue;
905
+ };
906
+ //If possible pass same object stored in $select.selected
907
+ if ($select.selected && checkFnSingle($select.selected)) {
908
+ return $select.selected;
909
+ }
910
+ for (var i = data.length - 1; i >= 0; i--) {
911
+ if (checkFnSingle(data[i])) return data[i];
912
+ }
913
+ }
914
+ }
915
+ return inputValue;
916
+ });
917
+
918
+ //Set reference to ngModel from uiSelectCtrl
919
+ $select.ngModel = ngModel;
920
+
921
+ //Idea from: https://github.com/ivaynberg/select2/blob/79b5bf6db918d7560bdd959109b7bcfb47edaf43/select2.js#L1954
922
+ var focusser = angular.element("<input ng-disabled='$select.disabled' class='ui-select-focusser ui-select-offscreen' type='text' aria-haspopup='true' role='button' />");
923
+
924
+ if(attrs.tabindex){
925
+ //tabindex might be an expression, wait until it contains the actual value before we set the focusser tabindex
926
+ attrs.$observe('tabindex', function(value) {
927
+ //If we are using multiple, add tabindex to the search input
928
+ if($select.multiple){
929
+ searchInput.attr("tabindex", value);
930
+ } else {
931
+ focusser.attr("tabindex", value);
932
+ }
933
+ //Remove the tabindex on the parent so that it is not focusable
934
+ element.removeAttr("tabindex");
935
+ });
936
+ }
937
+
938
+ $compile(focusser)(scope);
939
+ $select.focusser = focusser;
940
+
941
+ if (!$select.multiple){
942
+
943
+ element.append(focusser);
944
+ focusser.bind("focus", function(){
945
+ scope.$evalAsync(function(){
946
+ $select.focus = true;
947
+ });
948
+ });
949
+ focusser.bind("blur", function(){
950
+ scope.$evalAsync(function(){
951
+ $select.focus = false;
952
+ });
953
+ });
954
+ focusser.bind("keydown", function(e){
955
+
956
+ if (e.which === KEY.BACKSPACE) {
957
+ e.preventDefault();
958
+ e.stopPropagation();
959
+ $select.select(undefined);
960
+ scope.$apply();
961
+ return;
962
+ }
963
+
964
+ if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.ESC) {
965
+ return;
966
+ }
967
+
968
+ if (e.which == KEY.DOWN || e.which == KEY.UP || e.which == KEY.ENTER || e.which == KEY.SPACE){
969
+ e.preventDefault();
970
+ e.stopPropagation();
971
+ $select.activate();
972
+ }
973
+
974
+ scope.$digest();
975
+ });
976
+
977
+ focusser.bind("keyup input", function(e){
978
+
979
+ if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.ESC || e.which == KEY.ENTER || e.which === KEY.BACKSPACE) {
980
+ return;
981
+ }
982
+
983
+ $select.activate(focusser.val()); //User pressed some regular key, so we pass it to the search input
984
+ focusser.val('');
985
+ scope.$digest();
986
+
987
+ });
988
+
989
+ }
990
+
991
+
992
+ scope.$watch('searchEnabled', function() {
993
+ var searchEnabled = scope.$eval(attrs.searchEnabled);
994
+ $select.searchEnabled = searchEnabled !== undefined ? searchEnabled : uiSelectConfig.searchEnabled;
995
+ });
996
+
997
+ attrs.$observe('disabled', function() {
998
+ // No need to use $eval() (thanks to ng-disabled) since we already get a boolean instead of a string
999
+ $select.disabled = attrs.disabled !== undefined ? attrs.disabled : false;
1000
+ });
1001
+
1002
+ attrs.$observe('resetSearchInput', function() {
1003
+ // $eval() is needed otherwise we get a string instead of a boolean
1004
+ var resetSearchInput = scope.$eval(attrs.resetSearchInput);
1005
+ $select.resetSearchInput = resetSearchInput !== undefined ? resetSearchInput : true;
1006
+ });
1007
+
1008
+ attrs.$observe('tagging', function() {
1009
+ if(attrs.tagging !== undefined)
1010
+ {
1011
+ // $eval() is needed otherwise we get a string instead of a boolean
1012
+ var taggingEval = scope.$eval(attrs.tagging);
1013
+ $select.tagging = {isActivated: true, fct: taggingEval !== true ? taggingEval : undefined};
1014
+ }
1015
+ else
1016
+ {
1017
+ $select.tagging = {isActivated: false, fct: undefined};
1018
+ }
1019
+ });
1020
+
1021
+ attrs.$observe('taggingLabel', function() {
1022
+ if(attrs.tagging !== undefined && attrs.taggingLabel !== undefined)
1023
+ {
1024
+ // check eval for FALSE, in this case, we disable the labels
1025
+ // associated with tagging
1026
+ if ( attrs.taggingLabel === 'false' ) {
1027
+ $select.taggingLabel = false;
1028
+ }
1029
+ else
1030
+ {
1031
+ $select.taggingLabel = attrs.taggingLabel !== undefined ? attrs.taggingLabel : '(new)';
1032
+ }
1033
+ }
1034
+ });
1035
+
1036
+ attrs.$observe('taggingTokens', function() {
1037
+ if (attrs.tagging !== undefined) {
1038
+ var tokens = attrs.taggingTokens !== undefined ? attrs.taggingTokens.split('|') : [',','ENTER'];
1039
+ $select.taggingTokens = {isActivated: true, tokens: tokens };
1040
+ }
1041
+ });
1042
+
1043
+ if ($select.multiple){
1044
+ scope.$watchCollection(function(){ return ngModel.$modelValue; }, function(newValue, oldValue) {
1045
+ if (oldValue != newValue)
1046
+ ngModel.$modelValue = null; //Force scope model value and ngModel value to be out of sync to re-run formatters
1047
+ });
1048
+ scope.$watchCollection('$select.selected', function() {
1049
+ ngModel.$setViewValue(Date.now()); //Set timestamp as a unique string to force changes
1050
+ });
1051
+ focusser.prop('disabled', true); //Focusser isn't needed if multiple
1052
+ }else{
1053
+ scope.$watch('$select.selected', function(newValue) {
1054
+ if (ngModel.$viewValue !== newValue) {
1055
+ ngModel.$setViewValue(newValue);
1056
+ }
1057
+ });
1058
+ }
1059
+
1060
+ ngModel.$render = function() {
1061
+ if($select.multiple){
1062
+ // Make sure that model value is array
1063
+ if(!angular.isArray(ngModel.$viewValue)){
1064
+ // Have tolerance for null or undefined values
1065
+ if(angular.isUndefined(ngModel.$viewValue) || ngModel.$viewValue === null){
1066
+ $select.selected = [];
1067
+ } else {
1068
+ throw uiSelectMinErr('multiarr', "Expected model value to be array but got '{0}'", ngModel.$viewValue);
1069
+ }
1070
+ }
1071
+ }
1072
+ $select.selected = ngModel.$viewValue;
1073
+ };
1074
+
1075
+ function onDocumentClick(e) {
1076
+ var contains = false;
1077
+
1078
+ if (window.jQuery) {
1079
+ // Firefox 3.6 does not support element.contains()
1080
+ // See Node.contains https://developer.mozilla.org/en-US/docs/Web/API/Node.contains
1081
+ contains = window.jQuery.contains(element[0], e.target);
1082
+ } else {
1083
+ contains = element[0].contains(e.target);
1084
+ }
1085
+
1086
+ if (!contains && !$select.clickTriggeredSelect) {
1087
+ $select.close();
1088
+ scope.$digest();
1089
+ }
1090
+ $select.clickTriggeredSelect = false;
1091
+ }
1092
+
1093
+ // See Click everywhere but here event http://stackoverflow.com/questions/12931369
1094
+ $document.on('click', onDocumentClick);
1095
+
1096
+ scope.$on('$destroy', function() {
1097
+ $document.off('click', onDocumentClick);
1098
+ });
1099
+
1100
+ // Move transcluded elements to their correct position in main template
1101
+ transcludeFn(scope, function(clone) {
1102
+ // See Transclude in AngularJS http://blog.omkarpatil.com/2012/11/transclude-in-angularjs.html
1103
+
1104
+ // One day jqLite will be replaced by jQuery and we will be able to write:
1105
+ // var transcludedElement = clone.filter('.my-class')
1106
+ // instead of creating a hackish DOM element:
1107
+ var transcluded = angular.element('<div>').append(clone);
1108
+
1109
+ var transcludedMatch = transcluded.querySelectorAll('.ui-select-match');
1110
+ transcludedMatch.removeAttr('ui-select-match'); //To avoid loop in case directive as attr
1111
+ if (transcludedMatch.length !== 1) {
1112
+ throw uiSelectMinErr('transcluded', "Expected 1 .ui-select-match but got '{0}'.", transcludedMatch.length);
1113
+ }
1114
+ element.querySelectorAll('.ui-select-match').replaceWith(transcludedMatch);
1115
+
1116
+ var transcludedChoices = transcluded.querySelectorAll('.ui-select-choices');
1117
+ transcludedChoices.removeAttr('ui-select-choices'); //To avoid loop in case directive as attr
1118
+ if (transcludedChoices.length !== 1) {
1119
+ throw uiSelectMinErr('transcluded', "Expected 1 .ui-select-choices but got '{0}'.", transcludedChoices.length);
1120
+ }
1121
+ element.querySelectorAll('.ui-select-choices').replaceWith(transcludedChoices);
1122
+
1123
+ var transcludedFooter = transcluded.querySelectorAll('.ui-select-footer');
1124
+ transcludedFooter.removeAttr('ui-select-footer'); //To avoid loop in case directive as attr
1125
+ if (transcludedFooter.length > 0) {
1126
+ element.querySelectorAll('.ui-select-footer').replaceWith(transcludedFooter);
1127
+ }
1128
+ });
1129
+ }
1130
+ };
1131
+ }])
1132
+
1133
+ .directive('uiSelectChoices',
1134
+ ['uiSelectConfig', 'RepeatParser', 'uiSelectMinErr', '$compile',
1135
+ function(uiSelectConfig, RepeatParser, uiSelectMinErr, $compile) {
1136
+
1137
+ return {
1138
+ restrict: 'EA',
1139
+ require: '^uiSelect',
1140
+ replace: true,
1141
+ transclude: true,
1142
+ templateUrl: function(tElement) {
1143
+ // Gets theme attribute from parent (ui-select)
1144
+ var theme = tElement.parent().attr('theme') || uiSelectConfig.theme;
1145
+ return theme + '/choices.tpl.html';
1146
+ },
1147
+
1148
+ compile: function(tElement, tAttrs) {
1149
+
1150
+ if (!tAttrs.repeat) throw uiSelectMinErr('repeat', "Expected 'repeat' expression.");
1151
+
1152
+ return function link(scope, element, attrs, $select, transcludeFn) {
1153
+
1154
+ // var repeat = RepeatParser.parse(attrs.repeat);
1155
+ var groupByExp = attrs.groupBy;
1156
+
1157
+ $select.parseRepeatAttr(attrs.repeat, groupByExp); //Result ready at $select.parserResult
1158
+
1159
+ $select.disableChoiceExpression = attrs.uiDisableChoice;
1160
+ $select.onHighlightCallback = attrs.onHighlight;
1161
+
1162
+ if(groupByExp) {
1163
+ var groups = element.querySelectorAll('.ui-select-choices-group');
1164
+ if (groups.length !== 1) throw uiSelectMinErr('rows', "Expected 1 .ui-select-choices-group but got '{0}'.", groups.length);
1165
+ groups.attr('ng-repeat', RepeatParser.getGroupNgRepeatExpression());
1166
+ }
1167
+
1168
+ var choices = element.querySelectorAll('.ui-select-choices-row');
1169
+ if (choices.length !== 1) {
1170
+ throw uiSelectMinErr('rows', "Expected 1 .ui-select-choices-row but got '{0}'.", choices.length);
1171
+ }
1172
+
1173
+ choices.attr('ng-repeat', RepeatParser.getNgRepeatExpression($select.parserResult.itemName, '$select.items', $select.parserResult.trackByExp, groupByExp))
1174
+ .attr('ng-if', '$select.open') //Prevent unnecessary watches when dropdown is closed
1175
+ .attr('ng-mouseenter', '$select.setActiveItem('+$select.parserResult.itemName +')')
1176
+ .attr('ng-click', '$select.select(' + $select.parserResult.itemName + ',false,$event)');
1177
+
1178
+ var rowsInner = element.querySelectorAll('.ui-select-choices-row-inner');
1179
+ if (rowsInner.length !== 1) throw uiSelectMinErr('rows', "Expected 1 .ui-select-choices-row-inner but got '{0}'.", rowsInner.length);
1180
+ rowsInner.attr('uis-transclude-append', ''); //Adding uisTranscludeAppend directive to row element after choices element has ngRepeat
1181
+
1182
+ $compile(element, transcludeFn)(scope); //Passing current transcludeFn to be able to append elements correctly from uisTranscludeAppend
1183
+
1184
+ scope.$watch('$select.search', function(newValue) {
1185
+ if(newValue && !$select.open && $select.multiple) $select.activate(false, true);
1186
+ $select.activeIndex = $select.tagging.isActivated ? -1 : 0;
1187
+ $select.refresh(attrs.refresh);
1188
+ });
1189
+
1190
+ attrs.$observe('refreshDelay', function() {
1191
+ // $eval() is needed otherwise we get a string instead of a number
1192
+ var refreshDelay = scope.$eval(attrs.refreshDelay);
1193
+ $select.refreshDelay = refreshDelay !== undefined ? refreshDelay : uiSelectConfig.refreshDelay;
1194
+ });
1195
+ };
1196
+ }
1197
+ };
1198
+ }])
1199
+ // Recreates old behavior of ng-transclude. Used internally.
1200
+ .directive('uisTranscludeAppend', function () {
1201
+ return {
1202
+ link: function (scope, element, attrs, ctrl, transclude) {
1203
+ transclude(scope, function (clone) {
1204
+ element.append(clone);
1205
+ });
1206
+ }
1207
+ };
1208
+ })
1209
+ .directive('uiSelectMatch', ['uiSelectConfig', function(uiSelectConfig) {
1210
+ return {
1211
+ restrict: 'EA',
1212
+ require: '^uiSelect',
1213
+ replace: true,
1214
+ transclude: true,
1215
+ templateUrl: function(tElement) {
1216
+ // Gets theme attribute from parent (ui-select)
1217
+ var theme = tElement.parent().attr('theme') || uiSelectConfig.theme;
1218
+ var multi = tElement.parent().attr('multiple');
1219
+ return theme + (multi ? '/match-multiple.tpl.html' : '/match.tpl.html');
1220
+ },
1221
+ link: function(scope, element, attrs, $select) {
1222
+ $select.lockChoiceExpression = attrs.uiLockChoice;
1223
+ attrs.$observe('placeholder', function(placeholder) {
1224
+ $select.placeholder = placeholder !== undefined ? placeholder : uiSelectConfig.placeholder;
1225
+ });
1226
+
1227
+ $select.allowClear = (angular.isDefined(attrs.allowClear)) ? (attrs.allowClear === '') ? true : (attrs.allowClear.toLowerCase() === 'true') : false;
1228
+
1229
+ if($select.multiple){
1230
+ $select.sizeSearchInput();
1231
+ }
1232
+
1233
+ }
1234
+ };
1235
+ }])
1236
+
1237
+ .directive('uiSelectFooter', ['uiSelectConfig', function(uiSelectConfig) {
1238
+ return {
1239
+ restrict: 'EA',
1240
+ //require: '^uiSelect',
1241
+ replace: true,
1242
+ transclude: true,
1243
+ templateUrl: function(tElement) {
1244
+ // Gets theme attribute from parent (ui-select)
1245
+ var theme = tElement.parent().attr('theme') || uiSelectConfig.theme;
1246
+ return theme + '/footer.tpl.html';
1247
+ }
1248
+ };
1249
+ }])
1250
+
1251
+ /**
1252
+ * Highlights text that matches $select.search.
1253
+ *
1254
+ * Taken from AngularUI Bootstrap Typeahead
1255
+ * See https://github.com/angular-ui/bootstrap/blob/0.10.0/src/typeahead/typeahead.js#L340
1256
+ */
1257
+ .filter('highlight', function() {
1258
+ function escapeRegexp(queryToEscape) {
1259
+ return queryToEscape.replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1');
1260
+ }
1261
+
1262
+ return function(matchItem, query) {
1263
+ return query && matchItem ? matchItem.replace(new RegExp(escapeRegexp(query), 'gi'), '<span class="ui-select-highlight">$&</span>') : matchItem;
1264
+ };
1265
+ });
1266
+ }());
1267
+
1268
+ 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=\"menu\" aria-labelledby=\"dLabel\" ng-show=\"$select.items.length > 0\"><li class=\"ui-select-choices-group\"><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-html=\"$group.name\"></div><div class=\"ui-select-choices-row\" ng-class=\"{active: $select.isActive(this), disabled: $select.isDisabled(this)}\"><a href=\"javascript:void(0)\" class=\"ui-select-choices-row-inner\"></a></div></li></ul>");
1269
+ $templateCache.put("bootstrap/match-multiple.tpl.html","<span class=\"ui-select-match\"><span ng-repeat=\"$item in $select.selected\"><span style=\"margin-right: 3px;\" class=\"ui-select-match-item btn btn-default btn-xs\" tabindex=\"-1\" type=\"button\" ng-disabled=\"$select.disabled\" ng-click=\"$select.activeMatchIndex = $index;\" ng-class=\"{\'btn-primary\':$select.activeMatchIndex === $index}\"><span class=\"close ui-select-match-close\" ng-hide=\"$select.disabled\" ng-click=\"$select.removeChoice($index)\">&nbsp;&times;</span> <span uis-transclude-append=\"\"></span></span></span></span>");
1270
+ $templateCache.put("bootstrap/match.tpl.html","<button type=\"button\" class=\"btn btn-default form-control ui-select-match\" tabindex=\"-1\" ng-hide=\"$select.open\" ng-disabled=\"$select.disabled\" ng-class=\"{\'btn-default-focus\':$select.focus}\" ;=\"\" ng-click=\"$select.activate()\"><span ng-show=\"$select.isEmpty()\" class=\"text-muted\">{{$select.placeholder}}</span> <span ng-hide=\"$select.isEmpty()\" ng-transclude=\"\"></span> <span class=\"caret ui-select-toggle\" ng-click=\"$select.toggle($event)\"></span></button>");
1271
+ $templateCache.put("bootstrap/select-multiple.tpl.html","<div class=\"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=\"{{$select.getPlaceholder()}}\" ng-disabled=\"$select.disabled\" ng-hide=\"$select.disabled\" ng-click=\"$select.activate()\" ng-model=\"$select.search\"></div><div class=\"ui-select-choices\"></div></div>");
1272
+ $templateCache.put("bootstrap/select.tpl.html","<div class=\"ui-select-bootstrap dropdown\" ng-class=\"{open: $select.open}\"><div class=\"ui-select-match\"></div><input type=\"text\" autocomplete=\"off\" tabindex=\"-1\" class=\"form-control ui-select-search\" placeholder=\"{{$select.placeholder}}\" ng-model=\"$select.search\" ng-show=\"$select.searchEnabled && $select.open\"><div class=\"ui-select-choices\"></div></div>");
1273
+ $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.isGrouped}\"><div ng-show=\"$select.isGrouped\" class=\"ui-select-choices-group-label select2-result-label\" ng-bind-html=\"$group.name\"></div><ul ng-class=\"{\'select2-result-sub\': $select.isGrouped, \'select2-result-single\': !$select.isGrouped}\"><li 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>");
1274
+ $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\':$select.activeMatchIndex === $index, \'select2-locked\':$select.isLocked(this, $index)}\"><span uis-transclude-append=\"\"></span> <a href=\"javascript:;\" class=\"ui-select-match-close select2-search-choice-close\" ng-click=\"$select.removeChoice($index)\" tabindex=\"-1\"></a></li></span>");
1275
+ $templateCache.put("select2/match.tpl.html","<a class=\"select2-choice ui-select-match\" ng-class=\"{\'select2-default\': $select.isEmpty()}\" ng-click=\"$select.activate()\"><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.select(undefined)\"></abbr> <span class=\"select2-arrow ui-select-toggle\" ng-click=\"$select.toggle($event)\"><b></b></span></a>");
1276
+ $templateCache.put("select2/select-multiple.tpl.html","<div class=\"ui-select-multiple select2 select2-container select2-container-multi\" ng-class=\"{\'select2-container-active select2-dropdown-open\': $select.open,\n \'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\" class=\"select2-input ui-select-search\" placeholder=\"{{$select.getPlaceholder()}}\" ng-disabled=\"$select.disabled\" ng-hide=\"$select.disabled\" ng-model=\"$select.search\" ng-click=\"$select.activate()\" style=\"width: 34px;\"></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>");
1277
+ $templateCache.put("select2/select.tpl.html","<div class=\"select2 select2-container\" ng-class=\"{\'select2-container-active select2-dropdown-open\': $select.open,\n \'select2-container-disabled\': $select.disabled,\n \'select2-container-active\': $select.focus, \n \'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\" class=\"ui-select-search select2-input\" ng-model=\"$select.search\"></div><div class=\"ui-select-choices\"></div></div></div>");
1278
+ $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\"><div ng-show=\"$select.isGrouped\" class=\"ui-select-choices-group-label optgroup-header\" ng-bind-html=\"$group.name\"></div><div 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 class=\"ui-select-footer\"></div></div>");
1279
+ $templateCache.put("selectize/footer.tpl.html","<div ng-show=\"$select.open\" class=\"ui-select-footer\" ng-transclude=\"\"></div>");
1280
+ $templateCache.put("selectize/match.tpl.html","<div ng-hide=\"($select.open || $select.isEmpty())\" class=\"ui-select-match\" ng-transclude=\"\"></div>");
1281
+ $templateCache.put("selectize/select.tpl.html","<div class=\"selectize-control single\"><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\"></div><div class=\"ui-select-choices\"></div></div>");}]);