Commit 91413026 by nabil el mahiri

Initial commit

parents
Pipeline #295 failed with stages
in 3 seconds
node_modules
*npm-debug
/logs/*
image: docker
services:
- docker:dind
before_script:
- docker info
- echo $CI_BUILD_REF
- echo $CI_PROJECT_DIR
- echo ${PWD}
stages:
- build
- deploy
build:
stage: build
environment: Production
tags:
- atlasvoyages-prod-runner
only:
- master
script:
- chmod +x sh/run.sh
- docker build -f docker/Dockerfile -t atlasvoyages-docker:prod .
- sh sh/clean.sh
deploy:
stage: deploy
environment: Production
tags:
- atlasvoyages-prod-runner
only:
- master
script:
- chmod +x sh/run.sh
- sh sh/run.sh
- docker run -d -p 9034:80 --name atlasvoyages-docker-prod atlasvoyages-docker:prod
- sh sh/clean.sh
\ No newline at end of file
{"app":{"name":"atlas-voyages"},"dev":{"plugin":""}}
\ No newline at end of file
"use strict";
module.exports = function(grunt) {
var pkg = require('./package.json');
var conf = {
clean: ['logs'],
prompt: {
setup: {
options: {
questions: [{
config: 'app.name',
type: 'list',
message: 'App your working on?',
choices: grunt.file.expand({
filter: 'isDirectory'
}, './apps/*').map(function(d) {
return d.replace('./apps/', '')
})
}, {
config: 'dev.plugin',
type: 'input',
message: 'Module to watch for changes ?',
validate: function(name) {
if (!name) return true;
var dir = grunt.file.expand({
filter: 'isDirectory'
}, './node_modules/' + name);
return dir.length === 1 || (name + " not found in ./node_modules (leave empty to ignore)");
}
}]
}
}
},
watch: {
/*
gruntfile: {
files: "<%= jshint.gruntfile.src %>",
//tasks: ["jshint:gruntfile"]
},
*/
css: {
files: ['node_modules/<%= app.theme %>/public/css/*.css'],
tasks: ['pine:newer:copy:css'],
debounceDelay: 1000,
},
modScripts: {
files: ['node_modules/<%= dev.plugin %>/html/scripts/*.js'],
tasks: ['pine:newer:copy:scripts']
}
},
nodemon: {
dev: {
script: 'index.js',
options: {
args: ['<%= app.name %>'],
watch: [
'node_modules/<%= app.theme %>/templates',
'apps/<%= app.name %>/public/scripts'
],
ext: 'html,js'
}
}
},
bump: {
options: {
commit: true,
commitMessage: grunt.option("message") || 'Release v%VERSION%',
commitFiles: ['-a'], // '-a' for all files
createTag: false,
push: true,
pushTo: 'origin',
}
},
copy: {
css: {
expand: true,
cwd: 'node_modules/<%= app.theme %>/public/css',
src: "*",
dest: 'apps/<%= app.name %>/public/css/'
},
img: {
expand: true,
cwd: 'node_modules/<%= app.theme %>/public/img',
src: ["*"],
dest: './apps/<%= app.name %>/public/img'
},
scripts: {
expand: true,
cwd: 'node_modules/',
src: ["{<%= app.conf.plugins %>}/html/scripts/**/*"],
rename: function(dest, src) {
return dest + src.replace(/^(.+)\/html\/scripts\/(.+)$/, '$1/$2');
},
dest: './apps/<%= app.name %>/public/scripts/'
}
},
concurrent: {
dev: {
tasks: ['pine:nodemon:dev', 'pine:watch'],
options: {
logConcurrentOutput: true
}
}
}
}
grunt.registerTask('pine', function() {
var setup;
try {
setup = grunt.file.readJSON('./.pinedev');
} catch (e) {
grunt.log.error(e);
if (e.origError && e.origError.code === 'ENOENT') {
grunt.fail.warn('You haven\'t set up your pine dev settings. Run grunt pine:setup then retry');
} else {
grunt.fail.warn('Unable to read pine dev settings (.pinedev). Run grunt pine:setup then retry');
throw e;
}
return false;
}
setup.app.dir = process.cwd() + "/apps/" + setup.app.name;
setup.app.conf = require('pine/lib/conf.js')(setup.app.dir);
if (setup.app.conf.html) {
setup.app.theme = setup.app.conf.html.theme;
} else {
delete conf.copy;
delete conf.watch.css;
delete conf.watch.modScripts;
conf.nodemon.dev.options.watch = ['index.js'];
conf.nodemon.dev.options.ext;
conf.nodemon.dev.options.ignore = ['**'];
conf.concurrent.dev.tasks.pop();
}
grunt.config('app', setup.app);
grunt.config('dev', setup.dev);
grunt.log.subhead("Application " + setup.app);
var _task = Array.prototype.slice.call(arguments, 0);
grunt.task.run(_task.join(':'));
});
grunt.registerTask('pine:setupSave', function() {
var pineSetup = {
'app': grunt.config('app'),
'dev': grunt.config('dev')
}
console.log(pineSetup);
grunt.file.write('./.pinedev', JSON.stringify(pineSetup));
});
grunt.registerTask('pine:setup', ['prompt', 'pine:setupSave']);
grunt.registerTask('serve', ['concurrent:dev'])
require('load-grunt-tasks')(grunt);
//require('./grunt/sync-versions.js')(grunt);
// Project configuration.
grunt.initConfig(conf);
};
\ No newline at end of file
# One code base multiple apps
# Install
```
cd [your-workspace]
# clone pine-server
git clone git@labs.fractalite.com:pine/pine-server.git
cd pine-server
npm install
# clone an app
cd apps
git clone git@labs.fractalite.com:webapps/atlas-incoming.git
# continue if app has html ui
# install theme
cd [your-workspace]/pine-server
npm install $theme-name
# copy browser scripts from modules to apps/atlasincoming
# copy css from theme to apps/atlasincoming/public
# copy img from theme to apps/atlasincoming/public
cd <your-workspace>/pine-server
grunt pine --app atlasincoming
```
# Create an app
```
cd [your-workspace]/pine-server/apps
mkdir yourapp
mkdir yourapp/etc
touch yourapp/etc/conf.json
touch yourapp/etc/conf.dev.json
touch yourapp/etc/conf.stage.json
touch yourapp/etc/conf.prod.json
mkdir yourapp/etc/nginx
mkdir yourapp/public
touch yourapp/robots.txt
```
## add nginx config
### 1. Copy sample conf
```
cd [your-workspace]/pine-server
cp etc/nginx.sample.conf apps/yourapp/etc/nginx/nginx.dev.conf
```
### 2. Edit
```
vim apps/yourapp/etc/nginx/nginx.dev.conf
```
change $public var to:
```
set $public _your-workspace_/pine-server/apps/yourapp/public;
```
change upstream name and port (the same as in conf.json#http.port)
when binding express to a unix socket use nginx's unix:path/to/socket syntax
```
upstream node_[yourappname] {
server 127.0.0.1:[express-port];
}
```
change the vhost port (the port nginx will listen on, must be different from upstream port)
```
server {
listen [port];
server_name localhost;
```
change the proxy_pass under ``location /`` so as it points to you upstream
```
proxy_pass http://node_[yourappname];
```
\ No newline at end of file
atlas-voyages @ 6e2cfc3b
Subproject commit 6e2cfc3b74c9fa793df8c9fe2dbf395ebfc728af
{
"name": "angular-ui-select",
"homepage": "https://github.com/angular-ui/ui-select",
"authors": [
"AngularUI"
],
"description": "AngularJS ui-select",
"main": [
"dist/select.js",
"dist/select.css"
],
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"src",
"test",
"gulpfile.js",
"karma.conf.js",
"examples"
],
"dependencies": {
"angular": ">=1.2.18"
},
"devDependencies": {
"jquery": "~1.11",
"angular-sanitize": ">=1.2.18",
"angular-mocks": ">=1.2.18"
},
"version": "0.19.6",
"_release": "0.19.6",
"_resolution": {
"type": "version",
"tag": "v0.19.6",
"commit": "9b85d97b07da651aa5ba76ae9e50325d3587c9f6"
},
"_source": "https://github.com/angular-ui/ui-select.git",
"_target": "~0.19.6",
"_originalSource": "angular-ui-select",
"_direct": true
}
\ No newline at end of file
<a name="0.19.5"></a>
## [0.19.5](https://github.com/angular-ui/ui-select/compare/v0.19.5...v0.19.5) (2016-10-24)
## Reverted
* **Bug fix:** Search input isn't blocked ([0d81493](https://github.com/angular-ui/ui-select/commit/0d81493))
<a name="0.19.4"></a>
## [0.19.4](https://github.com/angular-ui/ui-select/compare/v0.19.4...v0.19.4) (2016-10-19)
### Bug Fixes
* **bootstrap:** add aria-expanded to the multiple select ([6766754](https://github.com/angular-ui/ui-select/commit/6766754)), closes [#1775](https://github.com/angular-ui/ui-select/issues/1775)
* ensure aria-activedescendant is correct ([e3be4d1](https://github.com/angular-ui/ui-select/commit/e3be4d1))
* only apply listbox role when open ([e902ffc](https://github.com/angular-ui/ui-select/commit/e902ffc))
* **bootstrap:** add search role ([f3194bf](https://github.com/angular-ui/ui-select/commit/f3194bf))
### Features
* **selectize:** add support for multiple selection ([ff8071d](https://github.com/angular-ui/ui-select/commit/ff8071d)), closes [#295](https://github.com/angular-ui/ui-select/issues/295) [#1787](https://github.com/angular-ui/ui-select/issues/1787)
<a name="0.19.3"></a>
## [0.19.3](https://github.com/angular-ui/ui-select/compare/v0.19.3...v0.19.3) (2016-08-17)
<a name="0.19.2"></a>
## [0.19.2](https://github.com/angular-ui/ui-select/compare/v0.19.0...v0.19.2) (2016-08-16)
### Bug Fixes
* **bootstrap layout:** Restrict selected length to ui-select-container (#1680) ([01055c5](https://github.com/angular-ui/ui-select/commit/01055c5)), closes [#1576](https://github.com/angular-ui/ui-select/issues/1576)
* **release:** bump version with built files ([76cf9c3](https://github.com/angular-ui/ui-select/commit/76cf9c3))
<a name="0.19.1"></a>
## [0.19.1](https://github.com/angular-ui/ui-select/compare/v0.19.0...v0.19.1) (2016-08-09)
### Bug Fixes
* **bootstrap layout:** Restrict selected length to ui-select-container (#1680) ([01055c5](https://github.com/angular-ui/ui-select/commit/01055c5)), closes [#1576](https://github.com/angular-ui/ui-select/issues/1576)
<a name="0.19.0"></a>
# [0.19.0](https://github.com/angular-ui/ui-select/compare/v0.19.0...v0.19.0) (2016-08-07)
### Bug Fixes
* **bootstrap layout:** Restrict selected length to ui-select-container (#1680) ([01055c5](https://github.com/angular-ui/ui-select/commit/01055c5)), closes [#1576](https://github.com/angular-ui/ui-select/issues/1576)
<a name="0.18.1"></a>
## [0.18.1](https://github.com/angular-ui/ui-select/compare/v0.18.1...v0.18.1) (2016-08-07)
### Bug Fixes
* **bootstrap:** remove anchor tag in choices ([b15189d](https://github.com/angular-ui/ui-select/commit/b15189d))
* **uiSelect:** remove flicker on search change ([81c33d0](https://github.com/angular-ui/ui-select/commit/81c33d0)), closes [#1298](https://github.com/angular-ui/ui-select/issues/1298) [#1594](https://github.com/angular-ui/ui-select/issues/1594) [#1557](https://github.com/angular-ui/ui-select/issues/1557)
* **uiSelectController:** Select by click on non-multiple tagging (bis) (#1727) ([3dfde71](https://github.com/angular-ui/ui-select/commit/3dfde71))
### Features
* **events:** add open-close callback ([21bcd5e](https://github.com/angular-ui/ui-select/commit/21bcd5e)), closes [#432](https://github.com/angular-ui/ui-select/issues/432) [#1153](https://github.com/angular-ui/ui-select/issues/1153)
### Performance Improvements
* **repeatParserService:** track groups by name ([1770038](https://github.com/angular-ui/ui-select/commit/1770038)), closes [#1721](https://github.com/angular-ui/ui-select/issues/1721) [#1722](https://github.com/angular-ui/ui-select/issues/1722)
<a name="0.18.1"></a>
## [0.18.1](https://github.com/angular-ui/ui-select/compare/v0.18.0...v0.18.1) (2016-07-10)
### Bug Fixes
* **isDisabled:** do not modify item ([b95bf9f](https://github.com/angular-ui/ui-select/commit/b95bf9f)), closes [#1200](https://github.com/angular-ui/ui-select/issues/1200) [#1661](https://github.com/angular-ui/ui-select/issues/1661)
* **isLocked:** do not modify item ([c01d363](https://github.com/angular-ui/ui-select/commit/c01d363)), closes [#1269](https://github.com/angular-ui/ui-select/issues/1269) [#514](https://github.com/angular-ui/ui-select/issues/514)
* **removeSelected:** fix incorrect removal of preselected item ([32b7924](https://github.com/angular-ui/ui-select/commit/32b7924)), closes [#1672](https://github.com/angular-ui/ui-select/issues/1672)
* **searchEnabled:** watch evaluated attribute value ([4503295](https://github.com/angular-ui/ui-select/commit/4503295)), closes [#505](https://github.com/angular-ui/ui-select/issues/505)
* **select2:** Up-direction when using global theme ([5336dc5](https://github.com/angular-ui/ui-select/commit/5336dc5)), closes [#1674](https://github.com/angular-ui/ui-select/issues/1674)
* **Selectize:** hide input box when selected data is 0 ([e179dc6](https://github.com/angular-ui/ui-select/commit/e179dc6)), closes [#1304](https://github.com/angular-ui/ui-select/issues/1304)
* **tagging:** infite digest loops when name is similar ([fcd9bc5](https://github.com/angular-ui/ui-select/commit/fcd9bc5)), closes [#1693](https://github.com/angular-ui/ui-select/issues/1693)
* **tagging:** Support paste with tagging enabled and tagging-label="false" ([668a0f3](https://github.com/angular-ui/ui-select/commit/668a0f3)), closes [#1668](https://github.com/angular-ui/ui-select/issues/1668)
* **uiSelectMultiple:** $select.refreshItems is not a function ([a41a7fc](https://github.com/angular-ui/ui-select/commit/a41a7fc))
* **uiSelectMultiple:** Allow duplicates in $select.selected ([9f5d6ec](https://github.com/angular-ui/ui-select/commit/9f5d6ec)), closes [#1688](https://github.com/angular-ui/ui-select/issues/1688)
* **uiSelectMultiple:** tolerate null/undefined view value ([0c29b64](https://github.com/angular-ui/ui-select/commit/0c29b64))
* **uiSelectNoChoice:** support Select2 theme ([e59e008](https://github.com/angular-ui/ui-select/commit/e59e008)), closes [#1608](https://github.com/angular-ui/ui-select/issues/1608)
* **uiSelectNoChoice:** support Selectize theme ([a7210c4](https://github.com/angular-ui/ui-select/commit/a7210c4)), closes [#1692](https://github.com/angular-ui/ui-select/issues/1692)
<a name="0.18.0"></a>
## [0.18.0](https://github.com/angular-ui/ui-select/compare/v0.17.1...v0.18.0) (2016-06-09)
### Bug Fixes
* **positioning:** stop flicker when closed ([ca4d09e](https://github.com/angular-ui/ui-select/commit/ca4d09e))
* **positioning:** wait for animation to complete ([aa90dd8](https://github.com/angular-ui/ui-select/commit/aa90dd8)), closes [#1593](https://github.com/angular-ui/ui-select/issues/1593)
* search input width resizing ([5c8cf86](https://github.com/angular-ui/ui-select/commit/5c8cf86)), closes [#1575](https://github.com/angular-ui/ui-select/issues/1575)
* **uiSelectCtrl:** Prevent error when using ngAnimate < v1.4 ([8becac3](https://github.com/angular-ui/ui-select/commit/8becac3)), closes [#1626](https://github.com/angular-ui/ui-select/issues/1626)
* **uiSelectNoChoice:** make compatible with Angular 1.5 ([c944307](https://github.com/angular-ui/ui-select/commit/c944307)), closes [#1609](https://github.com/angular-ui/ui-select/issues/1609)
* **uiSelectNoChoice:** support bootstrap-multiple ([9d29307](https://github.com/angular-ui/ui-select/commit/9d29307)), closes [#1614](https://github.com/angular-ui/ui-select/issues/1614) [#1615](https://github.com/angular-ui/ui-select/issues/1615)
### Features
* **limit:** Change multi-select limit attr (#1632) ([f5888fb](https://github.com/angular-ui/ui-select/commit/f5888fb))
* **removeSelected:** Implement removeSelected property for multiple selects ([3ad084f](https://github.com/angular-ui/ui-select/commit/3ad084f))
<a name="0.17.1"></a>
## [0.17.1](https://github.com/angular-ui/ui-select/compare/v0.17.0...v0.17.1) (2016-05-16)
### Bug Fixes
* **parserResult:** Ignore undefined parserResult when using custom tpl ([cee24e5](https://github.com/angular-ui/ui-select/commit/cee24e5)), closes [#1597](https://github.com/angular-ui/ui-select/issues/1597)
* **select2:** hide dropdown if there are no items to show (same as #1588 for bootstrap) ([4c561ac](https://github.com/angular-ui/ui-select/commit/4c561ac))
<a name="0.17.0"></a>
## [0.17.0](https://github.com/angular-ui/ui-select/compare/v0.16.1...v0.17.0) (2016-05-11)
### Bug Fixes
* **a11y:** prevent list from being focusable ([4e9ab7e](https://github.com/angular-ui/ui-select/commit/4e9ab7e)), closes [#898](https://github.com/angular-ui/ui-select/issues/898)
* **autocomplete:** change to type="search" ([48cf1ba](https://github.com/angular-ui/ui-select/commit/48cf1ba)), closes [#991](https://github.com/angular-ui/ui-select/issues/991)
* **bootstrap:** hide clear button if disabled ([fe0c0c1](https://github.com/angular-ui/ui-select/commit/fe0c0c1)), closes [#1388](https://github.com/angular-ui/ui-select/issues/1388) [#980](https://github.com/angular-ui/ui-select/issues/980)
* **bootstrap:** hide dropdown if there are no items to show ([7c8b3a0](https://github.com/angular-ui/ui-select/commit/7c8b3a0)), closes [#1588](https://github.com/angular-ui/ui-select/issues/1588)
* **build:** fix sourcemap logic ([6d4849f](https://github.com/angular-ui/ui-select/commit/6d4849f))
* **demo-tagging:** error in Object Tags for input "a" ([7963684](https://github.com/angular-ui/ui-select/commit/7963684))
* **sortable:** remove classes properly ([4b1ed47](https://github.com/angular-ui/ui-select/commit/4b1ed47)), closes [#902](https://github.com/angular-ui/ui-select/issues/902)
* **tagging:** do not remove selected items when invalid ([331f819](https://github.com/angular-ui/ui-select/commit/331f819)), closes [#1359](https://github.com/angular-ui/ui-select/issues/1359)
* **tagging groupBy:** fix group-by to work with tagging ([80be85b](https://github.com/angular-ui/ui-select/commit/80be85b))
* **tagging multiple:** hide tagging item if null returned ([2f14045](https://github.com/angular-ui/ui-select/commit/2f14045))
* **uiSelectCtrl:** correcting input focus ([6444d6b](https://github.com/angular-ui/ui-select/commit/6444d6b)), closes [#1253](https://github.com/angular-ui/ui-select/issues/1253)
* **uiSelectSingleDirective:** strictly compare matching value ([a574cd4](https://github.com/angular-ui/ui-select/commit/a574cd4)), closes [#1328](https://github.com/angular-ui/ui-select/issues/1328)
* **uiSelectSort:** update model on sort completion ([9a40b6f](https://github.com/angular-ui/ui-select/commit/9a40b6f)), closes [#974](https://github.com/angular-ui/ui-select/issues/974) [#1036](https://github.com/angular-ui/ui-select/issues/1036)
* ensure highlighted before selecting on tab ([06bbd31](https://github.com/angular-ui/ui-select/commit/06bbd31)), closes [#1030](https://github.com/angular-ui/ui-select/issues/1030)
* properly gc on destruction ([95692e7](https://github.com/angular-ui/ui-select/commit/95692e7))
* show input when search is disabled ([83132b0](https://github.com/angular-ui/ui-select/commit/83132b0)), closes [#595](https://github.com/angular-ui/ui-select/issues/595) [#453](https://github.com/angular-ui/ui-select/issues/453)
* show select element when search is disabled ([f37bafd](https://github.com/angular-ui/ui-select/commit/f37bafd)), closes [#861](https://github.com/angular-ui/ui-select/issues/861)
### Features
* **perf:** debounce resize callback ([115ebf4](https://github.com/angular-ui/ui-select/commit/115ebf4))
* **perf:** optimize width resizing ([d78ba5f](https://github.com/angular-ui/ui-select/commit/d78ba5f))
### Performance Improvements
* **tagging multiple:** transform tagging item only once when filtering ([2b4a9ea](https://github.com/angular-ui/ui-select/commit/2b4a9ea))
* **uiSelectCtrl:** moving activate events out of $timeout ([926f462](https://github.com/angular-ui/ui-select/commit/926f462))
* change test in ctrl.isActive ([d6c14d4](https://github.com/angular-ui/ui-select/commit/d6c14d4))
<a name="0.16.1"></a>
# [0.16.1](https://github.com/angular-ui/ui-select/compare/v0.16.0...v0.16.1) (2016-03-23)
### Bug Fixes
* **$window:** change input size on window resize ([ce24981](https://github.com/angular-ui/ui-select/commit/ce24981)), closes [#522](https://github.com/angular-ui/ui-select/issues/522)
* **uiSelectMultipleDirective:** add $isEmpty handler ([fccc29a](https://github.com/angular-ui/ui-select/commit/fccc29a)), closes [#850](https://github.com/angular-ui/ui-select/issues/850)
* **uiSelectMultipleDirective:** refresh choices upon selection change ([03293ff](https://github.com/angular-ui/ui-select/commit/03293ff)), closes [#1243](https://github.com/angular-ui/ui-select/issues/1243)
<a name="0.16.0"></a>
## [0.15.0](https://github.com/angular-ui/ui-select/compare/v0.15.0...v0.16.0)
<a name="0.15.0"></a>
## [0.15.0](https://github.com/angular-ui/ui-select/compare/v0.14.9...v0.15.0) (2016-03-15)
### Bug Fixes
* corrects out of scope variable ([d5e30fb](https://github.com/angular-ui/ui-select/commit/d5e30fb))
### Features
* provide a way to skip the focusser ([302e80f](https://github.com/angular-ui/ui-select/commit/302e80f)), closes [#869](https://github.com/angular-ui/ui-select/issues/869) [#401](https://github.com/angular-ui/ui-select/issues/401) [#818](https://github.com/angular-ui/ui-select/issues/818) [#603](https://github.com/angular-ui/ui-select/issues/603) [#432](https://github.com/angular-ui/ui-select/issues/432)
<a name="0.14.10"></a>
## [0.14.10](https://github.com/angular-ui/ui-select/compare/v0.14.9...v0.14.10) (2016-03-13)
### Features
* provide a way to skip the focusser ([302e80f](https://github.com/angular-ui/ui-select/commit/302e80f)), closes [#869](https://github.com/angular-ui/ui-select/issues/869) [#401](https://github.com/angular-ui/ui-select/issues/401) [#818](https://github.com/angular-ui/ui-select/issues/818) [#603](https://github.com/angular-ui/ui-select/issues/603) [#432](https://github.com/angular-ui/ui-select/issues/432)
<a name="0.14.9"></a>
## [0.14.9](https://github.com/angular-ui/ui-select/compare/v0.14.9...v0.14.9) (2016-03-06)
<a name="0.14.8"></a>
## [0.14.8](https://github.com/angular-ui/ui-select/compare/v0.14.7...v0.14.8) (2016-02-18)
<a name="0.14.7"></a>
## [0.14.7](https://github.com/angular-ui/ui-select/compare/v0.14.6...v0.14.7) (2016-02-18)
### Bug Fixes
* **IE:** selects not working on IE8 ([ee65677](https://github.com/angular-ui/ui-select/commit/ee65677)), closes [#158](https://github.com/angular-ui/ui-select/issues/158)
<a name="0.14.6"></a>
## [0.14.6](https://github.com/angular-ui/ui-select/compare/v0.14.5...v0.14.6) (2016-02-18)
### Bug Fixes
* **paste:** add paste support ([1ad6f60](https://github.com/angular-ui/ui-select/commit/1ad6f60)), closes [#910](https://github.com/angular-ui/ui-select/issues/910) [#704](https://github.com/angular-ui/ui-select/issues/704) [#789](https://github.com/angular-ui/ui-select/issues/789) [#848](https://github.com/angular-ui/ui-select/issues/848) [#429](https://github.com/angular-ui/ui-select/issues/429)
* **uiSelectSort:** fix dependency not found error ([a5a6554](https://github.com/angular-ui/ui-select/commit/a5a6554))
<a name="0.14.5"></a>
## [0.14.5](https://github.com/angular-ui/ui-select/compare/v0.14.4...v0.14.5) (2016-02-18)
### Bug Fixes
* **uiSelectMultipleDirective:** fix track by error ([ced1cc0](https://github.com/angular-ui/ui-select/commit/ced1cc0)), closes [#1343](https://github.com/angular-ui/ui-select/issues/1343)
<a name="0.14.4"></a>
## [0.14.4](https://github.com/angular-ui/ui-select/compare/v0.14.3...v0.14.4) (2016-02-18)
### Bug Fixes
* Allow setting a ngClass on <ui-select> element ([6a99b08](https://github.com/angular-ui/ui-select/commit/6a99b08)), closes [#277](https://github.com/angular-ui/ui-select/issues/277)
<a name="0.14.3"></a>
## [0.14.3](https://github.com/angular-ui/ui-select/compare/v0.14.2...v0.14.3) (2016-02-18)
<a name="0.14.2"></a>
## [0.14.2](https://github.com/angular-ui/ui-select/compare/v0.14.1...v0.14.2) (2016-02-18)
### Bug Fixes
* make compatible with Angular 1.5 and non-cached templates ([0e85670](https://github.com/angular-ui/ui-select/commit/0e85670)), closes [#1422](https://github.com/angular-ui/ui-select/issues/1422) [#1356](https://github.com/angular-ui/ui-select/issues/1356) [#1325](https://github.com/angular-ui/ui-select/issues/1325) [#1239](https://github.com/angular-ui/ui-select/issues/1239)
* **commonjs:** remove CSS require ([81b0f03](https://github.com/angular-ui/ui-select/commit/81b0f03))
* **track by:** fix "track by" ([6c52e41](https://github.com/angular-ui/ui-select/commit/6c52e41)), closes [#806](https://github.com/angular-ui/ui-select/issues/806) [#665](https://github.com/angular-ui/ui-select/issues/665)
<a name="0.14.1"></a>
## [0.14.1](https://github.com/angular-ui/ui-select/compare/v0.14.0...v0.14.1) (2016-01-27)
<a name="0.14.0"></a>
# [0.14.0](https://github.com/angular-ui/ui-select/compare/v0.13.2...v0.14.0) (2016-01-25)
### Features
* **ngAnimate:** add support for ngAnimate ([8da8a6d](https://github.com/angular-ui/ui-select/commit/8da8a6d))
<a name="0.13.3"></a>
## 0.13.3 (2016-01-25)
### Added
- Add support for commonjs and npm
<a name="0.13.2"></a>
## [0.13.2](https://github.com/angular-ui/ui-select/compare/v0.13.1...v0.13.2) (2016-01-25)
### Bug Fixes
* **CSP:** avoid inline execution of javascript in choices template. ([fb88ec8](https://github.com/angular-ui/ui-select/commit/fb88ec8))
<a name="0.13.1"></a>
## [v0.13.1](https://github.com/angular-ui/ui-select/compare/v0.13.0...v0.13.1) (2015-09-29)
### Fixed
- Remove hardcoded source name when using (key,value) syntax [#1217](https://github.com/angular-ui/ui-select/pull/1217)
- Modify regex to accept a full 'collection expression' when not using (key,value) syntax [#1216](https://github.com/angular-ui/ui-select/pull/1216)
- Avoid to recalculate position when set 'down' [#1214](https://github.com/angular-ui/ui-select/issues/1214#issuecomment-144271352)
<a name="0.13.0"></a>
## [v0.13.0](https://github.com/angular-ui/ui-select/compare/v0.12.1...v0.13.0) (2015-09-29)
### Added
- Allow to configure default dropdown position [#1213](https://github.com/angular-ui/ui-select/pull/1213)
- Can use object as source with (key,value) syntax [#1208](https://github.com/angular-ui/ui-select/pull/1208)
- CHANGELOG.md file created
### Changed
- Do not run bower after install automatically [#982](https://github.com/angular-ui/ui-select/pull/982)
- Avoid setting activeItem on mouseenter to improve performance [#1211](https://github.com/angular-ui/ui-select/pull/1211)
### Fixed
- Position dropdown UP or DOWN correctly depending on the available space [#1212](https://github.com/angular-ui/ui-select/pull/1212)
- Scroll to selected item [#976](https://github.com/angular-ui/ui-select/issues/976)
- Change `autocomplete='off'` to `autocomplete='false'` [#1210](https://github.com/angular-ui/ui-select/pull/1210)
- Fix to work correctly with debugInfoEnabled(false) [#1131](https://github.com/angular-ui/ui-select/pull/1131)
- Limit the maximum number of selections allowed in multiple mode [#1110](https://github.com/angular-ui/ui-select/pull/1110)
We are excited to have you working on the project and cordially request that you follow the Guidelines:
- [Got a question or problem?](#question)
- [You think you've found a bug?](#bug)
- [Code Style Guidelines](#rules)
- [Commit Message Guidelines](#commit)
## <a name="question"></a> Got a question or problem?
Firstly, please go over our FAQ: https://github.com/angular-ui/ui-select/wiki/FAQs
Please, do not open issues for the general support questions as we want to keep GitHub issues for bug reports and feature requests. You've got much better chances of getting your question answered on [StackOverflow](http://stackoverflow.com/questions/tagged/angular-ui-select) where maintainers are looking at questions tagged with `angular-ui-select`.
StackOverflow is a much better place to ask questions since:
* there are hundreds of people willing to help on StackOverflow
* questions and answers stay available for public viewing so your question / answer might help someone else
* SO voting system assures that the best answers are prominently visible.
To save your and our time we will be systematically closing all the issues that are requests for general support and redirecting people to StackOverflow.
## <a name="bug"></a> You think you've found a bug?
Oh, we are ashamed and want to fix it asap! But before fixing a bug we need to reproduce and confirm it. In order to reproduce bugs we will systematically ask you to provide a _minimal_ reproduce scenario using http://plnkr.co/. Having a live reproduce scenario gives us wealth of important information without going back & forth to you with additional questions like:
* version of AngularJS used
* version of this library that you are using
* 3rd-party libraries used, if any
* and most importantly - a use-case that fails
A minimal reproduce scenario using http://plnkr.co/ allows us to quickly confirm a bug (or point out coding problem) as well as confirm that we are fixing the right problem.
We will be insisting on a minimal reproduce scenario in order to save maintainers time and ultimately be able to fix more bugs. Interestingly, from our experience users often find coding problems themselves while preparing a minimal plunk. We understand that sometimes it might be hard to extract essentials bits of code from a larger code-base but we really need to isolate the problem before we can fix it.
The best part is that you don't need to create plunks from scratch - you can use one from our [demo page](http://plnkr.co/edit/a3KlK8dKH3wwiiksDSn2?p=preview).
Unfortunately we are not able to investigate / fix bugs without a minimal reproduce scenario using http://plnkr.co/, so if we don't hear back from you we are going to close an issue that don't have enough info to be reproduced.
## <a name="rules"></a> Coding Rules
To ensure consistency throughout the source code, keep these rules in mind as you are working:
* All features or bug fixes **must pass all tests** (run `gulp` to jshint, build and test).
* All public API methods **must be documented** with ngdoc, an extended version of jsdoc (we added
support for markdown and templating via @ngdoc tag). To see how we document our APIs, please check
out the existing ngdocs and see [this wiki page][ngDocs].
## <a name="commit"></a> Git Commit Guidelines
We have very precise rules over how our git commit messages can be formatted for maintenance of the changelog and semvar versioning. This leads to **more
readable messages** that are easy to follow when looking through the **project history**. But also,
we use the git commit messages to **generate the change log**.
## Development
### Prepare your environment
* Install [Node.js](http://nodejs.org/) and NPM (should come with)
* Install global dev dependencies: `npm install -g bower gulp`
* Install local dev dependencies: `npm install && bower install` in repository directory
### Development Commands
* `gulp` to jshint, build and test
* `gulp build` to jshint and build
* `gulp test` for one-time test with karma (also build and jshint)
* `gulp watch` to watch src files to jshint, build and test when changed
## Recommended workflow
1. Make changes
2. Run `gulp` or `gulp test` to run Karma tests and ensure they pass.
3. Reset all `dist/*` files
4. Commit changes using the commit message conventions below.
5. Push
6. Create PR
### Commit Message Format
Each commit message consists of a **header**, a **body** and a **footer**. The header has a special
format that includes a **type**, a **scope** and a **subject**:
```
<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
```
The **header** is mandatory and the **scope** of the header is optional.
Any line of the commit message cannot be longer 100 characters! This allows the message to be easier
to read on GitHub as well as in various git tools.
### Revert
If the commit reverts a previous commit, it should begin with `revert: `, followed by the header of the reverted commit. In the body it should say: `This reverts commit <hash>.`, where the hash is the SHA of the commit being reverted.
### Type
Must be one of the following:
* **feat**: A new feature
* **fix**: A bug fix
* **docs**: Documentation only changes
* **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing
semi-colons, etc)
* **refactor**: A code change that neither fixes a bug nor adds a feature
* **perf**: A code change that improves performance
* **test**: Adding missing tests
* **chore**: Changes to the build process or auxiliary tools and libraries such as documentation
generation
### Scope
The scope could be anything specifying place of the commit change. For example `$location`,
`$browser`, `$compile`, `$rootScope`, `ngHref`, `ngClick`, `ngView`, etc...
### Subject
The subject contains succinct description of the change:
* use the imperative, present tense: "change" not "changed" nor "changes"
* don't capitalize first letter
* no dot (.) at the end
### Body
Just as in the **subject**, use the imperative, present tense: "change" not "changed" nor "changes".
The body should include the motivation for the change and contrast this with previous behavior.
### Footer
The footer should contain any information about **Breaking Changes** and is also the place to
reference github issues that this commit **Closes**.
**Breaking Changes** should start with the word `BREAKING CHANGE:` with a space or two newlines. The rest of the commit message is then used for this.
#### Examples
Appears under "Features" header, pencil subheader:
```
feat(pencil): add 'graphiteWidth' option
```
Appears under "Bug Fixes" header, graphite subheader, with a link to issue #GSNP-28:
```
fix(graphite): stop graphite breaking when width < 0.1
Closes #123
```
Appears under "Performance Improvements" header, and under "Breaking Changes" with the breaking change explanation:
```
perf(pencil): remove graphiteWidth option
BREAKING CHANGE: The graphiteWidth option has been removed. The default graphite width of 10mm is always used for performance reason.
```
The following commit and commit `667ecc1` do not appear in the changelog if they are under the same release. If not, the revert commit appears under the "Reverts" header.
```
revert: feat(pencil): add 'graphiteWidth' option
This reverts commit 667ecc1654a317a13331b17617d973392f415f02.
```
A detailed explanation can be found in this [document][https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit#].
The MIT License (MIT)
Copyright (c) 2013-2014 AngularUI
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# AngularJS ui-select [![Build Status](https://travis-ci.org/angular-ui/ui-select.svg?branch=master)](https://travis-ci.org/angular-ui/ui-select) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/angular-ui/ui-select?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
AngularJS-native version of [Select2](http://ivaynberg.github.io/select2/) and [Selectize](http://brianreavis.github.io/selectize.js/). [http://angular-ui.github.io/ui-select/](http://angular-ui.github.io/ui-select/)
[Getting Started](https://github.com/angular-ui/ui-select/wiki/Getting-Started)
- [Examples](http://angular-ui.github.io/ui-select/#examples)
- [Examples Source](./docs/examples)
- [Documentation](https://github.com/angular-ui/ui-select/wiki)
## Latest Changes
- Check [CHANGELOG.md](/CHANGELOG.md)
## Features
- Search, Select, Multi-select and Tagging
- Multiple Themes: Bootstrap, Select2 and Selectize
- Keyboard support
- No jQuery required (except for old browsers)
- Small code base: 4.57KB min/gzipped vs 20KB for select2
For the roadmap, check [issue #3](https://github.com/angular-ui/ui-select/issues/3) and the [Wiki page](https://github.com/angular-ui/ui-select/wiki/Roadmap).
## Installation Methods
### npm
```
$ npm install ui-select
```
### bower
```
$ bower install angular-ui-select
```
## Development
### Prepare your environment
* Install [Node.js](http://nodejs.org/) and NPM (should come with)
* Install global dev dependencies: `npm install -g gulp`
* Install local dev dependencies: `npm install` in repository directory
### Development Commands
* `gulp` to jshint, build and test
* `gulp build` to jshint and build
* `gulp test` for one-time test with karma (also build and jshint)
* `gulp watch` to watch src files to jshint, build and test when changed
* `gulp docs` build docs and examples
## Contributing
- Check [CONTRIBUTING.md](/CONTRIBUTING.md)
- Run the tests
- Try the [examples](./docs/examples)
When issuing a pull request, please exclude changes from the "dist" folder to avoid merge conflicts.
{
"name": "angular-ui-select",
"homepage": "https://github.com/angular-ui/ui-select",
"authors": [
"AngularUI"
],
"description": "AngularJS ui-select",
"main": [
"dist/select.js",
"dist/select.css"
],
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"src",
"test",
"gulpfile.js",
"karma.conf.js",
"examples"
],
"dependencies": {
"angular": ">=1.2.18"
},
"devDependencies": {
"jquery": "~1.11",
"angular-sanitize": ">=1.2.18",
"angular-mocks": ">=1.2.18"
}
}
{
"name": "components/ui-select",
"description": "AngularJS UI Select",
"keywords": ["angular", "angular-ui", "select", "select2", "angularjs"],
"type": "component",
"homepage": "https://github.com/angular-ui/ui-select",
"license": "MIT",
"support": {
"issues": "https://github.com/angular-ui/ui-select/issues",
"wiki": "https://github.com/angular-ui/ui-select/wiki",
"source": "https://github.com/angular-ui/ui-select"
},
"require": {
"robloach/component-installer": "*"
},
"extra": {
"component": {
"scripts": [
"dist/select.js"
],
"files": [
"dist/select.js",
"dist/select.css",
"dist/select.min.js",
"dist/select.min.css"
]
}
}
}
\ No newline at end of file
#!/bin/bash
set -e
[[ $TRAVIS_SECURE_ENV_VARS == "true" ]] || { echo "No github key avaliable, aborting publishing"; exit 0; }
ID_REF="$(git rev-parse --short HEAD)"
git clone "https://${GH_KEY}@${GH_REF}" ./docs-out -b ${GH_PAGES_BRANCH} --single-branch --depth=1
cd docs-out
# clear out everything
git rm -rf .
git clean -fxd
# get new content
cp ../docs-built/* . -R
git add .
# inside this git repo we'll pretend to be a new user
git config user.name "Travis CI"
git config user.email "travisci@users.noreply.github.com"
# The first and only commit to this new Git repo contains all the
# files present with the commit message "Deploy to GitHub Pages".
git commit -m "docs(*): new deploy (angular-ui/ui-select@${ID_REF})"
git push origin --quiet
#> /dev/null 2>&1
/*!
* ui-select
* http://github.com/angular-ui/ui-select
* Version: 0.19.5 - 2016-10-24T23:13:59.551Z
* License: MIT
*/
/* Style when highlighting a search. */
.ui-select-highlight {
font-weight: bold;
}
.ui-select-offscreen {
clip: rect(0 0 0 0) !important;
width: 1px !important;
height: 1px !important;
border: 0 !important;
margin: 0 !important;
padding: 0 !important;
overflow: hidden !important;
position: absolute !important;
outline: 0 !important;
left: 0px !important;
top: 0px !important;
}
.ui-select-choices-row:hover {
background-color: #f5f5f5;
}
/* Select2 theme */
/* Mark invalid Select2 */
.ng-dirty.ng-invalid > a.select2-choice {
border-color: #D44950;
}
.select2-result-single {
padding-left: 0;
}
.select2-locked > .select2-search-choice-close{
display:none;
}
.select-locked > .ui-select-match-close{
display:none;
}
body > .select2-container.open {
z-index: 9999; /* The z-index Select2 applies to the select2-drop */
}
/* Handle up direction Select2 */
.ui-select-container[theme="select2"].direction-up .ui-select-match,
.ui-select-container.select2.direction-up .ui-select-match {
border-radius: 4px; /* FIXME hardcoded value :-/ */
border-top-left-radius: 0;
border-top-right-radius: 0;
}
.ui-select-container[theme="select2"].direction-up .ui-select-dropdown,
.ui-select-container.select2.direction-up .ui-select-dropdown {
border-radius: 4px; /* FIXME hardcoded value :-/ */
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
border-top-width: 1px; /* FIXME hardcoded value :-/ */
border-top-style: solid;
box-shadow: 0 -4px 8px rgba(0, 0, 0, 0.25);
margin-top: -4px; /* FIXME hardcoded value :-/ */
}
.ui-select-container[theme="select2"].direction-up .ui-select-dropdown .select2-search,
.ui-select-container.select2.direction-up .ui-select-dropdown .select2-search {
margin-top: 4px; /* FIXME hardcoded value :-/ */
}
.ui-select-container[theme="select2"].direction-up.select2-dropdown-open .ui-select-match,
.ui-select-container.select2.direction-up.select2-dropdown-open .ui-select-match {
border-bottom-color: #5897fb;
}
.ui-select-container[theme="select2"] .ui-select-dropdown .ui-select-search-hidden,
.ui-select-container[theme="select2"] .ui-select-dropdown .ui-select-search-hidden input{
opacity: 0;
height: 0;
min-height: 0;
padding: 0;
margin: 0;
border:0;
}
/* Selectize theme */
/* Helper class to show styles when focus */
.selectize-input.selectize-focus{
border-color: #007FBB !important;
}
/* Fix input width for Selectize theme */
.selectize-control.single > .selectize-input > input {
width: 100%;
}
/* Fix line break when there's at least one item selected with the Selectize theme */
.selectize-control.multi > .selectize-input > input {
margin: 0 !important;
}
/* Fix dropdown width for Selectize theme */
.selectize-control > .selectize-dropdown {
width: 100%;
}
/* Mark invalid Selectize */
.ng-dirty.ng-invalid > div.selectize-input {
border-color: #D44950;
}
/* Handle up direction Selectize */
.ui-select-container[theme="selectize"].direction-up .ui-select-dropdown {
box-shadow: 0 -4px 8px rgba(0, 0, 0, 0.25);
margin-top: -2px; /* FIXME hardcoded value :-/ */
}
.ui-select-container[theme="selectize"] input.ui-select-search-hidden{
opacity: 0;
height: 0;
min-height: 0;
padding: 0;
margin: 0;
border:0;
width: 0;
}
/* Bootstrap theme */
/* Helper class to show styles when focus */
.btn-default-focus {
color: #333;
background-color: #EBEBEB;
border-color: #ADADAD;
text-decoration: none;
outline: 5px auto -webkit-focus-ring-color;
outline-offset: -2px;
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6);
}
.ui-select-bootstrap .ui-select-toggle {
position: relative;
}
.ui-select-bootstrap .ui-select-toggle > .caret {
position: absolute;
height: 10px;
top: 50%;
right: 10px;
margin-top: -2px;
}
/* Fix Bootstrap dropdown position when inside a input-group */
.input-group > .ui-select-bootstrap.dropdown {
/* Instead of relative */
position: static;
}
.input-group > .ui-select-bootstrap > input.ui-select-search.form-control {
border-radius: 4px; /* FIXME hardcoded value :-/ */
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.input-group > .ui-select-bootstrap > input.ui-select-search.form-control.direction-up {
border-radius: 4px !important; /* FIXME hardcoded value :-/ */
border-top-right-radius: 0 !important;
border-bottom-right-radius: 0 !important;
}
.ui-select-bootstrap .ui-select-search-hidden{
opacity: 0;
height: 0;
min-height: 0;
padding: 0;
margin: 0;
border:0;
}
.ui-select-bootstrap > .ui-select-match > .btn{
/* Instead of center because of .btn */
text-align: left !important;
}
.ui-select-bootstrap > .ui-select-match > .caret {
position: absolute;
top: 45%;
right: 15px;
}
/* See Scrollable Menu with Bootstrap 3 http://stackoverflow.com/questions/19227496 */
.ui-select-bootstrap > .ui-select-choices ,.ui-select-bootstrap > .ui-select-no-choice {
width: 100%;
height: auto;
max-height: 200px;
overflow-x: hidden;
margin-top: -1px;
}
body > .ui-select-bootstrap.open {
z-index: 1000; /* Standard Bootstrap dropdown z-index */
}
.ui-select-multiple.ui-select-bootstrap {
height: auto;
padding: 3px 3px 0 3px;
}
.ui-select-multiple.ui-select-bootstrap input.ui-select-search {
background-color: transparent !important; /* To prevent double background when disabled */
border: none;
outline: none;
height: 1.666666em;
margin-bottom: 3px;
}
.ui-select-multiple.ui-select-bootstrap .ui-select-match .close {
font-size: 1.6em;
line-height: 0.75;
}
.ui-select-multiple.ui-select-bootstrap .ui-select-match-item {
outline: 0;
margin: 0 3px 3px 0;
}
.ui-select-multiple .ui-select-match-item {
position: relative;
}
.ui-select-multiple .ui-select-match-item.dropping .ui-select-match-close {
pointer-events: none;
}
.ui-select-multiple:hover .ui-select-match-item.dropping-before:before {
content: "";
position: absolute;
top: 0;
right: 100%;
height: 100%;
margin-right: 2px;
border-left: 1px solid #428bca;
}
.ui-select-multiple:hover .ui-select-match-item.dropping-after:after {
content: "";
position: absolute;
top: 0;
left: 100%;
height: 100%;
margin-left: 2px;
border-right: 1px solid #428bca;
}
.ui-select-bootstrap .ui-select-choices-row>span {
cursor: pointer;
display: block;
padding: 3px 20px;
clear: both;
font-weight: 400;
line-height: 1.42857143;
color: #333;
white-space: nowrap;
}
.ui-select-bootstrap .ui-select-choices-row>span:hover, .ui-select-bootstrap .ui-select-choices-row>span:focus {
text-decoration: none;
color: #262626;
background-color: #f5f5f5;
}
.ui-select-bootstrap .ui-select-choices-row.active>span {
color: #fff;
text-decoration: none;
outline: 0;
background-color: #428bca;
}
.ui-select-bootstrap .ui-select-choices-row.disabled>span,
.ui-select-bootstrap .ui-select-choices-row.active.disabled>span {
color: #777;
cursor: not-allowed;
background-color: #fff;
}
/* fix hide/show angular animation */
.ui-select-match.ng-hide-add,
.ui-select-search.ng-hide-add {
display: none !important;
}
/* Mark invalid Bootstrap */
.ui-select-bootstrap.ng-dirty.ng-invalid > button.btn.ui-select-match {
border-color: #D44950;
}
/* Handle up direction Bootstrap */
.ui-select-container[theme="bootstrap"].direction-up .ui-select-dropdown {
box-shadow: 0 -4px 8px rgba(0, 0, 0, 0.25);
}
.ui-select-bootstrap .ui-select-match-text {
width: 100%;
padding-right: 1em;
}
.ui-select-bootstrap .ui-select-match-text span {
display: inline-block;
width: 100%;
overflow: hidden;
}
.ui-select-bootstrap .ui-select-toggle > a.btn {
position: absolute;
height: 10px;
right: 10px;
margin-top: -2px;
}
/* Spinner */
.ui-select-refreshing {
position: absolute;
right: 0;
padding: 8px 27px;
top: 1px;
display: inline-block;
font-family: 'Glyphicons Halflings';
font-style: normal;
font-weight: normal;
line-height: 1;
-webkit-font-smoothing:antialiased;
}
@-webkit-keyframes ui-select-spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(359deg);
transform: rotate(359deg);
}
}
@keyframes ui-select-spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(359deg);
transform: rotate(359deg);
}
}
.ui-select-spin {
-webkit-animation: ui-select-spin 2s infinite linear;
animation: ui-select-spin 2s infinite linear;
}
.ui-select-refreshing.ng-animate {
-webkit-animation: none 0s;
}
\ No newline at end of file
/*!
* ui-select
* http://github.com/angular-ui/ui-select
* Version: 0.19.5 - 2016-10-24T23:13:59.434Z
* License: MIT
*/
(function () {
"use strict";
var KEY = {
TAB: 9,
ENTER: 13,
ESC: 27,
SPACE: 32,
LEFT: 37,
UP: 38,
RIGHT: 39,
DOWN: 40,
SHIFT: 16,
CTRL: 17,
ALT: 18,
PAGE_UP: 33,
PAGE_DOWN: 34,
HOME: 36,
END: 35,
BACKSPACE: 8,
DELETE: 46,
COMMAND: 91,
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 : "," , 189 : "-" , 190 : "." , 191 : "/" , 192 : "`" , 219 : "[" , 220 : "\\" , 221 : "]" , 222 : "'"
},
isControl: function (e) {
var k = e.which;
switch (k) {
case KEY.COMMAND:
case KEY.SHIFT:
case KEY.CTRL:
case KEY.ALT:
return true;
}
if (e.metaKey || e.ctrlKey || e.altKey) return true;
return false;
},
isFunctionKey: function (k) {
k = k.which ? k.which : k;
return k >= 112 && k <= 123;
},
isVerticalMovement: function (k){
return ~[KEY.UP, KEY.DOWN].indexOf(k);
},
isHorizontalMovement: function (k){
return ~[KEY.LEFT,KEY.RIGHT,KEY.BACKSPACE,KEY.DELETE].indexOf(k);
},
toSeparator: function (k) {
var sep = {ENTER:"\n",TAB:"\t",SPACE:" "}[k];
if (sep) return sep;
// return undefined for special keys other than enter, tab or space.
// no way to use them to cut strings.
return KEY[k] ? undefined : k;
}
};
/**
* Add querySelectorAll() to jqLite.
*
* jqLite find() is limited to lookups by tag name.
* TODO This will change with future versions of AngularJS, to be removed when this happens
*
* See jqLite.find - why not use querySelectorAll? https://github.com/angular/angular.js/issues/3586
* See feat(jqLite): use querySelectorAll instead of getElementsByTagName in jqLite.find https://github.com/angular/angular.js/pull/3598
*/
if (angular.element.prototype.querySelectorAll === undefined) {
angular.element.prototype.querySelectorAll = function(selector) {
return angular.element(this[0].querySelectorAll(selector));
};
}
/**
* Add closest() to jqLite.
*/
if (angular.element.prototype.closest === undefined) {
angular.element.prototype.closest = function( selector) {
var elem = this[0];
var matchesSelector = elem.matches || elem.webkitMatchesSelector || elem.mozMatchesSelector || elem.msMatchesSelector;
while (elem) {
if (matchesSelector.bind(elem)(selector)) {
return elem;
} else {
elem = elem.parentElement;
}
}
return false;
};
}
var latestId = 0;
var uis = angular.module('ui.select', [])
.constant('uiSelectConfig', {
theme: 'bootstrap',
searchEnabled: true,
sortable: false,
placeholder: '', // Empty by default, like HTML tag <select>
refreshDelay: 1000, // In milliseconds
closeOnSelect: true,
skipFocusser: false,
dropdownPosition: 'auto',
removeSelected: true,
resetSearchInput: true,
generateId: function() {
return latestId++;
},
appendToBody: false,
spinnerEnabled: false,
spinnerClass: 'glyphicon-refresh ui-select-spin'
})
// See Rename minErr and make it accessible from outside https://github.com/angular/angular.js/issues/6913
.service('uiSelectMinErr', function() {
var minErr = angular.$$minErr('ui.select');
return function() {
var error = minErr.apply(this, arguments);
var message = error.message.replace(new RegExp('\nhttp://errors.angularjs.org/.*'), '');
return new Error(message);
};
})
// Recreates old behavior of ng-transclude. Used internally.
.directive('uisTranscludeAppend', function () {
return {
link: function (scope, element, attrs, ctrl, transclude) {
transclude(scope, function (clone) {
element.append(clone);
});
}
};
})
/**
* Highlights text that matches $select.search.
*
* Taken from AngularUI Bootstrap Typeahead
* See https://github.com/angular-ui/bootstrap/blob/0.10.0/src/typeahead/typeahead.js#L340
*/
.filter('highlight', function() {
function escapeRegexp(queryToEscape) {
return ('' + queryToEscape).replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1');
}
return function(matchItem, query) {
return query && matchItem ? ('' + matchItem).replace(new RegExp(escapeRegexp(query), 'gi'), '<span class="ui-select-highlight">$&</span>') : matchItem;
};
})
/**
* A read-only equivalent of jQuery's offset function: http://api.jquery.com/offset/
*
* Taken from AngularUI Bootstrap Position:
* See https://github.com/angular-ui/bootstrap/blob/master/src/position/position.js#L70
*/
.factory('uisOffset',
['$document', '$window',
function ($document, $window) {
return function(element) {
var boundingClientRect = element[0].getBoundingClientRect();
return {
width: boundingClientRect.width || element.prop('offsetWidth'),
height: boundingClientRect.height || element.prop('offsetHeight'),
top: boundingClientRect.top + ($window.pageYOffset || $document[0].documentElement.scrollTop),
left: boundingClientRect.left + ($window.pageXOffset || $document[0].documentElement.scrollLeft)
};
};
}]);
uis.directive('uiSelectChoices',
['uiSelectConfig', 'uisRepeatParser', 'uiSelectMinErr', '$compile', '$window',
function(uiSelectConfig, RepeatParser, uiSelectMinErr, $compile, $window) {
return {
restrict: 'EA',
require: '^uiSelect',
replace: true,
transclude: true,
templateUrl: function(tElement) {
// Needed so the uiSelect can detect the transcluded content
tElement.addClass('ui-select-choices');
// Gets theme attribute from parent (ui-select)
var theme = tElement.parent().attr('theme') || uiSelectConfig.theme;
return theme + '/choices.tpl.html';
},
compile: function(tElement, tAttrs) {
if (!tAttrs.repeat) throw uiSelectMinErr('repeat', "Expected 'repeat' expression.");
// var repeat = RepeatParser.parse(attrs.repeat);
var groupByExp = tAttrs.groupBy;
var groupFilterExp = tAttrs.groupFilter;
if (groupByExp) {
var groups = tElement.querySelectorAll('.ui-select-choices-group');
if (groups.length !== 1) throw uiSelectMinErr('rows', "Expected 1 .ui-select-choices-group but got '{0}'.", groups.length);
groups.attr('ng-repeat', RepeatParser.getGroupNgRepeatExpression());
}
var parserResult = RepeatParser.parse(tAttrs.repeat);
var choices = tElement.querySelectorAll('.ui-select-choices-row');
if (choices.length !== 1) {
throw uiSelectMinErr('rows', "Expected 1 .ui-select-choices-row but got '{0}'.", choices.length);
}
choices.attr('ng-repeat', parserResult.repeatExpression(groupByExp))
.attr('ng-if', '$select.open'); //Prevent unnecessary watches when dropdown is closed
var rowsInner = tElement.querySelectorAll('.ui-select-choices-row-inner');
if (rowsInner.length !== 1) {
throw uiSelectMinErr('rows', "Expected 1 .ui-select-choices-row-inner but got '{0}'.", rowsInner.length);
}
rowsInner.attr('uis-transclude-append', ''); //Adding uisTranscludeAppend directive to row element after choices element has ngRepeat
// If IE8 then need to target rowsInner to apply the ng-click attr as choices will not capture the event.
var clickTarget = $window.document.addEventListener ? choices : rowsInner;
clickTarget.attr('ng-click', '$select.select(' + parserResult.itemName + ',$select.skipFocusser,$event)');
return function link(scope, element, attrs, $select) {
$select.parseRepeatAttr(attrs.repeat, groupByExp, groupFilterExp); //Result ready at $select.parserResult
$select.disableChoiceExpression = attrs.uiDisableChoice;
$select.onHighlightCallback = attrs.onHighlight;
$select.dropdownPosition = attrs.position ? attrs.position.toLowerCase() : uiSelectConfig.dropdownPosition;
scope.$on('$destroy', function() {
choices.remove();
});
scope.$watch('$select.search', function(newValue) {
if(newValue && !$select.open && $select.multiple) $select.activate(false, true);
$select.activeIndex = $select.tagging.isActivated ? -1 : 0;
if (!attrs.minimumInputLength || $select.search.length >= attrs.minimumInputLength) {
$select.refresh(attrs.refresh);
} else {
$select.items = [];
}
});
attrs.$observe('refreshDelay', function() {
// $eval() is needed otherwise we get a string instead of a number
var refreshDelay = scope.$eval(attrs.refreshDelay);
$select.refreshDelay = refreshDelay !== undefined ? refreshDelay : uiSelectConfig.refreshDelay;
});
scope.$watch('$select.open', function(open) {
if (open) {
tElement.attr('role', 'listbox');
} else {
tElement.removeAttr('role');
}
});
};
}
};
}]);
/**
* Contains ui-select "intelligence".
*
* The goal is to limit dependency on the DOM whenever possible and
* put as much logic in the controller (instead of the link functions) as possible so it can be easily tested.
*/
uis.controller('uiSelectCtrl',
['$scope', '$element', '$timeout', '$filter', '$$uisDebounce', 'uisRepeatParser', 'uiSelectMinErr', 'uiSelectConfig', '$parse', '$injector', '$window',
function($scope, $element, $timeout, $filter, $$uisDebounce, RepeatParser, uiSelectMinErr, uiSelectConfig, $parse, $injector, $window) {
var ctrl = this;
var EMPTY_SEARCH = '';
ctrl.placeholder = uiSelectConfig.placeholder;
ctrl.searchEnabled = uiSelectConfig.searchEnabled;
ctrl.sortable = uiSelectConfig.sortable;
ctrl.refreshDelay = uiSelectConfig.refreshDelay;
ctrl.paste = uiSelectConfig.paste;
ctrl.resetSearchInput = uiSelectConfig.resetSearchInput;
ctrl.refreshing = false;
ctrl.spinnerEnabled = uiSelectConfig.spinnerEnabled;
ctrl.spinnerClass = uiSelectConfig.spinnerClass;
ctrl.removeSelected = uiSelectConfig.removeSelected; //If selected item(s) should be removed from dropdown list
ctrl.closeOnSelect = true; //Initialized inside uiSelect directive link function
ctrl.skipFocusser = false; //Set to true to avoid returning focus to ctrl when item is selected
ctrl.search = EMPTY_SEARCH;
ctrl.activeIndex = 0; //Dropdown of choices
ctrl.items = []; //All available choices
ctrl.open = false;
ctrl.focus = false;
ctrl.disabled = false;
ctrl.selected = undefined;
ctrl.dropdownPosition = 'auto';
ctrl.focusser = undefined; //Reference to input element used to handle focus events
ctrl.multiple = undefined; // Initialized inside uiSelect directive link function
ctrl.disableChoiceExpression = undefined; // Initialized inside uiSelectChoices directive link function
ctrl.tagging = {isActivated: false, fct: undefined};
ctrl.taggingTokens = {isActivated: false, tokens: undefined};
ctrl.lockChoiceExpression = undefined; // Initialized inside uiSelectMatch directive link function
ctrl.clickTriggeredSelect = false;
ctrl.$filter = $filter;
ctrl.$element = $element;
// Use $injector to check for $animate and store a reference to it
ctrl.$animate = (function () {
try {
return $injector.get('$animate');
} catch (err) {
// $animate does not exist
return null;
}
})();
ctrl.searchInput = $element.querySelectorAll('input.ui-select-search');
if (ctrl.searchInput.length !== 1) {
throw uiSelectMinErr('searchInput', "Expected 1 input.ui-select-search but got '{0}'.", ctrl.searchInput.length);
}
ctrl.isEmpty = function() {
return angular.isUndefined(ctrl.selected) || ctrl.selected === null || ctrl.selected === '' || (ctrl.multiple && ctrl.selected.length === 0);
};
function _findIndex(collection, predicate, thisArg){
if (collection.findIndex){
return collection.findIndex(predicate, thisArg);
} else {
var list = Object(collection);
var length = list.length >>> 0;
var value;
for (var i = 0; i < length; i++) {
value = list[i];
if (predicate.call(thisArg, value, i, list)) {
return i;
}
}
return -1;
}
}
// Most of the time the user does not want to empty the search input when in typeahead mode
function _resetSearchInput() {
if (ctrl.resetSearchInput) {
ctrl.search = EMPTY_SEARCH;
//reset activeIndex
if (ctrl.selected && ctrl.items.length && !ctrl.multiple) {
ctrl.activeIndex = _findIndex(ctrl.items, function(item){
return angular.equals(this, item);
}, ctrl.selected);
}
}
}
function _groupsFilter(groups, groupNames) {
var i, j, result = [];
for(i = 0; i < groupNames.length ;i++){
for(j = 0; j < groups.length ;j++){
if(groups[j].name == [groupNames[i]]){
result.push(groups[j]);
}
}
}
return result;
}
// When the user clicks on ui-select, displays the dropdown list
ctrl.activate = function(initSearchValue, avoidReset) {
if (!ctrl.disabled && !ctrl.open) {
if(!avoidReset) _resetSearchInput();
$scope.$broadcast('uis:activate');
ctrl.open = true;
ctrl.activeIndex = ctrl.activeIndex >= ctrl.items.length ? 0 : ctrl.activeIndex;
// ensure that the index is set to zero for tagging variants
// that where first option is auto-selected
if ( ctrl.activeIndex === -1 && ctrl.taggingLabel !== false ) {
ctrl.activeIndex = 0;
}
var container = $element.querySelectorAll('.ui-select-choices-content');
var searchInput = $element.querySelectorAll('.ui-select-search');
if (ctrl.$animate && ctrl.$animate.on && ctrl.$animate.enabled(container[0])) {
var animateHandler = function(elem, phase) {
if (phase === 'start' && ctrl.items.length === 0) {
// Only focus input after the animation has finished
ctrl.$animate.off('removeClass', searchInput[0], animateHandler);
$timeout(function () {
ctrl.focusSearchInput(initSearchValue);
});
} else if (phase === 'close') {
// Only focus input after the animation has finished
ctrl.$animate.off('enter', container[0], animateHandler);
$timeout(function () {
ctrl.focusSearchInput(initSearchValue);
});
}
};
if (ctrl.items.length > 0) {
ctrl.$animate.on('enter', container[0], animateHandler);
} else {
ctrl.$animate.on('removeClass', searchInput[0], animateHandler);
}
} else {
$timeout(function () {
ctrl.focusSearchInput(initSearchValue);
if(!ctrl.tagging.isActivated && ctrl.items.length > 1) {
_ensureHighlightVisible();
}
});
}
}
else if (ctrl.open && !ctrl.searchEnabled) {
// Close the selection if we don't have search enabled, and we click on the select again
ctrl.close();
}
};
ctrl.focusSearchInput = function (initSearchValue) {
ctrl.search = initSearchValue || ctrl.search;
ctrl.searchInput[0].focus();
};
ctrl.findGroupByName = function(name) {
return ctrl.groups && ctrl.groups.filter(function(group) {
return group.name === name;
})[0];
};
ctrl.parseRepeatAttr = function(repeatAttr, groupByExp, groupFilterExp) {
function updateGroups(items) {
var groupFn = $scope.$eval(groupByExp);
ctrl.groups = [];
angular.forEach(items, function(item) {
var groupName = angular.isFunction(groupFn) ? groupFn(item) : item[groupFn];
var group = ctrl.findGroupByName(groupName);
if(group) {
group.items.push(item);
}
else {
ctrl.groups.push({name: groupName, items: [item]});
}
});
if(groupFilterExp){
var groupFilterFn = $scope.$eval(groupFilterExp);
if( angular.isFunction(groupFilterFn)){
ctrl.groups = groupFilterFn(ctrl.groups);
} else if(angular.isArray(groupFilterFn)){
ctrl.groups = _groupsFilter(ctrl.groups, groupFilterFn);
}
}
ctrl.items = [];
ctrl.groups.forEach(function(group) {
ctrl.items = ctrl.items.concat(group.items);
});
}
function setPlainItems(items) {
ctrl.items = items;
}
ctrl.setItemsFn = groupByExp ? updateGroups : setPlainItems;
ctrl.parserResult = RepeatParser.parse(repeatAttr);
ctrl.isGrouped = !!groupByExp;
ctrl.itemProperty = ctrl.parserResult.itemName;
//If collection is an Object, convert it to Array
var originalSource = ctrl.parserResult.source;
//When an object is used as source, we better create an array and use it as 'source'
var createArrayFromObject = function(){
var origSrc = originalSource($scope);
$scope.$uisSource = Object.keys(origSrc).map(function(v){
var result = {};
result[ctrl.parserResult.keyName] = v;
result.value = origSrc[v];
return result;
});
};
if (ctrl.parserResult.keyName){ // Check for (key,value) syntax
createArrayFromObject();
ctrl.parserResult.source = $parse('$uisSource' + ctrl.parserResult.filters);
$scope.$watch(originalSource, function(newVal, oldVal){
if (newVal !== oldVal) createArrayFromObject();
}, true);
}
ctrl.refreshItems = function (data){
data = data || ctrl.parserResult.source($scope);
var selectedItems = ctrl.selected;
//TODO should implement for single mode removeSelected
if (ctrl.isEmpty() || (angular.isArray(selectedItems) && !selectedItems.length) || !ctrl.multiple || !ctrl.removeSelected) {
ctrl.setItemsFn(data);
}else{
if ( data !== undefined && data !== null ) {
var filteredItems = data.filter(function(i) {
return angular.isArray(selectedItems) ? selectedItems.every(function(selectedItem) {
return !angular.equals(i, selectedItem);
}) : !angular.equals(i, selectedItems);
});
ctrl.setItemsFn(filteredItems);
}
}
if (ctrl.dropdownPosition === 'auto' || ctrl.dropdownPosition === 'up'){
$scope.calculateDropdownPos();
}
$scope.$broadcast('uis:refresh');
};
// See https://github.com/angular/angular.js/blob/v1.2.15/src/ng/directive/ngRepeat.js#L259
$scope.$watchCollection(ctrl.parserResult.source, function(items) {
if (items === undefined || items === null) {
// If the user specifies undefined or null => reset the collection
// Special case: items can be undefined if the user did not initialized the collection on the scope
// i.e $scope.addresses = [] is missing
ctrl.items = [];
} else {
if (!angular.isArray(items)) {
throw uiSelectMinErr('items', "Expected an array but got '{0}'.", items);
} else {
//Remove already selected items (ex: while searching)
//TODO Should add a test
ctrl.refreshItems(items);
//update the view value with fresh data from items, if there is a valid model value
if(angular.isDefined(ctrl.ngModel.$modelValue)) {
ctrl.ngModel.$modelValue = null; //Force scope model value and ngModel value to be out of sync to re-run formatters
}
}
}
});
};
var _refreshDelayPromise;
/**
* Typeahead mode: lets the user refresh the collection using his own function.
*
* See Expose $select.search for external / remote filtering https://github.com/angular-ui/ui-select/pull/31
*/
ctrl.refresh = function(refreshAttr) {
if (refreshAttr !== undefined) {
// Debounce
// See https://github.com/angular-ui/bootstrap/blob/0.10.0/src/typeahead/typeahead.js#L155
// FYI AngularStrap typeahead does not have debouncing: https://github.com/mgcrea/angular-strap/blob/v2.0.0-rc.4/src/typeahead/typeahead.js#L177
if (_refreshDelayPromise) {
$timeout.cancel(_refreshDelayPromise);
}
_refreshDelayPromise = $timeout(function() {
var refreshPromise = $scope.$eval(refreshAttr);
if (refreshPromise && angular.isFunction(refreshPromise.then) && !ctrl.refreshing) {
ctrl.refreshing = true;
refreshPromise.then(function() {
ctrl.refreshing = false;
});
}}, ctrl.refreshDelay);
}
};
ctrl.isActive = function(itemScope) {
if ( !ctrl.open ) {
return false;
}
var itemIndex = ctrl.items.indexOf(itemScope[ctrl.itemProperty]);
var isActive = itemIndex == ctrl.activeIndex;
if ( !isActive || itemIndex < 0 ) {
return false;
}
if (isActive && !angular.isUndefined(ctrl.onHighlightCallback)) {
itemScope.$eval(ctrl.onHighlightCallback);
}
return isActive;
};
var _isItemSelected = function (item) {
return (ctrl.selected && angular.isArray(ctrl.selected) &&
ctrl.selected.filter(function (selection) { return angular.equals(selection, item); }).length > 0);
};
var disabledItems = [];
function _updateItemDisabled(item, isDisabled) {
var disabledItemIndex = disabledItems.indexOf(item);
if (isDisabled && disabledItemIndex === -1) {
disabledItems.push(item);
}
if (!isDisabled && disabledItemIndex > -1) {
disabledItems.splice(disabledItemIndex, 1);
}
}
function _isItemDisabled(item) {
return disabledItems.indexOf(item) > -1;
}
ctrl.isDisabled = function(itemScope) {
if (!ctrl.open) return;
var item = itemScope[ctrl.itemProperty];
var itemIndex = ctrl.items.indexOf(item);
var isDisabled = false;
if (itemIndex >= 0 && (angular.isDefined(ctrl.disableChoiceExpression) || ctrl.multiple)) {
if (item.isTag) return false;
if (ctrl.multiple) {
isDisabled = _isItemSelected(item);
}
if (!isDisabled && angular.isDefined(ctrl.disableChoiceExpression)) {
isDisabled = !!(itemScope.$eval(ctrl.disableChoiceExpression));
}
_updateItemDisabled(item, isDisabled);
}
return isDisabled;
};
// When the user selects an item with ENTER or clicks the dropdown
ctrl.select = function(item, skipFocusser, $event) {
if (item === undefined || !_isItemDisabled(item)) {
if ( ! ctrl.items && ! ctrl.search && ! ctrl.tagging.isActivated) return;
if (!item || !_isItemDisabled(item)) {
// if click is made on existing item, prevent from tagging, ctrl.search does not matter
ctrl.clickTriggeredSelect = false;
if($event && ($event.type === 'click' || $event.type === 'touchend') && item)
ctrl.clickTriggeredSelect = true;
if(ctrl.tagging.isActivated && ctrl.clickTriggeredSelect === false) {
// if taggingLabel is disabled and item is undefined we pull from ctrl.search
if ( ctrl.taggingLabel === false ) {
if ( ctrl.activeIndex < 0 ) {
if (item === undefined) {
item = ctrl.tagging.fct !== undefined ? ctrl.tagging.fct(ctrl.search) : ctrl.search;
}
if (!item || angular.equals( ctrl.items[0], item ) ) {
return;
}
} else {
// keyboard nav happened first, user selected from dropdown
item = ctrl.items[ctrl.activeIndex];
}
} else {
// tagging always operates at index zero, taggingLabel === false pushes
// the ctrl.search value without having it injected
if ( ctrl.activeIndex === 0 ) {
// ctrl.tagging pushes items to ctrl.items, so we only have empty val
// for `item` if it is a detected duplicate
if ( item === undefined ) return;
// create new item on the fly if we don't already have one;
// use tagging function if we have one
if ( ctrl.tagging.fct !== undefined && typeof item === 'string' ) {
item = ctrl.tagging.fct(item);
if (!item) return;
// if item type is 'string', apply the tagging label
} else if ( typeof item === 'string' ) {
// trim the trailing space
item = item.replace(ctrl.taggingLabel,'').trim();
}
}
}
// search ctrl.selected for dupes potentially caused by tagging and return early if found
if (_isItemSelected(item)) {
ctrl.close(skipFocusser);
return;
}
}
_resetSearchInput();
$scope.$broadcast('uis:select', item);
var locals = {};
locals[ctrl.parserResult.itemName] = item;
$timeout(function(){
ctrl.onSelectCallback($scope, {
$item: item,
$model: ctrl.parserResult.modelMapper($scope, locals)
});
});
if (ctrl.closeOnSelect) {
ctrl.close(skipFocusser);
}
}
}
};
// Closes the dropdown
ctrl.close = function(skipFocusser) {
if (!ctrl.open) return;
if (ctrl.ngModel && ctrl.ngModel.$setTouched) ctrl.ngModel.$setTouched();
ctrl.open = false;
_resetSearchInput();
$scope.$broadcast('uis:close', skipFocusser);
};
ctrl.setFocus = function(){
if (!ctrl.focus) ctrl.focusInput[0].focus();
};
ctrl.clear = function($event) {
ctrl.select(undefined);
$event.stopPropagation();
$timeout(function() {
ctrl.focusser[0].focus();
}, 0, false);
};
// Toggle dropdown
ctrl.toggle = function(e) {
if (ctrl.open) {
ctrl.close();
e.preventDefault();
e.stopPropagation();
} else {
ctrl.activate();
}
};
// Set default function for locked choices - avoids unnecessary
// logic if functionality is not being used
ctrl.isLocked = function () {
return false;
};
$scope.$watch(function () {
return angular.isDefined(ctrl.lockChoiceExpression) && ctrl.lockChoiceExpression !== "";
}, _initaliseLockedChoices);
function _initaliseLockedChoices(doInitalise) {
if(!doInitalise) return;
var lockedItems = [];
function _updateItemLocked(item, isLocked) {
var lockedItemIndex = lockedItems.indexOf(item);
if (isLocked && lockedItemIndex === -1) {
lockedItems.push(item);
}
if (!isLocked && lockedItemIndex > -1) {
lockedItems.splice(lockedItemIndex, 0);
}
}
function _isItemlocked(item) {
return lockedItems.indexOf(item) > -1;
}
ctrl.isLocked = function (itemScope, itemIndex) {
var isLocked = false,
item = ctrl.selected[itemIndex];
if(item) {
if (itemScope) {
isLocked = !!(itemScope.$eval(ctrl.lockChoiceExpression));
_updateItemLocked(item, isLocked);
} else {
isLocked = _isItemlocked(item);
}
}
return isLocked;
};
}
var sizeWatch = null;
var updaterScheduled = false;
ctrl.sizeSearchInput = function() {
var input = ctrl.searchInput[0],
container = ctrl.searchInput.parent().parent()[0],
calculateContainerWidth = function() {
// Return the container width only if the search input is visible
return container.clientWidth * !!input.offsetParent;
},
updateIfVisible = function(containerWidth) {
if (containerWidth === 0) {
return false;
}
var inputWidth = containerWidth - input.offsetLeft - 10;
if (inputWidth < 50) inputWidth = containerWidth;
ctrl.searchInput.css('width', inputWidth+'px');
return true;
};
ctrl.searchInput.css('width', '10px');
$timeout(function() { //Give tags time to render correctly
if (sizeWatch === null && !updateIfVisible(calculateContainerWidth())) {
sizeWatch = $scope.$watch(function() {
if (!updaterScheduled) {
updaterScheduled = true;
$scope.$$postDigest(function() {
updaterScheduled = false;
if (updateIfVisible(calculateContainerWidth())) {
sizeWatch();
sizeWatch = null;
}
});
}
}, angular.noop);
}
});
};
function _handleDropDownSelection(key) {
var processed = true;
switch (key) {
case KEY.DOWN:
if (!ctrl.open && ctrl.multiple) ctrl.activate(false, true); //In case its the search input in 'multiple' mode
else if (ctrl.activeIndex < ctrl.items.length - 1) { ctrl.activeIndex++; }
break;
case KEY.UP:
if (!ctrl.open && ctrl.multiple) ctrl.activate(false, true); //In case its the search input in 'multiple' mode
else if (ctrl.activeIndex > 0 || (ctrl.search.length === 0 && ctrl.tagging.isActivated && ctrl.activeIndex > -1)) { ctrl.activeIndex--; }
break;
case KEY.TAB:
if (!ctrl.multiple || ctrl.open) ctrl.select(ctrl.items[ctrl.activeIndex], true);
break;
case KEY.ENTER:
if(ctrl.open && (ctrl.tagging.isActivated || ctrl.activeIndex >= 0)){
ctrl.select(ctrl.items[ctrl.activeIndex], ctrl.skipFocusser); // Make sure at least one dropdown item is highlighted before adding if not in tagging mode
} else {
ctrl.activate(false, true); //In case its the search input in 'multiple' mode
}
break;
case KEY.ESC:
ctrl.close();
break;
default:
processed = false;
}
return processed;
}
// Bind to keyboard shortcuts
ctrl.searchInput.on('keydown', function(e) {
var key = e.which;
if (~[KEY.ENTER,KEY.ESC].indexOf(key)){
e.preventDefault();
e.stopPropagation();
}
$scope.$apply(function() {
var tagged = false;
if (ctrl.items.length > 0 || ctrl.tagging.isActivated) {
if(!_handleDropDownSelection(key) && !ctrl.searchEnabled) {
e.preventDefault();
e.stopPropagation();
}
if ( ctrl.taggingTokens.isActivated ) {
for (var i = 0; i < ctrl.taggingTokens.tokens.length; i++) {
if ( ctrl.taggingTokens.tokens[i] === KEY.MAP[e.keyCode] ) {
// make sure there is a new value to push via tagging
if ( ctrl.search.length > 0 ) {
tagged = true;
}
}
}
if ( tagged ) {
$timeout(function() {
ctrl.searchInput.triggerHandler('tagged');
var newItem = ctrl.search.replace(KEY.MAP[e.keyCode],'').trim();
if ( ctrl.tagging.fct ) {
newItem = ctrl.tagging.fct( newItem );
}
if (newItem) ctrl.select(newItem, true);
});
}
}
}
});
if(KEY.isVerticalMovement(key) && ctrl.items.length > 0){
_ensureHighlightVisible();
}
if (key === KEY.ENTER || key === KEY.ESC) {
e.preventDefault();
e.stopPropagation();
}
});
ctrl.searchInput.on('paste', function (e) {
var data;
if (window.clipboardData && window.clipboardData.getData) { // IE
data = window.clipboardData.getData('Text');
} else {
data = (e.originalEvent || e).clipboardData.getData('text/plain');
}
// Prepend the current input field text to the paste buffer.
data = ctrl.search + data;
if (data && data.length > 0) {
// If tagging try to split by tokens and add items
if (ctrl.taggingTokens.isActivated) {
var items = [];
for (var i = 0; i < ctrl.taggingTokens.tokens.length; i++) { // split by first token that is contained in data
var separator = KEY.toSeparator(ctrl.taggingTokens.tokens[i]) || ctrl.taggingTokens.tokens[i];
if (data.indexOf(separator) > -1) {
items = data.split(separator);
break; // only split by one token
}
}
if (items.length === 0) {
items = [data];
}
var oldsearch = ctrl.search;
angular.forEach(items, function (item) {
var newItem = ctrl.tagging.fct ? ctrl.tagging.fct(item) : item;
if (newItem) {
ctrl.select(newItem, true);
}
});
ctrl.search = oldsearch || EMPTY_SEARCH;
e.preventDefault();
e.stopPropagation();
} else if (ctrl.paste) {
ctrl.paste(data);
ctrl.search = EMPTY_SEARCH;
e.preventDefault();
e.stopPropagation();
}
}
});
ctrl.searchInput.on('tagged', function() {
$timeout(function() {
_resetSearchInput();
});
});
// See https://github.com/ivaynberg/select2/blob/3.4.6/select2.js#L1431
function _ensureHighlightVisible() {
var container = $element.querySelectorAll('.ui-select-choices-content');
var choices = container.querySelectorAll('.ui-select-choices-row');
if (choices.length < 1) {
throw uiSelectMinErr('choices', "Expected multiple .ui-select-choices-row but got '{0}'.", choices.length);
}
if (ctrl.activeIndex < 0) {
return;
}
var highlighted = choices[ctrl.activeIndex];
var posY = highlighted.offsetTop + highlighted.clientHeight - container[0].scrollTop;
var height = container[0].offsetHeight;
if (posY > height) {
container[0].scrollTop += posY - height;
} else if (posY < highlighted.clientHeight) {
if (ctrl.isGrouped && ctrl.activeIndex === 0)
container[0].scrollTop = 0; //To make group header visible when going all the way up
else
container[0].scrollTop -= highlighted.clientHeight - posY;
}
}
var onResize = $$uisDebounce(function() {
ctrl.sizeSearchInput();
}, 50);
angular.element($window).bind('resize', onResize);
$scope.$on('$destroy', function() {
ctrl.searchInput.off('keyup keydown tagged blur paste');
angular.element($window).off('resize', onResize);
});
$scope.$watch('$select.activeIndex', function(activeIndex) {
if (activeIndex)
$element.find('input').attr(
'aria-activedescendant',
'ui-select-choices-row-' + ctrl.generatedId + '-' + activeIndex);
});
$scope.$watch('$select.open', function(open) {
if (!open)
$element.find('input').removeAttr('aria-activedescendant');
});
}]);
uis.directive('uiSelect',
['$document', 'uiSelectConfig', 'uiSelectMinErr', 'uisOffset', '$compile', '$parse', '$timeout',
function($document, uiSelectConfig, uiSelectMinErr, uisOffset, $compile, $parse, $timeout) {
return {
restrict: 'EA',
templateUrl: function(tElement, tAttrs) {
var theme = tAttrs.theme || uiSelectConfig.theme;
return theme + (angular.isDefined(tAttrs.multiple) ? '/select-multiple.tpl.html' : '/select.tpl.html');
},
replace: true,
transclude: true,
require: ['uiSelect', '^ngModel'],
scope: true,
controller: 'uiSelectCtrl',
controllerAs: '$select',
compile: function(tElement, tAttrs) {
// Allow setting ngClass on uiSelect
var match = /{(.*)}\s*{(.*)}/.exec(tAttrs.ngClass);
if(match) {
var combined = '{'+ match[1] +', '+ match[2] +'}';
tAttrs.ngClass = combined;
tElement.attr('ng-class', combined);
}
//Multiple or Single depending if multiple attribute presence
if (angular.isDefined(tAttrs.multiple))
tElement.append('<ui-select-multiple/>').removeAttr('multiple');
else
tElement.append('<ui-select-single/>');
if (tAttrs.inputId)
tElement.querySelectorAll('input.ui-select-search')[0].id = tAttrs.inputId;
return function(scope, element, attrs, ctrls, transcludeFn) {
var $select = ctrls[0];
var ngModel = ctrls[1];
$select.generatedId = uiSelectConfig.generateId();
$select.baseTitle = attrs.title || 'Select box';
$select.focusserTitle = $select.baseTitle + ' focus';
$select.focusserId = 'focusser-' + $select.generatedId;
$select.closeOnSelect = function() {
if (angular.isDefined(attrs.closeOnSelect)) {
return $parse(attrs.closeOnSelect)();
} else {
return uiSelectConfig.closeOnSelect;
}
}();
scope.$watch('skipFocusser', function() {
var skipFocusser = scope.$eval(attrs.skipFocusser);
$select.skipFocusser = skipFocusser !== undefined ? skipFocusser : uiSelectConfig.skipFocusser;
});
$select.onSelectCallback = $parse(attrs.onSelect);
$select.onRemoveCallback = $parse(attrs.onRemove);
//Set reference to ngModel from uiSelectCtrl
$select.ngModel = ngModel;
$select.choiceGrouped = function(group){
return $select.isGrouped && group && group.name;
};
if(attrs.tabindex){
attrs.$observe('tabindex', function(value) {
$select.focusInput.attr('tabindex', value);
element.removeAttr('tabindex');
});
}
scope.$watch(function () { return scope.$eval(attrs.searchEnabled); }, function(newVal) {
$select.searchEnabled = newVal !== undefined ? newVal : uiSelectConfig.searchEnabled;
});
scope.$watch('sortable', function() {
var sortable = scope.$eval(attrs.sortable);
$select.sortable = sortable !== undefined ? sortable : uiSelectConfig.sortable;
});
attrs.$observe('limit', function() {
//Limit the number of selections allowed
$select.limit = (angular.isDefined(attrs.limit)) ? parseInt(attrs.limit, 10) : undefined;
});
scope.$watch('removeSelected', function() {
var removeSelected = scope.$eval(attrs.removeSelected);
$select.removeSelected = removeSelected !== undefined ? removeSelected : uiSelectConfig.removeSelected;
});
attrs.$observe('disabled', function() {
// No need to use $eval() (thanks to ng-disabled) since we already get a boolean instead of a string
$select.disabled = attrs.disabled !== undefined ? attrs.disabled : false;
});
attrs.$observe('resetSearchInput', function() {
// $eval() is needed otherwise we get a string instead of a boolean
var resetSearchInput = scope.$eval(attrs.resetSearchInput);
$select.resetSearchInput = resetSearchInput !== undefined ? resetSearchInput : true;
});
attrs.$observe('paste', function() {
$select.paste = scope.$eval(attrs.paste);
});
attrs.$observe('tagging', function() {
if(attrs.tagging !== undefined)
{
// $eval() is needed otherwise we get a string instead of a boolean
var taggingEval = scope.$eval(attrs.tagging);
$select.tagging = {isActivated: true, fct: taggingEval !== true ? taggingEval : undefined};
}
else
{
$select.tagging = {isActivated: false, fct: undefined};
}
});
attrs.$observe('taggingLabel', function() {
if(attrs.tagging !== undefined )
{
// check eval for FALSE, in this case, we disable the labels
// associated with tagging
if ( attrs.taggingLabel === 'false' ) {
$select.taggingLabel = false;
}
else
{
$select.taggingLabel = attrs.taggingLabel !== undefined ? attrs.taggingLabel : '(new)';
}
}
});
attrs.$observe('taggingTokens', function() {
if (attrs.tagging !== undefined) {
var tokens = attrs.taggingTokens !== undefined ? attrs.taggingTokens.split('|') : [',','ENTER'];
$select.taggingTokens = {isActivated: true, tokens: tokens };
}
});
attrs.$observe('spinnerEnabled', function() {
// $eval() is needed otherwise we get a string instead of a boolean
var spinnerEnabled = scope.$eval(attrs.spinnerEnabled);
$select.spinnerEnabled = spinnerEnabled !== undefined ? spinnerEnabled : uiSelectConfig.spinnerEnabled;
});
attrs.$observe('spinnerClass', function() {
var spinnerClass = attrs.spinnerClass;
$select.spinnerClass = spinnerClass !== undefined ? attrs.spinnerClass : uiSelectConfig.spinnerClass;
});
//Automatically gets focus when loaded
if (angular.isDefined(attrs.autofocus)){
$timeout(function(){
$select.setFocus();
});
}
//Gets focus based on scope event name (e.g. focus-on='SomeEventName')
if (angular.isDefined(attrs.focusOn)){
scope.$on(attrs.focusOn, function() {
$timeout(function(){
$select.setFocus();
});
});
}
function onDocumentClick(e) {
if (!$select.open) return; //Skip it if dropdown is close
var contains = false;
if (window.jQuery) {
// Firefox 3.6 does not support element.contains()
// See Node.contains https://developer.mozilla.org/en-US/docs/Web/API/Node.contains
contains = window.jQuery.contains(element[0], e.target);
} else {
contains = element[0].contains(e.target);
}
if (!contains && !$select.clickTriggeredSelect) {
var skipFocusser;
if (!$select.skipFocusser) {
//Will lose focus only with certain targets
var focusableControls = ['input','button','textarea','select'];
var targetController = angular.element(e.target).controller('uiSelect'); //To check if target is other ui-select
skipFocusser = targetController && targetController !== $select; //To check if target is other ui-select
if (!skipFocusser) skipFocusser = ~focusableControls.indexOf(e.target.tagName.toLowerCase()); //Check if target is input, button or textarea
} else {
skipFocusser = true;
}
$select.close(skipFocusser);
scope.$digest();
}
$select.clickTriggeredSelect = false;
}
// See Click everywhere but here event http://stackoverflow.com/questions/12931369
$document.on('click', onDocumentClick);
scope.$on('$destroy', function() {
$document.off('click', onDocumentClick);
});
// Move transcluded elements to their correct position in main template
transcludeFn(scope, function(clone) {
// See Transclude in AngularJS http://blog.omkarpatil.com/2012/11/transclude-in-angularjs.html
// One day jqLite will be replaced by jQuery and we will be able to write:
// var transcludedElement = clone.filter('.my-class')
// instead of creating a hackish DOM element:
var transcluded = angular.element('<div>').append(clone);
var transcludedMatch = transcluded.querySelectorAll('.ui-select-match');
transcludedMatch.removeAttr('ui-select-match'); //To avoid loop in case directive as attr
transcludedMatch.removeAttr('data-ui-select-match'); // Properly handle HTML5 data-attributes
if (transcludedMatch.length !== 1) {
throw uiSelectMinErr('transcluded', "Expected 1 .ui-select-match but got '{0}'.", transcludedMatch.length);
}
element.querySelectorAll('.ui-select-match').replaceWith(transcludedMatch);
var transcludedChoices = transcluded.querySelectorAll('.ui-select-choices');
transcludedChoices.removeAttr('ui-select-choices'); //To avoid loop in case directive as attr
transcludedChoices.removeAttr('data-ui-select-choices'); // Properly handle HTML5 data-attributes
if (transcludedChoices.length !== 1) {
throw uiSelectMinErr('transcluded', "Expected 1 .ui-select-choices but got '{0}'.", transcludedChoices.length);
}
element.querySelectorAll('.ui-select-choices').replaceWith(transcludedChoices);
var transcludedNoChoice = transcluded.querySelectorAll('.ui-select-no-choice');
transcludedNoChoice.removeAttr('ui-select-no-choice'); //To avoid loop in case directive as attr
transcludedNoChoice.removeAttr('data-ui-select-no-choice'); // Properly handle HTML5 data-attributes
if (transcludedNoChoice.length == 1) {
element.querySelectorAll('.ui-select-no-choice').replaceWith(transcludedNoChoice);
}
});
// Support for appending the select field to the body when its open
var appendToBody = scope.$eval(attrs.appendToBody);
if (appendToBody !== undefined ? appendToBody : uiSelectConfig.appendToBody) {
scope.$watch('$select.open', function(isOpen) {
if (isOpen) {
positionDropdown();
} else {
resetDropdown();
}
});
// Move the dropdown back to its original location when the scope is destroyed. Otherwise
// it might stick around when the user routes away or the select field is otherwise removed
scope.$on('$destroy', function() {
resetDropdown();
});
}
// Hold on to a reference to the .ui-select-container element for appendToBody support
var placeholder = null,
originalWidth = '';
function positionDropdown() {
// Remember the absolute position of the element
var offset = uisOffset(element);
// Clone the element into a placeholder element to take its original place in the DOM
placeholder = angular.element('<div class="ui-select-placeholder"></div>');
placeholder[0].style.width = offset.width + 'px';
placeholder[0].style.height = offset.height + 'px';
element.after(placeholder);
// Remember the original value of the element width inline style, so it can be restored
// when the dropdown is closed
originalWidth = element[0].style.width;
// Now move the actual dropdown element to the end of the body
$document.find('body').append(element);
element[0].style.position = 'absolute';
element[0].style.left = offset.left + 'px';
element[0].style.top = offset.top + 'px';
element[0].style.width = offset.width + 'px';
}
function resetDropdown() {
if (placeholder === null) {
// The dropdown has not actually been display yet, so there's nothing to reset
return;
}
// Move the dropdown element back to its original location in the DOM
placeholder.replaceWith(element);
placeholder = null;
element[0].style.position = '';
element[0].style.left = '';
element[0].style.top = '';
element[0].style.width = originalWidth;
// Set focus back on to the moved element
$select.setFocus();
}
// Hold on to a reference to the .ui-select-dropdown element for direction support.
var dropdown = null,
directionUpClassName = 'direction-up';
// Support changing the direction of the dropdown if there isn't enough space to render it.
scope.$watch('$select.open', function() {
if ($select.dropdownPosition === 'auto' || $select.dropdownPosition === 'up'){
scope.calculateDropdownPos();
}
});
var setDropdownPosUp = function(offset, offsetDropdown){
offset = offset || uisOffset(element);
offsetDropdown = offsetDropdown || uisOffset(dropdown);
dropdown[0].style.position = 'absolute';
dropdown[0].style.top = (offsetDropdown.height * -1) + 'px';
element.addClass(directionUpClassName);
};
var setDropdownPosDown = function(offset, offsetDropdown){
element.removeClass(directionUpClassName);
offset = offset || uisOffset(element);
offsetDropdown = offsetDropdown || uisOffset(dropdown);
dropdown[0].style.position = '';
dropdown[0].style.top = '';
};
var calculateDropdownPosAfterAnimation = function() {
// Delay positioning the dropdown until all choices have been added so its height is correct.
$timeout(function() {
if ($select.dropdownPosition === 'up') {
//Go UP
setDropdownPosUp();
} else {
//AUTO
element.removeClass(directionUpClassName);
var offset = uisOffset(element);
var offsetDropdown = uisOffset(dropdown);
//https://code.google.com/p/chromium/issues/detail?id=342307#c4
var scrollTop = $document[0].documentElement.scrollTop || $document[0].body.scrollTop; //To make it cross browser (blink, webkit, IE, Firefox).
// Determine if the direction of the dropdown needs to be changed.
if (offset.top + offset.height + offsetDropdown.height > scrollTop + $document[0].documentElement.clientHeight) {
//Go UP
setDropdownPosUp(offset, offsetDropdown);
}else{
//Go DOWN
setDropdownPosDown(offset, offsetDropdown);
}
}
// Display the dropdown once it has been positioned.
dropdown[0].style.opacity = 1;
});
};
var opened = false;
scope.calculateDropdownPos = function() {
if ($select.open) {
dropdown = angular.element(element).querySelectorAll('.ui-select-dropdown');
if (dropdown.length === 0) {
return;
}
// Hide the dropdown so there is no flicker until $timeout is done executing.
if ($select.search === '' && !opened) {
dropdown[0].style.opacity = 0;
opened = true;
}
if (!uisOffset(dropdown).height && $select.$animate && $select.$animate.on && $select.$animate.enabled(dropdown)) {
var needsCalculated = true;
$select.$animate.on('enter', dropdown, function (elem, phase) {
if (phase === 'close' && needsCalculated) {
calculateDropdownPosAfterAnimation();
needsCalculated = false;
}
});
} else {
calculateDropdownPosAfterAnimation();
}
} else {
if (dropdown === null || dropdown.length === 0) {
return;
}
// Reset the position of the dropdown.
dropdown[0].style.opacity = 0;
dropdown[0].style.position = '';
dropdown[0].style.top = '';
element.removeClass(directionUpClassName);
}
};
};
}
};
}]);
uis.directive('uiSelectMatch', ['uiSelectConfig', function(uiSelectConfig) {
return {
restrict: 'EA',
require: '^uiSelect',
replace: true,
transclude: true,
templateUrl: function(tElement) {
// Needed so the uiSelect can detect the transcluded content
tElement.addClass('ui-select-match');
var parent = tElement.parent();
// Gets theme attribute from parent (ui-select)
var theme = getAttribute(parent, 'theme') || uiSelectConfig.theme;
var multi = angular.isDefined(getAttribute(parent, 'multiple'));
return theme + (multi ? '/match-multiple.tpl.html' : '/match.tpl.html');
},
link: function(scope, element, attrs, $select) {
$select.lockChoiceExpression = attrs.uiLockChoice;
attrs.$observe('placeholder', function(placeholder) {
$select.placeholder = placeholder !== undefined ? placeholder : uiSelectConfig.placeholder;
});
function setAllowClear(allow) {
$select.allowClear = (angular.isDefined(allow)) ? (allow === '') ? true : (allow.toLowerCase() === 'true') : false;
}
attrs.$observe('allowClear', setAllowClear);
setAllowClear(attrs.allowClear);
if($select.multiple){
$select.sizeSearchInput();
}
}
};
function getAttribute(elem, attribute) {
if (elem[0].hasAttribute(attribute))
return elem.attr(attribute);
if (elem[0].hasAttribute('data-' + attribute))
return elem.attr('data-' + attribute);
if (elem[0].hasAttribute('x-' + attribute))
return elem.attr('x-' + attribute);
}
}]);
uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelectMinErr, $timeout) {
return {
restrict: 'EA',
require: ['^uiSelect', '^ngModel'],
controller: ['$scope','$timeout', function($scope, $timeout){
var ctrl = this,
$select = $scope.$select,
ngModel;
if (angular.isUndefined($select.selected))
$select.selected = [];
//Wait for link fn to inject it
$scope.$evalAsync(function(){ ngModel = $scope.ngModel; });
ctrl.activeMatchIndex = -1;
ctrl.updateModel = function(){
ngModel.$setViewValue(Date.now()); //Set timestamp as a unique string to force changes
ctrl.refreshComponent();
};
ctrl.refreshComponent = function(){
//Remove already selected items
//e.g. When user clicks on a selection, the selected array changes and
//the dropdown should remove that item
if($select.refreshItems){
$select.refreshItems();
}
if($select.sizeSearchInput){
$select.sizeSearchInput();
}
};
// Remove item from multiple select
ctrl.removeChoice = function(index){
// if the choice is locked, don't remove it
if($select.isLocked(null, index)) return false;
var removedChoice = $select.selected[index];
var locals = {};
locals[$select.parserResult.itemName] = removedChoice;
$select.selected.splice(index, 1);
ctrl.activeMatchIndex = -1;
$select.sizeSearchInput();
// Give some time for scope propagation.
$timeout(function(){
$select.onRemoveCallback($scope, {
$item: removedChoice,
$model: $select.parserResult.modelMapper($scope, locals)
});
});
ctrl.updateModel();
return true;
};
ctrl.getPlaceholder = function(){
//Refactor single?
if($select.selected && $select.selected.length) return;
return $select.placeholder;
};
}],
controllerAs: '$selectMultiple',
link: function(scope, element, attrs, ctrls) {
var $select = ctrls[0];
var ngModel = scope.ngModel = ctrls[1];
var $selectMultiple = scope.$selectMultiple;
//$select.selected = raw selected objects (ignoring any property binding)
$select.multiple = true;
//Input that will handle focus
$select.focusInput = $select.searchInput;
//Properly check for empty if set to multiple
ngModel.$isEmpty = function(value) {
return !value || value.length === 0;
};
//From view --> model
ngModel.$parsers.unshift(function () {
var locals = {},
result,
resultMultiple = [];
for (var j = $select.selected.length - 1; j >= 0; j--) {
locals = {};
locals[$select.parserResult.itemName] = $select.selected[j];
result = $select.parserResult.modelMapper(scope, locals);
resultMultiple.unshift(result);
}
return resultMultiple;
});
// From model --> view
ngModel.$formatters.unshift(function (inputValue) {
var data = $select.parserResult && $select.parserResult.source (scope, { $select : {search:''}}), //Overwrite $search
locals = {},
result;
if (!data) return inputValue;
var resultMultiple = [];
var checkFnMultiple = function(list, value){
if (!list || !list.length) return;
for (var p = list.length - 1; p >= 0; p--) {
locals[$select.parserResult.itemName] = list[p];
result = $select.parserResult.modelMapper(scope, locals);
if($select.parserResult.trackByExp){
var propsItemNameMatches = /(\w*)\./.exec($select.parserResult.trackByExp);
var matches = /\.([^\s]+)/.exec($select.parserResult.trackByExp);
if(propsItemNameMatches && propsItemNameMatches.length > 0 && propsItemNameMatches[1] == $select.parserResult.itemName){
if(matches && matches.length>0 && result[matches[1]] == value[matches[1]]){
resultMultiple.unshift(list[p]);
return true;
}
}
}
if (angular.equals(result,value)){
resultMultiple.unshift(list[p]);
return true;
}
}
return false;
};
if (!inputValue) return resultMultiple; //If ngModel was undefined
for (var k = inputValue.length - 1; k >= 0; k--) {
//Check model array of currently selected items
if (!checkFnMultiple($select.selected, inputValue[k])){
//Check model array of all items available
if (!checkFnMultiple(data, inputValue[k])){
//If not found on previous lists, just add it directly to resultMultiple
resultMultiple.unshift(inputValue[k]);
}
}
}
return resultMultiple;
});
//Watch for external model changes
scope.$watchCollection(function(){ return ngModel.$modelValue; }, function(newValue, oldValue) {
if (oldValue != newValue){
//update the view value with fresh data from items, if there is a valid model value
if(angular.isDefined(ngModel.$modelValue)) {
ngModel.$modelValue = null; //Force scope model value and ngModel value to be out of sync to re-run formatters
}
$selectMultiple.refreshComponent();
}
});
ngModel.$render = function() {
// Make sure that model value is array
if(!angular.isArray(ngModel.$viewValue)){
// Have tolerance for null or undefined values
if(angular.isUndefined(ngModel.$viewValue) || ngModel.$viewValue === null){
ngModel.$viewValue = [];
} else {
throw uiSelectMinErr('multiarr', "Expected model value to be array but got '{0}'", ngModel.$viewValue);
}
}
$select.selected = ngModel.$viewValue;
$selectMultiple.refreshComponent();
scope.$evalAsync(); //To force $digest
};
scope.$on('uis:select', function (event, item) {
if($select.selected.length >= $select.limit) {
return;
}
$select.selected.push(item);
$selectMultiple.updateModel();
});
scope.$on('uis:activate', function () {
$selectMultiple.activeMatchIndex = -1;
});
scope.$watch('$select.disabled', function(newValue, oldValue) {
// As the search input field may now become visible, it may be necessary to recompute its size
if (oldValue && !newValue) $select.sizeSearchInput();
});
$select.searchInput.on('keydown', function(e) {
var key = e.which;
scope.$apply(function() {
var processed = false;
// var tagged = false; //Checkme
if(KEY.isHorizontalMovement(key)){
processed = _handleMatchSelection(key);
}
if (processed && key != KEY.TAB) {
//TODO Check si el tab selecciona aun correctamente
//Crear test
e.preventDefault();
e.stopPropagation();
}
});
});
function _getCaretPosition(el) {
if(angular.isNumber(el.selectionStart)) return el.selectionStart;
// selectionStart is not supported in IE8 and we don't want hacky workarounds so we compromise
else return el.value.length;
}
// Handles selected options in "multiple" mode
function _handleMatchSelection(key){
var caretPosition = _getCaretPosition($select.searchInput[0]),
length = $select.selected.length,
// none = -1,
first = 0,
last = length-1,
curr = $selectMultiple.activeMatchIndex,
next = $selectMultiple.activeMatchIndex+1,
prev = $selectMultiple.activeMatchIndex-1,
newIndex = curr;
if(caretPosition > 0 || ($select.search.length && key == KEY.RIGHT)) return false;
$select.close();
function getNewActiveMatchIndex(){
switch(key){
case KEY.LEFT:
// Select previous/first item
if(~$selectMultiple.activeMatchIndex) return prev;
// Select last item
else return last;
break;
case KEY.RIGHT:
// Open drop-down
if(!~$selectMultiple.activeMatchIndex || curr === last){
$select.activate();
return false;
}
// Select next/last item
else return next;
break;
case KEY.BACKSPACE:
// Remove selected item and select previous/first
if(~$selectMultiple.activeMatchIndex){
if($selectMultiple.removeChoice(curr)) {
return prev;
} else {
return curr;
}
} else {
// If nothing yet selected, select last item
return last;
}
break;
case KEY.DELETE:
// Remove selected item and select next item
if(~$selectMultiple.activeMatchIndex){
$selectMultiple.removeChoice($selectMultiple.activeMatchIndex);
return curr;
}
else return false;
}
}
newIndex = getNewActiveMatchIndex();
if(!$select.selected.length || newIndex === false) $selectMultiple.activeMatchIndex = -1;
else $selectMultiple.activeMatchIndex = Math.min(last,Math.max(first,newIndex));
return true;
}
$select.searchInput.on('keyup', function(e) {
if ( ! KEY.isVerticalMovement(e.which) ) {
scope.$evalAsync( function () {
$select.activeIndex = $select.taggingLabel === false ? -1 : 0;
});
}
// Push a "create new" item into array if there is a search string
if ( $select.tagging.isActivated && $select.search.length > 0 ) {
// return early with these keys
if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.ESC || KEY.isVerticalMovement(e.which) ) {
return;
}
// always reset the activeIndex to the first item when tagging
$select.activeIndex = $select.taggingLabel === false ? -1 : 0;
// taggingLabel === false bypasses all of this
if ($select.taggingLabel === false) return;
var items = angular.copy( $select.items );
var stashArr = angular.copy( $select.items );
var newItem;
var item;
var hasTag = false;
var dupeIndex = -1;
var tagItems;
var tagItem;
// case for object tagging via transform `$select.tagging.fct` function
if ( $select.tagging.fct !== undefined) {
tagItems = $select.$filter('filter')(items,{'isTag': true});
if ( tagItems.length > 0 ) {
tagItem = tagItems[0];
}
// remove the first element, if it has the `isTag` prop we generate a new one with each keyup, shaving the previous
if ( items.length > 0 && tagItem ) {
hasTag = true;
items = items.slice(1,items.length);
stashArr = stashArr.slice(1,stashArr.length);
}
newItem = $select.tagging.fct($select.search);
// verify the new tag doesn't match the value of a possible selection choice or an already selected item.
if (
stashArr.some(function (origItem) {
return angular.equals(origItem, newItem);
}) ||
$select.selected.some(function (origItem) {
return angular.equals(origItem, newItem);
})
) {
scope.$evalAsync(function () {
$select.activeIndex = 0;
$select.items = items;
});
return;
}
if (newItem) newItem.isTag = true;
// handle newItem string and stripping dupes in tagging string context
} else {
// find any tagging items already in the $select.items array and store them
tagItems = $select.$filter('filter')(items,function (item) {
return item.match($select.taggingLabel);
});
if ( tagItems.length > 0 ) {
tagItem = tagItems[0];
}
item = items[0];
// remove existing tag item if found (should only ever be one tag item)
if ( item !== undefined && items.length > 0 && tagItem ) {
hasTag = true;
items = items.slice(1,items.length);
stashArr = stashArr.slice(1,stashArr.length);
}
newItem = $select.search+' '+$select.taggingLabel;
if ( _findApproxDupe($select.selected, $select.search) > -1 ) {
return;
}
// verify the the tag doesn't match the value of an existing item from
// the searched data set or the items already selected
if ( _findCaseInsensitiveDupe(stashArr.concat($select.selected)) ) {
// if there is a tag from prev iteration, strip it / queue the change
// and return early
if ( hasTag ) {
items = stashArr;
scope.$evalAsync( function () {
$select.activeIndex = 0;
$select.items = items;
});
}
return;
}
if ( _findCaseInsensitiveDupe(stashArr) ) {
// if there is a tag from prev iteration, strip it
if ( hasTag ) {
$select.items = stashArr.slice(1,stashArr.length);
}
return;
}
}
if ( hasTag ) dupeIndex = _findApproxDupe($select.selected, newItem);
// dupe found, shave the first item
if ( dupeIndex > -1 ) {
items = items.slice(dupeIndex+1,items.length-1);
} else {
items = [];
if (newItem) items.push(newItem);
items = items.concat(stashArr);
}
scope.$evalAsync( function () {
$select.activeIndex = 0;
$select.items = items;
if ($select.isGrouped) {
// update item references in groups, so that indexOf will work after angular.copy
var itemsWithoutTag = newItem ? items.slice(1) : items;
$select.setItemsFn(itemsWithoutTag);
if (newItem) {
// add tag item as a new group
$select.items.unshift(newItem);
$select.groups.unshift({name: '', items: [newItem], tagging: true});
}
}
});
}
});
function _findCaseInsensitiveDupe(arr) {
if ( arr === undefined || $select.search === undefined ) {
return false;
}
var hasDupe = arr.filter( function (origItem) {
if ( $select.search.toUpperCase() === undefined || origItem === undefined ) {
return false;
}
return origItem.toUpperCase() === $select.search.toUpperCase();
}).length > 0;
return hasDupe;
}
function _findApproxDupe(haystack, needle) {
var dupeIndex = -1;
if(angular.isArray(haystack)) {
var tempArr = angular.copy(haystack);
for (var i = 0; i <tempArr.length; i++) {
// handle the simple string version of tagging
if ( $select.tagging.fct === undefined ) {
// search the array for the match
if ( tempArr[i]+' '+$select.taggingLabel === needle ) {
dupeIndex = i;
}
// handle the object tagging implementation
} else {
var mockObj = tempArr[i];
if (angular.isObject(mockObj)) {
mockObj.isTag = true;
}
if ( angular.equals(mockObj, needle) ) {
dupeIndex = i;
}
}
}
}
return dupeIndex;
}
$select.searchInput.on('blur', function() {
$timeout(function() {
$selectMultiple.activeMatchIndex = -1;
});
});
}
};
}]);
uis.directive('uiSelectNoChoice',
['uiSelectConfig', function (uiSelectConfig) {
return {
restrict: 'EA',
require: '^uiSelect',
replace: true,
transclude: true,
templateUrl: function (tElement) {
// Needed so the uiSelect can detect the transcluded content
tElement.addClass('ui-select-no-choice');
// Gets theme attribute from parent (ui-select)
var theme = tElement.parent().attr('theme') || uiSelectConfig.theme;
return theme + '/no-choice.tpl.html';
}
};
}]);
uis.directive('uiSelectSingle', ['$timeout','$compile', function($timeout, $compile) {
return {
restrict: 'EA',
require: ['^uiSelect', '^ngModel'],
link: function(scope, element, attrs, ctrls) {
var $select = ctrls[0];
var ngModel = ctrls[1];
//From view --> model
ngModel.$parsers.unshift(function (inputValue) {
var locals = {},
result;
locals[$select.parserResult.itemName] = inputValue;
result = $select.parserResult.modelMapper(scope, locals);
return result;
});
//From model --> view
ngModel.$formatters.unshift(function (inputValue) {
var data = $select.parserResult && $select.parserResult.source (scope, { $select : {search:''}}), //Overwrite $search
locals = {},
result;
if (data){
var checkFnSingle = function(d){
locals[$select.parserResult.itemName] = d;
result = $select.parserResult.modelMapper(scope, locals);
return result === inputValue;
};
//If possible pass same object stored in $select.selected
if ($select.selected && checkFnSingle($select.selected)) {
return $select.selected;
}
for (var i = data.length - 1; i >= 0; i--) {
if (checkFnSingle(data[i])) return data[i];
}
}
return inputValue;
});
//Update viewValue if model change
scope.$watch('$select.selected', function(newValue) {
if (ngModel.$viewValue !== newValue) {
ngModel.$setViewValue(newValue);
}
});
ngModel.$render = function() {
$select.selected = ngModel.$viewValue;
};
scope.$on('uis:select', function (event, item) {
$select.selected = item;
});
scope.$on('uis:close', function (event, skipFocusser) {
$timeout(function(){
$select.focusser.prop('disabled', false);
if (!skipFocusser) $select.focusser[0].focus();
},0,false);
});
scope.$on('uis:activate', function () {
focusser.prop('disabled', true); //Will reactivate it on .close()
});
//Idea from: https://github.com/ivaynberg/select2/blob/79b5bf6db918d7560bdd959109b7bcfb47edaf43/select2.js#L1954
var focusser = angular.element("<input ng-disabled='$select.disabled' class='ui-select-focusser ui-select-offscreen' type='text' id='{{ $select.focusserId }}' aria-label='{{ $select.focusserTitle }}' aria-haspopup='true' role='button' />");
$compile(focusser)(scope);
$select.focusser = focusser;
//Input that will handle focus
$select.focusInput = focusser;
element.parent().append(focusser);
focusser.bind("focus", function(){
scope.$evalAsync(function(){
$select.focus = true;
});
});
focusser.bind("blur", function(){
scope.$evalAsync(function(){
$select.focus = false;
});
});
focusser.bind("keydown", function(e){
if (e.which === KEY.BACKSPACE) {
e.preventDefault();
e.stopPropagation();
$select.select(undefined);
scope.$apply();
return;
}
if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.ESC) {
return;
}
if (e.which == KEY.DOWN || e.which == KEY.UP || e.which == KEY.ENTER || e.which == KEY.SPACE){
e.preventDefault();
e.stopPropagation();
$select.activate();
}
scope.$digest();
});
focusser.bind("keyup input", function(e){
if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.ESC || e.which == KEY.ENTER || e.which === KEY.BACKSPACE) {
return;
}
$select.activate(focusser.val()); //User pressed some regular key, so we pass it to the search input
focusser.val('');
scope.$digest();
});
}
};
}]);
// Make multiple matches sortable
uis.directive('uiSelectSort', ['$timeout', 'uiSelectConfig', 'uiSelectMinErr', function($timeout, uiSelectConfig, uiSelectMinErr) {
return {
require: ['^^uiSelect', '^ngModel'],
link: function(scope, element, attrs, ctrls) {
if (scope[attrs.uiSelectSort] === null) {
throw uiSelectMinErr('sort', 'Expected a list to sort');
}
var $select = ctrls[0];
var $ngModel = ctrls[1];
var options = angular.extend({
axis: 'horizontal'
},
scope.$eval(attrs.uiSelectSortOptions));
var axis = options.axis;
var draggingClassName = 'dragging';
var droppingClassName = 'dropping';
var droppingBeforeClassName = 'dropping-before';
var droppingAfterClassName = 'dropping-after';
scope.$watch(function(){
return $select.sortable;
}, function(newValue){
if (newValue) {
element.attr('draggable', true);
} else {
element.removeAttr('draggable');
}
});
element.on('dragstart', function(event) {
element.addClass(draggingClassName);
(event.dataTransfer || event.originalEvent.dataTransfer).setData('text', scope.$index.toString());
});
element.on('dragend', function() {
removeClass(draggingClassName);
});
var move = function(from, to) {
/*jshint validthis: true */
this.splice(to, 0, this.splice(from, 1)[0]);
};
var removeClass = function(className) {
angular.forEach($select.$element.querySelectorAll('.' + className), function(el){
angular.element(el).removeClass(className);
});
};
var dragOverHandler = function(event) {
event.preventDefault();
var offset = axis === 'vertical' ? event.offsetY || event.layerY || (event.originalEvent ? event.originalEvent.offsetY : 0) : event.offsetX || event.layerX || (event.originalEvent ? event.originalEvent.offsetX : 0);
if (offset < (this[axis === 'vertical' ? 'offsetHeight' : 'offsetWidth'] / 2)) {
removeClass(droppingAfterClassName);
element.addClass(droppingBeforeClassName);
} else {
removeClass(droppingBeforeClassName);
element.addClass(droppingAfterClassName);
}
};
var dropTimeout;
var dropHandler = function(event) {
event.preventDefault();
var droppedItemIndex = parseInt((event.dataTransfer || event.originalEvent.dataTransfer).getData('text'), 10);
// prevent event firing multiple times in firefox
$timeout.cancel(dropTimeout);
dropTimeout = $timeout(function() {
_dropHandler(droppedItemIndex);
}, 20);
};
var _dropHandler = function(droppedItemIndex) {
var theList = scope.$eval(attrs.uiSelectSort);
var itemToMove = theList[droppedItemIndex];
var newIndex = null;
if (element.hasClass(droppingBeforeClassName)) {
if (droppedItemIndex < scope.$index) {
newIndex = scope.$index - 1;
} else {
newIndex = scope.$index;
}
} else {
if (droppedItemIndex < scope.$index) {
newIndex = scope.$index;
} else {
newIndex = scope.$index + 1;
}
}
move.apply(theList, [droppedItemIndex, newIndex]);
$ngModel.$setViewValue(Date.now());
scope.$apply(function() {
scope.$emit('uiSelectSort:change', {
array: theList,
item: itemToMove,
from: droppedItemIndex,
to: newIndex
});
});
removeClass(droppingClassName);
removeClass(droppingBeforeClassName);
removeClass(droppingAfterClassName);
element.off('drop', dropHandler);
};
element.on('dragenter', function() {
if (element.hasClass(draggingClassName)) {
return;
}
element.addClass(droppingClassName);
element.on('dragover', dragOverHandler);
element.on('drop', dropHandler);
});
element.on('dragleave', function(event) {
if (event.target != element) {
return;
}
removeClass(droppingClassName);
removeClass(droppingBeforeClassName);
removeClass(droppingAfterClassName);
element.off('dragover', dragOverHandler);
element.off('drop', dropHandler);
});
}
};
}]);
/**
* Debounces functions
*
* Taken from UI Bootstrap $$debounce source code
* See https://github.com/angular-ui/bootstrap/blob/master/src/debounce/debounce.js
*
*/
uis.factory('$$uisDebounce', ['$timeout', function($timeout) {
return function(callback, debounceTime) {
var timeoutPromise;
return function() {
var self = this;
var args = Array.prototype.slice.call(arguments);
if (timeoutPromise) {
$timeout.cancel(timeoutPromise);
}
timeoutPromise = $timeout(function() {
callback.apply(self, args);
}, debounceTime);
};
};
}]);
uis.directive('uisOpenClose', ['$parse', '$timeout', function ($parse, $timeout) {
return {
restrict: 'A',
require: 'uiSelect',
link: function (scope, element, attrs, $select) {
$select.onOpenCloseCallback = $parse(attrs.uisOpenClose);
scope.$watch('$select.open', function (isOpen, previousState) {
if (isOpen !== previousState) {
$timeout(function () {
$select.onOpenCloseCallback(scope, {
isOpen: isOpen
});
});
}
});
}
};
}]);
/**
* Parses "repeat" attribute.
*
* Taken from AngularJS ngRepeat source code
* See https://github.com/angular/angular.js/blob/v1.2.15/src/ng/directive/ngRepeat.js#L211
*
* Original discussion about parsing "repeat" attribute instead of fully relying on ng-repeat:
* https://github.com/angular-ui/ui-select/commit/5dd63ad#commitcomment-5504697
*/
uis.service('uisRepeatParser', ['uiSelectMinErr','$parse', function(uiSelectMinErr, $parse) {
var self = this;
/**
* Example:
* expression = "address in addresses | filter: {street: $select.search} track by $index"
* itemName = "address",
* source = "addresses | filter: {street: $select.search}",
* trackByExp = "$index",
*/
self.parse = function(expression) {
var match;
//var isObjectCollection = /\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)/.test(expression);
// If an array is used as collection
// if (isObjectCollection){
// 000000000000000000000000000000111111111000000000000000222222222222220033333333333333333333330000444444444444444444000000000000000055555555555000000000000000000000066666666600000000
match = expression.match(/^\s*(?:([\s\S]+?)\s+as\s+)?(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+(\s*[\s\S]+?)?(?:\s+track\s+by\s+([\s\S]+?))?\s*$/);
// 1 Alias
// 2 Item
// 3 Key on (key,value)
// 4 Value on (key,value)
// 5 Source expression (including filters)
// 6 Track by
if (!match) {
throw uiSelectMinErr('iexp', "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",
expression);
}
var source = match[5],
filters = '';
// When using (key,value) ui-select requires filters to be extracted, since the object
// is converted to an array for $select.items
// (in which case the filters need to be reapplied)
if (match[3]) {
// Remove any enclosing parenthesis
source = match[5].replace(/(^\()|(\)$)/g, '');
// match all after | but not after ||
var filterMatch = match[5].match(/^\s*(?:[\s\S]+?)(?:[^\|]|\|\|)+([\s\S]*)\s*$/);
if(filterMatch && filterMatch[1].trim()) {
filters = filterMatch[1];
source = source.replace(filters, '');
}
}
return {
itemName: match[4] || match[2], // (lhs) Left-hand side,
keyName: match[3], //for (key, value) syntax
source: $parse(source),
filters: filters,
trackByExp: match[6],
modelMapper: $parse(match[1] || match[4] || match[2]),
repeatExpression: function (grouped) {
var expression = this.itemName + ' in ' + (grouped ? '$group.items' : '$select.items');
if (this.trackByExp) {
expression += ' track by ' + this.trackByExp;
}
return expression;
}
};
};
self.getGroupNgRepeatExpression = function() {
return '$group in $select.groups track by $group.name';
};
}]);
}());
angular.module("ui.select").run(["$templateCache", function($templateCache) {$templateCache.put("bootstrap/choices.tpl.html","<ul class=\"ui-select-choices ui-select-choices-content ui-select-dropdown dropdown-menu\" ng-show=\"$select.open && $select.items.length > 0\"><li class=\"ui-select-choices-group\" id=\"ui-select-choices-{{ $select.generatedId }}\"><div class=\"divider\" ng-show=\"$select.isGrouped && $index > 0\"></div><div ng-show=\"$select.isGrouped\" class=\"ui-select-choices-group-label dropdown-header\" ng-bind=\"$group.name\"></div><div ng-attr-id=\"ui-select-choices-row-{{ $select.generatedId }}-{{$index}}\" class=\"ui-select-choices-row\" ng-class=\"{active: $select.isActive(this), disabled: $select.isDisabled(this)}\" role=\"option\"><span class=\"ui-select-choices-row-inner\"></span></div></li></ul>");
$templateCache.put("bootstrap/match-multiple.tpl.html","<span class=\"ui-select-match\"><span ng-repeat=\"$item in $select.selected track by $index\"><span class=\"ui-select-match-item btn btn-default btn-xs\" tabindex=\"-1\" type=\"button\" ng-disabled=\"$select.disabled\" ng-click=\"$selectMultiple.activeMatchIndex = $index;\" ng-class=\"{\'btn-primary\':$selectMultiple.activeMatchIndex === $index, \'select-locked\':$select.isLocked(this, $index)}\" ui-select-sort=\"$select.selected\"><span class=\"close ui-select-match-close\" ng-hide=\"$select.disabled\" ng-click=\"$selectMultiple.removeChoice($index)\">&nbsp;&times;</span> <span uis-transclude-append=\"\"></span></span></span></span>");
$templateCache.put("bootstrap/match.tpl.html","<div class=\"ui-select-match\" ng-hide=\"$select.open && $select.searchEnabled\" ng-disabled=\"$select.disabled\" ng-class=\"{\'btn-default-focus\':$select.focus}\"><span tabindex=\"-1\" class=\"btn btn-default form-control ui-select-toggle\" aria-label=\"{{ $select.baseTitle }} activate\" ng-disabled=\"$select.disabled\" ng-click=\"$select.activate()\" style=\"outline: 0;\"><span ng-show=\"$select.isEmpty()\" class=\"ui-select-placeholder text-muted\">{{$select.placeholder}}</span> <span ng-hide=\"$select.isEmpty()\" class=\"ui-select-match-text pull-left\" ng-class=\"{\'ui-select-allow-clear\': $select.allowClear && !$select.isEmpty()}\" ng-transclude=\"\"></span> <i class=\"caret pull-right\" ng-click=\"$select.toggle($event)\"></i> <a ng-show=\"$select.allowClear && !$select.isEmpty() && ($select.disabled !== true)\" aria-label=\"{{ $select.baseTitle }} clear\" style=\"margin-right: 10px\" ng-click=\"$select.clear($event)\" class=\"btn btn-xs btn-link pull-right\"><i class=\"glyphicon glyphicon-remove\" aria-hidden=\"true\"></i></a></span></div>");
$templateCache.put("bootstrap/no-choice.tpl.html","<ul class=\"ui-select-no-choice dropdown-menu\" ng-show=\"$select.items.length == 0\"><li ng-transclude=\"\"></li></ul>");
$templateCache.put("bootstrap/select-multiple.tpl.html","<div class=\"ui-select-container ui-select-multiple ui-select-bootstrap dropdown form-control\" ng-class=\"{open: $select.open}\"><div><div class=\"ui-select-match\"></div><input type=\"search\" autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" class=\"ui-select-search input-xs\" placeholder=\"{{$selectMultiple.getPlaceholder()}}\" ng-disabled=\"$select.disabled\" ng-click=\"$select.activate()\" ng-model=\"$select.search\" role=\"combobox\" aria-expanded=\"{{$select.open}}\" aria-label=\"{{$select.baseTitle}}\" ng-class=\"{\'spinner\': $select.refreshing}\" ondrop=\"return false;\"></div><div class=\"ui-select-choices\"></div><div class=\"ui-select-no-choice\"></div></div>");
$templateCache.put("bootstrap/select.tpl.html","<div class=\"ui-select-container ui-select-bootstrap dropdown\" ng-class=\"{open: $select.open}\"><div class=\"ui-select-match\"></div><span ng-show=\"$select.open && $select.refreshing && $select.spinnerEnabled\" class=\"ui-select-refreshing {{$select.spinnerClass}}\"></span> <input type=\"search\" autocomplete=\"off\" tabindex=\"-1\" aria-expanded=\"true\" aria-label=\"{{ $select.baseTitle }}\" aria-owns=\"ui-select-choices-{{ $select.generatedId }}\" class=\"form-control ui-select-search\" ng-class=\"{ \'ui-select-search-hidden\' : !$select.searchEnabled }\" placeholder=\"{{$select.placeholder}}\" ng-model=\"$select.search\" ng-show=\"$select.open\"><div class=\"ui-select-choices\"></div><div class=\"ui-select-no-choice\"></div></div>");
$templateCache.put("select2/choices.tpl.html","<ul tabindex=\"-1\" class=\"ui-select-choices ui-select-choices-content select2-results\"><li class=\"ui-select-choices-group\" ng-class=\"{\'select2-result-with-children\': $select.choiceGrouped($group) }\"><div ng-show=\"$select.choiceGrouped($group)\" class=\"ui-select-choices-group-label select2-result-label\" ng-bind=\"$group.name\"></div><ul id=\"ui-select-choices-{{ $select.generatedId }}\" ng-class=\"{\'select2-result-sub\': $select.choiceGrouped($group), \'select2-result-single\': !$select.choiceGrouped($group) }\"><li role=\"option\" ng-attr-id=\"ui-select-choices-row-{{ $select.generatedId }}-{{$index}}\" class=\"ui-select-choices-row\" ng-class=\"{\'select2-highlighted\': $select.isActive(this), \'select2-disabled\': $select.isDisabled(this)}\"><div class=\"select2-result-label ui-select-choices-row-inner\"></div></li></ul></li></ul>");
$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 track by $index\" ng-class=\"{\'select2-search-choice-focus\':$selectMultiple.activeMatchIndex === $index, \'select2-locked\':$select.isLocked(this, $index)}\" ui-select-sort=\"$select.selected\"><span uis-transclude-append=\"\"></span> <a href=\"javascript:;\" class=\"ui-select-match-close select2-search-choice-close\" ng-click=\"$selectMultiple.removeChoice($index)\" tabindex=\"-1\"></a></li></span>");
$templateCache.put("select2/match.tpl.html","<a class=\"select2-choice ui-select-match\" ng-class=\"{\'select2-default\': $select.isEmpty()}\" ng-click=\"$select.toggle($event)\" aria-label=\"{{ $select.baseTitle }} select\"><span ng-show=\"$select.isEmpty()\" class=\"select2-chosen\">{{$select.placeholder}}</span> <span ng-hide=\"$select.isEmpty()\" class=\"select2-chosen\" ng-transclude=\"\"></span> <abbr ng-if=\"$select.allowClear && !$select.isEmpty()\" class=\"select2-search-choice-close\" ng-click=\"$select.clear($event)\"></abbr> <span class=\"select2-arrow ui-select-toggle\"><b></b></span></a>");
$templateCache.put("select2/no-choice.tpl.html","<div class=\"ui-select-no-choice dropdown\" ng-show=\"$select.items.length == 0\"><div class=\"dropdown-content\"><div data-selectable=\"\" ng-transclude=\"\"></div></div></div>");
$templateCache.put("select2/select-multiple.tpl.html","<div class=\"ui-select-container ui-select-multiple select2 select2-container select2-container-multi\" ng-class=\"{\'select2-container-active select2-dropdown-open open\': $select.open, \'select2-container-disabled\': $select.disabled}\"><ul class=\"select2-choices\"><span class=\"ui-select-match\"></span><li class=\"select2-search-field\"><input type=\"search\" autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" role=\"combobox\" aria-expanded=\"true\" aria-owns=\"ui-select-choices-{{ $select.generatedId }}\" aria-label=\"{{ $select.baseTitle }}\" aria-activedescendant=\"ui-select-choices-row-{{ $select.generatedId }}-{{ $select.activeIndex }}\" class=\"select2-input ui-select-search\" placeholder=\"{{$selectMultiple.getPlaceholder()}}\" ng-disabled=\"$select.disabled\" ng-hide=\"$select.disabled\" ng-model=\"$select.search\" ng-click=\"$select.activate()\" style=\"width: 34px;\" ondrop=\"return false;\"></li></ul><div class=\"ui-select-dropdown select2-drop select2-with-searchbox select2-drop-active\" ng-class=\"{\'select2-display-none\': !$select.open || $select.items.length === 0}\"><div class=\"ui-select-choices\"></div></div></div>");
$templateCache.put("select2/select.tpl.html","<div class=\"ui-select-container select2 select2-container\" ng-class=\"{\'select2-container-active select2-dropdown-open open\': $select.open, \'select2-container-disabled\': $select.disabled, \'select2-container-active\': $select.focus, \'select2-allowclear\': $select.allowClear && !$select.isEmpty()}\"><div class=\"ui-select-match\"></div><div class=\"ui-select-dropdown select2-drop select2-with-searchbox select2-drop-active\" ng-class=\"{\'select2-display-none\': !$select.open}\"><div class=\"search-container\" ng-class=\"{\'ui-select-search-hidden\':!$select.searchEnabled, \'select2-search\':$select.searchEnabled}\"><input type=\"search\" autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" ng-class=\"{\'select2-active\': $select.refreshing}\" role=\"combobox\" aria-expanded=\"true\" aria-owns=\"ui-select-choices-{{ $select.generatedId }}\" aria-label=\"{{ $select.baseTitle }}\" class=\"ui-select-search select2-input\" ng-model=\"$select.search\"></div><div class=\"ui-select-choices\"></div><div class=\"ui-select-no-choice\"></div></div></div>");
$templateCache.put("selectize/choices.tpl.html","<div ng-show=\"$select.open\" class=\"ui-select-choices ui-select-dropdown selectize-dropdown\" ng-class=\"{\'single\': !$select.multiple, \'multi\': $select.multiple}\"><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=\"$group.name\"></div><div role=\"option\" class=\"ui-select-choices-row\" ng-class=\"{active: $select.isActive(this), disabled: $select.isDisabled(this)}\"><div class=\"option ui-select-choices-row-inner\" data-selectable=\"\"></div></div></div></div></div>");
$templateCache.put("selectize/match-multiple.tpl.html","<div class=\"ui-select-match\" data-value=\"\" ng-repeat=\"$item in $select.selected track by $index\" ng-click=\"$selectMultiple.activeMatchIndex = $index;\" ng-class=\"{\'active\':$selectMultiple.activeMatchIndex === $index}\" ui-select-sort=\"$select.selected\"><span class=\"ui-select-match-item\" ng-class=\"{\'select-locked\':$select.isLocked(this, $index)}\"><span uis-transclude-append=\"\"></span> <span class=\"remove ui-select-match-close\" ng-hide=\"$select.disabled\" ng-click=\"$selectMultiple.removeChoice($index)\">&times;</span></span></div>");
$templateCache.put("selectize/match.tpl.html","<div ng-hide=\"$select.searchEnabled && ($select.open || $select.isEmpty())\" class=\"ui-select-match\"><span ng-show=\"!$select.searchEnabled && ($select.isEmpty() || $select.open)\" class=\"ui-select-placeholder text-muted\">{{$select.placeholder}}</span> <span ng-hide=\"$select.isEmpty() || $select.open\" ng-transclude=\"\"></span></div>");
$templateCache.put("selectize/no-choice.tpl.html","<div class=\"ui-select-no-choice selectize-dropdown\" ng-show=\"$select.items.length == 0\"><div class=\"selectize-dropdown-content\"><div data-selectable=\"\" ng-transclude=\"\"></div></div></div>");
$templateCache.put("selectize/select-multiple.tpl.html","<div class=\"ui-select-container selectize-control multi plugin-remove_button\" ng-class=\"{\'open\': $select.open}\"><div class=\"selectize-input\" ng-class=\"{\'focus\': $select.open, \'disabled\': $select.disabled, \'selectize-focus\' : $select.focus}\" ng-click=\"$select.open && !$select.searchEnabled ? $select.toggle($event) : $select.activate()\"><div class=\"ui-select-match\"></div><input type=\"search\" autocomplete=\"off\" tabindex=\"-1\" class=\"ui-select-search\" ng-class=\"{\'ui-select-search-hidden\':!$select.searchEnabled}\" placeholder=\"{{$selectMultiple.getPlaceholder()}}\" ng-model=\"$select.search\" ng-disabled=\"$select.disabled\" aria-expanded=\"{{$select.open}}\" aria-label=\"{{ $select.baseTitle }}\" ondrop=\"return false;\"></div><div class=\"ui-select-choices\"></div><div class=\"ui-select-no-choice\"></div></div>");
$templateCache.put("selectize/select.tpl.html","<div class=\"ui-select-container selectize-control single\" ng-class=\"{\'open\': $select.open}\"><div class=\"selectize-input\" ng-class=\"{\'focus\': $select.open, \'disabled\': $select.disabled, \'selectize-focus\' : $select.focus}\" ng-click=\"$select.open && !$select.searchEnabled ? $select.toggle($event) : $select.activate()\"><div class=\"ui-select-match\"></div><input type=\"search\" autocomplete=\"off\" tabindex=\"-1\" class=\"ui-select-search ui-select-toggle\" ng-class=\"{\'ui-select-search-hidden\':!$select.searchEnabled}\" ng-click=\"$select.toggle($event)\" placeholder=\"{{$select.placeholder}}\" ng-model=\"$select.search\" ng-hide=\"!$select.isEmpty() && !$select.open\" ng-disabled=\"$select.disabled\" aria-label=\"{{ $select.baseTitle }}\"></div><div class=\"ui-select-choices\"></div><div class=\"ui-select-no-choice\"></div></div>");}]);
\ No newline at end of file
/*!
* ui-select
* http://github.com/angular-ui/ui-select
* Version: 0.19.5 - 2016-10-24T23:13:59.551Z
* License: MIT
*/.ui-select-highlight{font-weight:700}.ui-select-offscreen{clip:rect(0 0 0 0)!important;width:1px!important;height:1px!important;border:0!important;margin:0!important;padding:0!important;overflow:hidden!important;position:absolute!important;outline:0!important;left:0!important;top:0!important}.selectize-control.single>.selectize-input>input,.selectize-control>.selectize-dropdown{width:100%}.ui-select-choices-row:hover{background-color:#f5f5f5}.ng-dirty.ng-invalid>a.select2-choice{border-color:#D44950}.select2-result-single{padding-left:0}.select-locked>.ui-select-match-close,.select2-locked>.select2-search-choice-close{display:none}body>.select2-container.open{z-index:9999}.ui-select-container.select2.direction-up .ui-select-match,.ui-select-container[theme=select2].direction-up .ui-select-match{border-radius:0 0 4px 4px}.ui-select-container.select2.direction-up .ui-select-dropdown,.ui-select-container[theme=select2].direction-up .ui-select-dropdown{border-radius:4px 4px 0 0;border-top-width:1px;border-top-style:solid;box-shadow:0 -4px 8px rgba(0,0,0,.25);margin-top:-4px}.ui-select-container.select2.direction-up .ui-select-dropdown .select2-search,.ui-select-container[theme=select2].direction-up .ui-select-dropdown .select2-search{margin-top:4px}.ui-select-container.select2.direction-up.select2-dropdown-open .ui-select-match,.ui-select-container[theme=select2].direction-up.select2-dropdown-open .ui-select-match{border-bottom-color:#5897fb}.ui-select-container[theme=select2] .ui-select-dropdown .ui-select-search-hidden,.ui-select-container[theme=select2] .ui-select-dropdown .ui-select-search-hidden input{opacity:0;height:0;min-height:0;padding:0;margin:0;border:0}.selectize-input.selectize-focus{border-color:#007FBB!important}.selectize-control.multi>.selectize-input>input{margin:0!important}.ng-dirty.ng-invalid>div.selectize-input{border-color:#D44950}.ui-select-container[theme=selectize].direction-up .ui-select-dropdown{box-shadow:0 -4px 8px rgba(0,0,0,.25);margin-top:-2px}.ui-select-container[theme=selectize] input.ui-select-search-hidden{opacity:0;height:0;min-height:0;padding:0;margin:0;border:0;width:0}.btn-default-focus{color:#333;background-color:#EBEBEB;border-color:#ADADAD;text-decoration:none;outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.ui-select-bootstrap .ui-select-toggle{position:relative}.ui-select-bootstrap .ui-select-toggle>.caret{position:absolute;height:10px;top:50%;right:10px;margin-top:-2px}.input-group>.ui-select-bootstrap.dropdown{position:static}.input-group>.ui-select-bootstrap>input.ui-select-search.form-control{border-radius:4px 0 0 4px}.input-group>.ui-select-bootstrap>input.ui-select-search.form-control.direction-up{border-radius:4px 0 0 4px!important}.ui-select-bootstrap .ui-select-search-hidden{opacity:0;height:0;min-height:0;padding:0;margin:0;border:0}.ui-select-bootstrap>.ui-select-match>.btn{text-align:left!important}.ui-select-bootstrap>.ui-select-match>.caret{position:absolute;top:45%;right:15px}.ui-select-bootstrap>.ui-select-choices,.ui-select-bootstrap>.ui-select-no-choice{width:100%;height:auto;max-height:200px;overflow-x:hidden;margin-top:-1px}body>.ui-select-bootstrap.open{z-index:1000}.ui-select-multiple.ui-select-bootstrap{height:auto;padding:3px 3px 0}.ui-select-multiple.ui-select-bootstrap input.ui-select-search{background-color:transparent!important;border:none;outline:0;height:1.666666em;margin-bottom:3px}.ui-select-multiple.ui-select-bootstrap .ui-select-match .close{font-size:1.6em;line-height:.75}.ui-select-multiple.ui-select-bootstrap .ui-select-match-item{outline:0;margin:0 3px 3px 0}.ui-select-multiple .ui-select-match-item{position:relative}.ui-select-multiple .ui-select-match-item.dropping .ui-select-match-close{pointer-events:none}.ui-select-multiple:hover .ui-select-match-item.dropping-before:before{content:"";position:absolute;top:0;right:100%;height:100%;margin-right:2px;border-left:1px solid #428bca}.ui-select-multiple:hover .ui-select-match-item.dropping-after:after{content:"";position:absolute;top:0;left:100%;height:100%;margin-left:2px;border-right:1px solid #428bca}.ui-select-bootstrap .ui-select-choices-row>span{cursor:pointer;display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.ui-select-bootstrap .ui-select-choices-row>span:focus,.ui-select-bootstrap .ui-select-choices-row>span:hover{text-decoration:none;color:#262626;background-color:#f5f5f5}.ui-select-bootstrap .ui-select-choices-row.active>span{color:#fff;text-decoration:none;outline:0;background-color:#428bca}.ui-select-bootstrap .ui-select-choices-row.active.disabled>span,.ui-select-bootstrap .ui-select-choices-row.disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.ui-select-match.ng-hide-add,.ui-select-search.ng-hide-add{display:none!important}.ui-select-bootstrap.ng-dirty.ng-invalid>button.btn.ui-select-match{border-color:#D44950}.ui-select-container[theme=bootstrap].direction-up .ui-select-dropdown{box-shadow:0 -4px 8px rgba(0,0,0,.25)}.ui-select-bootstrap .ui-select-match-text{width:100%;padding-right:1em}.ui-select-bootstrap .ui-select-match-text span{display:inline-block;width:100%;overflow:hidden}.ui-select-bootstrap .ui-select-toggle>a.btn{position:absolute;height:10px;right:10px;margin-top:-2px}.ui-select-refreshing{position:absolute;right:0;padding:8px 27px;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased}@-webkit-keyframes ui-select-spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes ui-select-spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.ui-select-spin{-webkit-animation:ui-select-spin 2s infinite linear;animation:ui-select-spin 2s infinite linear}.ui-select-refreshing.ng-animate{-webkit-animation:none 0s}
/*# sourceMappingURL=select.min.css.map */
{"version":3,"sources":["common.css"],"names":[],"mappings":";;;;;AACA,qBACA,YAAA,IAGA,qBACA,KAAA,wBACA,MAAA,cACA,OAAA,cACA,OAAA,YACA,OAAA,YACA,QAAA,YACA,SAAA,iBACA,SAAA,mBACA,QAAA,YACA,KAAA,YACA,IAAA,YA8EA,iDAUA,uCACA,MAAA,KArFA,6BACA,iBAAA,QAMA,sCACA,aAAA,QAGA,uBACA,aAAA,EAOA,sCAJA,6CACA,QAAA,KAOA,6BACA,QAAA,KAKA,2DADA,kEAEA,cACA,EACA,EAFA,IAAA,IAKA,8DADA,qEAEA,cAAA,IAAA,IAEA,EADA,EAGA,iBAAA,IACA,iBAAA,MAEA,WAAA,EAAA,KAAA,IAAA,gBAEA,WAAA,KAGA,8EADA,qFAEA,WAAA,IAGA,iFADA,wFAEA,oBAAA,QAGA,iFACA,uFACA,QAAA,EACA,OAAA,EACA,WAAA,EACA,QAAA,EACA,OAAA,EACA,OAAA,EAMA,iCACA,aAAA,kBASA,gDACA,OAAA,YASA,yCACA,aAAA,QAIA,uEACA,WAAA,EAAA,KAAA,IAAA,gBACA,WAAA,KAGA,oEACA,QAAA,EACA,OAAA,EACA,WAAA,EACA,QAAA,EACA,OAAA,EACA,OAAA,EACA,MAAA,EAMA,mBACA,MAAA,KACA,iBAAA,QACA,aAAA,QACA,gBAAA,KACA,QAAA,yBAAA,KAAA,IACA,eAAA,KACA,WAAA,MAAA,EAAA,IAAA,IAAA,iBAAA,EAAA,EAAA,IAAA,qBAGA,uCACA,SAAA,SAGA,8CACA,SAAA,SACA,OAAA,KACA,IAAA,IACA,MAAA,KACA,WAAA,KAIA,2CAEA,SAAA,OAGA,sEACA,cAAA,IACA,EACA,EAFA,IAIA,mFACA,cAAA,IACA,EACA,EAFA,cAKA,8CACA,QAAA,EACA,OAAA,EACA,WAAA,EACA,QAAA,EACA,OAAA,EACA,OAAA,EAGA,2CAEA,WAAA,eAGA,6CACA,SAAA,SACA,IAAA,IACA,MAAA,KAIA,wCAAA,0CACA,MAAA,KACA,OAAA,KACA,WAAA,MACA,WAAA,OACA,WAAA,KAGA,+BACA,QAAA,KAGA,wCACA,OAAA,KACA,QAAA,IAAA,IAAA,EAGA,+DACA,iBAAA,sBACA,YACA,QAAA,EACA,OAAA,WACA,cAAA,IAGA,gEACA,UAAA,MACA,YAAA,IAGA,8DACA,QAAA,EACA,OAAA,EAAA,IAAA,IAAA,EAGA,0CACA,SAAA,SAGA,0EACA,eAAA,KAGA,uEACA,QAAA,GACA,SAAA,SACA,IAAA,EACA,MAAA,KACA,OAAA,KACA,aAAA,IACA,YAAA,IAAA,MAAA,QAGA,qEACA,QAAA,GACA,SAAA,SACA,IAAA,EACA,KAAA,KACA,OAAA,KACA,YAAA,IACA,aAAA,IAAA,MAAA,QAGA,iDACA,OAAA,QACA,QAAA,MACA,QAAA,IAAA,KACA,MAAA,KACA,YAAA,IACA,YAAA,WACA,MAAA,KACA,YAAA,OAGA,uDAAA,uDACA,gBAAA,KACA,MAAA,QACA,iBAAA,QAGA,wDACA,MAAA,KACA,gBAAA,KACA,QAAA,EACA,iBAAA,QAIA,iEADA,0DAEA,MAAA,KACA,OAAA,YACA,iBAAA,KAIA,6BACA,8BACA,QAAA,eAIA,oEACA,aAAA,QAIA,uEACA,WAAA,EAAA,KAAA,IAAA,gBAGA,2CACA,MAAA,KACA,cAAA,IAEA,gDACA,QAAA,aACA,MAAA,KACA,SAAA,OAEA,6CACA,SAAA,SACA,OAAA,KACA,MAAA,KACA,WAAA,KAIA,sBACA,SAAA,SACA,MAAA,EACA,QAAA,IAAA,KACA,IAAA,IACA,QAAA,aACA,YAAA,uBACA,WAAA,OACA,YAAA,IACA,YAAA,EACA,uBAAA,YAGA,kCACA,GACA,kBAAA,UACA,UAAA,UAEA,KACA,kBAAA,eACA,UAAA,gBAGA,0BACA,GACA,kBAAA,UACA,UAAA,UAEA,KACA,kBAAA,eACA,UAAA,gBAIA,gBACA,kBAAA,eAAA,GAAA,SAAA,OACA,UAAA,eAAA,GAAA,SAAA,OAGA,iCACA,kBAAA,KAAA","file":"select.min.css","sourcesContent":["/* Style when highlighting a search. */\n.ui-select-highlight {\n font-weight: bold;\n}\n\n.ui-select-offscreen {\n clip: rect(0 0 0 0) !important;\n width: 1px !important;\n height: 1px !important;\n border: 0 !important;\n margin: 0 !important;\n padding: 0 !important;\n overflow: hidden !important;\n position: absolute !important;\n outline: 0 !important;\n left: 0px !important;\n top: 0px !important;\n}\n\n\n.ui-select-choices-row:hover {\n background-color: #f5f5f5;\n}\n\n/* Select2 theme */\n\n/* Mark invalid Select2 */\n.ng-dirty.ng-invalid > a.select2-choice {\n border-color: #D44950;\n}\n\n.select2-result-single {\n padding-left: 0;\n}\n\n.select2-locked > .select2-search-choice-close{\n display:none;\n}\n\n.select-locked > .ui-select-match-close{\n display:none;\n}\n\nbody > .select2-container.open {\n z-index: 9999; /* The z-index Select2 applies to the select2-drop */\n}\n\n/* Handle up direction Select2 */\n.ui-select-container[theme=\"select2\"].direction-up .ui-select-match,\n.ui-select-container.select2.direction-up .ui-select-match {\n border-radius: 4px; /* FIXME hardcoded value :-/ */\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n.ui-select-container[theme=\"select2\"].direction-up .ui-select-dropdown,\n.ui-select-container.select2.direction-up .ui-select-dropdown {\n border-radius: 4px; /* FIXME hardcoded value :-/ */\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n\n border-top-width: 1px; /* FIXME hardcoded value :-/ */\n border-top-style: solid;\n\n box-shadow: 0 -4px 8px rgba(0, 0, 0, 0.25);\n\n margin-top: -4px; /* FIXME hardcoded value :-/ */\n}\n.ui-select-container[theme=\"select2\"].direction-up .ui-select-dropdown .select2-search,\n.ui-select-container.select2.direction-up .ui-select-dropdown .select2-search {\n margin-top: 4px; /* FIXME hardcoded value :-/ */\n}\n.ui-select-container[theme=\"select2\"].direction-up.select2-dropdown-open .ui-select-match,\n.ui-select-container.select2.direction-up.select2-dropdown-open .ui-select-match {\n border-bottom-color: #5897fb;\n}\n\n.ui-select-container[theme=\"select2\"] .ui-select-dropdown .ui-select-search-hidden,\n.ui-select-container[theme=\"select2\"] .ui-select-dropdown .ui-select-search-hidden input{\n opacity: 0;\n height: 0;\n min-height: 0;\n padding: 0;\n margin: 0;\n border:0;\n}\n\n/* Selectize theme */\n\n/* Helper class to show styles when focus */\n.selectize-input.selectize-focus{\n border-color: #007FBB !important;\n}\n\n/* Fix input width for Selectize theme */\n.selectize-control.single > .selectize-input > input {\n width: 100%;\n}\n\n/* Fix line break when there's at least one item selected with the Selectize theme */\n.selectize-control.multi > .selectize-input > input {\n margin: 0 !important;\n}\n\n/* Fix dropdown width for Selectize theme */\n.selectize-control > .selectize-dropdown {\n width: 100%;\n}\n\n/* Mark invalid Selectize */\n.ng-dirty.ng-invalid > div.selectize-input {\n border-color: #D44950;\n}\n\n/* Handle up direction Selectize */\n.ui-select-container[theme=\"selectize\"].direction-up .ui-select-dropdown {\n box-shadow: 0 -4px 8px rgba(0, 0, 0, 0.25);\n margin-top: -2px; /* FIXME hardcoded value :-/ */\n}\n\n.ui-select-container[theme=\"selectize\"] input.ui-select-search-hidden{\n opacity: 0;\n height: 0;\n min-height: 0;\n padding: 0;\n margin: 0;\n border:0;\n width: 0;\n}\n\n/* Bootstrap theme */\n\n/* Helper class to show styles when focus */\n.btn-default-focus {\n color: #333;\n background-color: #EBEBEB;\n border-color: #ADADAD;\n text-decoration: none;\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6);\n}\n\n.ui-select-bootstrap .ui-select-toggle {\n position: relative;\n}\n\n.ui-select-bootstrap .ui-select-toggle > .caret {\n position: absolute;\n height: 10px;\n top: 50%;\n right: 10px;\n margin-top: -2px;\n}\n\n/* Fix Bootstrap dropdown position when inside a input-group */\n.input-group > .ui-select-bootstrap.dropdown {\n /* Instead of relative */\n position: static;\n}\n\n.input-group > .ui-select-bootstrap > input.ui-select-search.form-control {\n border-radius: 4px; /* FIXME hardcoded value :-/ */\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n.input-group > .ui-select-bootstrap > input.ui-select-search.form-control.direction-up {\n border-radius: 4px !important; /* FIXME hardcoded value :-/ */\n border-top-right-radius: 0 !important;\n border-bottom-right-radius: 0 !important;\n}\n\n.ui-select-bootstrap .ui-select-search-hidden{\n opacity: 0;\n height: 0;\n min-height: 0;\n padding: 0;\n margin: 0;\n border:0;\n}\n\n.ui-select-bootstrap > .ui-select-match > .btn{\n /* Instead of center because of .btn */\n text-align: left !important;\n}\n\n.ui-select-bootstrap > .ui-select-match > .caret {\n position: absolute;\n top: 45%;\n right: 15px;\n}\n\n/* See Scrollable Menu with Bootstrap 3 http://stackoverflow.com/questions/19227496 */\n.ui-select-bootstrap > .ui-select-choices ,.ui-select-bootstrap > .ui-select-no-choice {\n width: 100%;\n height: auto;\n max-height: 200px;\n overflow-x: hidden;\n margin-top: -1px;\n}\n\nbody > .ui-select-bootstrap.open {\n z-index: 1000; /* Standard Bootstrap dropdown z-index */\n}\n\n.ui-select-multiple.ui-select-bootstrap {\n height: auto;\n padding: 3px 3px 0 3px;\n}\n\n.ui-select-multiple.ui-select-bootstrap input.ui-select-search {\n background-color: transparent !important; /* To prevent double background when disabled */\n border: none;\n outline: none;\n height: 1.666666em;\n margin-bottom: 3px;\n}\n\n.ui-select-multiple.ui-select-bootstrap .ui-select-match .close {\n font-size: 1.6em;\n line-height: 0.75;\n}\n\n.ui-select-multiple.ui-select-bootstrap .ui-select-match-item {\n outline: 0;\n margin: 0 3px 3px 0;\n}\n\n.ui-select-multiple .ui-select-match-item {\n position: relative;\n}\n\n.ui-select-multiple .ui-select-match-item.dropping .ui-select-match-close {\n pointer-events: none;\n}\n\n.ui-select-multiple:hover .ui-select-match-item.dropping-before:before {\n content: \"\";\n position: absolute;\n top: 0;\n right: 100%;\n height: 100%;\n margin-right: 2px;\n border-left: 1px solid #428bca;\n}\n\n.ui-select-multiple:hover .ui-select-match-item.dropping-after:after {\n content: \"\";\n position: absolute;\n top: 0;\n left: 100%;\n height: 100%;\n margin-left: 2px;\n border-right: 1px solid #428bca;\n}\n\n.ui-select-bootstrap .ui-select-choices-row>span {\n cursor: pointer;\n display: block;\n padding: 3px 20px;\n clear: both;\n font-weight: 400;\n line-height: 1.42857143;\n color: #333;\n white-space: nowrap;\n}\n\n.ui-select-bootstrap .ui-select-choices-row>span:hover, .ui-select-bootstrap .ui-select-choices-row>span:focus {\n text-decoration: none;\n color: #262626;\n background-color: #f5f5f5;\n}\n\n.ui-select-bootstrap .ui-select-choices-row.active>span {\n color: #fff;\n text-decoration: none;\n outline: 0;\n background-color: #428bca;\n}\n\n.ui-select-bootstrap .ui-select-choices-row.disabled>span,\n.ui-select-bootstrap .ui-select-choices-row.active.disabled>span {\n color: #777;\n cursor: not-allowed;\n background-color: #fff;\n}\n\n/* fix hide/show angular animation */\n.ui-select-match.ng-hide-add,\n.ui-select-search.ng-hide-add {\n display: none !important;\n}\n\n/* Mark invalid Bootstrap */\n.ui-select-bootstrap.ng-dirty.ng-invalid > button.btn.ui-select-match {\n border-color: #D44950;\n}\n\n/* Handle up direction Bootstrap */\n.ui-select-container[theme=\"bootstrap\"].direction-up .ui-select-dropdown {\n box-shadow: 0 -4px 8px rgba(0, 0, 0, 0.25);\n}\n\n.ui-select-bootstrap .ui-select-match-text {\n width: 100%;\n padding-right: 1em;\n}\n.ui-select-bootstrap .ui-select-match-text span {\n display: inline-block;\n width: 100%;\n overflow: hidden;\n}\n.ui-select-bootstrap .ui-select-toggle > a.btn {\n position: absolute;\n height: 10px;\n right: 10px;\n margin-top: -2px;\n}\n\n/* Spinner */\n.ui-select-refreshing {\n position: absolute;\n right: 0;\n padding: 8px 27px;\n top: 1px;\n display: inline-block;\n font-family: 'Glyphicons Halflings';\n font-style: normal;\n font-weight: normal;\n line-height: 1;\n -webkit-font-smoothing:antialiased;\n }\n \n@-webkit-keyframes ui-select-spin {\n 0% {\n -webkit-transform: rotate(0deg);\n transform: rotate(0deg);\n }\n 100% {\n -webkit-transform: rotate(359deg);\n transform: rotate(359deg);\n }\n}\n@keyframes ui-select-spin {\n 0% {\n -webkit-transform: rotate(0deg);\n transform: rotate(0deg);\n }\n 100% {\n -webkit-transform: rotate(359deg);\n transform: rotate(359deg);\n }\n}\n\n.ui-select-spin {\n -webkit-animation: ui-select-spin 2s infinite linear;\n animation: ui-select-spin 2s infinite linear;\n}\n\n.ui-select-refreshing.ng-animate {\n -webkit-animation: none 0s;\n} "],"sourceRoot":"/source/"}
\ No newline at end of file
/*!
* ui-select
* http://github.com/angular-ui/ui-select
* Version: 0.19.5 - 2016-10-24T23:13:59.434Z
* License: MIT
*/
!function(){"use strict";var e={TAB:9,ENTER:13,ESC:27,SPACE:32,LEFT:37,UP:38,RIGHT:39,DOWN:40,SHIFT:16,CTRL:17,ALT:18,PAGE_UP:33,PAGE_DOWN:34,HOME:36,END:35,BACKSPACE:8,DELETE:46,COMMAND:91,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:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'"},isControl:function(t){var s=t.which;switch(s){case e.COMMAND:case e.SHIFT:case e.CTRL:case e.ALT:return!0}return!!(t.metaKey||t.ctrlKey||t.altKey)},isFunctionKey:function(e){return e=e.which?e.which:e,e>=112&&123>=e},isVerticalMovement:function(t){return~[e.UP,e.DOWN].indexOf(t)},isHorizontalMovement:function(t){return~[e.LEFT,e.RIGHT,e.BACKSPACE,e.DELETE].indexOf(t)},toSeparator:function(t){var s={ENTER:"\n",TAB:" ",SPACE:" "}[t];return s?s:e[t]?void 0:t}};void 0===angular.element.prototype.querySelectorAll&&(angular.element.prototype.querySelectorAll=function(e){return angular.element(this[0].querySelectorAll(e))}),void 0===angular.element.prototype.closest&&(angular.element.prototype.closest=function(e){for(var t=this[0],s=t.matches||t.webkitMatchesSelector||t.mozMatchesSelector||t.msMatchesSelector;t;){if(s.bind(t)(e))return t;t=t.parentElement}return!1});var t=0,s=angular.module("ui.select",[]).constant("uiSelectConfig",{theme:"bootstrap",searchEnabled:!0,sortable:!1,placeholder:"",refreshDelay:1e3,closeOnSelect:!0,skipFocusser:!1,dropdownPosition:"auto",removeSelected:!0,resetSearchInput:!0,generateId:function(){return t++},appendToBody:!1,spinnerEnabled:!1,spinnerClass:"glyphicon-refresh ui-select-spin"}).service("uiSelectMinErr",function(){var e=angular.$$minErr("ui.select");return function(){var t=e.apply(this,arguments),s=t.message.replace(new RegExp("\nhttp://errors.angularjs.org/.*"),"");return new Error(s)}}).directive("uisTranscludeAppend",function(){return{link:function(e,t,s,i,c){c(e,function(e){t.append(e)})}}}).filter("highlight",function(){function e(e){return(""+e).replace(/([.?*+^$[\]\\(){}|-])/g,"\\$1")}return function(t,s){return s&&t?(""+t).replace(new RegExp(e(s),"gi"),'<span class="ui-select-highlight">$&</span>'):t}}).factory("uisOffset",["$document","$window",function(e,t){return function(s){var i=s[0].getBoundingClientRect();return{width:i.width||s.prop("offsetWidth"),height:i.height||s.prop("offsetHeight"),top:i.top+(t.pageYOffset||e[0].documentElement.scrollTop),left:i.left+(t.pageXOffset||e[0].documentElement.scrollLeft)}}}]);s.directive("uiSelectChoices",["uiSelectConfig","uisRepeatParser","uiSelectMinErr","$compile","$window",function(e,t,s,i,c){return{restrict:"EA",require:"^uiSelect",replace:!0,transclude:!0,templateUrl:function(t){t.addClass("ui-select-choices");var s=t.parent().attr("theme")||e.theme;return s+"/choices.tpl.html"},compile:function(i,n){if(!n.repeat)throw s("repeat","Expected 'repeat' expression.");var l=n.groupBy,a=n.groupFilter;if(l){var r=i.querySelectorAll(".ui-select-choices-group");if(1!==r.length)throw s("rows","Expected 1 .ui-select-choices-group but got '{0}'.",r.length);r.attr("ng-repeat",t.getGroupNgRepeatExpression())}var o=t.parse(n.repeat),u=i.querySelectorAll(".ui-select-choices-row");if(1!==u.length)throw s("rows","Expected 1 .ui-select-choices-row but got '{0}'.",u.length);u.attr("ng-repeat",o.repeatExpression(l)).attr("ng-if","$select.open");var d=i.querySelectorAll(".ui-select-choices-row-inner");if(1!==d.length)throw s("rows","Expected 1 .ui-select-choices-row-inner but got '{0}'.",d.length);d.attr("uis-transclude-append","");var p=c.document.addEventListener?u:d;return p.attr("ng-click","$select.select("+o.itemName+",$select.skipFocusser,$event)"),function(t,s,c,n){n.parseRepeatAttr(c.repeat,l,a),n.disableChoiceExpression=c.uiDisableChoice,n.onHighlightCallback=c.onHighlight,n.dropdownPosition=c.position?c.position.toLowerCase():e.dropdownPosition,t.$on("$destroy",function(){u.remove()}),t.$watch("$select.search",function(e){e&&!n.open&&n.multiple&&n.activate(!1,!0),n.activeIndex=n.tagging.isActivated?-1:0,!c.minimumInputLength||n.search.length>=c.minimumInputLength?n.refresh(c.refresh):n.items=[]}),c.$observe("refreshDelay",function(){var s=t.$eval(c.refreshDelay);n.refreshDelay=void 0!==s?s:e.refreshDelay}),t.$watch("$select.open",function(e){e?i.attr("role","listbox"):i.removeAttr("role")})}}}}]),s.controller("uiSelectCtrl",["$scope","$element","$timeout","$filter","$$uisDebounce","uisRepeatParser","uiSelectMinErr","uiSelectConfig","$parse","$injector","$window",function(t,s,i,c,n,l,a,r,o,u,d){function p(e,t,s){if(e.findIndex)return e.findIndex(t,s);for(var i,c=Object(e),n=c.length>>>0,l=0;n>l;l++)if(i=c[l],t.call(s,i,l,c))return l;return-1}function h(){w.resetSearchInput&&(w.search=y,w.selected&&w.items.length&&!w.multiple&&(w.activeIndex=p(w.items,function(e){return angular.equals(this,e)},w.selected)))}function g(e,t){var s,i,c=[];for(s=0;s<t.length;s++)for(i=0;i<e.length;i++)e[i].name==[t[s]]&&c.push(e[i]);return c}function f(e,t){var s=S.indexOf(e);t&&-1===s&&S.push(e),!t&&s>-1&&S.splice(s,1)}function v(e){return S.indexOf(e)>-1}function $(e){function t(e,t){var s=i.indexOf(e);t&&-1===s&&i.push(e),!t&&s>-1&&i.splice(s,0)}function s(e){return i.indexOf(e)>-1}if(e){var i=[];w.isLocked=function(e,i){var c=!1,n=w.selected[i];return n&&(e?(c=!!e.$eval(w.lockChoiceExpression),t(n,c)):c=s(n)),c}}}function m(t){var s=!0;switch(t){case e.DOWN:!w.open&&w.multiple?w.activate(!1,!0):w.activeIndex<w.items.length-1&&w.activeIndex++;break;case e.UP:!w.open&&w.multiple?w.activate(!1,!0):(w.activeIndex>0||0===w.search.length&&w.tagging.isActivated&&w.activeIndex>-1)&&w.activeIndex--;break;case e.TAB:w.multiple&&!w.open||w.select(w.items[w.activeIndex],!0);break;case e.ENTER:w.open&&(w.tagging.isActivated||w.activeIndex>=0)?w.select(w.items[w.activeIndex],w.skipFocusser):w.activate(!1,!0);break;case e.ESC:w.close();break;default:s=!1}return s}function b(){var e=s.querySelectorAll(".ui-select-choices-content"),t=e.querySelectorAll(".ui-select-choices-row");if(t.length<1)throw a("choices","Expected multiple .ui-select-choices-row but got '{0}'.",t.length);if(!(w.activeIndex<0)){var i=t[w.activeIndex],c=i.offsetTop+i.clientHeight-e[0].scrollTop,n=e[0].offsetHeight;c>n?e[0].scrollTop+=c-n:c<i.clientHeight&&(w.isGrouped&&0===w.activeIndex?e[0].scrollTop=0:e[0].scrollTop-=i.clientHeight-c)}}var w=this,y="";if(w.placeholder=r.placeholder,w.searchEnabled=r.searchEnabled,w.sortable=r.sortable,w.refreshDelay=r.refreshDelay,w.paste=r.paste,w.resetSearchInput=r.resetSearchInput,w.refreshing=!1,w.spinnerEnabled=r.spinnerEnabled,w.spinnerClass=r.spinnerClass,w.removeSelected=r.removeSelected,w.closeOnSelect=!0,w.skipFocusser=!1,w.search=y,w.activeIndex=0,w.items=[],w.open=!1,w.focus=!1,w.disabled=!1,w.selected=void 0,w.dropdownPosition="auto",w.focusser=void 0,w.multiple=void 0,w.disableChoiceExpression=void 0,w.tagging={isActivated:!1,fct:void 0},w.taggingTokens={isActivated:!1,tokens:void 0},w.lockChoiceExpression=void 0,w.clickTriggeredSelect=!1,w.$filter=c,w.$element=s,w.$animate=function(){try{return u.get("$animate")}catch(e){return null}}(),w.searchInput=s.querySelectorAll("input.ui-select-search"),1!==w.searchInput.length)throw a("searchInput","Expected 1 input.ui-select-search but got '{0}'.",w.searchInput.length);w.isEmpty=function(){return angular.isUndefined(w.selected)||null===w.selected||""===w.selected||w.multiple&&0===w.selected.length},w.activate=function(e,c){if(w.disabled||w.open)w.open&&!w.searchEnabled&&w.close();else{c||h(),t.$broadcast("uis:activate"),w.open=!0,w.activeIndex=w.activeIndex>=w.items.length?0:w.activeIndex,-1===w.activeIndex&&w.taggingLabel!==!1&&(w.activeIndex=0);var n=s.querySelectorAll(".ui-select-choices-content"),l=s.querySelectorAll(".ui-select-search");if(w.$animate&&w.$animate.on&&w.$animate.enabled(n[0])){var a=function(t,s){"start"===s&&0===w.items.length?(w.$animate.off("removeClass",l[0],a),i(function(){w.focusSearchInput(e)})):"close"===s&&(w.$animate.off("enter",n[0],a),i(function(){w.focusSearchInput(e)}))};w.items.length>0?w.$animate.on("enter",n[0],a):w.$animate.on("removeClass",l[0],a)}else i(function(){w.focusSearchInput(e),!w.tagging.isActivated&&w.items.length>1&&b()})}},w.focusSearchInput=function(e){w.search=e||w.search,w.searchInput[0].focus()},w.findGroupByName=function(e){return w.groups&&w.groups.filter(function(t){return t.name===e})[0]},w.parseRepeatAttr=function(e,s,i){function c(e){var c=t.$eval(s);if(w.groups=[],angular.forEach(e,function(e){var t=angular.isFunction(c)?c(e):e[c],s=w.findGroupByName(t);s?s.items.push(e):w.groups.push({name:t,items:[e]})}),i){var n=t.$eval(i);angular.isFunction(n)?w.groups=n(w.groups):angular.isArray(n)&&(w.groups=g(w.groups,n))}w.items=[],w.groups.forEach(function(e){w.items=w.items.concat(e.items)})}function n(e){w.items=e}w.setItemsFn=s?c:n,w.parserResult=l.parse(e),w.isGrouped=!!s,w.itemProperty=w.parserResult.itemName;var r=w.parserResult.source,u=function(){var e=r(t);t.$uisSource=Object.keys(e).map(function(t){var s={};return s[w.parserResult.keyName]=t,s.value=e[t],s})};w.parserResult.keyName&&(u(),w.parserResult.source=o("$uisSource"+w.parserResult.filters),t.$watch(r,function(e,t){e!==t&&u()},!0)),w.refreshItems=function(e){e=e||w.parserResult.source(t);var s=w.selected;if(w.isEmpty()||angular.isArray(s)&&!s.length||!w.multiple||!w.removeSelected)w.setItemsFn(e);else if(void 0!==e&&null!==e){var i=e.filter(function(e){return angular.isArray(s)?s.every(function(t){return!angular.equals(e,t)}):!angular.equals(e,s)});w.setItemsFn(i)}"auto"!==w.dropdownPosition&&"up"!==w.dropdownPosition||t.calculateDropdownPos(),t.$broadcast("uis:refresh")},t.$watchCollection(w.parserResult.source,function(e){if(void 0===e||null===e)w.items=[];else{if(!angular.isArray(e))throw a("items","Expected an array but got '{0}'.",e);w.refreshItems(e),angular.isDefined(w.ngModel.$modelValue)&&(w.ngModel.$modelValue=null)}})};var x;w.refresh=function(e){void 0!==e&&(x&&i.cancel(x),x=i(function(){var s=t.$eval(e);s&&angular.isFunction(s.then)&&!w.refreshing&&(w.refreshing=!0,s.then(function(){w.refreshing=!1}))},w.refreshDelay))},w.isActive=function(e){if(!w.open)return!1;var t=w.items.indexOf(e[w.itemProperty]),s=t==w.activeIndex;return!s||0>t?!1:(s&&!angular.isUndefined(w.onHighlightCallback)&&e.$eval(w.onHighlightCallback),s)};var E=function(e){return w.selected&&angular.isArray(w.selected)&&w.selected.filter(function(t){return angular.equals(t,e)}).length>0},S=[];w.isDisabled=function(e){if(w.open){var t=e[w.itemProperty],s=w.items.indexOf(t),i=!1;if(s>=0&&(angular.isDefined(w.disableChoiceExpression)||w.multiple)){if(t.isTag)return!1;w.multiple&&(i=E(t)),!i&&angular.isDefined(w.disableChoiceExpression)&&(i=!!e.$eval(w.disableChoiceExpression)),f(t,i)}return i}},w.select=function(e,s,c){if(void 0===e||!v(e)){if(!w.items&&!w.search&&!w.tagging.isActivated)return;if(!e||!v(e)){if(w.clickTriggeredSelect=!1,c&&("click"===c.type||"touchend"===c.type)&&e&&(w.clickTriggeredSelect=!0),w.tagging.isActivated&&w.clickTriggeredSelect===!1){if(w.taggingLabel===!1)if(w.activeIndex<0){if(void 0===e&&(e=void 0!==w.tagging.fct?w.tagging.fct(w.search):w.search),!e||angular.equals(w.items[0],e))return}else e=w.items[w.activeIndex];else if(0===w.activeIndex){if(void 0===e)return;if(void 0!==w.tagging.fct&&"string"==typeof e){if(e=w.tagging.fct(e),!e)return}else"string"==typeof e&&(e=e.replace(w.taggingLabel,"").trim())}if(E(e))return void w.close(s)}h(),t.$broadcast("uis:select",e);var n={};n[w.parserResult.itemName]=e,i(function(){w.onSelectCallback(t,{$item:e,$model:w.parserResult.modelMapper(t,n)})}),w.closeOnSelect&&w.close(s)}}},w.close=function(e){w.open&&(w.ngModel&&w.ngModel.$setTouched&&w.ngModel.$setTouched(),w.open=!1,h(),t.$broadcast("uis:close",e))},w.setFocus=function(){w.focus||w.focusInput[0].focus()},w.clear=function(e){w.select(void 0),e.stopPropagation(),i(function(){w.focusser[0].focus()},0,!1)},w.toggle=function(e){w.open?(w.close(),e.preventDefault(),e.stopPropagation()):w.activate()},w.isLocked=function(){return!1},t.$watch(function(){return angular.isDefined(w.lockChoiceExpression)&&""!==w.lockChoiceExpression},$);var C=null,I=!1;w.sizeSearchInput=function(){var e=w.searchInput[0],s=w.searchInput.parent().parent()[0],c=function(){return s.clientWidth*!!e.offsetParent},n=function(t){if(0===t)return!1;var s=t-e.offsetLeft-10;return 50>s&&(s=t),w.searchInput.css("width",s+"px"),!0};w.searchInput.css("width","10px"),i(function(){null!==C||n(c())||(C=t.$watch(function(){I||(I=!0,t.$$postDigest(function(){I=!1,n(c())&&(C(),C=null)}))},angular.noop))})},w.searchInput.on("keydown",function(s){var c=s.which;~[e.ENTER,e.ESC].indexOf(c)&&(s.preventDefault(),s.stopPropagation()),t.$apply(function(){var t=!1;if((w.items.length>0||w.tagging.isActivated)&&(m(c)||w.searchEnabled||(s.preventDefault(),s.stopPropagation()),w.taggingTokens.isActivated)){for(var n=0;n<w.taggingTokens.tokens.length;n++)w.taggingTokens.tokens[n]===e.MAP[s.keyCode]&&w.search.length>0&&(t=!0);t&&i(function(){w.searchInput.triggerHandler("tagged");var t=w.search.replace(e.MAP[s.keyCode],"").trim();w.tagging.fct&&(t=w.tagging.fct(t)),t&&w.select(t,!0)})}}),e.isVerticalMovement(c)&&w.items.length>0&&b(),c!==e.ENTER&&c!==e.ESC||(s.preventDefault(),s.stopPropagation())}),w.searchInput.on("paste",function(t){var s;if(s=window.clipboardData&&window.clipboardData.getData?window.clipboardData.getData("Text"):(t.originalEvent||t).clipboardData.getData("text/plain"),s=w.search+s,s&&s.length>0)if(w.taggingTokens.isActivated){for(var i=[],c=0;c<w.taggingTokens.tokens.length;c++){var n=e.toSeparator(w.taggingTokens.tokens[c])||w.taggingTokens.tokens[c];if(s.indexOf(n)>-1){i=s.split(n);break}}0===i.length&&(i=[s]);var l=w.search;angular.forEach(i,function(e){var t=w.tagging.fct?w.tagging.fct(e):e;t&&w.select(t,!0)}),w.search=l||y,t.preventDefault(),t.stopPropagation()}else w.paste&&(w.paste(s),w.search=y,t.preventDefault(),t.stopPropagation())}),w.searchInput.on("tagged",function(){i(function(){h()})});var A=n(function(){w.sizeSearchInput()},50);angular.element(d).bind("resize",A),t.$on("$destroy",function(){w.searchInput.off("keyup keydown tagged blur paste"),angular.element(d).off("resize",A)}),t.$watch("$select.activeIndex",function(e){e&&s.find("input").attr("aria-activedescendant","ui-select-choices-row-"+w.generatedId+"-"+e)}),t.$watch("$select.open",function(e){e||s.find("input").removeAttr("aria-activedescendant")})}]),s.directive("uiSelect",["$document","uiSelectConfig","uiSelectMinErr","uisOffset","$compile","$parse","$timeout",function(e,t,s,i,c,n,l){return{restrict:"EA",templateUrl:function(e,s){var i=s.theme||t.theme;return i+(angular.isDefined(s.multiple)?"/select-multiple.tpl.html":"/select.tpl.html")},replace:!0,transclude:!0,require:["uiSelect","^ngModel"],scope:!0,controller:"uiSelectCtrl",controllerAs:"$select",compile:function(c,a){var r=/{(.*)}\s*{(.*)}/.exec(a.ngClass);if(r){var o="{"+r[1]+", "+r[2]+"}";a.ngClass=o,c.attr("ng-class",o)}return angular.isDefined(a.multiple)?c.append("<ui-select-multiple/>").removeAttr("multiple"):c.append("<ui-select-single/>"),a.inputId&&(c.querySelectorAll("input.ui-select-search")[0].id=a.inputId),function(c,a,r,o,u){function d(e){if(g.open){var t=!1;if(t=window.jQuery?window.jQuery.contains(a[0],e.target):a[0].contains(e.target),!t&&!g.clickTriggeredSelect){var s;if(g.skipFocusser)s=!0;else{var i=["input","button","textarea","select"],n=angular.element(e.target).controller("uiSelect");s=n&&n!==g,s||(s=~i.indexOf(e.target.tagName.toLowerCase()))}g.close(s),c.$digest()}g.clickTriggeredSelect=!1}}function p(){var t=i(a);$=angular.element('<div class="ui-select-placeholder"></div>'),$[0].style.width=t.width+"px",$[0].style.height=t.height+"px",a.after($),m=a[0].style.width,e.find("body").append(a),a[0].style.position="absolute",a[0].style.left=t.left+"px",a[0].style.top=t.top+"px",a[0].style.width=t.width+"px"}function h(){null!==$&&($.replaceWith(a),$=null,a[0].style.position="",a[0].style.left="",a[0].style.top="",a[0].style.width=m,g.setFocus())}var g=o[0],f=o[1];g.generatedId=t.generateId(),g.baseTitle=r.title||"Select box",g.focusserTitle=g.baseTitle+" focus",g.focusserId="focusser-"+g.generatedId,g.closeOnSelect=function(){return angular.isDefined(r.closeOnSelect)?n(r.closeOnSelect)():t.closeOnSelect}(),c.$watch("skipFocusser",function(){var e=c.$eval(r.skipFocusser);g.skipFocusser=void 0!==e?e:t.skipFocusser}),g.onSelectCallback=n(r.onSelect),g.onRemoveCallback=n(r.onRemove),g.ngModel=f,g.choiceGrouped=function(e){return g.isGrouped&&e&&e.name},r.tabindex&&r.$observe("tabindex",function(e){g.focusInput.attr("tabindex",e),a.removeAttr("tabindex")}),c.$watch(function(){return c.$eval(r.searchEnabled)},function(e){g.searchEnabled=void 0!==e?e:t.searchEnabled}),c.$watch("sortable",function(){var e=c.$eval(r.sortable);g.sortable=void 0!==e?e:t.sortable}),r.$observe("limit",function(){g.limit=angular.isDefined(r.limit)?parseInt(r.limit,10):void 0}),c.$watch("removeSelected",function(){var e=c.$eval(r.removeSelected);g.removeSelected=void 0!==e?e:t.removeSelected}),r.$observe("disabled",function(){g.disabled=void 0!==r.disabled?r.disabled:!1}),r.$observe("resetSearchInput",function(){var e=c.$eval(r.resetSearchInput);g.resetSearchInput=void 0!==e?e:!0}),r.$observe("paste",function(){g.paste=c.$eval(r.paste)}),r.$observe("tagging",function(){if(void 0!==r.tagging){var e=c.$eval(r.tagging);g.tagging={isActivated:!0,fct:e!==!0?e:void 0}}else g.tagging={isActivated:!1,fct:void 0}}),r.$observe("taggingLabel",function(){void 0!==r.tagging&&("false"===r.taggingLabel?g.taggingLabel=!1:g.taggingLabel=void 0!==r.taggingLabel?r.taggingLabel:"(new)")}),r.$observe("taggingTokens",function(){if(void 0!==r.tagging){var e=void 0!==r.taggingTokens?r.taggingTokens.split("|"):[",","ENTER"];g.taggingTokens={isActivated:!0,tokens:e}}}),r.$observe("spinnerEnabled",function(){var e=c.$eval(r.spinnerEnabled);g.spinnerEnabled=void 0!==e?e:t.spinnerEnabled}),r.$observe("spinnerClass",function(){var e=r.spinnerClass;g.spinnerClass=void 0!==e?r.spinnerClass:t.spinnerClass}),angular.isDefined(r.autofocus)&&l(function(){g.setFocus()}),angular.isDefined(r.focusOn)&&c.$on(r.focusOn,function(){l(function(){g.setFocus()})}),e.on("click",d),c.$on("$destroy",function(){e.off("click",d)}),u(c,function(e){var t=angular.element("<div>").append(e),i=t.querySelectorAll(".ui-select-match");if(i.removeAttr("ui-select-match"),i.removeAttr("data-ui-select-match"),1!==i.length)throw s("transcluded","Expected 1 .ui-select-match but got '{0}'.",i.length);a.querySelectorAll(".ui-select-match").replaceWith(i);var c=t.querySelectorAll(".ui-select-choices");if(c.removeAttr("ui-select-choices"),c.removeAttr("data-ui-select-choices"),1!==c.length)throw s("transcluded","Expected 1 .ui-select-choices but got '{0}'.",c.length);a.querySelectorAll(".ui-select-choices").replaceWith(c);var n=t.querySelectorAll(".ui-select-no-choice");n.removeAttr("ui-select-no-choice"),n.removeAttr("data-ui-select-no-choice"),1==n.length&&a.querySelectorAll(".ui-select-no-choice").replaceWith(n)});var v=c.$eval(r.appendToBody);(void 0!==v?v:t.appendToBody)&&(c.$watch("$select.open",function(e){e?p():h()}),c.$on("$destroy",function(){h()}));var $=null,m="",b=null,w="direction-up";c.$watch("$select.open",function(){"auto"!==g.dropdownPosition&&"up"!==g.dropdownPosition||c.calculateDropdownPos()});var y=function(e,t){e=e||i(a),t=t||i(b),b[0].style.position="absolute",b[0].style.top=-1*t.height+"px",a.addClass(w)},x=function(e,t){a.removeClass(w),e=e||i(a),t=t||i(b),b[0].style.position="",b[0].style.top=""},E=function(){l(function(){if("up"===g.dropdownPosition)y();else{a.removeClass(w);var t=i(a),s=i(b),c=e[0].documentElement.scrollTop||e[0].body.scrollTop;t.top+t.height+s.height>c+e[0].documentElement.clientHeight?y(t,s):x(t,s)}b[0].style.opacity=1})},S=!1;c.calculateDropdownPos=function(){if(g.open){if(b=angular.element(a).querySelectorAll(".ui-select-dropdown"),0===b.length)return;if(""!==g.search||S||(b[0].style.opacity=0,S=!0),!i(b).height&&g.$animate&&g.$animate.on&&g.$animate.enabled(b)){var e=!0;g.$animate.on("enter",b,function(t,s){"close"===s&&e&&(E(),e=!1)})}else E()}else{if(null===b||0===b.length)return;b[0].style.opacity=0,b[0].style.position="",b[0].style.top="",a.removeClass(w)}}}}}}]),s.directive("uiSelectMatch",["uiSelectConfig",function(e){function t(e,t){return e[0].hasAttribute(t)?e.attr(t):e[0].hasAttribute("data-"+t)?e.attr("data-"+t):e[0].hasAttribute("x-"+t)?e.attr("x-"+t):void 0}return{restrict:"EA",require:"^uiSelect",replace:!0,transclude:!0,templateUrl:function(s){s.addClass("ui-select-match");var i=s.parent(),c=t(i,"theme")||e.theme,n=angular.isDefined(t(i,"multiple"));return c+(n?"/match-multiple.tpl.html":"/match.tpl.html")},link:function(t,s,i,c){function n(e){c.allowClear=angular.isDefined(e)?""===e?!0:"true"===e.toLowerCase():!1}c.lockChoiceExpression=i.uiLockChoice,i.$observe("placeholder",function(t){c.placeholder=void 0!==t?t:e.placeholder}),i.$observe("allowClear",n),n(i.allowClear),c.multiple&&c.sizeSearchInput()}}}]),s.directive("uiSelectMultiple",["uiSelectMinErr","$timeout",function(t,s){return{restrict:"EA",require:["^uiSelect","^ngModel"],controller:["$scope","$timeout",function(e,t){var s,i=this,c=e.$select;angular.isUndefined(c.selected)&&(c.selected=[]),e.$evalAsync(function(){s=e.ngModel}),i.activeMatchIndex=-1,i.updateModel=function(){s.$setViewValue(Date.now()),i.refreshComponent()},i.refreshComponent=function(){c.refreshItems&&c.refreshItems(),c.sizeSearchInput&&c.sizeSearchInput()},i.removeChoice=function(s){if(c.isLocked(null,s))return!1;var n=c.selected[s],l={};return l[c.parserResult.itemName]=n,c.selected.splice(s,1),i.activeMatchIndex=-1,c.sizeSearchInput(),t(function(){c.onRemoveCallback(e,{$item:n,$model:c.parserResult.modelMapper(e,l)})}),i.updateModel(),!0},i.getPlaceholder=function(){return c.selected&&c.selected.length?void 0:c.placeholder}}],controllerAs:"$selectMultiple",link:function(i,c,n,l){function a(e){return angular.isNumber(e.selectionStart)?e.selectionStart:e.value.length}function r(t){function s(){switch(t){case e.LEFT:return~h.activeMatchIndex?u:l;case e.RIGHT:return~h.activeMatchIndex&&r!==l?o:(d.activate(),!1);case e.BACKSPACE:return~h.activeMatchIndex?h.removeChoice(r)?u:r:l;case e.DELETE:return~h.activeMatchIndex?(h.removeChoice(h.activeMatchIndex),r):!1}}var i=a(d.searchInput[0]),c=d.selected.length,n=0,l=c-1,r=h.activeMatchIndex,o=h.activeMatchIndex+1,u=h.activeMatchIndex-1,p=r;return i>0||d.search.length&&t==e.RIGHT?!1:(d.close(),p=s(),d.selected.length&&p!==!1?h.activeMatchIndex=Math.min(l,Math.max(n,p)):h.activeMatchIndex=-1,!0)}function o(e){if(void 0===e||void 0===d.search)return!1;var t=e.filter(function(e){return void 0===d.search.toUpperCase()||void 0===e?!1:e.toUpperCase()===d.search.toUpperCase()}).length>0;return t}function u(e,t){var s=-1;if(angular.isArray(e))for(var i=angular.copy(e),c=0;c<i.length;c++)if(void 0===d.tagging.fct)i[c]+" "+d.taggingLabel===t&&(s=c);else{var n=i[c];angular.isObject(n)&&(n.isTag=!0),angular.equals(n,t)&&(s=c)}return s}var d=l[0],p=i.ngModel=l[1],h=i.$selectMultiple;d.multiple=!0,d.focusInput=d.searchInput,p.$isEmpty=function(e){return!e||0===e.length},p.$parsers.unshift(function(){for(var e,t={},s=[],c=d.selected.length-1;c>=0;c--)t={},t[d.parserResult.itemName]=d.selected[c],e=d.parserResult.modelMapper(i,t),s.unshift(e);return s}),p.$formatters.unshift(function(e){var t,s=d.parserResult&&d.parserResult.source(i,{$select:{search:""}}),c={};if(!s)return e;var n=[],l=function(e,s){if(e&&e.length){for(var l=e.length-1;l>=0;l--){if(c[d.parserResult.itemName]=e[l],t=d.parserResult.modelMapper(i,c),d.parserResult.trackByExp){var a=/(\w*)\./.exec(d.parserResult.trackByExp),r=/\.([^\s]+)/.exec(d.parserResult.trackByExp);if(a&&a.length>0&&a[1]==d.parserResult.itemName&&r&&r.length>0&&t[r[1]]==s[r[1]])return n.unshift(e[l]),!0}if(angular.equals(t,s))return n.unshift(e[l]),!0}return!1}};if(!e)return n;for(var a=e.length-1;a>=0;a--)l(d.selected,e[a])||l(s,e[a])||n.unshift(e[a]);return n}),i.$watchCollection(function(){return p.$modelValue},function(e,t){t!=e&&(angular.isDefined(p.$modelValue)&&(p.$modelValue=null),h.refreshComponent())}),p.$render=function(){if(!angular.isArray(p.$viewValue)){if(!angular.isUndefined(p.$viewValue)&&null!==p.$viewValue)throw t("multiarr","Expected model value to be array but got '{0}'",p.$viewValue);p.$viewValue=[]}d.selected=p.$viewValue,h.refreshComponent(),i.$evalAsync()},i.$on("uis:select",function(e,t){d.selected.length>=d.limit||(d.selected.push(t),h.updateModel())}),i.$on("uis:activate",function(){h.activeMatchIndex=-1}),i.$watch("$select.disabled",function(e,t){t&&!e&&d.sizeSearchInput()}),d.searchInput.on("keydown",function(t){var s=t.which;i.$apply(function(){var i=!1;e.isHorizontalMovement(s)&&(i=r(s)),i&&s!=e.TAB&&(t.preventDefault(),t.stopPropagation())})}),d.searchInput.on("keyup",function(t){if(e.isVerticalMovement(t.which)||i.$evalAsync(function(){d.activeIndex=d.taggingLabel===!1?-1:0}),d.tagging.isActivated&&d.search.length>0){if(t.which===e.TAB||e.isControl(t)||e.isFunctionKey(t)||t.which===e.ESC||e.isVerticalMovement(t.which))return;if(d.activeIndex=d.taggingLabel===!1?-1:0,d.taggingLabel===!1)return;var s,c,n,l,a=angular.copy(d.items),r=angular.copy(d.items),p=!1,h=-1;if(void 0!==d.tagging.fct){if(n=d.$filter("filter")(a,{isTag:!0}),n.length>0&&(l=n[0]),a.length>0&&l&&(p=!0,a=a.slice(1,a.length),r=r.slice(1,r.length)),s=d.tagging.fct(d.search),r.some(function(e){return angular.equals(e,s)})||d.selected.some(function(e){return angular.equals(e,s)}))return void i.$evalAsync(function(){d.activeIndex=0,d.items=a});s&&(s.isTag=!0)}else{if(n=d.$filter("filter")(a,function(e){return e.match(d.taggingLabel)}),n.length>0&&(l=n[0]),c=a[0],void 0!==c&&a.length>0&&l&&(p=!0,a=a.slice(1,a.length),r=r.slice(1,r.length)),s=d.search+" "+d.taggingLabel,u(d.selected,d.search)>-1)return;if(o(r.concat(d.selected)))return void(p&&(a=r,i.$evalAsync(function(){d.activeIndex=0,d.items=a})));if(o(r))return void(p&&(d.items=r.slice(1,r.length)))}p&&(h=u(d.selected,s)),h>-1?a=a.slice(h+1,a.length-1):(a=[],s&&a.push(s),a=a.concat(r)),i.$evalAsync(function(){if(d.activeIndex=0,d.items=a,d.isGrouped){var e=s?a.slice(1):a;d.setItemsFn(e),s&&(d.items.unshift(s),d.groups.unshift({name:"",items:[s],tagging:!0}))}})}}),d.searchInput.on("blur",function(){s(function(){h.activeMatchIndex=-1})})}}}]),s.directive("uiSelectNoChoice",["uiSelectConfig",function(e){return{restrict:"EA",require:"^uiSelect",replace:!0,transclude:!0,templateUrl:function(t){t.addClass("ui-select-no-choice");var s=t.parent().attr("theme")||e.theme;return s+"/no-choice.tpl.html"}}}]),s.directive("uiSelectSingle",["$timeout","$compile",function(t,s){return{restrict:"EA",require:["^uiSelect","^ngModel"],link:function(i,c,n,l){var a=l[0],r=l[1];r.$parsers.unshift(function(e){var t,s={};return s[a.parserResult.itemName]=e,t=a.parserResult.modelMapper(i,s)}),r.$formatters.unshift(function(e){var t,s=a.parserResult&&a.parserResult.source(i,{$select:{search:""}}),c={};if(s){var n=function(s){return c[a.parserResult.itemName]=s,t=a.parserResult.modelMapper(i,c),t===e};if(a.selected&&n(a.selected))return a.selected;for(var l=s.length-1;l>=0;l--)if(n(s[l]))return s[l]}return e}),i.$watch("$select.selected",function(e){r.$viewValue!==e&&r.$setViewValue(e)}),r.$render=function(){a.selected=r.$viewValue},i.$on("uis:select",function(e,t){a.selected=t}),i.$on("uis:close",function(e,s){t(function(){a.focusser.prop("disabled",!1),s||a.focusser[0].focus()},0,!1)}),i.$on("uis:activate",function(){o.prop("disabled",!0)});var o=angular.element("<input ng-disabled='$select.disabled' class='ui-select-focusser ui-select-offscreen' type='text' id='{{ $select.focusserId }}' aria-label='{{ $select.focusserTitle }}' aria-haspopup='true' role='button' />");s(o)(i),a.focusser=o,a.focusInput=o,c.parent().append(o),o.bind("focus",function(){i.$evalAsync(function(){a.focus=!0})}),o.bind("blur",function(){i.$evalAsync(function(){a.focus=!1})}),o.bind("keydown",function(t){return t.which===e.BACKSPACE?(t.preventDefault(),t.stopPropagation(),a.select(void 0),void i.$apply()):void(t.which===e.TAB||e.isControl(t)||e.isFunctionKey(t)||t.which===e.ESC||(t.which!=e.DOWN&&t.which!=e.UP&&t.which!=e.ENTER&&t.which!=e.SPACE||(t.preventDefault(),t.stopPropagation(),a.activate()),i.$digest()))}),o.bind("keyup input",function(t){t.which===e.TAB||e.isControl(t)||e.isFunctionKey(t)||t.which===e.ESC||t.which==e.ENTER||t.which===e.BACKSPACE||(a.activate(o.val()),o.val(""),i.$digest())})}}}]),s.directive("uiSelectSort",["$timeout","uiSelectConfig","uiSelectMinErr",function(e,t,s){return{require:["^^uiSelect","^ngModel"],link:function(t,i,c,n){if(null===t[c.uiSelectSort])throw s("sort","Expected a list to sort");var l=n[0],a=n[1],r=angular.extend({axis:"horizontal"},t.$eval(c.uiSelectSortOptions)),o=r.axis,u="dragging",d="dropping",p="dropping-before",h="dropping-after";t.$watch(function(){return l.sortable},function(e){e?i.attr("draggable",!0):i.removeAttr("draggable")}),i.on("dragstart",function(e){i.addClass(u),(e.dataTransfer||e.originalEvent.dataTransfer).setData("text",t.$index.toString())}),i.on("dragend",function(){v(u)});var g,f=function(e,t){this.splice(t,0,this.splice(e,1)[0])},v=function(e){angular.forEach(l.$element.querySelectorAll("."+e),function(t){angular.element(t).removeClass(e)})},$=function(e){e.preventDefault();var t="vertical"===o?e.offsetY||e.layerY||(e.originalEvent?e.originalEvent.offsetY:0):e.offsetX||e.layerX||(e.originalEvent?e.originalEvent.offsetX:0);t<this["vertical"===o?"offsetHeight":"offsetWidth"]/2?(v(h),i.addClass(p)):(v(p),i.addClass(h))},m=function(t){t.preventDefault();var s=parseInt((t.dataTransfer||t.originalEvent.dataTransfer).getData("text"),10);e.cancel(g),g=e(function(){b(s)},20)},b=function(e){var s=t.$eval(c.uiSelectSort),n=s[e],l=null;l=i.hasClass(p)?e<t.$index?t.$index-1:t.$index:e<t.$index?t.$index:t.$index+1,f.apply(s,[e,l]),a.$setViewValue(Date.now()),t.$apply(function(){t.$emit("uiSelectSort:change",{array:s,item:n,from:e,to:l})}),v(d),v(p),v(h),i.off("drop",m)};i.on("dragenter",function(){i.hasClass(u)||(i.addClass(d),i.on("dragover",$),i.on("drop",m))}),i.on("dragleave",function(e){e.target==i&&(v(d),v(p),v(h),i.off("dragover",$),i.off("drop",m))})}}}]),s.factory("$$uisDebounce",["$timeout",function(e){return function(t,s){var i;return function(){var c=this,n=Array.prototype.slice.call(arguments);i&&e.cancel(i),i=e(function(){t.apply(c,n)},s)}}}]),s.directive("uisOpenClose",["$parse","$timeout",function(e,t){return{restrict:"A",require:"uiSelect",link:function(s,i,c,n){n.onOpenCloseCallback=e(c.uisOpenClose),s.$watch("$select.open",function(e,i){e!==i&&t(function(){n.onOpenCloseCallback(s,{isOpen:e})})})}}}]),s.service("uisRepeatParser",["uiSelectMinErr","$parse",function(e,t){var s=this;s.parse=function(s){var i;if(i=s.match(/^\s*(?:([\s\S]+?)\s+as\s+)?(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+(\s*[\s\S]+?)?(?:\s+track\s+by\s+([\s\S]+?))?\s*$/),!i)throw e("iexp","Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",s);var c=i[5],n="";if(i[3]){c=i[5].replace(/(^\()|(\)$)/g,"");var l=i[5].match(/^\s*(?:[\s\S]+?)(?:[^\|]|\|\|)+([\s\S]*)\s*$/);
l&&l[1].trim()&&(n=l[1],c=c.replace(n,""))}return{itemName:i[4]||i[2],keyName:i[3],source:t(c),filters:n,trackByExp:i[6],modelMapper:t(i[1]||i[4]||i[2]),repeatExpression:function(e){var t=this.itemName+" in "+(e?"$group.items":"$select.items");return this.trackByExp&&(t+=" track by "+this.trackByExp),t}}},s.getGroupNgRepeatExpression=function(){return"$group in $select.groups track by $group.name"}}])}(),angular.module("ui.select").run(["$templateCache",function(e){e.put("bootstrap/choices.tpl.html",'<ul class="ui-select-choices ui-select-choices-content ui-select-dropdown dropdown-menu" ng-show="$select.open && $select.items.length > 0"><li class="ui-select-choices-group" id="ui-select-choices-{{ $select.generatedId }}"><div class="divider" ng-show="$select.isGrouped && $index > 0"></div><div ng-show="$select.isGrouped" class="ui-select-choices-group-label dropdown-header" ng-bind="$group.name"></div><div ng-attr-id="ui-select-choices-row-{{ $select.generatedId }}-{{$index}}" class="ui-select-choices-row" ng-class="{active: $select.isActive(this), disabled: $select.isDisabled(this)}" role="option"><span class="ui-select-choices-row-inner"></span></div></li></ul>'),e.put("bootstrap/match-multiple.tpl.html",'<span class="ui-select-match"><span ng-repeat="$item in $select.selected track by $index"><span class="ui-select-match-item btn btn-default btn-xs" tabindex="-1" type="button" ng-disabled="$select.disabled" ng-click="$selectMultiple.activeMatchIndex = $index;" ng-class="{\'btn-primary\':$selectMultiple.activeMatchIndex === $index, \'select-locked\':$select.isLocked(this, $index)}" ui-select-sort="$select.selected"><span class="close ui-select-match-close" ng-hide="$select.disabled" ng-click="$selectMultiple.removeChoice($index)">&nbsp;&times;</span> <span uis-transclude-append=""></span></span></span></span>'),e.put("bootstrap/match.tpl.html",'<div class="ui-select-match" ng-hide="$select.open && $select.searchEnabled" ng-disabled="$select.disabled" ng-class="{\'btn-default-focus\':$select.focus}"><span tabindex="-1" class="btn btn-default form-control ui-select-toggle" aria-label="{{ $select.baseTitle }} activate" ng-disabled="$select.disabled" ng-click="$select.activate()" style="outline: 0;"><span ng-show="$select.isEmpty()" class="ui-select-placeholder text-muted">{{$select.placeholder}}</span> <span ng-hide="$select.isEmpty()" class="ui-select-match-text pull-left" ng-class="{\'ui-select-allow-clear\': $select.allowClear && !$select.isEmpty()}" ng-transclude=""></span> <i class="caret pull-right" ng-click="$select.toggle($event)"></i> <a ng-show="$select.allowClear && !$select.isEmpty() && ($select.disabled !== true)" aria-label="{{ $select.baseTitle }} clear" style="margin-right: 10px" ng-click="$select.clear($event)" class="btn btn-xs btn-link pull-right"><i class="glyphicon glyphicon-remove" aria-hidden="true"></i></a></span></div>'),e.put("bootstrap/no-choice.tpl.html",'<ul class="ui-select-no-choice dropdown-menu" ng-show="$select.items.length == 0"><li ng-transclude=""></li></ul>'),e.put("bootstrap/select-multiple.tpl.html",'<div class="ui-select-container ui-select-multiple ui-select-bootstrap dropdown form-control" ng-class="{open: $select.open}"><div><div class="ui-select-match"></div><input type="search" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" class="ui-select-search input-xs" placeholder="{{$selectMultiple.getPlaceholder()}}" ng-disabled="$select.disabled" ng-click="$select.activate()" ng-model="$select.search" role="combobox" aria-expanded="{{$select.open}}" aria-label="{{$select.baseTitle}}" ng-class="{\'spinner\': $select.refreshing}" ondrop="return false;"></div><div class="ui-select-choices"></div><div class="ui-select-no-choice"></div></div>'),e.put("bootstrap/select.tpl.html",'<div class="ui-select-container ui-select-bootstrap dropdown" ng-class="{open: $select.open}"><div class="ui-select-match"></div><span ng-show="$select.open && $select.refreshing && $select.spinnerEnabled" class="ui-select-refreshing {{$select.spinnerClass}}"></span> <input type="search" autocomplete="off" tabindex="-1" aria-expanded="true" aria-label="{{ $select.baseTitle }}" aria-owns="ui-select-choices-{{ $select.generatedId }}" class="form-control ui-select-search" ng-class="{ \'ui-select-search-hidden\' : !$select.searchEnabled }" placeholder="{{$select.placeholder}}" ng-model="$select.search" ng-show="$select.open"><div class="ui-select-choices"></div><div class="ui-select-no-choice"></div></div>'),e.put("select2/choices.tpl.html",'<ul tabindex="-1" class="ui-select-choices ui-select-choices-content select2-results"><li class="ui-select-choices-group" ng-class="{\'select2-result-with-children\': $select.choiceGrouped($group) }"><div ng-show="$select.choiceGrouped($group)" class="ui-select-choices-group-label select2-result-label" ng-bind="$group.name"></div><ul id="ui-select-choices-{{ $select.generatedId }}" ng-class="{\'select2-result-sub\': $select.choiceGrouped($group), \'select2-result-single\': !$select.choiceGrouped($group) }"><li role="option" ng-attr-id="ui-select-choices-row-{{ $select.generatedId }}-{{$index}}" class="ui-select-choices-row" ng-class="{\'select2-highlighted\': $select.isActive(this), \'select2-disabled\': $select.isDisabled(this)}"><div class="select2-result-label ui-select-choices-row-inner"></div></li></ul></li></ul>'),e.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 track by $index" ng-class="{\'select2-search-choice-focus\':$selectMultiple.activeMatchIndex === $index, \'select2-locked\':$select.isLocked(this, $index)}" ui-select-sort="$select.selected"><span uis-transclude-append=""></span> <a href="javascript:;" class="ui-select-match-close select2-search-choice-close" ng-click="$selectMultiple.removeChoice($index)" tabindex="-1"></a></li></span>'),e.put("select2/match.tpl.html",'<a class="select2-choice ui-select-match" ng-class="{\'select2-default\': $select.isEmpty()}" ng-click="$select.toggle($event)" aria-label="{{ $select.baseTitle }} select"><span ng-show="$select.isEmpty()" class="select2-chosen">{{$select.placeholder}}</span> <span ng-hide="$select.isEmpty()" class="select2-chosen" ng-transclude=""></span> <abbr ng-if="$select.allowClear && !$select.isEmpty()" class="select2-search-choice-close" ng-click="$select.clear($event)"></abbr> <span class="select2-arrow ui-select-toggle"><b></b></span></a>'),e.put("select2/no-choice.tpl.html",'<div class="ui-select-no-choice dropdown" ng-show="$select.items.length == 0"><div class="dropdown-content"><div data-selectable="" ng-transclude=""></div></div></div>'),e.put("select2/select-multiple.tpl.html",'<div class="ui-select-container ui-select-multiple select2 select2-container select2-container-multi" ng-class="{\'select2-container-active select2-dropdown-open open\': $select.open, \'select2-container-disabled\': $select.disabled}"><ul class="select2-choices"><span class="ui-select-match"></span><li class="select2-search-field"><input type="search" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" role="combobox" aria-expanded="true" aria-owns="ui-select-choices-{{ $select.generatedId }}" aria-label="{{ $select.baseTitle }}" aria-activedescendant="ui-select-choices-row-{{ $select.generatedId }}-{{ $select.activeIndex }}" class="select2-input ui-select-search" placeholder="{{$selectMultiple.getPlaceholder()}}" ng-disabled="$select.disabled" ng-hide="$select.disabled" ng-model="$select.search" ng-click="$select.activate()" style="width: 34px;" ondrop="return false;"></li></ul><div class="ui-select-dropdown select2-drop select2-with-searchbox select2-drop-active" ng-class="{\'select2-display-none\': !$select.open || $select.items.length === 0}"><div class="ui-select-choices"></div></div></div>'),e.put("select2/select.tpl.html",'<div class="ui-select-container select2 select2-container" ng-class="{\'select2-container-active select2-dropdown-open open\': $select.open, \'select2-container-disabled\': $select.disabled, \'select2-container-active\': $select.focus, \'select2-allowclear\': $select.allowClear && !$select.isEmpty()}"><div class="ui-select-match"></div><div class="ui-select-dropdown select2-drop select2-with-searchbox select2-drop-active" ng-class="{\'select2-display-none\': !$select.open}"><div class="search-container" ng-class="{\'ui-select-search-hidden\':!$select.searchEnabled, \'select2-search\':$select.searchEnabled}"><input type="search" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" ng-class="{\'select2-active\': $select.refreshing}" role="combobox" aria-expanded="true" aria-owns="ui-select-choices-{{ $select.generatedId }}" aria-label="{{ $select.baseTitle }}" class="ui-select-search select2-input" ng-model="$select.search"></div><div class="ui-select-choices"></div><div class="ui-select-no-choice"></div></div></div>'),e.put("selectize/choices.tpl.html",'<div ng-show="$select.open" class="ui-select-choices ui-select-dropdown selectize-dropdown" ng-class="{\'single\': !$select.multiple, \'multi\': $select.multiple}"><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="$group.name"></div><div role="option" class="ui-select-choices-row" ng-class="{active: $select.isActive(this), disabled: $select.isDisabled(this)}"><div class="option ui-select-choices-row-inner" data-selectable=""></div></div></div></div></div>'),e.put("selectize/match-multiple.tpl.html",'<div class="ui-select-match" data-value="" ng-repeat="$item in $select.selected track by $index" ng-click="$selectMultiple.activeMatchIndex = $index;" ng-class="{\'active\':$selectMultiple.activeMatchIndex === $index}" ui-select-sort="$select.selected"><span class="ui-select-match-item" ng-class="{\'select-locked\':$select.isLocked(this, $index)}"><span uis-transclude-append=""></span> <span class="remove ui-select-match-close" ng-hide="$select.disabled" ng-click="$selectMultiple.removeChoice($index)">&times;</span></span></div>'),e.put("selectize/match.tpl.html",'<div ng-hide="$select.searchEnabled && ($select.open || $select.isEmpty())" class="ui-select-match"><span ng-show="!$select.searchEnabled && ($select.isEmpty() || $select.open)" class="ui-select-placeholder text-muted">{{$select.placeholder}}</span> <span ng-hide="$select.isEmpty() || $select.open" ng-transclude=""></span></div>'),e.put("selectize/no-choice.tpl.html",'<div class="ui-select-no-choice selectize-dropdown" ng-show="$select.items.length == 0"><div class="selectize-dropdown-content"><div data-selectable="" ng-transclude=""></div></div></div>'),e.put("selectize/select-multiple.tpl.html",'<div class="ui-select-container selectize-control multi plugin-remove_button" ng-class="{\'open\': $select.open}"><div class="selectize-input" ng-class="{\'focus\': $select.open, \'disabled\': $select.disabled, \'selectize-focus\' : $select.focus}" ng-click="$select.open && !$select.searchEnabled ? $select.toggle($event) : $select.activate()"><div class="ui-select-match"></div><input type="search" autocomplete="off" tabindex="-1" class="ui-select-search" ng-class="{\'ui-select-search-hidden\':!$select.searchEnabled}" placeholder="{{$selectMultiple.getPlaceholder()}}" ng-model="$select.search" ng-disabled="$select.disabled" aria-expanded="{{$select.open}}" aria-label="{{ $select.baseTitle }}" ondrop="return false;"></div><div class="ui-select-choices"></div><div class="ui-select-no-choice"></div></div>'),e.put("selectize/select.tpl.html",'<div class="ui-select-container selectize-control single" ng-class="{\'open\': $select.open}"><div class="selectize-input" ng-class="{\'focus\': $select.open, \'disabled\': $select.disabled, \'selectize-focus\' : $select.focus}" ng-click="$select.open && !$select.searchEnabled ? $select.toggle($event) : $select.activate()"><div class="ui-select-match"></div><input type="search" autocomplete="off" tabindex="-1" class="ui-select-search ui-select-toggle" ng-class="{\'ui-select-search-hidden\':!$select.searchEnabled}" ng-click="$select.toggle($event)" placeholder="{{$select.placeholder}}" ng-model="$select.search" ng-hide="!$select.isEmpty() && !$select.open" ng-disabled="$select.disabled" aria-label="{{ $select.baseTitle }}"></div><div class="ui-select-choices"></div><div class="ui-select-no-choice"></div></div>')}]);
//# sourceMappingURL=select.min.js.map
This source diff could not be displayed because it is too large. You can view the blob instead.
var module = angular.module('ui.select.pages', ['plunkr']);
'use strict';
var app = angular.module('demo', ['ngSanitize', 'ui.select']);
/**
* AngularJS default filter with the following expression:
* "person in people | filter: {name: $select.search, age: $select.search}"
* performs an AND between 'name: $select.search' and 'age: $select.search'.
* We want to perform an OR.
*/
app.filter('propsFilter', function() {
return function(items, props) {
var out = [];
if (angular.isArray(items)) {
var keys = Object.keys(props);
items.forEach(function(item) {
var itemMatches = false;
for (var i = 0; i < keys.length; i++) {
var prop = keys[i];
var text = props[prop].toLowerCase();
if (item[prop].toString().toLowerCase().indexOf(text) !== -1) {
itemMatches = true;
break;
}
}
if (itemMatches) {
out.push(item);
}
});
} else {
// Let the output be the input untouched
out = items;
}
return out;
};
});
app.controller('DemoCtrl', function ($scope, $http, $timeout, $interval) {
var vm = this;
vm.disabled = undefined;
vm.searchEnabled = undefined;
vm.setInputFocus = function (){
$scope.$broadcast('UiSelectDemo1');
};
vm.enable = function() {
vm.disabled = false;
};
vm.disable = function() {
vm.disabled = true;
};
vm.enableSearch = function() {
vm.searchEnabled = true;
};
vm.disableSearch = function() {
vm.searchEnabled = false;
};
vm.clear = function() {
vm.person.selected = undefined;
vm.address.selected = undefined;
vm.country.selected = undefined;
};
vm.someGroupFn = function (item){
if (item.name[0] >= 'A' && item.name[0] <= 'M')
return 'From A - M';
if (item.name[0] >= 'N' && item.name[0] <= 'Z')
return 'From N - Z';
};
vm.firstLetterGroupFn = function (item){
return item.name[0];
};
vm.reverseOrderFilterFn = function(groups) {
return groups.reverse();
};
vm.personAsync = {selected : "wladimir@email.com"};
vm.peopleAsync = [];
$timeout(function(){
vm.peopleAsync = [
{ name: 'Adam', email: 'adam@email.com', age: 12, country: 'United States' },
{ name: 'Amalie', email: 'amalie@email.com', age: 12, country: 'Argentina' },
{ name: 'Estefanía', email: 'estefania@email.com', age: 21, country: 'Argentina' },
{ name: 'Adrian', email: 'adrian@email.com', age: 21, country: 'Ecuador' },
{ name: 'Wladimir', email: 'wladimir@email.com', age: 30, country: 'Ecuador' },
{ name: 'Samantha', email: 'samantha@email.com', age: 30, country: 'United States' },
{ name: 'Nicole', email: 'nicole@email.com', age: 43, country: 'Colombia' },
{ name: 'Natasha', email: 'natasha@email.com', age: 54, country: 'Ecuador' },
{ name: 'Michael', email: 'michael@email.com', age: 15, country: 'Colombia' },
{ name: 'Nicolás', email: 'nicole@email.com', age: 43, country: 'Colombia' }
];
},3000);
vm.counter = 0;
vm.onSelectCallback = function (item, model){
vm.counter++;
vm.eventResult = {item: item, model: model};
};
vm.removed = function (item, model) {
vm.lastRemoved = {
item: item,
model: model
};
};
vm.tagTransform = function (newTag) {
var item = {
name: newTag,
email: newTag.toLowerCase()+'@email.com',
age: 'unknown',
country: 'unknown'
};
return item;
};
vm.peopleObj = {
'1' : { name: 'Adam', email: 'adam@email.com', age: 12, country: 'United States' },
'2' : { name: 'Amalie', email: 'amalie@email.com', age: 12, country: 'Argentina' },
'3' : { name: 'Estefanía', email: 'estefania@email.com', age: 21, country: 'Argentina' },
'4' : { name: 'Adrian', email: 'adrian@email.com', age: 21, country: 'Ecuador' },
'5' : { name: 'Wladimir', email: 'wladimir@email.com', age: 30, country: 'Ecuador' },
'6' : { name: 'Samantha', email: 'samantha@email.com', age: 30, country: 'United States' },
'7' : { name: 'Nicole', email: 'nicole@email.com', age: 43, country: 'Colombia' },
'8' : { name: 'Natasha', email: 'natasha@email.com', age: 54, country: 'Ecuador' },
'9' : { name: 'Michael', email: 'michael@email.com', age: 15, country: 'Colombia' },
'10' : { name: 'Nicolás', email: 'nicolas@email.com', age: 43, country: 'Colombia' }
};
vm.person = {};
vm.person.selectedValue = vm.peopleObj[3];
vm.person.selectedSingle = 'Samantha';
vm.person.selectedSingleKey = '5';
// To run the demos with a preselected person object, uncomment the line below.
//vm.person.selected = vm.person.selectedValue;
vm.people = [
{ name: 'Adam', email: 'adam@email.com', age: 12, country: 'United States' },
{ name: 'Amalie', email: 'amalie@email.com', age: 12, country: 'Argentina' },
{ name: 'Estefanía', email: 'estefania@email.com', age: 21, country: 'Argentina' },
{ name: 'Adrian', email: 'adrian@email.com', age: 21, country: 'Ecuador' },
{ name: 'Wladimir', email: 'wladimir@email.com', age: 30, country: 'Ecuador' },
{ name: 'Samantha', email: 'samantha@email.com', age: 30, country: 'United States' },
{ name: 'Nicole', email: 'nicole@email.com', age: 43, country: 'Colombia' },
{ name: 'Natasha', email: 'natasha@email.com', age: 54, country: 'Ecuador' },
{ name: 'Michael', email: 'michael@email.com', age: 15, country: 'Colombia' },
{ name: 'Nicolás', email: 'nicolas@email.com', age: 43, country: 'Colombia' }
];
vm.availableColors = ['Red','Green','Blue','Yellow','Magenta','Maroon','Umbra','Turquoise'];
vm.singleDemo = {};
vm.singleDemo.color = '';
vm.multipleDemo = {};
vm.multipleDemo.colors = ['Blue','Red'];
vm.multipleDemo.colors2 = ['Blue','Red'];
vm.multipleDemo.selectedPeople = [vm.people[5], vm.people[4]];
vm.multipleDemo.selectedPeople2 = vm.multipleDemo.selectedPeople;
vm.multipleDemo.selectedPeopleWithGroupBy = [vm.people[8], vm.people[6]];
vm.multipleDemo.selectedPeopleSimple = ['samantha@email.com','wladimir@email.com'];
vm.multipleDemo.removeSelectIsFalse = [vm.people[2], vm.people[0]];
vm.appendToBodyDemo = {
remainingToggleTime: 0,
present: true,
startToggleTimer: function() {
var scope = vm.appendToBodyDemo;
var promise = $interval(function() {
if (scope.remainingTime < 1000) {
$interval.cancel(promise);
scope.present = !scope.present;
scope.remainingTime = 0;
} else {
scope.remainingTime -= 1000;
}
}, 1000);
scope.remainingTime = 3000;
}
};
vm.address = {};
vm.refreshAddresses = function(address) {
var params = {address: address, sensor: false};
return $http.get(
'http://maps.googleapis.com/maps/api/geocode/json',
{params: params}
).then(function(response) {
vm.addresses = response.data.results;
});
};
vm.addPerson = function(item, model){
if(item.hasOwnProperty('isTag')) {
delete item.isTag;
vm.people.push(item);
}
}
vm.country = {};
vm.countries = [ // Taken from https://gist.github.com/unceus/6501985
{name: 'Afghanistan', code: 'AF'},
{name: 'Åland Islands', code: 'AX'},
{name: 'Albania', code: 'AL'},
{name: 'Algeria', code: 'DZ'},
{name: 'American Samoa', code: 'AS'},
{name: 'Andorra', code: 'AD'},
{name: 'Angola', code: 'AO'},
{name: 'Anguilla', code: 'AI'},
{name: 'Antarctica', code: 'AQ'},
{name: 'Antigua and Barbuda', code: 'AG'},
{name: 'Argentina', code: 'AR'},
{name: 'Armenia', code: 'AM'},
{name: 'Aruba', code: 'AW'},
{name: 'Australia', code: 'AU'},
{name: 'Austria', code: 'AT'},
{name: 'Azerbaijan', code: 'AZ'},
{name: 'Bahamas', code: 'BS'},
{name: 'Bahrain', code: 'BH'},
{name: 'Bangladesh', code: 'BD'},
{name: 'Barbados', code: 'BB'},
{name: 'Belarus', code: 'BY'},
{name: 'Belgium', code: 'BE'},
{name: 'Belize', code: 'BZ'},
{name: 'Benin', code: 'BJ'},
{name: 'Bermuda', code: 'BM'},
{name: 'Bhutan', code: 'BT'},
{name: 'Bolivia', code: 'BO'},
{name: 'Bosnia and Herzegovina', code: 'BA'},
{name: 'Botswana', code: 'BW'},
{name: 'Bouvet Island', code: 'BV'},
{name: 'Brazil', code: 'BR'},
{name: 'British Indian Ocean Territory', code: 'IO'},
{name: 'Brunei Darussalam', code: 'BN'},
{name: 'Bulgaria', code: 'BG'},
{name: 'Burkina Faso', code: 'BF'},
{name: 'Burundi', code: 'BI'},
{name: 'Cambodia', code: 'KH'},
{name: 'Cameroon', code: 'CM'},
{name: 'Canada', code: 'CA'},
{name: 'Cape Verde', code: 'CV'},
{name: 'Cayman Islands', code: 'KY'},
{name: 'Central African Republic', code: 'CF'},
{name: 'Chad', code: 'TD'},
{name: 'Chile', code: 'CL'},
{name: 'China', code: 'CN'},
{name: 'Christmas Island', code: 'CX'},
{name: 'Cocos (Keeling) Islands', code: 'CC'},
{name: 'Colombia', code: 'CO'},
{name: 'Comoros', code: 'KM'},
{name: 'Congo', code: 'CG'},
{name: 'Congo, The Democratic Republic of the', code: 'CD'},
{name: 'Cook Islands', code: 'CK'},
{name: 'Costa Rica', code: 'CR'},
{name: 'Cote D\'Ivoire', code: 'CI'},
{name: 'Croatia', code: 'HR'},
{name: 'Cuba', code: 'CU'},
{name: 'Cyprus', code: 'CY'},
{name: 'Czech Republic', code: 'CZ'},
{name: 'Denmark', code: 'DK'},
{name: 'Djibouti', code: 'DJ'},
{name: 'Dominica', code: 'DM'},
{name: 'Dominican Republic', code: 'DO'},
{name: 'Ecuador', code: 'EC'},
{name: 'Egypt', code: 'EG'},
{name: 'El Salvador', code: 'SV'},
{name: 'Equatorial Guinea', code: 'GQ'},
{name: 'Eritrea', code: 'ER'},
{name: 'Estonia', code: 'EE'},
{name: 'Ethiopia', code: 'ET'},
{name: 'Falkland Islands (Malvinas)', code: 'FK'},
{name: 'Faroe Islands', code: 'FO'},
{name: 'Fiji', code: 'FJ'},
{name: 'Finland', code: 'FI'},
{name: 'France', code: 'FR'},
{name: 'French Guiana', code: 'GF'},
{name: 'French Polynesia', code: 'PF'},
{name: 'French Southern Territories', code: 'TF'},
{name: 'Gabon', code: 'GA'},
{name: 'Gambia', code: 'GM'},
{name: 'Georgia', code: 'GE'},
{name: 'Germany', code: 'DE'},
{name: 'Ghana', code: 'GH'},
{name: 'Gibraltar', code: 'GI'},
{name: 'Greece', code: 'GR'},
{name: 'Greenland', code: 'GL'},
{name: 'Grenada', code: 'GD'},
{name: 'Guadeloupe', code: 'GP'},
{name: 'Guam', code: 'GU'},
{name: 'Guatemala', code: 'GT'},
{name: 'Guernsey', code: 'GG'},
{name: 'Guinea', code: 'GN'},
{name: 'Guinea-Bissau', code: 'GW'},
{name: 'Guyana', code: 'GY'},
{name: 'Haiti', code: 'HT'},
{name: 'Heard Island and Mcdonald Islands', code: 'HM'},
{name: 'Holy See (Vatican City State)', code: 'VA'},
{name: 'Honduras', code: 'HN'},
{name: 'Hong Kong', code: 'HK'},
{name: 'Hungary', code: 'HU'},
{name: 'Iceland', code: 'IS'},
{name: 'India', code: 'IN'},
{name: 'Indonesia', code: 'ID'},
{name: 'Iran, Islamic Republic Of', code: 'IR'},
{name: 'Iraq', code: 'IQ'},
{name: 'Ireland', code: 'IE'},
{name: 'Isle of Man', code: 'IM'},
{name: 'Israel', code: 'IL'},
{name: 'Italy', code: 'IT'},
{name: 'Jamaica', code: 'JM'},
{name: 'Japan', code: 'JP'},
{name: 'Jersey', code: 'JE'},
{name: 'Jordan', code: 'JO'},
{name: 'Kazakhstan', code: 'KZ'},
{name: 'Kenya', code: 'KE'},
{name: 'Kiribati', code: 'KI'},
{name: 'Korea, Democratic People\'s Republic of', code: 'KP'},
{name: 'Korea, Republic of', code: 'KR'},
{name: 'Kuwait', code: 'KW'},
{name: 'Kyrgyzstan', code: 'KG'},
{name: 'Lao People\'s Democratic Republic', code: 'LA'},
{name: 'Latvia', code: 'LV'},
{name: 'Lebanon', code: 'LB'},
{name: 'Lesotho', code: 'LS'},
{name: 'Liberia', code: 'LR'},
{name: 'Libyan Arab Jamahiriya', code: 'LY'},
{name: 'Liechtenstein', code: 'LI'},
{name: 'Lithuania', code: 'LT'},
{name: 'Luxembourg', code: 'LU'},
{name: 'Macao', code: 'MO'},
{name: 'Macedonia, The Former Yugoslav Republic of', code: 'MK'},
{name: 'Madagascar', code: 'MG'},
{name: 'Malawi', code: 'MW'},
{name: 'Malaysia', code: 'MY'},
{name: 'Maldives', code: 'MV'},
{name: 'Mali', code: 'ML'},
{name: 'Malta', code: 'MT'},
{name: 'Marshall Islands', code: 'MH'},
{name: 'Martinique', code: 'MQ'},
{name: 'Mauritania', code: 'MR'},
{name: 'Mauritius', code: 'MU'},
{name: 'Mayotte', code: 'YT'},
{name: 'Mexico', code: 'MX'},
{name: 'Micronesia, Federated States of', code: 'FM'},
{name: 'Moldova, Republic of', code: 'MD'},
{name: 'Monaco', code: 'MC'},
{name: 'Mongolia', code: 'MN'},
{name: 'Montserrat', code: 'MS'},
{name: 'Morocco', code: 'MA'},
{name: 'Mozambique', code: 'MZ'},
{name: 'Myanmar', code: 'MM'},
{name: 'Namibia', code: 'NA'},
{name: 'Nauru', code: 'NR'},
{name: 'Nepal', code: 'NP'},
{name: 'Netherlands', code: 'NL'},
{name: 'Netherlands Antilles', code: 'AN'},
{name: 'New Caledonia', code: 'NC'},
{name: 'New Zealand', code: 'NZ'},
{name: 'Nicaragua', code: 'NI'},
{name: 'Niger', code: 'NE'},
{name: 'Nigeria', code: 'NG'},
{name: 'Niue', code: 'NU'},
{name: 'Norfolk Island', code: 'NF'},
{name: 'Northern Mariana Islands', code: 'MP'},
{name: 'Norway', code: 'NO'},
{name: 'Oman', code: 'OM'},
{name: 'Pakistan', code: 'PK'},
{name: 'Palau', code: 'PW'},
{name: 'Palestinian Territory, Occupied', code: 'PS'},
{name: 'Panama', code: 'PA'},
{name: 'Papua New Guinea', code: 'PG'},
{name: 'Paraguay', code: 'PY'},
{name: 'Peru', code: 'PE'},
{name: 'Philippines', code: 'PH'},
{name: 'Pitcairn', code: 'PN'},
{name: 'Poland', code: 'PL'},
{name: 'Portugal', code: 'PT'},
{name: 'Puerto Rico', code: 'PR'},
{name: 'Qatar', code: 'QA'},
{name: 'Reunion', code: 'RE'},
{name: 'Romania', code: 'RO'},
{name: 'Russian Federation', code: 'RU'},
{name: 'Rwanda', code: 'RW'},
{name: 'Saint Helena', code: 'SH'},
{name: 'Saint Kitts and Nevis', code: 'KN'},
{name: 'Saint Lucia', code: 'LC'},
{name: 'Saint Pierre and Miquelon', code: 'PM'},
{name: 'Saint Vincent and the Grenadines', code: 'VC'},
{name: 'Samoa', code: 'WS'},
{name: 'San Marino', code: 'SM'},
{name: 'Sao Tome and Principe', code: 'ST'},
{name: 'Saudi Arabia', code: 'SA'},
{name: 'Senegal', code: 'SN'},
{name: 'Serbia and Montenegro', code: 'CS'},
{name: 'Seychelles', code: 'SC'},
{name: 'Sierra Leone', code: 'SL'},
{name: 'Singapore', code: 'SG'},
{name: 'Slovakia', code: 'SK'},
{name: 'Slovenia', code: 'SI'},
{name: 'Solomon Islands', code: 'SB'},
{name: 'Somalia', code: 'SO'},
{name: 'South Africa', code: 'ZA'},
{name: 'South Georgia and the South Sandwich Islands', code: 'GS'},
{name: 'Spain', code: 'ES'},
{name: 'Sri Lanka', code: 'LK'},
{name: 'Sudan', code: 'SD'},
{name: 'Suriname', code: 'SR'},
{name: 'Svalbard and Jan Mayen', code: 'SJ'},
{name: 'Swaziland', code: 'SZ'},
{name: 'Sweden', code: 'SE'},
{name: 'Switzerland', code: 'CH'},
{name: 'Syrian Arab Republic', code: 'SY'},
{name: 'Taiwan, Province of China', code: 'TW'},
{name: 'Tajikistan', code: 'TJ'},
{name: 'Tanzania, United Republic of', code: 'TZ'},
{name: 'Thailand', code: 'TH'},
{name: 'Timor-Leste', code: 'TL'},
{name: 'Togo', code: 'TG'},
{name: 'Tokelau', code: 'TK'},
{name: 'Tonga', code: 'TO'},
{name: 'Trinidad and Tobago', code: 'TT'},
{name: 'Tunisia', code: 'TN'},
{name: 'Turkey', code: 'TR'},
{name: 'Turkmenistan', code: 'TM'},
{name: 'Turks and Caicos Islands', code: 'TC'},
{name: 'Tuvalu', code: 'TV'},
{name: 'Uganda', code: 'UG'},
{name: 'Ukraine', code: 'UA'},
{name: 'United Arab Emirates', code: 'AE'},
{name: 'United Kingdom', code: 'GB'},
{name: 'United States', code: 'US'},
{name: 'United States Minor Outlying Islands', code: 'UM'},
{name: 'Uruguay', code: 'UY'},
{name: 'Uzbekistan', code: 'UZ'},
{name: 'Vanuatu', code: 'VU'},
{name: 'Venezuela', code: 'VE'},
{name: 'Vietnam', code: 'VN'},
{name: 'Virgin Islands, British', code: 'VG'},
{name: 'Virgin Islands, U.S.', code: 'VI'},
{name: 'Wallis and Futuna', code: 'WF'},
{name: 'Western Sahara', code: 'EH'},
{name: 'Yemen', code: 'YE'},
{name: 'Zambia', code: 'ZM'},
{name: 'Zimbabwe', code: 'ZW'}
];
});
/*
Taken from angular-ui/bootstrap
See https://github.com/angular-ui/bootstrap/blob/master/misc/demo/assets/demo.css
*/
body {
opacity: 1;
-webkit-transition: opacity 1s ease;
-moz-transition: opacity 1s ease;
transition: opacity 1s;
}
.ng-cloak {
opacity: 0;
}
.ng-invalid {
border: 1px solid red !important;
}
section {
padding-top: 30px;
}
.page-header h1 > small > a {
color: #999;
}
.page-header h1 > small > a:hover {
text-decoration: none;
}
.footer {
text-align: center;
padding: 30px 0;
margin-top: 70px;
border-top: 1px solid #e5e5e5;
background-color: #f5f5f5;
}
.bs-social {
margin-top: 20px;
margin-bottom: 20px;
text-align: center;
}
@media (min-width: 768px) {
.bs-social {
text-align: left;
}
}
.nav, .pagination, .carousel, .panel-title a {
cursor: pointer;
}
.bs-social-buttons {
display: inline-block;
margin-bottom: 0;
padding-left: 0;
list-style: none;
}
.bs-social-buttons li {
display: inline-block;
padding: 5px 8px;
line-height: 1;
}
@media (max-width: 767px) {
.visible-xs.collapse.in {
display: block !important;
}
.visible-xs.collapse {
display: none !important;
}
}
.navbar .collapse {
border-top: 1px solid #e7e7e7;
margin-left: -15px;
margin-right: -15px;
padding-right: 15px;
padding-left: 15px;
}
.show-grid {
margin-bottom: 15px;
}
/*
* Container
*
* Tweak to width of container.
*/
/*@media (min-width: 1200px) {
.container{
max-width: 970px;
}
}*/
/*
* Tabs
*
* Tweaks to the Tabs.
*/
.code .nav-tabs {
border-bottom: 1px solid #ccc;
}
.code pre, .code code {
border-top: none;
border-top-left-radius: 0;
border-top-right-radius: 0;
}
.code .nav-tabs > li.active > a, .code .nav-tabs > li.active > a:hover, .code .nav-tabs > li.active > a:focus {
background-color: #f8f8f8;
border: 1px solid #ccc;
border-bottom-color: transparent;
}
/*
* Button Inverse
*
* Buttons in the masthead.
*/
.btn-outline-inverse {
color: #fff;
background-color: transparent;
border-color: #cdbfe3;
margin: 10px;
}
@media (min-width: 768px) {
.btn-outline-inverse {
width: auto;
margin: 20px 5px 20px 0;
padding: 18px 24px;
font-size: 21px;
}
}
.btn-outline-inverse:hover, .btn-outline-inverse:focus, .btn-outline-inverse:active {
color: #563d7c;
text-shadow: none;
background-color: #fff;
border-color: #fff;
}
/* Page headers */
.bs-header {
padding: 30px 15px 40px; /* side padding builds on .container 15px, so 30px */
font-size: 16px;
text-align: center;
text-shadow: 0 1px 0 rgba(0,0,0,.15);
color: #cdbfe3;
background-color: #563d7c;
}
.bs-header a {
color: #fff;
font-weight: normal;
}
.bs-header h1 {
color: #fff;
}
.bs-header p {
font-weight: 200;
line-height: 1.4;
}
.bs-header .container {
position: relative;
}
@media (min-width: 768px) {
.bs-header {
font-size: 30px;
text-align: left;
}
.bs-header h1 {
font-size: 100px;
line-height: 1;
}
}
@media (min-width: 992px) {
.bs-header p {
margin-right: 25%;
}
}
.navbar-inner {
-webkit-box-shadow: 0 3px 3px rgba(0,0,0,0.175);
box-shadow: 0 3px 3px rgba(0,0,0,0.175);
}
/*
* Side navigation
*
* Scrollspy and affixed enhanced navigation to highlight sections and secondary
* sections of docs content.
*/
/* By default it's not affixed in mobile views, so undo that */
.bs-sidebar.affix {
position: static;
}
/* First level of nav */
.bs-sidenav {
margin-top: 30px;
margin-bottom: 30px;
padding-top: 10px;
padding-bottom: 10px;
text-shadow: 0 1px 0 #fff;
background-color: #f7f5fa;
border-radius: 5px;
}
/* All levels of nav */
.bs-sidebar .nav > li > a {
display: block;
color: #716b7a;
padding: 5px 20px;
}
.bs-sidebar .nav > li > a:hover,
.bs-sidebar .nav > li > a:focus {
text-decoration: none;
background-color: #e5e3e9;
border-right: 1px solid #dbd8e0;
}
.bs-sidebar .nav > .active > a,
.bs-sidebar .nav > .active:hover > a,
.bs-sidebar .nav > .active:focus > a {
font-weight: bold;
color: #563d7c;
background-color: transparent;
border-right: 1px solid #563d7c;
}
/* Nav: second level (shown on .active) */
.bs-sidebar .nav .nav {
display: none; /* Hide by default, but at >768px, show it */
margin-bottom: 8px;
}
.bs-sidebar .nav .nav > li > a {
padding-top: 3px;
padding-bottom: 3px;
padding-left: 30px;
font-size: 90%;
}
/* Show and affix the side nav when space allows it */
@media (min-width: 992px) {
.bs-sidebar .nav > .active > ul {
display: block;
}
/* Widen the fixed sidebar */
.bs-sidebar.affix,
.bs-sidebar.affix-bottom {
width: 213px;
}
.bs-sidebar.affix {
position: fixed; /* Undo the static from mobile first approach */
top: 80px;
}
.bs-sidebar.affix-bottom {
position: absolute; /* Undo the static from mobile first approach */
}
.bs-sidebar.affix-bottom .bs-sidenav,
.bs-sidebar.affix .bs-sidenav {
margin-top: 0;
margin-bottom: 0;
}
}
@media (min-width: 1200px) {
/* Widen the fixed sidebar again */
.bs-sidebar.affix-bottom,
.bs-sidebar.affix {
width: 263px;
}
}
/* Not enough room on mobile for markup tab, js tab, and plunk btn.
And no one cares about plunk button on a phone anyway */
@media only screen and (max-device-width: 480px) {
#plunk-btn {
display: none;
}
}
.navbar-nav .dropdown .navbar-brand {
max-width: 100%;
margin-right: inherit;
margin-left: inherit;
}
.header-placeholder {
height: 50px;
}
@media screen and (min-width: 768px) {
.dropdown.open > .navbar-brand + .dropdown-menu {
left: 10px;
}
.header-placeholder {
height: 50px;
}
.navbar-nav .dropdown .navbar-brand {
max-width: 200px;
margin-right: 5px;
margin-left: 10px;
}
}
angular.module('plunkr', [])
.factory('formPostData', ['$document', function ($document) {
return function (url, newWindow, fields) {
/**
* If the form posts to target="_blank", pop-up blockers can cause it not to work.
* If a user choses to bypass pop-up blocker one time and click the link, they will arrive at
* a new default plnkr, not a plnkr with the desired template. Given this undesired behavior,
* some may still want to open the plnk in a new window by opting-in via ctrl+click. The
* newWindow param allows for this possibility.
*/
var target = newWindow ? '_blank' : '_self';
var form = angular.element('<form style="display: none;" method="post" action="' + url + '" target="' + target + '"></form>');
angular.forEach(fields, function (value, name) {
var input = angular.element('<input type="hidden" name="' + name + '">');
input.attr('value', value);
form.append(input);
});
$document.find('body').append(form);
form[0].submit();
form.remove();
};
}])
.directive('plnkrOpener', ['$q', 'getExampleData', 'formPostData', function ($q, getExampleData, formPostData) {
return {
scope: {},
bindToController: {
'examplePath': '@'
},
controllerAs: 'plnkr',
template: '<button ng-click="plnkr.open($event)" class="btn btn-info btn-sm plunk-btn"> <i class="glyphicon glyphicon-edit">&nbsp;</i> Edit in Plunker</button> ',
controller: [function () {
var ctrl = this;
ctrl.prepareExampleData = function (examplePath) {
if (ctrl.prepared) {
return $q.when(ctrl.prepared);
} else {
return getExampleData(examplePath).then(function (data) {
ctrl.prepared = data;
});
}
};
ctrl.open = function (clickEvent) {
var newWindow = clickEvent.ctrlKey || clickEvent.metaKey;
var postData = {
'tags[0]': "angularjs",
'tags[1]': "ui-select",
'private': true
};
// Make sure the example data is available.
// If an XHR must be made, this might break some pop-up blockers when
// new window is requested
ctrl.prepareExampleData(ctrl.examplePath)
.then(function () {
angular.forEach(ctrl.prepared, function (file) {
postData['files[' + file.name + ']'] = file.content;
});
postData.description = "Angular ui-select http://github.com/angular-ui/ui-select/";
formPostData('http://plnkr.co/edit/?p=preview', newWindow, postData);
});
};
// Initialize the example data, so it's ready when clicking the open button.
// Otherwise pop-up blockers will prevent a new window from opening
ctrl.prepareExampleData(ctrl.examplePath);
}]
};
}])
.factory('getExampleData', ['$http', '$q', function ($http, $q) {
return function (exampleFile) {
// Load the manifest for the example
var defaultFiles = {
'demo.js': './assets/',
'select.css': './dist',
'select.js': './dist'
};
files = angular.copy(defaultFiles);
files[exampleFile] = './';
var filePromises = [];
angular.forEach(files, function (folder, filename) {
filePromises.push($http.get(folder + '/' + filename, { transformResponse: [], cache: true })
.then(function (response) {
var content = response.data;
// Should only be one html (the example)
if (filename.match(/.html$/)) {
filename = "index.html";
content = content.replace(/.\/assets\//g, './').replace(/.\/dist\//g, './');
}
return {
name: filename,
content: content
};
}));
});
return $q.all(filePromises);
};
}]);
<!DOCTYPE html>
<html lang="en" ng-app="ui.select.pages">
<head>
<meta charset="utf-8">
<title>AngularJS ui-select</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular-sanitize.js"></script>
<script src="./assets/app.js" type="text/javascript"></script>
<script src="./assets/plunkr.js" type="text/javascript"></script>
<!-- themes -->
<link rel="stylesheet" href="https://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.css">
<link rel="stylesheet" href="./assets/docs.css" />
</head>
<body>
<header class="navbar navbar-default navbar-fixed-top navbar-inner">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-3" ng-click="isCollapsed = !isCollapsed">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand visible-xs" href="#">UI Select</a>
</div>
<nav class="hidden-xs">
<ul class="nav navbar-nav">
<a href="#top" role="button" class="navbar-brand">
UI Select
</a>
<li><a href="#getting_started">Getting started</a></li>
<li><a href="#documenation">Documentation</a></li>
<li><a href="#examples">Examples</a></li>
<!--<li class="dropdown" uib-dropdown>
<a role="button" class="dropdown-toggle" uib-dropdown-toggle>
Previous docs <b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li ng-repeat="version in oldDocs">
<a ng-href="{{version.url}}">{{version.version}}</a>
</li>
</ul>
</li>-->
</ul>
</nav>
<nav class="visible-xs" uib-collapse="!isCollapsed">
<ul class="nav navbar-nav">
<li><a href="#getting_started" ng-click="isCollapsed = !isCollapsed">Getting started</a></li>
<li><a href="#directives_small" ng-click="isCollapsed = !isCollapsed">Directives</a></li>
</ul>
</nav>
</div>
</header>
<div class="header-placeholder"></div>
<div role="main">
<header class="bs-header text-center" id="overview">
<div class="container">
<h1>UI Select</h1>
<p>
A native <a href="http://angularjs.org">AngularJS</a> implementation of Select2/Selectize by the
<a href="http://angular-ui.github.io">AngularUI Team</a>
</p>
<p>
<a class="btn btn-outline-inverse btn-lg" href="https://github.com/angular-ui/ui-select"><i class="icon-github"></i>Code on Github</a>
<!--<button type="button" class="btn btn-outline-inverse btn-lg" ng-click="showDownloadModal()">
<i class="glyphicon glyphicon-download-alt"></i> Download <small>(<%= pkg.version%>)</small>
</button>-->
</p>
</div>
<div class="bs-social container">
<ul class="bs-social-buttons">
<li>
<iframe src="//ghbtns.com/github-btn.html?user=angular-ui&repo=ui-select&type=watch&count=true"
allowtransparency="true" frameborder="0" scrolling="0" width="110" height="20"></iframe>
</li>
<li>
<iframe src="//ghbtns.com/github-btn.html?user=angular-ui&repo=ui-select&type=fork&count=true"
allowtransparency="true" frameborder="0" scrolling="0" width="110" height="20"></iframe>
</li>
<li>
<a href="https://twitter.com/share" class="twitter-share-button"
data-hashtags="angularjs">Tweet</a>
<script>
!function (d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (!d.getElementById(id)) {
js = d.createElement(s);
js.id = id;
js.src = "//platform.twitter.com/widgets.js";
fjs.parentNode.insertBefore(js, fjs);
}
}(document, "script", "twitter-wjs");</script>
</li>
<li>
<!-- Place this tag where you want the +1 button to render. -->
<div class="g-plusone" data-size="medium"></div>
<!-- Place this tag after the last +1 button tag. -->
<script type="text/javascript">
(function () {
var po = document.createElement('script');
po.type = 'text/javascript';
po.async = true;
po.src = 'https://apis.google.com/js/plusone.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(po, s);
})();
</script>
</li>
</ul>
</div>
</header>
<div class="container">
<div class="row">
<div class="col-md-12">
<section id="getting_started">
<div class="page-header">
<h1>Getting started</h1>
</div>
<h3>Dependencies</h3>
<p>
This repository contains a <strong>native AngularJS</strong> select directive based on
Bootstrap/Select2/Selectize's CSS. As a result no dependency on jQuery or 3rd-Party
JavaScript is required. The only <strong>required</strong> dependencies are:
</p>
<ul>
<li>
<a href="http://angularjs.org" target="_blank">AngularJS</a> (requires AngularJS 1.2.x or higher, tested with 1.5.3).
</li>
<li>
<a href="http://angularjs.org" target="_blank">Angular-Sanitize</a> (the version should match your version of angular.js).
</li>
<li>
The matching CSS for your the theme you wish to use:
<ul>
<li>Bootstrap</li>
<li>Select2</li>
<li>Selectize</li>
</ul>
</li>
</ul>
<h3>Installation</h3>
<h4>Install via npm</h4>
<pre>$ npm install ui-select</pre>
<h4>Install via bower</h4>
<pre>$ bower install angular-ui-select</pre>
<p>
As soon as you've got all the files downloaded and included in your page you just need to declare
a dependency on the <code>ui.select</code> <a href="http://docs.angularjs.org/guide/module">module</a>:<br>
<pre><code>angular.module('myModule', ['ui.select', 'ngSanitize']);</code></pre>
</p>
</section>
<section id="documenation">
<div class="page-header">
<h1>Documentation</h1>
</div>
<h3>Wiki</h3>
For up to date information please refer to the <a href="https://github.com/angular-ui/ui-select/wiki" target="_blank">Wiki</a>
<h3>FAQ</h3>
<p>Please check <a href="https://github.com/angular-ui/ui-select/wiki/FAQs" target="_blank">our FAQ section</a> for common problems / solutions.</p>
</section>
<section id="examples">
<div class="page-header">
<h1>Examples</h1>
</div>
<p>You can fork one of the plunkers from this page to see a working example of what is described here.</p>
<!-- INSERT EXAMPLES HERE -->
</section>
</div>
</div>
</div><!-- /.container -->
</div><!-- /.main -->
<footer class="footer">
<div class="container">
<p>Designed and built by all ui-select <a href="https://github.com/angular-ui/ui-select/graphs/contributors" target="_blank">contributors</a>.</p>
<p>Code licensed under <a href="https://github.com/angular-ui/ui-select/blob/master/LICENSE">MIT License</a>.</p>
<p><a href="https://github.com/angular-ui/ui-select/issues?state=open">Issues</a></p>
</div>
</footer>
</body>
</html>
<!DOCTYPE html>
<html lang="en" ng-app="demo">
<head>
<meta charset="utf-8">
<title>AngularJS ui-select</title>
<!--
IE8 support, see AngularJS Internet Explorer Compatibility http://docs.angularjs.org/guide/ie
For Firefox 3.6, you will also need to include jQuery and ECMAScript 5 shim
-->
<!--[if lt IE 9]>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/es5-shim/2.2.0/es5-shim.js"></script>
<script>
document.createElement('ui-select');
document.createElement('ui-select-match');
document.createElement('ui-select-choices');
</script>
<![endif]-->
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular-sanitize.js"></script>
<!-- ui-select files -->
<script src="./dist/select.js"></script>
<link rel="stylesheet" href="./dist/select.css">
<script src="./assets/demo.js"></script>
<!-- themes -->
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.css">
<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/select2/3.4.5/select2.css">
<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/selectize.js/0.8.5/css/selectize.default.css">
<!-- <link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/selectize.js/0.8.5/css/selectize.bootstrap2.css"> -->
<!--<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/selectize.js/0.8.5/css/selectize.bootstrap3.css">-->
<style>
body {
padding: 15px;
}
.select2 > .select2-choice.ui-select-match {
/* Because of the inclusion of Bootstrap */
height: 29px;
}
.selectize-control > .selectize-dropdown {
top: 36px;
}
/* Some additional styling to demonstrate that append-to-body helps achieve the proper z-index layering. */
.select-box {
background: #fff;
position: relative;
z-index: 1;
}
.alert-info.positioned {
margin-top: 1em;
position: relative;
z-index: 10000; /* The select2 dropdown has a z-index of 9999 */
}
</style>
</head>
<body class="ng-cloak" ng-controller="DemoCtrl as ctrl">
require('./dist/select.js');
module.exports = 'ui.select';
0 info it worked if it ends with ok
1 verbose cli [ '/usr/local/bin/node',
1 verbose cli '/usr/local/bin/npm',
1 verbose cli 'unpublish',
1 verbose cli 'ui-select@0.19.5' ]
2 info using npm@2.14.4
3 info using node@v4.1.1
4 silly unpublish args[0] ui-select@0.19.5
5 silly unpublish thing Result {
5 silly unpublish raw: 'ui-select@0.19.5',
5 silly unpublish scope: null,
5 silly unpublish name: 'ui-select',
5 silly unpublish rawSpec: '0.19.5',
5 silly unpublish spec: '0.19.5',
5 silly unpublish type: 'version' }
6 verbose getPublishConfig null
7 silly ls normalized ui-select/0.19.5
8 silly gentlyRm /Users/arob35/.npm/ui-select/0.19.5 is being purged
9 verbose gentlyRm don't care about contents; nuking /Users/arob35/.npm/ui-select/0.19.5
10 silly vacuum-fs purging /Users/arob35/.npm/ui-select/0.19.5
11 silly vacuum-fs quitting because other entries in /Users/arob35/.npm/ui-select
12 silly mapToRegistry name ui-select
13 silly mapToRegistry using default registry
14 silly mapToRegistry registry https://registry.npmjs.org/
15 silly mapToRegistry uri https://registry.npmjs.org/ui-select
16 verbose get GET as part of write; not caching result
17 verbose request uri https://registry.npmjs.org/ui-select?write=true
18 verbose request no auth needed
19 info attempt registry request try #1 at 4:15:12 PM
20 verbose request using bearer token for auth
21 verbose request id 5ca39f33f3f44109
22 http request GET https://registry.npmjs.org/ui-select?write=true
23 http 200 https://registry.npmjs.org/ui-select?write=true
24 silly get cb [ 200,
24 silly get { server: 'CouchDB/1.6.1 (Erlang OTP/R16B03)',
24 silly get etag: '"3PFJ7OP67OCII47YIYGTYZUSW"',
24 silly get 'content-type': 'application/json',
24 silly get 'content-encoding': 'gzip',
24 silly get 'cache-control': 'max-age=0',
24 silly get 'transfer-encoding': 'chunked',
24 silly get 'accept-ranges': 'bytes',
24 silly get date: 'Mon, 24 Oct 2016 23:15:11 GMT',
24 silly get via: '1.1 varnish',
24 silly get connection: 'keep-alive',
24 silly get 'x-served-by': 'cache-den6025-DEN',
24 silly get 'x-cache': 'MISS',
24 silly get 'x-cache-hits': '0',
24 silly get 'x-timer': 'S1477350911.526110,VS0,VE239',
24 silly get vary: 'Accept-Encoding' } ]
25 verbose get saving ui-select to /Users/arob35/.npm/registry.npmjs.org/ui-select_3Fwrite_3Dtrue/.cache.json
26 verbose unpublish removing attachments { shasum: '95662d8e086ab7800553a9f11cf24523dcf8d7da',
26 verbose unpublish tarball: 'http://registry.npmjs.org/ui-select/-/ui-select-0.19.5.tgz' }
27 verbose request uri https://registry.npmjs.org/ui-select/-rev/33-46749c4a981bb9aba3d0bb0008a0117a
28 verbose request sending authorization for write operation
29 info attempt registry request try #1 at 4:15:12 PM
30 verbose request using bearer token for auth
31 http request PUT https://registry.npmjs.org/ui-select/-rev/33-46749c4a981bb9aba3d0bb0008a0117a
32 http 500 https://registry.npmjs.org/ui-select/-rev/33-46749c4a981bb9aba3d0bb0008a0117a
33 info retry will retry, error on last attempt: Error: "cannot unpublish a version that is >24 hours old" : ui-select
34 info attempt registry request try #2 at 4:15:24 PM
35 verbose request using bearer token for auth
36 http request PUT https://registry.npmjs.org/ui-select/-rev/33-46749c4a981bb9aba3d0bb0008a0117a
37 http 500 https://registry.npmjs.org/ui-select/-rev/33-46749c4a981bb9aba3d0bb0008a0117a
38 info retry will retry, error on last attempt: Error: "cannot unpublish a version that is >24 hours old" : ui-select
39 info attempt registry request try #3 at 4:16:25 PM
40 verbose request using bearer token for auth
41 http request PUT https://registry.npmjs.org/ui-select/-rev/33-46749c4a981bb9aba3d0bb0008a0117a
42 http 500 https://registry.npmjs.org/ui-select/-rev/33-46749c4a981bb9aba3d0bb0008a0117a
43 verbose headers { 'content-type': 'application/json',
43 verbose headers 'cache-control': 'max-age=0',
43 verbose headers 'content-length': '80',
43 verbose headers 'accept-ranges': 'bytes',
43 verbose headers date: 'Mon, 24 Oct 2016 23:16:25 GMT',
43 verbose headers via: '1.1 varnish',
43 verbose headers connection: 'keep-alive',
43 verbose headers 'x-served-by': 'cache-dfw1830-DFW',
43 verbose headers 'x-cache': 'MISS',
43 verbose headers 'x-cache-hits': '0',
43 verbose headers 'x-timer': 'S1477350984.944033,VS0,VE923' }
44 verbose request invalidating /Users/arob35/.npm/registry.npmjs.org/ui-select on PUT
45 error unpublish Failed to update data
46 verbose stack Error: "cannot unpublish a version that is >24 hours old" : ui-select
46 verbose stack at makeError (/usr/local/lib/node_modules/npm/node_modules/npm-registry-client/lib/request.js:263:12)
46 verbose stack at CachingRegistryClient.<anonymous> (/usr/local/lib/node_modules/npm/node_modules/npm-registry-client/lib/request.js:251:14)
46 verbose stack at Request._callback (/usr/local/lib/node_modules/npm/node_modules/npm-registry-client/lib/request.js:171:14)
46 verbose stack at Request.self.callback (/usr/local/lib/node_modules/npm/node_modules/request/request.js:198:22)
46 verbose stack at emitTwo (events.js:87:13)
46 verbose stack at Request.emit (events.js:172:7)
46 verbose stack at Request.<anonymous> (/usr/local/lib/node_modules/npm/node_modules/request/request.js:1073:14)
46 verbose stack at emitOne (events.js:82:20)
46 verbose stack at Request.emit (events.js:169:7)
46 verbose stack at IncomingMessage.<anonymous> (/usr/local/lib/node_modules/npm/node_modules/request/request.js:1019:12)
47 verbose statusCode 500
48 verbose pkgid ui-select
49 verbose cwd /Users/arob35/Sites/forks/ui-select
50 error Darwin 15.6.0
51 error argv "/usr/local/bin/node" "/usr/local/bin/npm" "unpublish" "ui-select@0.19.5"
52 error node v4.1.1
53 error npm v2.14.4
54 error code E500
55 error "cannot unpublish a version that is >24 hours old" : ui-select
56 error If you need help, you may report this error at:
56 error <https://github.com/npm/npm/issues>
57 verbose exit [ 1, true ]
{
"name": "ui-select",
"main": "./index.js",
"author": "http://github.com/angular-ui/ui-select/graphs/contributors",
"homepage": "http://github.com/angular-ui/ui-select",
"repository": {
"url": "git://github.com/angular-ui/ui-select.git"
},
"style": "dist/select.css",
"version": "0.19.6",
"devDependencies": {
"angular": "^1.2.18",
"angular-mocks": "^1.2.18",
"angular-sanitize": "^1.2.18",
"conventional-changelog": "^0.5.3",
"conventional-recommended-bump": "0.0.3",
"del": "~0.1.1",
"event-stream": "~3.1.0",
"gulp": "^3.9.1",
"gulp-angular-templatecache": "^1.8.0",
"gulp-bump": "^1.0.0",
"gulp-concat": "^2.6.0",
"gulp-conventional-changelog": "^0.7.0",
"gulp-filenames": "^2.0.0",
"gulp-footer": "^1.0.5",
"gulp-git": "^1.4.0",
"gulp-header": "^1.7.1",
"gulp-jshint": "^2.0.0",
"gulp-load-plugins": "^1.1.0",
"gulp-minify-css": "^1.2.4",
"gulp-minify-html": "^1.0.6",
"gulp-plumber": "^0.6.3",
"gulp-replace": "^0.5.4",
"gulp-sourcemaps": "^1.6.0",
"gulp-tag-version": "^1.3.0",
"gulp-uglify": "^1.5.3",
"gulp-util": "^2.2.19",
"jquery": "~1.11",
"jshint": "^2.9.1",
"jshint-stylish": "~0.3.0",
"karma": "^0.12.16",
"karma-chrome-launcher": "^0.1.3",
"karma-coverage": "~0.2",
"karma-firefox-launcher": "~0.1",
"karma-jasmine": "~0.2",
"karma-ng-html2js-preprocessor": "^0.1.0",
"karma-phantomjs-launcher": "~0.1.4",
"run-sequence": "^1.1.5",
"streamqueue": "^1.1.1",
"title-case": "^1.1.2"
},
"scripts": {
"test": "gulp test"
},
"spm": {
"main": "dist/select.js",
"output": [
"dist/select.css"
]
},
"license": "MIT"
}
{
"name": "angular",
"version": "1.6.3",
"license": "MIT",
"main": "./angular.js",
"ignore": [],
"dependencies": {},
"homepage": "https://github.com/angular/bower-angular",
"_release": "1.6.3",
"_resolution": {
"type": "version",
"tag": "v1.6.3",
"commit": "40d67030765b0024618d348d78be3e30f4f8f29b"
},
"_source": "https://github.com/angular/bower-angular.git",
"_target": ">=1.2.18",
"_originalSource": "angular"
}
\ No newline at end of file
The MIT License (MIT)
Copyright (c) 2016 Angular
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# packaged angular
This repo is for distribution on `npm` and `bower`. The source for this module is in the
[main AngularJS repo](https://github.com/angular/angular.js).
Please file issues and pull requests against that repo.
## Install
You can install this package either with `npm` or with `bower`.
### npm
```shell
npm install angular
```
Then add a `<script>` to your `index.html`:
```html
<script src="/node_modules/angular/angular.js"></script>
```
Or `require('angular')` from your code.
### bower
```shell
bower install angular
```
Then add a `<script>` to your `index.html`:
```html
<script src="/bower_components/angular/angular.js"></script>
```
## Documentation
Documentation is available on the
[AngularJS docs site](http://docs.angularjs.org/).
## License
The MIT License
Copyright (c) 2010-2015 Google, Inc. http://angularjs.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
/* Include this file in your html if you are using the CSP mode. */
@charset "UTF-8";
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak],
.ng-cloak, .x-ng-cloak,
.ng-hide:not(.ng-hide-animate) {
display: none !important;
}
ng\:form {
display: block;
}
.ng-animate-shim {
visibility:hidden;
}
.ng-anchor {
position:absolute;
}
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "angular",
"version": "1.6.3",
"license": "MIT",
"main": "./angular.js",
"ignore": [],
"dependencies": {
}
}
require('./angular');
module.exports = angular;
{
"name": "angular",
"version": "1.6.3",
"description": "HTML enhanced for web apps",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "https://github.com/angular/angular.js.git"
},
"keywords": [
"angular",
"framework",
"browser",
"client-side"
],
"author": "Angular Core Team <angular-core+npm@google.com>",
"license": "MIT",
"bugs": {
"url": "https://github.com/angular/angular.js/issues"
},
"homepage": "http://angularjs.org"
}
# Stage 0, "build-stage", based on Node.js, to build and compile Angular
FROM node:6.11.1 as build-stage
RUN DEBIAN_FRONTEND=noninteractive apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get -y dist-upgrade
# Installing supervisord
RUN apt-get install -y supervisor
ADD ./docker/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
RUN DEBIAN_FRONTEND=noninteractive apt-get -yq install net-tools nginx lsb-release
RUN rm -f /etc/nginx/fastcgi.conf /etc/nginx/fastcgi_params && \
rm -f /etc/nginx/snippets/fastcgi-php.conf /etc/nginx/snippets/snakeoil.conf \
rm -f /etc/nginx/sites-available/default \
rm -f /etc/nginx/sites-enabled/default
COPY /nginx/default.conf /etc/nginx/sites-available
COPY /nginx/default.conf /etc/nginx/sites-enabled
RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 0C49F3730359A14518585931BC711F9BA15703C6
RUN echo "deb http://repo.mongodb.org/apt/debian jessie/mongodb-org/3.4 main" | sudo tee /etc/apt/sources.list.d/mongodb-org-3.4.list
RUN apt-get update && apt-get -yq install mongodb-org && apt-get -yq install redis-server
RUN service mongod start --fork --logpath /var/log/mongod.log
# sudo ./mongodb/bin/mongodump --host localhost --port 27017 --db atlasvoyages-dev --out ./
# sudo ./mongodb/bin/mongodump --host localhost --port 27017 --db atlasvoyages-dev --gzip --archive=atlasvoyages-dev.archive
WORKDIR /atlasvoyages
COPY package*.json /atlasvoyages/
RUN npm install --unsafe-perm=true
RUN npm install --global grunt-cli
COPY ./ /atlasvoyages/
RUN mongorestore --host localhost --port 27017 --gzip --archive=atlasvoyages-dev.archive
RUN find ./node_modules -maxdepth 1 -name 'pine*' -type d \( ! -name . \) -exec bash -c "cd '{}' && npm i --unsafe-perm=true && grunt build:dist" \; \
find ./node_modules -maxdepth 1 -name 'hermes*' -type d \( ! -name . \) -exec bash -c "cd '{}' && npm i --unsafe-perm=true && grunt build:dist" \;
find ./node_modules -maxdepth 1 -name 'theme-atlasvoyages*' -type d \( ! -name . \) -exec bash -c "cd '{}' && npm i --unsafe-perm=true && grunt build:dist" \;
RUN echo '\n' | grunt pine:setup
RUN grunt pine:copy
# expose port 80 443
EXPOSE 80
EXPOSE 443
# USER postgres
ENTRYPOINT ["/usr/bin/supervisord"]
[supervisord]
nodaemon=true
[program:redis]
command=redis-server --daemonize yes
[program:mongodb]
command=service mongod start --fork --logpath /var/log/mongod.log
[program:nginx]
command=/etc/init.d/nginx start
[program:pine]
command=grunt pine:serve
{
"logdir":"./logs"
}
\ No newline at end of file
node_modules
npm-debug.log
tmp
{
"curly": true,
"eqeqeq": true,
"immed": true,
"latedef": true,
"newcap": true,
"noarg": true,
"sub": true,
"undef": true,
"boss": true,
"eqnull": true,
"node": true
}
/*
* grunt-sync-version
*
*
* Copyright (c) 2014 Reda Bendiar
* Licensed under the MIT license.
*/
'use strict';
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
jshint: {
all: [
'Gruntfile.js',
'tasks/*.js',
'<%= nodeunit.tests %>'
],
options: {
jshintrc: '.jshintrc'
}
},
// Before generating any new files, remove any previously-created files.
clean: {
tests: ['tmp']
},
// Configuration to be run (and then tested).
sync_version: {
default_options: {
options: {
},
files: {
'tmp/default_options': ['test/fixtures/testing', 'test/fixtures/123']
}
},
custom_options: {
options: {
separator: ': ',
punctuation: ' !!!'
},
files: {
'tmp/custom_options': ['test/fixtures/testing', 'test/fixtures/123']
}
}
},
// Unit tests.
nodeunit: {
tests: ['test/*_test.js']
}
});
// Actually load this plugin's task(s).
grunt.loadTasks('tasks');
// These plugins provide necessary tasks.
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-contrib-nodeunit');
// Whenever the "test" task is run, first clean the "tmp" dir, then run this
// plugin's task(s), then test the result.
grunt.registerTask('test', ['clean', 'sync_version', 'nodeunit']);
// By default, lint and run all tests.
grunt.registerTask('default', ['jshint', 'test']);
};
Copyright (c) 2014 Reda Bendiar
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
# grunt-sync-version
> The best Grunt plugin ever.
## Getting Started
This plugin requires Grunt `~0.4.5`
If you haven't used [Grunt](http://gruntjs.com/) before, be sure to check out the [Getting Started](http://gruntjs.com/getting-started) guide, as it explains how to create a [Gruntfile](http://gruntjs.com/sample-gruntfile) as well as install and use Grunt plugins. Once you're familiar with that process, you may install this plugin with this command:
```shell
npm install grunt-sync-version --save-dev
```
Once the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript:
```js
grunt.loadNpmTasks('grunt-sync-version');
```
## The "sync_version" task
### Overview
In your project's Gruntfile, add a section named `sync_version` to the data object passed into `grunt.initConfig()`.
```js
grunt.initConfig({
sync_version: {
options: {
// Task-specific options go here.
},
your_target: {
// Target-specific file lists and/or options go here.
},
},
});
```
### Options
#### options.separator
Type: `String`
Default value: `', '`
A string value that is used to do something with whatever.
#### options.punctuation
Type: `String`
Default value: `'.'`
A string value that is used to do something else with whatever else.
### Usage Examples
#### Default Options
In this example, the default options are used to do something with whatever. So if the `testing` file has the content `Testing` and the `123` file had the content `1 2 3`, the generated result would be `Testing, 1 2 3.`
```js
grunt.initConfig({
sync_version: {
options: {},
files: {
'dest/default_options': ['src/testing', 'src/123'],
},
},
});
```
#### Custom Options
In this example, custom options are used to do something else with whatever else. So if the `testing` file has the content `Testing` and the `123` file had the content `1 2 3`, the generated result in this case would be `Testing: 1 2 3 !!!`
```js
grunt.initConfig({
sync_version: {
options: {
separator: ': ',
punctuation: ' !!!',
},
files: {
'dest/default_options': ['src/testing', 'src/123'],
},
},
});
```
## Contributing
In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using [Grunt](http://gruntjs.com/).
## Release History
_(Nothing yet)_
{
"name": "grunt-sync-version",
"description": "The best Grunt plugin ever.",
"version": "0.1.0",
"homepage": "",
"author": {
"name": "Reda Bendiar",
"email": "rb@fractalite.com"
},
"repository": {
"type": "git",
"url": "git://labs.fractalite.com/pine/pine-server.git"
},
"bugs": {
"url": ""
},
"licenses": [
{
"type": "MIT",
"url": "/blob/master/LICENSE-MIT"
}
],
"engines": {
"node": ">= 0.8.0"
},
"scripts": {
"test": "grunt test"
},
"devDependencies": {
"grunt-contrib-jshint": "^0.9.2",
"grunt-contrib-clean": "^0.5.0",
"grunt-contrib-nodeunit": "^0.3.3",
"grunt": "~0.4.5"
},
"peerDependencies": {
"grunt": "~0.4.5"
},
"keywords": [
"gruntplugin"
]
}
\ No newline at end of file
/*
* grunt-sync-version
*
*
* Copyright (c) 2014 Reda Bendiar
* Licensed under the MIT license.
*/
'use strict';
module.exports = function(grunt) {
// Please see the Grunt documentation for more information regarding task
// creation: http://gruntjs.com/creating-tasks
grunt.registerMultiTask('sync_version', 'The best Grunt plugin ever.', function() {
// Merge task-specific and/or target-specific options with these defaults.
var options = this.options({
punctuation: '.',
separator: ', '
});
// Iterate over all specified file groups.
this.files.forEach(function(f) {
// Concat specified files.
var src = f.src.filter(function(filepath) {
// Warn on and remove invalid source files (if nonull was set).
if (!grunt.file.exists(filepath)) {
grunt.log.warn('Source file "' + filepath + '" not found.');
return false;
} else {
return true;
}
}).map(function(filepath) {
// Read file source.
return grunt.file.read(filepath);
}).join(grunt.util.normalizelf(options.separator));
// Handle options.
src += options.punctuation;
// Write the destination file.
grunt.file.write(f.dest, src);
// Print a success message.
grunt.log.writeln('File "' + f.dest + '" created.');
});
});
};
Testing: 1 2 3 !!!
\ No newline at end of file
Testing, 1 2 3.
\ No newline at end of file
1 2 3
\ No newline at end of file
Testing
\ No newline at end of file
'use strict';
var grunt = require('grunt');
/*
======== A Handy Little Nodeunit Reference ========
https://github.com/caolan/nodeunit
Test methods:
test.expect(numAssertions)
test.done()
Test assertions:
test.ok(value, [message])
test.equal(actual, expected, [message])
test.notEqual(actual, expected, [message])
test.deepEqual(actual, expected, [message])
test.notDeepEqual(actual, expected, [message])
test.strictEqual(actual, expected, [message])
test.notStrictEqual(actual, expected, [message])
test.throws(block, [error], [message])
test.doesNotThrow(block, [error], [message])
test.ifError(value)
*/
exports.sync_version = {
setUp: function(done) {
// setup here if necessary
done();
},
default_options: function(test) {
test.expect(1);
var actual = grunt.file.read('tmp/default_options');
var expected = grunt.file.read('test/expected/default_options');
test.equal(actual, expected, 'should describe what the default behavior is.');
test.done();
},
custom_options: function(test) {
test.expect(1);
var actual = grunt.file.read('tmp/custom_options');
var expected = grunt.file.read('test/expected/custom_options');
test.equal(actual, expected, 'should describe what the custom option(s) behavior is.');
test.done();
},
};
module.exports = function(grunt) {
// Please see the Grunt documentation for more information regarding task
// creation: http://gruntjs.com/creating-tasks
grunt.registerTask('pinedev', 'The best Grunt plugin ever.', function() {
var main = grunt.file.readJSON('./package.json');
grunt.log.writeln('main',main.dependencies)
grunt.file.expand('node_modules/*/package.json')
.map(function(filepath) {
return grunt.file.readJSON(filepath);
})
.filter(function(pkg) {
return (pkg.keywords && pkg.keywords.indexOf('pine') >= 0)
})
.forEach(function(pkg) {
main.dependencies[pkg.name] = '~' + pkg.version
}, {});
grunt.log.writeln('main',main.dependencies)
});
}
\ No newline at end of file
var pine = require("pine");
pine.start();
\ No newline at end of file
# NGINX CONF ATLAS VOYAGES
upstream node_atlasvoyage_de {
server unix:/Users/hotelia/nodejs/atlasvoyages.com/apps/atlas-voyages/http.sock;
}
server {
listen 80 default_server;
listen [::]:80 default_server;
set $public /Users/hotelia/nodejs/atlasvoyages.com/apps/atlas-voyages/public;
#access_log /Users/hotelia/atlasvoyages/pine-server-old/logs/atlas-voyages.access.log;
#error_log /Users/hotelia/atlasvoyages/pine-server-old/logs/atlas-voyages.error.log;
location / {
# Set this to your upstream module.
proxy_pass http://node_atlasvoyage_de;
proxy_read_timeout 40s;
proxy_send_timeout 20s;
proxy_connect_timeout 5s;
proxy_buffers 8 32k;
proxy_buffer_size 64k;
# Proxy headers.
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_set_header X-NginX-Proxy true;
# these for for socket
# proxy_set_header Upgrade $http_upgrade;
# proxy_set_header Connection "upgrade";
# proxy_cache_bypass $http_upgrade;
proxy_set_header Connection "";
proxy_http_version 1.1;
proxy_redirect off;
}
# Cache busting for scripts
location ~ ^/scripts/(.+)/\d+\.([^/]+)\.js$ {
alias $public/scripts/$1/$2.js;
add_header Vary Accept-Encoding;
#expires max;
}
# CSS and Javascript
location ~ ^/(robots.txt|sitemap.xml|favicon.ico|img/|css/|scripts/|assets/) {
root $public;
expires 24h;
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "atlasvoyages.com",
"version": "0.0.1",
"description": "Atlas Voyages, leader du voyage au Maroc: plus de 300 000 hôtels au Maroc et dans le monde, billets d'avion, voyages organisés, Omra, Club Med, croisières. Paiement en Dirhams.",
"main": "index.js",
"author": "Fractalite",
"license": "UNLICENSED",
"dependencies": {
"pine": "git+http://nabilelmahiri:_uLszKm2QvRcG_GCojPj@labs.atlasvoyages.com/pine/pine.git#0.3",
"pine-express": "git+http://nabilelmahiri:_uLszKm2QvRcG_GCojPj@labs.atlasvoyages.com/pine/pine-express.git#0.3-dev",
"pine-mongo": "git+http://nabilelmahiri:_uLszKm2QvRcG_GCojPj@labs.atlasvoyages.com/pine/pine-mongo.git#0.3",
"pine-blocks": "git+http://nabilelmahiri:_uLszKm2QvRcG_GCojPj@labs.atlasvoyages.com/pine/pine-blocks.git#0.3",
"pine-angular": "git+http://nabilelmahiri:_uLszKm2QvRcG_GCojPj@labs.atlasvoyages.com/pine/pine-angular.git#0.3",
"pine-access": "git+http://nabilelmahiri:_uLszKm2QvRcG_GCojPj@labs.atlasvoyages.com/pine/pine-access.git#0.3",
"pine-admin": "git+http://nabilelmahiri:_uLszKm2QvRcG_GCojPj@labs.atlasvoyages.com/pine/pine-admin.git#0.3",
"pine-urls": "git+http://nabilelmahiri:_uLszKm2QvRcG_GCojPj@labs.atlasvoyages.com/pine/pine-urls.git#0.3",
"pine-checkout": "git+http://nabilelmahiri:_uLszKm2QvRcG_GCojPj@labs.atlasvoyages.com/pine/pine-checkout.git#0.3",
"pine-analytics": "git+http://nabilelmahiri:_uLszKm2QvRcG_GCojPj@labs.atlasvoyages.com/pine/pine-analytics.git#0.3",
"pine-hermes": "git+http://nabilelmahiri:_uLszKm2QvRcG_GCojPj@labs.atlasvoyages.com/pine-hermes/pine-hermes.git#0.3",
"pine-hermes-air": "git+http://nabilelmahiri:_uLszKm2QvRcG_GCojPj@labs.atlasvoyages.com/pine-hermes/pine-hermes-air.git#0.3-baggage",
"pine-hermes-lodge": "git+http://nabilelmahiri:_uLszKm2QvRcG_GCojPj@labs.atlasvoyages.com/pine-hermes/pine-hermes-lodge.git#0.4-fix-hotel-dest",
"pine-payzone": "git+http://nabilelmahiri:_uLszKm2QvRcG_GCojPj@labs.atlasvoyages.com/pine/pine-payzone.git#0.3",
"pine-payments": "git+http://nabilelmahiri:_uLszKm2QvRcG_GCojPj@labs.atlasvoyages.com/pine/pine-payments.git#0.3",
"pine-i18n": "git+http://nabilelmahiri:_uLszKm2QvRcG_GCojPj@labs.atlasvoyages.com/pine/pine-i18n.git#0.3-newdev",
"pine-avi-extra": "git+http://nabilelmahiri:_uLszKm2QvRcG_GCojPj@labs.atlasvoyages.com/pine/pine-avi-extras.git#master",
"hermes-tour": "git+http://nabilelmahiri:_uLszKm2QvRcG_GCojPj@labs.atlasvoyages.com/tour/hermes-tour.git#v0.2",
"hermes-travel": "git+http://nabilelmahiri:_uLszKm2QvRcG_GCojPj@labs.atlasvoyages.com/pine/pine-travel.git#0.3-beta-v1",
"theme-atlasvoyages": "git+http://nabilelmahiri:_uLszKm2QvRcG_GCojPj@labs.atlasvoyages.com/pine/theme-atlasvoyages.git#0.3-beta-v1",
"pine-redis": "git+http://nabilelmahiri:_uLszKm2QvRcG_GCojPj@labs.atlasvoyages.com/pine/pine-redis.git#0.3-newdev",
"async": "^0.7.0",
"connect-redis": "1.4.7",
"extend": "~1.2.1",
"grunt-contrib-copy": "~0.5.0",
"grunt-newer": "~0.7.0",
"jayschema": "~0.2.7",
"q": "^1.1.2",
"request": "^2.55.0",
"simple-lru-cache": "^0.0.1",
"winston": "^0.7.2"
},
"devDependencies": {
"grunt": "~0.4.4",
"grunt-bump": "0.0.13",
"grunt-concurrent": "~0.5.0",
"grunt-contrib-watch": "~0.6.1",
"grunt-exit": "~1.0.0",
"grunt-nodemon": "~0.3.0",
"grunt-prompt": "^1.3.0",
"grunt-shell": "~0.7.0",
"handlebars": "^2.0.0",
"load-grunt-tasks": "~0.3.0",
"nginx-conf": "~0.2.3",
"parent-require": "~1.0.0"
}
}
\ No newline at end of file
#!/bin/sh
docker ps -a | grep Exit | cut -d ' ' -f 1 | xargs --no-run-if-empty docker rm
docker image prune -f
\ No newline at end of file
#!/bin/sh
docker stop atlasvoyages-docker-prod
docker rm atlasvoyages-docker-prod
docker ps -a | awk '{ print $1,$2 }' | grep atlasvoyages:prod | awk '{print $1 }' | xargs -I {} docker rm --force {}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment