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.
- data/.gitignore +1 -0
- data/.ruby-version +1 -0
- data/.yardopts +5 -0
- data/.yardopts.rb +1 -0
- data/Gemfile +9 -0
- data/README.md +40 -75
- data/Rakefile +61 -4
- data/fanforce-plugin-factory.gemspec +21 -21
- data/lib/fanforce/plugin_factory.rb +16 -58
- data/lib/fanforce/plugin_factory/Rakefile +51 -0
- data/lib/fanforce/plugin_factory/Routes.rb +33 -0
- data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/_bootstrap.scss +2 -0
- data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/_common.scss +1 -0
- data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/_directives.scss +7 -0
- data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/_font-awesome.scss +1 -0
- data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/_ui-select.scss +3 -0
- data/lib/fanforce/plugin_factory/{assets/lib/common → asset_framework/plugin_factory/bootstrap}/_bootstrap-overrides.scss +2 -0
- data/lib/fanforce/plugin_factory/{assets/lib/vendors/bootstrap/css → asset_framework/plugin_factory/bootstrap}/bootstrap.css +2 -2
- data/lib/fanforce/plugin_factory/{assets/lib/vendors/bootstrap/js → asset_framework/plugin_factory/bootstrap}/bootstrap.js +0 -0
- data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/bootstrap/bootstrap.min.css +7 -0
- data/lib/fanforce/plugin_factory/{assets/lib/vendors/bootstrap/js → asset_framework/plugin_factory/bootstrap}/bootstrap.min.js +0 -0
- data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/bootstrap/glyphicons-halflings-regular.eot +0 -0
- data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/bootstrap/glyphicons-halflings-regular.svg +229 -0
- data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/bootstrap/glyphicons-halflings-regular.ttf +0 -0
- data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/bootstrap/glyphicons-halflings-regular.woff +0 -0
- data/lib/fanforce/plugin_factory/{assets/lib → asset_framework/plugin_factory}/common/_mixins.scss +2 -1
- data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/directives.coffee +1 -0
- data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/directives/error/_error.scss +6 -0
- data/lib/fanforce/plugin_factory/{assets/lib/common/module-error → asset_framework/plugin_factory/directives/error}/arrow-left.png +0 -0
- data/lib/fanforce/plugin_factory/{assets/lib/common/module-error → asset_framework/plugin_factory/directives/error}/icon-error.png +0 -0
- data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/directives/initiative-footer/_initiative-footer.coffee +16 -0
- 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
- data/lib/fanforce/plugin_factory/{assets/lib/common/_module-initiative-searcher.scss → asset_framework/plugin_factory/directives/initiative-searcher/_initiative-searcher.scss} +14 -13
- data/lib/fanforce/plugin_factory/{assets/lib/common/module-initiative-searcher → asset_framework/plugin_factory/directives/initiative-searcher}/icon-search.png +0 -0
- data/lib/fanforce/plugin_factory/{assets/lib/common/module-initiative-searcher → asset_framework/plugin_factory/directives/initiative-searcher}/spinner.gif +0 -0
- data/lib/fanforce/plugin_factory/{assets/lib/common/module-initiative-searcher → asset_framework/plugin_factory/directives/initiative-searcher}/sprite-arrows.png +0 -0
- data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/directives/loading/_loading.coffee +4 -0
- data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/directives/loading/_loading.scss +4 -0
- 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
- data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/directives/saving-to-server/_saving-to-server.scss +6 -0
- data/lib/fanforce/plugin_factory/{assets/lib/common/module-saving-initiative → asset_framework/plugin_factory/directives/saving-to-server}/spinner.gif +0 -0
- data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/directives/start-arrow/_start-arrow.coffee +8 -0
- data/lib/fanforce/plugin_factory/{assets/lib/common/_module-start-here.scss → asset_framework/plugin_factory/directives/start-arrow/_start-arrow.scss} +5 -4
- data/lib/fanforce/plugin_factory/{assets/lib/common/module-start-here → asset_framework/plugin_factory/directives/start-arrow}/arrow.png +0 -0
- data/lib/fanforce/plugin_factory/{assets/lib/common/_module-video-thumbnail.scss → asset_framework/plugin_factory/directives/video-thumbnail/_video-thumbnail.scss} +4 -4
- data/lib/fanforce/plugin_factory/{assets/lib/common/module-video-thumbnail → asset_framework/plugin_factory/directives/video-thumbnail}/icon-play.png +0 -0
- data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/font-awesome.coffee +1 -0
- data/lib/fanforce/plugin_factory/{assets/lib/vendors/font-awesome/font → asset_framework/plugin_factory/font-awesome}/FontAwesome.otf +0 -0
- data/lib/fanforce/plugin_factory/{assets/lib/vendors/font-awesome/css → asset_framework/plugin_factory/font-awesome}/font-awesome.css +2 -2
- data/lib/fanforce/plugin_factory/{assets/lib/vendors/font-awesome/css → asset_framework/plugin_factory/font-awesome}/font-awesome.min.css +0 -0
- data/lib/fanforce/plugin_factory/{assets/lib/vendors/font-awesome/font → asset_framework/plugin_factory/font-awesome}/fontawesome-webfont.eot +0 -0
- data/lib/fanforce/plugin_factory/{assets/lib/vendors/font-awesome/font → asset_framework/plugin_factory/font-awesome}/fontawesome-webfont.svg +0 -0
- data/lib/fanforce/plugin_factory/{assets/lib/vendors/font-awesome/font → asset_framework/plugin_factory/font-awesome}/fontawesome-webfont.ttf +0 -0
- data/lib/fanforce/plugin_factory/{assets/lib/vendors/font-awesome/font → asset_framework/plugin_factory/font-awesome}/fontawesome-webfont.woff +0 -0
- data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/lib.coffee +1 -0
- data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/lib/ng-focus-blur.js +68 -0
- data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/lib/ng-visible.js +7 -0
- data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/ui-select.coffee +1 -0
- data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/ui-select/select.css +171 -0
- data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/ui-select/select.js +1281 -0
- data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/ui-select/select_override.scss +1 -0
- data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/ui-select/selectize.default.css +443 -0
- data/lib/fanforce/plugin_factory/cli.rb +5 -0
- data/lib/fanforce/plugin_factory/cli/lib/bitbucket.rb +77 -0
- data/lib/fanforce/plugin_factory/cli/lib/bundler.rb +21 -0
- data/lib/fanforce/plugin_factory/cli/lib/env.rb +96 -0
- data/lib/fanforce/plugin_factory/cli/lib/git.rb +59 -0
- data/lib/fanforce/plugin_factory/cli/lib/heroku.rb +94 -0
- data/lib/fanforce/plugin_factory/cli/lib/iron.rb +71 -0
- data/lib/fanforce/plugin_factory/cli/lib/pow.rb +46 -0
- data/lib/fanforce/plugin_factory/cli/lib/scaffolding.rb +74 -0
- data/lib/fanforce/plugin_factory/cli/lib/scaffolding_file.rb +510 -0
- data/lib/fanforce/plugin_factory/cli/lib/uranium.rb +77 -0
- data/lib/fanforce/plugin_factory/cli/lib/utils.rb +57 -0
- data/lib/fanforce/plugin_factory/cli/scripts/config.rb +9 -0
- data/lib/fanforce/plugin_factory/cli/scripts/create.rb +64 -0
- data/lib/fanforce/plugin_factory/cli/scripts/destroy.rb +61 -0
- data/lib/fanforce/plugin_factory/cli/scripts/diff.rb +156 -0
- data/lib/fanforce/plugin_factory/cli/scripts/push.rb +88 -0
- data/lib/fanforce/plugin_factory/cli/scripts/restart.rb +41 -0
- data/lib/fanforce/plugin_factory/cli/scripts/setup.rb +70 -0
- data/lib/fanforce/plugin_factory/cli/scripts/update.rb +132 -0
- data/lib/fanforce/plugin_factory/cli_directory_of_plugins.rb +51 -0
- data/lib/fanforce/plugin_factory/cli_single_plugin.rb +52 -0
- data/lib/fanforce/plugin_factory/controllers/base_controller.rb +15 -0
- data/lib/fanforce/plugin_factory/core_config.rb +94 -0
- data/lib/fanforce/plugin_factory/directive_views/initiative-footer.haml +8 -0
- data/lib/fanforce/plugin_factory/load.rb +7 -0
- data/lib/fanforce/plugin_factory/load_iron_worker.rb +2 -0
- data/lib/fanforce/plugin_factory/load_sprockets.rb +2 -0
- data/lib/fanforce/plugin_factory/plugin.rb +60 -0
- data/lib/fanforce/plugin_factory/scaffolding/._.gitignore.registry +1 -0
- data/lib/fanforce/plugin_factory/scaffolding/._Gemfile.registry +3 -0
- data/lib/fanforce/plugin_factory/scaffolding/._Rakefile.registry +3 -0
- data/lib/fanforce/plugin_factory/scaffolding/._config.json.registry +2 -0
- data/lib/fanforce/plugin_factory/scaffolding/._config.ru.registry +4 -0
- data/lib/fanforce/plugin_factory/scaffolding/._favicon.ico.registry +1 -0
- data/lib/fanforce/plugin_factory/scaffolding/._robots.txt.registry +3 -0
- data/lib/fanforce/plugin_factory/scaffolding/.gitignore +27 -0
- data/lib/fanforce/plugin_factory/scaffolding/Gemfile +9 -0
- data/lib/fanforce/plugin_factory/scaffolding/Rakefile +7 -0
- data/lib/fanforce/plugin_factory/scaffolding/Routes.rb +67 -0
- data/lib/fanforce/plugin_factory/scaffolding/assets/css/._fembedded.scss.registry +4 -0
- data/lib/fanforce/plugin_factory/scaffolding/assets/css/._promotional.scss.registry +4 -0
- data/lib/fanforce/plugin_factory/scaffolding/assets/css/._visitor.scss.registry +4 -0
- data/lib/fanforce/plugin_factory/scaffolding/assets/css/fembedded.scss +24 -0
- data/lib/fanforce/plugin_factory/scaffolding/assets/css/promotional.scss +33 -0
- data/lib/fanforce/plugin_factory/scaffolding/assets/css/visitor.scss +61 -0
- data/lib/fanforce/plugin_factory/scaffolding/assets/img/._icon-16.png.registry +1 -0
- data/lib/fanforce/plugin_factory/scaffolding/assets/img/._icon-32.png.registry +1 -0
- data/lib/fanforce/plugin_factory/scaffolding/assets/img/._icon-42.png.registry +1 -0
- data/lib/fanforce/plugin_factory/scaffolding/assets/img/._marketplace.png.registry +1 -0
- data/lib/fanforce/plugin_factory/{assets → scaffolding/assets}/img/icon-16.png +0 -0
- data/lib/fanforce/plugin_factory/{assets → scaffolding/assets}/img/icon-32.png +0 -0
- data/lib/fanforce/plugin_factory/{assets → scaffolding/assets}/img/icon-42.png +0 -0
- data/lib/fanforce/plugin_factory/scaffolding/assets/img/marketplace.png +0 -0
- data/lib/fanforce/plugin_factory/scaffolding/assets/img/promotional/._fanforce_bg.png.registry +1 -0
- data/lib/fanforce/plugin_factory/scaffolding/assets/img/promotional/._icon-42.png.registry +1 -0
- data/lib/fanforce/plugin_factory/scaffolding/assets/img/promotional/._icon-plus.png.registry +1 -0
- data/lib/fanforce/plugin_factory/{assets/lib → scaffolding/assets/img}/promotional/fanforce_bg.png +0 -0
- data/lib/fanforce/plugin_factory/{assets/lib → scaffolding/assets/img}/promotional/icon-42.png +0 -0
- data/lib/fanforce/plugin_factory/scaffolding/assets/img/promotional/icon-plus.png +0 -0
- data/lib/fanforce/plugin_factory/scaffolding/assets/js/._fembedded-app.coffee.registry +5 -0
- data/lib/fanforce/plugin_factory/scaffolding/assets/js/._fembedded.js.registry +3 -0
- data/lib/fanforce/plugin_factory/scaffolding/assets/js/._promotional.js.registry +3 -0
- data/lib/fanforce/plugin_factory/scaffolding/assets/js/fembedded-app.coffee +11 -0
- data/lib/fanforce/plugin_factory/scaffolding/assets/js/fembedded.js +12 -0
- data/lib/fanforce/plugin_factory/scaffolding/assets/js/lib/._cookie.coffee.registry +3 -0
- data/lib/fanforce/plugin_factory/scaffolding/assets/js/lib/._filters.coffee.registry +3 -0
- data/lib/fanforce/plugin_factory/scaffolding/assets/js/lib/._utils.coffee.registry +3 -0
- data/lib/fanforce/plugin_factory/scaffolding/assets/js/lib/cookie.coffee +24 -0
- data/lib/fanforce/plugin_factory/scaffolding/assets/js/lib/filters.coffee +9 -0
- data/lib/fanforce/plugin_factory/scaffolding/assets/js/lib/utils.coffee +40 -0
- data/lib/fanforce/plugin_factory/scaffolding/assets/js/promotional.js +4 -0
- data/lib/fanforce/plugin_factory/scaffolding/config.json +24 -0
- data/lib/fanforce/plugin_factory/scaffolding/config.ru +8 -0
- data/lib/fanforce/plugin_factory/{public → scaffolding}/favicon.ico +0 -0
- data/lib/fanforce/plugin_factory/scaffolding/layouts/._fembedded.haml.registry +4 -0
- data/lib/fanforce/plugin_factory/scaffolding/layouts/._promotional.haml.registry +2 -0
- data/lib/fanforce/plugin_factory/scaffolding/layouts/._visitor.haml.registry +6 -0
- data/lib/fanforce/plugin_factory/scaffolding/layouts/fembedded.haml +26 -0
- data/lib/fanforce/plugin_factory/{layouts → scaffolding/layouts}/promotional.haml +6 -6
- data/lib/fanforce/plugin_factory/{layouts/engage.haml → scaffolding/layouts/visitor.haml} +10 -7
- data/lib/fanforce/plugin_factory/scaffolding/robots.txt +7 -0
- data/lib/fanforce/plugin_factory/scaffolding/views/._index.haml.registry +3 -0
- data/lib/fanforce/plugin_factory/{views → scaffolding/views}/index.haml +13 -7
- data/lib/fanforce/plugin_factory/sinatra/_load.rb +87 -0
- data/lib/fanforce/plugin_factory/sinatra/error_handling.rb +48 -0
- data/lib/fanforce/plugin_factory/sinatra/helper_routes/com_behavior.rb +19 -0
- data/lib/fanforce/plugin_factory/sinatra/helper_routes/com_broadcaster.rb +7 -0
- data/lib/fanforce/plugin_factory/sinatra/helper_routes/com_connector.rb +11 -0
- data/lib/fanforce/plugin_factory/sinatra/helper_routes/com_identifier.rb +3 -0
- data/lib/fanforce/plugin_factory/sinatra/helper_routes/com_js_widget.rb +8 -0
- data/lib/fanforce/plugin_factory/sinatra/helper_routes/plugin.rb +50 -0
- data/lib/fanforce/plugin_factory/sinatra/helpers/assets.rb +23 -0
- data/lib/fanforce/plugin_factory/sinatra/helpers/css_frameworks.rb +70 -0
- data/lib/fanforce/plugin_factory/sinatra/helpers/fanforce.rb +18 -0
- data/lib/fanforce/plugin_factory/{config → sinatra}/helpers/json.rb +2 -2
- data/lib/fanforce/plugin_factory/sinatra/helpers/ractive.rb +45 -0
- data/lib/fanforce/plugin_factory/sprockets/compiler.rb +5 -11
- data/lib/fanforce/plugin_factory/sprockets/hacks.rb +2 -2
- data/lib/fanforce/plugin_factory/version.rb +2 -2
- metadata +201 -195
- data/.rbenv-gemsets +0 -1
- data/.rbenv-version +0 -1
- data/lib/fanforce/plugin_factory.rake +0 -72
- data/lib/fanforce/plugin_factory/_init_sinatra.rb +0 -54
- data/lib/fanforce/plugin_factory/assets/css/add_edit_initiative.scss +0 -1
- data/lib/fanforce/plugin_factory/assets/css/add_source.scss +0 -1
- data/lib/fanforce/plugin_factory/assets/css/convert_pending_initiative.scss +0 -1
- data/lib/fanforce/plugin_factory/assets/css/engage.scss +0 -1
- data/lib/fanforce/plugin_factory/assets/css/new_message.scss +0 -1
- data/lib/fanforce/plugin_factory/assets/css/promotional.scss +0 -1
- data/lib/fanforce/plugin_factory/assets/css/source_details.scss +0 -1
- data/lib/fanforce/plugin_factory/assets/js/add_edit_initiative.js +0 -1
- data/lib/fanforce/plugin_factory/assets/js/add_source.js +0 -1
- data/lib/fanforce/plugin_factory/assets/js/convert_pending_initiative.js +0 -1
- data/lib/fanforce/plugin_factory/assets/js/engage.js +0 -1
- data/lib/fanforce/plugin_factory/assets/js/new_message.js +0 -1
- data/lib/fanforce/plugin_factory/assets/js/promotional.js +0 -2
- data/lib/fanforce/plugin_factory/assets/js/source_details.js +0 -0
- data/lib/fanforce/plugin_factory/assets/lib/common/_module-error.scss +0 -11
- data/lib/fanforce/plugin_factory/assets/lib/common/_module-page-loading.scss +0 -1
- data/lib/fanforce/plugin_factory/assets/lib/common/_module-saving-initiative.scss +0 -6
- data/lib/fanforce/plugin_factory/assets/lib/common/_tags.scss +0 -1
- data/lib/fanforce/plugin_factory/assets/lib/common/_variables.scss +0 -27
- data/lib/fanforce/plugin_factory/assets/lib/common/broadcaster-divider-arrow.png +0 -0
- data/lib/fanforce/plugin_factory/assets/lib/common/icons/dropdown-arrow.png +0 -0
- data/lib/fanforce/plugin_factory/assets/lib/common/icons/initiative.png +0 -0
- data/lib/fanforce/plugin_factory/assets/lib/common/layouts/_add_edit_initiative.scss +0 -27
- data/lib/fanforce/plugin_factory/assets/lib/common/layouts/_add_source.scss +0 -18
- data/lib/fanforce/plugin_factory/assets/lib/common/layouts/_convert_pending_initiative.scss +0 -27
- data/lib/fanforce/plugin_factory/assets/lib/common/layouts/_engage.scss +0 -78
- data/lib/fanforce/plugin_factory/assets/lib/common/layouts/_new_message.scss +0 -24
- data/lib/fanforce/plugin_factory/assets/lib/common/layouts/_promotional.scss +0 -27
- data/lib/fanforce/plugin_factory/assets/lib/common/layouts/_source_details.scss +0 -17
- data/lib/fanforce/plugin_factory/assets/lib/common/layouts/add_edit_initiative.js +0 -6
- data/lib/fanforce/plugin_factory/assets/lib/common/layouts/add_source.js +0 -6
- data/lib/fanforce/plugin_factory/assets/lib/common/layouts/convert_pending_initiative.js +0 -6
- data/lib/fanforce/plugin_factory/assets/lib/common/layouts/engage.js +0 -0
- data/lib/fanforce/plugin_factory/assets/lib/common/layouts/new_message.js +0 -5
- data/lib/fanforce/plugin_factory/assets/lib/common/layouts/promotional.js +0 -1
- data/lib/fanforce/plugin_factory/assets/lib/common/layouts/source_details.js +0 -5
- data/lib/fanforce/plugin_factory/assets/lib/promotional/icon-behavior.png +0 -0
- data/lib/fanforce/plugin_factory/assets/lib/promotional/icon-broadcaster.png +0 -0
- data/lib/fanforce/plugin_factory/assets/lib/promotional/icon-data-connector.png +0 -0
- data/lib/fanforce/plugin_factory/assets/lib/promotional/icon-data-processor.png +0 -0
- data/lib/fanforce/plugin_factory/assets/lib/promotional/icon-identifier.png +0 -0
- data/lib/fanforce/plugin_factory/assets/lib/vendors/bootstrap-datepicker/datepicker.css +0 -7
- data/lib/fanforce/plugin_factory/assets/lib/vendors/bootstrap-datepicker/datepicker.js +0 -454
- data/lib/fanforce/plugin_factory/assets/lib/vendors/bootstrap-timepicker/timepicker.css +0 -82
- data/lib/fanforce/plugin_factory/assets/lib/vendors/bootstrap-timepicker/timepicker.js +0 -803
- data/lib/fanforce/plugin_factory/assets/lib/vendors/bootstrap/css/bootstrap.min.css +0 -7
- data/lib/fanforce/plugin_factory/assets/lib/vendors/bootstrap/img/glyphicons-halflings-regular.eot +0 -0
- data/lib/fanforce/plugin_factory/assets/lib/vendors/bootstrap/img/glyphicons-halflings-regular.svg +0 -0
- data/lib/fanforce/plugin_factory/assets/lib/vendors/bootstrap/img/glyphicons-halflings-regular.ttf +0 -0
- data/lib/fanforce/plugin_factory/assets/lib/vendors/bootstrap/img/glyphicons-halflings-regular.woff +0 -0
- data/lib/fanforce/plugin_factory/assets/lib/vendors/chosen/_chosen_override.scss +0 -6
- data/lib/fanforce/plugin_factory/assets/lib/vendors/chosen/chosen-sprite.png +0 -0
- data/lib/fanforce/plugin_factory/assets/lib/vendors/chosen/chosen-sprite@2x.png +0 -0
- data/lib/fanforce/plugin_factory/assets/lib/vendors/chosen/chosen.jquery.js +0 -1166
- data/lib/fanforce/plugin_factory/assets/lib/vendors/chosen/chosen.scss +0 -434
- data/lib/fanforce/plugin_factory/assets/lib/vendors/jquery/jquery-1.10.2.js +0 -9789
- data/lib/fanforce/plugin_factory/assets/lib/vendors/jquery/jquery.inputHint.js +0 -154
- data/lib/fanforce/plugin_factory/assets/lib/vendors/jquery/jquery.tmpl.debug.js +0 -484
- data/lib/fanforce/plugin_factory/assets/lib/vendors/knockout/knockout.custom-handlers.coffee +0 -155
- data/lib/fanforce/plugin_factory/assets/lib/vendors/knockout/knockout.debug.js +0 -4469
- data/lib/fanforce/plugin_factory/assets/lib/vendors/knockout/knockout.min.js +0 -96
- data/lib/fanforce/plugin_factory/assets/lib/vendors/select2/_select2_override.scss +0 -47
- data/lib/fanforce/plugin_factory/assets/lib/vendors/select2/select2-spinner.gif +0 -0
- data/lib/fanforce/plugin_factory/assets/lib/vendors/select2/select2.png +0 -0
- data/lib/fanforce/plugin_factory/assets/lib/vendors/select2/select2.scss +0 -617
- data/lib/fanforce/plugin_factory/assets/lib/vendors/select2/select2_modified.js +0 -3225
- data/lib/fanforce/plugin_factory/assets/lib/vendors/select2/select2x2.png +0 -0
- data/lib/fanforce/plugin_factory/assets/lib/vendors/underscore/underscore.debug.js +0 -999
- data/lib/fanforce/plugin_factory/config/_error_handling.rb +0 -27
- data/lib/fanforce/plugin_factory/config/core_config.rb +0 -92
- data/lib/fanforce/plugin_factory/config/helpers/assets.rb +0 -72
- data/lib/fanforce/plugin_factory/config/helpers/fanforce.rb +0 -19
- data/lib/fanforce/plugin_factory/layouts/add_edit_initiative.haml +0 -19
- data/lib/fanforce/plugin_factory/layouts/add_source.haml +0 -19
- data/lib/fanforce/plugin_factory/layouts/convert_pending_initiative.haml +0 -19
- data/lib/fanforce/plugin_factory/layouts/new_message.haml +0 -19
- data/lib/fanforce/plugin_factory/layouts/source_details.haml +0 -19
- data/lib/fanforce/plugin_factory/public/robots.txt +0 -2
- data/lib/fanforce/plugin_factory/routes.rb +0 -48
- data/lib/fanforce/plugin_factory/routes_behavior.rb +0 -34
- data/lib/fanforce/plugin_factory/routes_broadcaster.rb +0 -9
- data/lib/fanforce/plugin_factory/routes_data_connector.rb +0 -21
- data/lib/fanforce/plugin_factory/routes_identifier.rb +0 -3
- data/lib/fanforce/plugin_factory/views/add_initiative.haml +0 -1
- data/lib/fanforce/plugin_factory/views/add_source.haml +0 -1
- data/lib/fanforce/plugin_factory/views/close_popup.haml +0 -8
- data/lib/fanforce/plugin_factory/views/convert_pending_initiative.haml +0 -1
- data/lib/fanforce/plugin_factory/views/edit_initiative.haml +0 -1
- data/lib/fanforce/plugin_factory/views/engage.haml +0 -1
- data/lib/fanforce/plugin_factory/views/new_message.haml +0 -1
- data/lib/fanforce/plugin_factory/views/source_details.haml +0 -1
- data/lib/fanforce/plugin_factory/views/widget_tmpls.haml +0 -1
- data/lib/fanforce/plugin_factory_workers.rb +0 -2
File without changes
|
File without changes
|
File without changes
|
data/lib/fanforce/plugin_factory/asset_framework/plugin_factory/directives/loading/_loading.scss
ADDED
@@ -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; }
|
File without changes
|
@@ -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
|
+
}
|
File without changes
|
@@ -1,6 +1,7 @@
|
|
1
|
-
$module_path: '/assets/
|
2
|
-
|
3
|
-
|
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:
|
6
|
+
.text { color: #afb7c8; font-weight: bold; position:absolute; top: 78px; left: 125px; white-space: nowrap; }
|
6
7
|
}
|
File without changes
|
@@ -1,7 +1,7 @@
|
|
1
|
-
$module_path: '/assets/
|
2
|
-
|
1
|
+
$module_path: '/assets/plugin_factory/directives/video-thumbnail';
|
2
|
+
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
3
3
|
|
4
|
-
|
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
|
+
}
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
#=require_tree ./font-awesome
|
File without changes
|
@@ -27,8 +27,8 @@
|
|
27
27
|
* -------------------------- */
|
28
28
|
@font-face {
|
29
29
|
font-family: 'FontAwesome';
|
30
|
-
src: url('/assets/
|
31
|
-
src: url('/assets/
|
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
|
}
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
#=require_tree ./lib
|
@@ -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 @@
|
|
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)\"> ×</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>");}]);
|