Commit 40fbec4fb9bbfc06185afe1b90f6fe4074e23c5c
1 parent
4ec6a915
update
Showing
19 changed files
with
3407 additions
and
184 deletions
src/main/resources/static/assets/bower_components/angular-ui-select/.bower.json
0 → 100644
| 1 | +{ | |
| 2 | + "name": "ui-select", | |
| 3 | + "version": "0.13.2", | |
| 4 | + "homepage": "https://github.com/angular-ui/ui-select", | |
| 5 | + "authors": [ | |
| 6 | + "AngularUI" | |
| 7 | + ], | |
| 8 | + "description": "AngularJS ui-select", | |
| 9 | + "main": [ | |
| 10 | + "dist/select.js", | |
| 11 | + "dist/select.css" | |
| 12 | + ], | |
| 13 | + "license": "MIT", | |
| 14 | + "ignore": [ | |
| 15 | + "**/.*", | |
| 16 | + "node_modules", | |
| 17 | + "bower_components", | |
| 18 | + "src", | |
| 19 | + "test", | |
| 20 | + "gulpfile.js", | |
| 21 | + "karma.conf.js", | |
| 22 | + "examples" | |
| 23 | + ], | |
| 24 | + "dependencies": { | |
| 25 | + "angular": ">=1.2.18" | |
| 26 | + }, | |
| 27 | + "devDependencies": { | |
| 28 | + "jquery": "~1.11", | |
| 29 | + "angular-sanitize": ">=1.2.18", | |
| 30 | + "angular-mocks": ">=1.2.18" | |
| 31 | + }, | |
| 32 | + "_release": "0.13.2", | |
| 33 | + "_resolution": { | |
| 34 | + "type": "version", | |
| 35 | + "tag": "v0.13.2", | |
| 36 | + "commit": "e507f2fa3d821270f6c862f221c3e33379d1f74e" | |
| 37 | + }, | |
| 38 | + "_source": "https://github.com/angular-ui/ui-select.git", | |
| 39 | + "_target": "0.13.2", | |
| 40 | + "_originalSource": "angular-ui-select" | |
| 41 | +} | |
| 0 | 42 | \ No newline at end of file | ... | ... |
src/main/resources/static/assets/bower_components/angular-ui-select/CHANGELOG.md
0 → 100644
| 1 | +# Change Log | |
| 2 | +All notable changes to this project will be documented in this file. | |
| 3 | + | |
| 4 | +## [v0.13.1][v0.13.1] (2015-09-29) | |
| 5 | +### Fixed | |
| 6 | +- Remove hardcoded source name when using (key,value) syntax [#1217](https://github.com/angular-ui/ui-select/pull/1217) | |
| 7 | +- Modify regex to accept a full 'collection expression' when not using (key,value) syntax [#1216](https://github.com/angular-ui/ui-select/pull/1216) | |
| 8 | +- Avoid to recalculate position when set 'down' [#1214](https://github.com/angular-ui/ui-select/issues/1214#issuecomment-144271352) | |
| 9 | + | |
| 10 | +## [v0.13.0][v0.13.0] (2015-09-29) | |
| 11 | +### Added | |
| 12 | +- Allow to configure default dropdown position [#1213](https://github.com/angular-ui/ui-select/pull/1213) | |
| 13 | +- Can use object as source with (key,value) syntax [#1208](https://github.com/angular-ui/ui-select/pull/1208) | |
| 14 | +- CHANGELOG.md file created | |
| 15 | + | |
| 16 | +### Changed | |
| 17 | +- Do not run bower after install automatically [#982](https://github.com/angular-ui/ui-select/pull/982) | |
| 18 | +- Avoid setting activeItem on mouseenter to improve performance [#1211](https://github.com/angular-ui/ui-select/pull/1211) | |
| 19 | + | |
| 20 | +### Fixed | |
| 21 | +- Position dropdown UP or DOWN correctly depending on the available space [#1212](https://github.com/angular-ui/ui-select/pull/1212) | |
| 22 | +- Scroll to selected item [#976](https://github.com/angular-ui/ui-select/issues/976) | |
| 23 | +- Change `autocomplete='off'` to `autocomplete='false'` [#1210](https://github.com/angular-ui/ui-select/pull/1210) | |
| 24 | +- Fix to work correctly with debugInfoEnabled(false) [#1131](https://github.com/angular-ui/ui-select/pull/1131) | |
| 25 | +- Limit the maximum number of selections allowed in multiple mode [#1110](https://github.com/angular-ui/ui-select/pull/1110) | |
| 26 | + | |
| 27 | +[v0.13.1]: https://github.com/angular-ui/ui-select/compare/v0.13.0...v0.13.1 | |
| 28 | +[v0.13.0]: https://github.com/angular-ui/ui-select/compare/v0.12.1...v0.13.0 | ... | ... |
src/main/resources/static/assets/bower_components/angular-ui-select/LICENSE
0 → 100644
| 1 | +The MIT License (MIT) | |
| 2 | + | |
| 3 | +Copyright (c) 2013-2014 AngularUI | |
| 4 | + | |
| 5 | +Permission is hereby granted, free of charge, to any person obtaining a copy of | |
| 6 | +this software and associated documentation files (the "Software"), to deal in | |
| 7 | +the Software without restriction, including without limitation the rights to | |
| 8 | +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of | |
| 9 | +the Software, and to permit persons to whom the Software is furnished to do so, | |
| 10 | +subject to the following conditions: | |
| 11 | + | |
| 12 | +The above copyright notice and this permission notice shall be included in all | |
| 13 | +copies or substantial portions of the Software. | |
| 14 | + | |
| 15 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 16 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS | |
| 17 | +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | |
| 18 | +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | |
| 19 | +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
| 20 | +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ... | ... |
src/main/resources/static/assets/bower_components/angular-ui-select/README.md
0 → 100644
| 1 | +# AngularJS ui-select [](https://travis-ci.org/angular-ui/ui-select) | |
| 2 | + | |
| 3 | +[](https://gitter.im/angular-ui/ui-select?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) | |
| 4 | + | |
| 5 | +AngularJS-native version of [Select2](http://ivaynberg.github.io/select2/) and [Selectize](http://brianreavis.github.io/selectize.js/). | |
| 6 | + | |
| 7 | +- [Demo](http://plnkr.co/edit/a3KlK8dKH3wwiiksDSn2?p=preview) | |
| 8 | +- [Demo Multiselect](http://plnkr.co/edit/juqoNOt1z1Gb349XabQ2?p=preview) | |
| 9 | +- [Examples](https://github.com/angular-ui/ui-select/blob/master/examples) | |
| 10 | +- [Documentation](https://github.com/angular-ui/ui-select/wiki) | |
| 11 | + | |
| 12 | +## Last Changes | |
| 13 | + | |
| 14 | +- Check [CHANGELOG.md](/CHANGELOG.md) | |
| 15 | + | |
| 16 | +## Features | |
| 17 | + | |
| 18 | +- Search, Select, and Multi-select | |
| 19 | +- Themes: Bootstrap, Select2 and Selectize | |
| 20 | +- Keyboard support | |
| 21 | +- jQuery not required (except for old browsers) | |
| 22 | +- Small code base: 4.57KB min/gzipped vs 20KB for select2 | |
| 23 | + | |
| 24 | +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). | |
| 25 | + | |
| 26 | + | |
| 27 | +## Development | |
| 28 | + | |
| 29 | +### Prepare your environment | |
| 30 | +* Install [Node.js](http://nodejs.org/) and NPM (should come with) | |
| 31 | +* Install global dev dependencies: `npm install -g bower gulp` | |
| 32 | +* Install local dev dependencies: `npm install && bower install` in repository directory | |
| 33 | + | |
| 34 | +### Development Commands | |
| 35 | + | |
| 36 | +* `gulp` to jshint, build and test | |
| 37 | +* `gulp build` to jshint and build | |
| 38 | +* `gulp test` for one-time test with karma (also build and jshint) | |
| 39 | +* `gulp watch` to watch src files to jshin, build and test when changed | |
| 40 | + | |
| 41 | +## Contributing | |
| 42 | + | |
| 43 | +- Run the tests | |
| 44 | +- Try the [examples](https://github.com/angular-ui/ui-select/blob/master/examples) | |
| 45 | + | |
| 46 | +When issuing a pull request, please exclude changes from the "dist" folder to avoid merge conflicts. | ... | ... |
src/main/resources/static/assets/bower_components/angular-ui-select/bower.json
0 → 100644
| 1 | +{ | |
| 2 | + "name": "ui-select", | |
| 3 | + "version": "0.13.2", | |
| 4 | + "homepage": "https://github.com/angular-ui/ui-select", | |
| 5 | + "authors": [ | |
| 6 | + "AngularUI" | |
| 7 | + ], | |
| 8 | + "description": "AngularJS ui-select", | |
| 9 | + "main": ["dist/select.js", "dist/select.css"], | |
| 10 | + "license": "MIT", | |
| 11 | + "ignore": [ | |
| 12 | + "**/.*", | |
| 13 | + "node_modules", | |
| 14 | + "bower_components", | |
| 15 | + "src", | |
| 16 | + "test", | |
| 17 | + "gulpfile.js", | |
| 18 | + "karma.conf.js", | |
| 19 | + "examples" | |
| 20 | + ], | |
| 21 | + "dependencies": { | |
| 22 | + "angular": ">=1.2.18" | |
| 23 | + }, | |
| 24 | + "devDependencies": { | |
| 25 | + "jquery": "~1.11", | |
| 26 | + "angular-sanitize": ">=1.2.18", | |
| 27 | + "angular-mocks": ">=1.2.18" | |
| 28 | + } | |
| 29 | +} | ... | ... |
src/main/resources/static/assets/bower_components/angular-ui-select/dist/select.css
0 → 100644
| 1 | +/*! | |
| 2 | + * ui-select | |
| 3 | + * http://github.com/angular-ui/ui-select | |
| 4 | + * Version: 0.13.2 - 2015-10-09T15:34:24.045Z | |
| 5 | + * License: MIT | |
| 6 | + */ | |
| 7 | + | |
| 8 | + | |
| 9 | +/* Style when highlighting a search. */ | |
| 10 | +.ui-select-highlight { | |
| 11 | + font-weight: bold; | |
| 12 | +} | |
| 13 | + | |
| 14 | +.ui-select-offscreen { | |
| 15 | + clip: rect(0 0 0 0) !important; | |
| 16 | + width: 1px !important; | |
| 17 | + height: 1px !important; | |
| 18 | + border: 0 !important; | |
| 19 | + margin: 0 !important; | |
| 20 | + padding: 0 !important; | |
| 21 | + overflow: hidden !important; | |
| 22 | + position: absolute !important; | |
| 23 | + outline: 0 !important; | |
| 24 | + left: 0px !important; | |
| 25 | + top: 0px !important; | |
| 26 | +} | |
| 27 | + | |
| 28 | + | |
| 29 | +.ui-select-choices-row:hover { | |
| 30 | + background-color: #f5f5f5; | |
| 31 | +} | |
| 32 | + | |
| 33 | +/* Select2 theme */ | |
| 34 | + | |
| 35 | +/* Mark invalid Select2 */ | |
| 36 | +.ng-dirty.ng-invalid > a.select2-choice { | |
| 37 | + border-color: #D44950; | |
| 38 | +} | |
| 39 | + | |
| 40 | +.select2-result-single { | |
| 41 | + padding-left: 0; | |
| 42 | +} | |
| 43 | + | |
| 44 | +.select2-locked > .select2-search-choice-close{ | |
| 45 | + display:none; | |
| 46 | +} | |
| 47 | + | |
| 48 | +.select-locked > .ui-select-match-close{ | |
| 49 | + display:none; | |
| 50 | +} | |
| 51 | + | |
| 52 | +body > .select2-container.open { | |
| 53 | + z-index: 9999; /* The z-index Select2 applies to the select2-drop */ | |
| 54 | +} | |
| 55 | + | |
| 56 | +/* Handle up direction Select2 */ | |
| 57 | +.ui-select-container[theme="select2"].direction-up .ui-select-match { | |
| 58 | + border-radius: 4px; /* FIXME hardcoded value :-/ */ | |
| 59 | + border-top-left-radius: 0; | |
| 60 | + border-top-right-radius: 0; | |
| 61 | +} | |
| 62 | +.ui-select-container[theme="select2"].direction-up .ui-select-dropdown { | |
| 63 | + border-radius: 4px; /* FIXME hardcoded value :-/ */ | |
| 64 | + border-bottom-left-radius: 0; | |
| 65 | + border-bottom-right-radius: 0; | |
| 66 | + | |
| 67 | + border-top-width: 1px; /* FIXME hardcoded value :-/ */ | |
| 68 | + border-top-style: solid; | |
| 69 | + | |
| 70 | + box-shadow: 0 -4px 8px rgba(0, 0, 0, 0.25); | |
| 71 | + | |
| 72 | + margin-top: -4px; /* FIXME hardcoded value :-/ */ | |
| 73 | +} | |
| 74 | +.ui-select-container[theme="select2"].direction-up .ui-select-dropdown .select2-search { | |
| 75 | + margin-top: 4px; /* FIXME hardcoded value :-/ */ | |
| 76 | +} | |
| 77 | +.ui-select-container[theme="select2"].direction-up.select2-dropdown-open .ui-select-match { | |
| 78 | + border-bottom-color: #5897fb; | |
| 79 | +} | |
| 80 | + | |
| 81 | +/* Selectize theme */ | |
| 82 | + | |
| 83 | +/* Helper class to show styles when focus */ | |
| 84 | +.selectize-input.selectize-focus{ | |
| 85 | + border-color: #007FBB !important; | |
| 86 | +} | |
| 87 | + | |
| 88 | +/* Fix input width for Selectize theme */ | |
| 89 | +.selectize-control > .selectize-input > input { | |
| 90 | + width: 100%; | |
| 91 | +} | |
| 92 | + | |
| 93 | +/* Fix dropdown width for Selectize theme */ | |
| 94 | +.selectize-control > .selectize-dropdown { | |
| 95 | + width: 100%; | |
| 96 | +} | |
| 97 | + | |
| 98 | +/* Mark invalid Selectize */ | |
| 99 | +.ng-dirty.ng-invalid > div.selectize-input { | |
| 100 | + border-color: #D44950; | |
| 101 | +} | |
| 102 | + | |
| 103 | +/* Handle up direction Selectize */ | |
| 104 | +.ui-select-container[theme="selectize"].direction-up .ui-select-dropdown { | |
| 105 | + box-shadow: 0 -4px 8px rgba(0, 0, 0, 0.25); | |
| 106 | + | |
| 107 | + margin-top: -2px; /* FIXME hardcoded value :-/ */ | |
| 108 | +} | |
| 109 | + | |
| 110 | +/* Bootstrap theme */ | |
| 111 | + | |
| 112 | +/* Helper class to show styles when focus */ | |
| 113 | +.btn-default-focus { | |
| 114 | + color: #333; | |
| 115 | + background-color: #EBEBEB; | |
| 116 | + border-color: #ADADAD; | |
| 117 | + text-decoration: none; | |
| 118 | + outline: 5px auto -webkit-focus-ring-color; | |
| 119 | + outline-offset: -2px; | |
| 120 | + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6); | |
| 121 | +} | |
| 122 | + | |
| 123 | +.ui-select-bootstrap .ui-select-toggle { | |
| 124 | + position: relative; | |
| 125 | +} | |
| 126 | + | |
| 127 | +.ui-select-bootstrap .ui-select-toggle > .caret { | |
| 128 | + position: absolute; | |
| 129 | + height: 10px; | |
| 130 | + top: 50%; | |
| 131 | + right: 10px; | |
| 132 | + margin-top: -2px; | |
| 133 | +} | |
| 134 | + | |
| 135 | +/* Fix Bootstrap dropdown position when inside a input-group */ | |
| 136 | +.input-group > .ui-select-bootstrap.dropdown { | |
| 137 | + /* Instead of relative */ | |
| 138 | + position: static; | |
| 139 | +} | |
| 140 | + | |
| 141 | +.input-group > .ui-select-bootstrap > input.ui-select-search.form-control { | |
| 142 | + border-radius: 4px; /* FIXME hardcoded value :-/ */ | |
| 143 | + border-top-right-radius: 0; | |
| 144 | + border-bottom-right-radius: 0; | |
| 145 | +} | |
| 146 | +.input-group > .ui-select-bootstrap > input.ui-select-search.form-control.direction-up { | |
| 147 | + border-radius: 4px !important; /* FIXME hardcoded value :-/ */ | |
| 148 | + border-top-right-radius: 0 !important; | |
| 149 | + border-bottom-right-radius: 0 !important; | |
| 150 | +} | |
| 151 | + | |
| 152 | +.ui-select-bootstrap > .ui-select-match > .btn{ | |
| 153 | + /* Instead of center because of .btn */ | |
| 154 | + text-align: left !important; | |
| 155 | +} | |
| 156 | + | |
| 157 | +.ui-select-bootstrap > .ui-select-match > .caret { | |
| 158 | + position: absolute; | |
| 159 | + top: 45%; | |
| 160 | + right: 15px; | |
| 161 | +} | |
| 162 | + | |
| 163 | +/* See Scrollable Menu with Bootstrap 3 http://stackoverflow.com/questions/19227496 */ | |
| 164 | +.ui-select-bootstrap > .ui-select-choices { | |
| 165 | + width: 100%; | |
| 166 | + height: auto; | |
| 167 | + max-height: 200px; | |
| 168 | + overflow-x: hidden; | |
| 169 | + margin-top: -1px; | |
| 170 | +} | |
| 171 | + | |
| 172 | +body > .ui-select-bootstrap.open { | |
| 173 | + z-index: 1000; /* Standard Bootstrap dropdown z-index */ | |
| 174 | +} | |
| 175 | + | |
| 176 | +.ui-select-multiple.ui-select-bootstrap { | |
| 177 | + height: auto; | |
| 178 | + padding: 3px 3px 0 3px; | |
| 179 | +} | |
| 180 | + | |
| 181 | +.ui-select-multiple.ui-select-bootstrap input.ui-select-search { | |
| 182 | + background-color: transparent !important; /* To prevent double background when disabled */ | |
| 183 | + border: none; | |
| 184 | + outline: none; | |
| 185 | + height: 1.666666em; | |
| 186 | + margin-bottom: 3px; | |
| 187 | +} | |
| 188 | + | |
| 189 | +.ui-select-multiple.ui-select-bootstrap .ui-select-match .close { | |
| 190 | + font-size: 1.6em; | |
| 191 | + line-height: 0.75; | |
| 192 | +} | |
| 193 | + | |
| 194 | +.ui-select-multiple.ui-select-bootstrap .ui-select-match-item { | |
| 195 | + outline: 0; | |
| 196 | + margin: 0 3px 3px 0; | |
| 197 | +} | |
| 198 | + | |
| 199 | +.ui-select-multiple .ui-select-match-item { | |
| 200 | + position: relative; | |
| 201 | +} | |
| 202 | + | |
| 203 | +.ui-select-multiple .ui-select-match-item.dropping-before:before { | |
| 204 | + content: ""; | |
| 205 | + position: absolute; | |
| 206 | + top: 0; | |
| 207 | + right: 100%; | |
| 208 | + height: 100%; | |
| 209 | + margin-right: 2px; | |
| 210 | + border-left: 1px solid #428bca; | |
| 211 | +} | |
| 212 | + | |
| 213 | +.ui-select-multiple .ui-select-match-item.dropping-after:after { | |
| 214 | + content: ""; | |
| 215 | + position: absolute; | |
| 216 | + top: 0; | |
| 217 | + left: 100%; | |
| 218 | + height: 100%; | |
| 219 | + margin-left: 2px; | |
| 220 | + border-right: 1px solid #428bca; | |
| 221 | +} | |
| 222 | + | |
| 223 | +.ui-select-bootstrap .ui-select-choices-row>a { | |
| 224 | + display: block; | |
| 225 | + padding: 3px 20px; | |
| 226 | + clear: both; | |
| 227 | + font-weight: 400; | |
| 228 | + line-height: 1.42857143; | |
| 229 | + color: #333; | |
| 230 | + white-space: nowrap; | |
| 231 | +} | |
| 232 | + | |
| 233 | +.ui-select-bootstrap .ui-select-choices-row>a:hover, .ui-select-bootstrap .ui-select-choices-row>a:focus { | |
| 234 | + text-decoration: none; | |
| 235 | + color: #262626; | |
| 236 | + background-color: #f5f5f5; | |
| 237 | +} | |
| 238 | + | |
| 239 | +.ui-select-bootstrap .ui-select-choices-row.active>a { | |
| 240 | + color: #fff; | |
| 241 | + text-decoration: none; | |
| 242 | + outline: 0; | |
| 243 | + background-color: #428bca; | |
| 244 | +} | |
| 245 | + | |
| 246 | +.ui-select-bootstrap .ui-select-choices-row.disabled>a, | |
| 247 | +.ui-select-bootstrap .ui-select-choices-row.active.disabled>a { | |
| 248 | + color: #777; | |
| 249 | + cursor: not-allowed; | |
| 250 | + background-color: #fff; | |
| 251 | +} | |
| 252 | + | |
| 253 | +/* fix hide/show angular animation */ | |
| 254 | +.ui-select-match.ng-hide-add, | |
| 255 | +.ui-select-search.ng-hide-add { | |
| 256 | + display: none !important; | |
| 257 | +} | |
| 258 | + | |
| 259 | +/* Mark invalid Bootstrap */ | |
| 260 | +.ui-select-bootstrap.ng-dirty.ng-invalid > button.btn.ui-select-match { | |
| 261 | + border-color: #D44950; | |
| 262 | +} | |
| 263 | + | |
| 264 | +/* Handle up direction Bootstrap */ | |
| 265 | +.ui-select-container[theme="bootstrap"].direction-up .ui-select-dropdown { | |
| 266 | + box-shadow: 0 -4px 8px rgba(0, 0, 0, 0.25); | |
| 267 | +} | ... | ... |
src/main/resources/static/assets/bower_components/angular-ui-select/dist/select.js
0 → 100644
| 1 | +/*! | |
| 2 | + * ui-select | |
| 3 | + * http://github.com/angular-ui/ui-select | |
| 4 | + * Version: 0.13.2 - 2015-10-09T15:34:24.040Z | |
| 5 | + * License: MIT | |
| 6 | + */ | |
| 7 | + | |
| 8 | + | |
| 9 | +(function () { | |
| 10 | +"use strict"; | |
| 11 | + | |
| 12 | +var KEY = { | |
| 13 | + TAB: 9, | |
| 14 | + ENTER: 13, | |
| 15 | + ESC: 27, | |
| 16 | + SPACE: 32, | |
| 17 | + LEFT: 37, | |
| 18 | + UP: 38, | |
| 19 | + RIGHT: 39, | |
| 20 | + DOWN: 40, | |
| 21 | + SHIFT: 16, | |
| 22 | + CTRL: 17, | |
| 23 | + ALT: 18, | |
| 24 | + PAGE_UP: 33, | |
| 25 | + PAGE_DOWN: 34, | |
| 26 | + HOME: 36, | |
| 27 | + END: 35, | |
| 28 | + BACKSPACE: 8, | |
| 29 | + DELETE: 46, | |
| 30 | + COMMAND: 91, | |
| 31 | + | |
| 32 | + MAP: { 91 : "COMMAND", 8 : "BACKSPACE" , 9 : "TAB" , 13 : "ENTER" , 16 : "SHIFT" , 17 : "CTRL" , 18 : "ALT" , 19 : "PAUSEBREAK" , 20 : "CAPSLOCK" , 27 : "ESC" , 32 : "SPACE" , 33 : "PAGE_UP", 34 : "PAGE_DOWN" , 35 : "END" , 36 : "HOME" , 37 : "LEFT" , 38 : "UP" , 39 : "RIGHT" , 40 : "DOWN" , 43 : "+" , 44 : "PRINTSCREEN" , 45 : "INSERT" , 46 : "DELETE", 48 : "0" , 49 : "1" , 50 : "2" , 51 : "3" , 52 : "4" , 53 : "5" , 54 : "6" , 55 : "7" , 56 : "8" , 57 : "9" , 59 : ";", 61 : "=" , 65 : "A" , 66 : "B" , 67 : "C" , 68 : "D" , 69 : "E" , 70 : "F" , 71 : "G" , 72 : "H" , 73 : "I" , 74 : "J" , 75 : "K" , 76 : "L", 77 : "M" , 78 : "N" , 79 : "O" , 80 : "P" , 81 : "Q" , 82 : "R" , 83 : "S" , 84 : "T" , 85 : "U" , 86 : "V" , 87 : "W" , 88 : "X" , 89 : "Y" , 90 : "Z", 96 : "0" , 97 : "1" , 98 : "2" , 99 : "3" , 100 : "4" , 101 : "5" , 102 : "6" , 103 : "7" , 104 : "8" , 105 : "9", 106 : "*" , 107 : "+" , 109 : "-" , 110 : "." , 111 : "/", 112 : "F1" , 113 : "F2" , 114 : "F3" , 115 : "F4" , 116 : "F5" , 117 : "F6" , 118 : "F7" , 119 : "F8" , 120 : "F9" , 121 : "F10" , 122 : "F11" , 123 : "F12", 144 : "NUMLOCK" , 145 : "SCROLLLOCK" , 186 : ";" , 187 : "=" , 188 : "," , 189 : "-" , 190 : "." , 191 : "/" , 192 : "`" , 219 : "[" , 220 : "\\" , 221 : "]" , 222 : "'" | |
| 33 | + }, | |
| 34 | + | |
| 35 | + isControl: function (e) { | |
| 36 | + var k = e.which; | |
| 37 | + switch (k) { | |
| 38 | + case KEY.COMMAND: | |
| 39 | + case KEY.SHIFT: | |
| 40 | + case KEY.CTRL: | |
| 41 | + case KEY.ALT: | |
| 42 | + return true; | |
| 43 | + } | |
| 44 | + | |
| 45 | + if (e.metaKey) return true; | |
| 46 | + | |
| 47 | + return false; | |
| 48 | + }, | |
| 49 | + isFunctionKey: function (k) { | |
| 50 | + k = k.which ? k.which : k; | |
| 51 | + return k >= 112 && k <= 123; | |
| 52 | + }, | |
| 53 | + isVerticalMovement: function (k){ | |
| 54 | + return ~[KEY.UP, KEY.DOWN].indexOf(k); | |
| 55 | + }, | |
| 56 | + isHorizontalMovement: function (k){ | |
| 57 | + return ~[KEY.LEFT,KEY.RIGHT,KEY.BACKSPACE,KEY.DELETE].indexOf(k); | |
| 58 | + } | |
| 59 | + }; | |
| 60 | + | |
| 61 | +/** | |
| 62 | + * Add querySelectorAll() to jqLite. | |
| 63 | + * | |
| 64 | + * jqLite find() is limited to lookups by tag name. | |
| 65 | + * TODO This will change with future versions of AngularJS, to be removed when this happens | |
| 66 | + * | |
| 67 | + * See jqLite.find - why not use querySelectorAll? https://github.com/angular/angular.js/issues/3586 | |
| 68 | + * See feat(jqLite): use querySelectorAll instead of getElementsByTagName in jqLite.find https://github.com/angular/angular.js/pull/3598 | |
| 69 | + */ | |
| 70 | +if (angular.element.prototype.querySelectorAll === undefined) { | |
| 71 | + angular.element.prototype.querySelectorAll = function(selector) { | |
| 72 | + return angular.element(this[0].querySelectorAll(selector)); | |
| 73 | + }; | |
| 74 | +} | |
| 75 | + | |
| 76 | +/** | |
| 77 | + * Add closest() to jqLite. | |
| 78 | + */ | |
| 79 | +if (angular.element.prototype.closest === undefined) { | |
| 80 | + angular.element.prototype.closest = function( selector) { | |
| 81 | + var elem = this[0]; | |
| 82 | + var matchesSelector = elem.matches || elem.webkitMatchesSelector || elem.mozMatchesSelector || elem.msMatchesSelector; | |
| 83 | + | |
| 84 | + while (elem) { | |
| 85 | + if (matchesSelector.bind(elem)(selector)) { | |
| 86 | + return elem; | |
| 87 | + } else { | |
| 88 | + elem = elem.parentElement; | |
| 89 | + } | |
| 90 | + } | |
| 91 | + return false; | |
| 92 | + }; | |
| 93 | +} | |
| 94 | + | |
| 95 | +var latestId = 0; | |
| 96 | + | |
| 97 | +var uis = angular.module('ui.select', []) | |
| 98 | + | |
| 99 | +.constant('uiSelectConfig', { | |
| 100 | + theme: 'bootstrap', | |
| 101 | + searchEnabled: true, | |
| 102 | + sortable: false, | |
| 103 | + placeholder: '', // Empty by default, like HTML tag <select> | |
| 104 | + refreshDelay: 1000, // In milliseconds | |
| 105 | + closeOnSelect: true, | |
| 106 | + dropdownPosition: 'auto', | |
| 107 | + generateId: function() { | |
| 108 | + return latestId++; | |
| 109 | + }, | |
| 110 | + appendToBody: false | |
| 111 | +}) | |
| 112 | + | |
| 113 | +// See Rename minErr and make it accessible from outside https://github.com/angular/angular.js/issues/6913 | |
| 114 | +.service('uiSelectMinErr', function() { | |
| 115 | + var minErr = angular.$$minErr('ui.select'); | |
| 116 | + return function() { | |
| 117 | + var error = minErr.apply(this, arguments); | |
| 118 | + var message = error.message.replace(new RegExp('\nhttp://errors.angularjs.org/.*'), ''); | |
| 119 | + return new Error(message); | |
| 120 | + }; | |
| 121 | +}) | |
| 122 | + | |
| 123 | +// Recreates old behavior of ng-transclude. Used internally. | |
| 124 | +.directive('uisTranscludeAppend', function () { | |
| 125 | + return { | |
| 126 | + link: function (scope, element, attrs, ctrl, transclude) { | |
| 127 | + transclude(scope, function (clone) { | |
| 128 | + element.append(clone); | |
| 129 | + }); | |
| 130 | + } | |
| 131 | + }; | |
| 132 | +}) | |
| 133 | + | |
| 134 | +/** | |
| 135 | + * Highlights text that matches $select.search. | |
| 136 | + * | |
| 137 | + * Taken from AngularUI Bootstrap Typeahead | |
| 138 | + * See https://github.com/angular-ui/bootstrap/blob/0.10.0/src/typeahead/typeahead.js#L340 | |
| 139 | + */ | |
| 140 | +.filter('highlight', function() { | |
| 141 | + function escapeRegexp(queryToEscape) { | |
| 142 | + return queryToEscape.replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1'); | |
| 143 | + } | |
| 144 | + | |
| 145 | + return function(matchItem, query) { | |
| 146 | + return query && matchItem ? matchItem.replace(new RegExp(escapeRegexp(query), 'gi'), '<span class="ui-select-highlight">$&</span>') : matchItem; | |
| 147 | + }; | |
| 148 | +}) | |
| 149 | + | |
| 150 | +/** | |
| 151 | + * A read-only equivalent of jQuery's offset function: http://api.jquery.com/offset/ | |
| 152 | + * | |
| 153 | + * Taken from AngularUI Bootstrap Position: | |
| 154 | + * See https://github.com/angular-ui/bootstrap/blob/master/src/position/position.js#L70 | |
| 155 | + */ | |
| 156 | +.factory('uisOffset', | |
| 157 | + ['$document', '$window', | |
| 158 | + function ($document, $window) { | |
| 159 | + | |
| 160 | + return function(element) { | |
| 161 | + var boundingClientRect = element[0].getBoundingClientRect(); | |
| 162 | + return { | |
| 163 | + width: boundingClientRect.width || element.prop('offsetWidth'), | |
| 164 | + height: boundingClientRect.height || element.prop('offsetHeight'), | |
| 165 | + top: boundingClientRect.top + ($window.pageYOffset || $document[0].documentElement.scrollTop), | |
| 166 | + left: boundingClientRect.left + ($window.pageXOffset || $document[0].documentElement.scrollLeft) | |
| 167 | + }; | |
| 168 | + }; | |
| 169 | +}]); | |
| 170 | + | |
| 171 | +uis.directive('uiSelectChoices', | |
| 172 | + ['uiSelectConfig', 'uisRepeatParser', 'uiSelectMinErr', '$compile', | |
| 173 | + function(uiSelectConfig, RepeatParser, uiSelectMinErr, $compile) { | |
| 174 | + | |
| 175 | + return { | |
| 176 | + restrict: 'EA', | |
| 177 | + require: '^uiSelect', | |
| 178 | + replace: true, | |
| 179 | + transclude: true, | |
| 180 | + templateUrl: function(tElement) { | |
| 181 | + // Gets theme attribute from parent (ui-select) | |
| 182 | + var theme = tElement.parent().attr('theme') || uiSelectConfig.theme; | |
| 183 | + return theme + '/choices.tpl.html'; | |
| 184 | + }, | |
| 185 | + | |
| 186 | + compile: function(tElement, tAttrs) { | |
| 187 | + | |
| 188 | + if (!tAttrs.repeat) throw uiSelectMinErr('repeat', "Expected 'repeat' expression."); | |
| 189 | + | |
| 190 | + return function link(scope, element, attrs, $select, transcludeFn) { | |
| 191 | + | |
| 192 | + // var repeat = RepeatParser.parse(attrs.repeat); | |
| 193 | + var groupByExp = attrs.groupBy; | |
| 194 | + var groupFilterExp = attrs.groupFilter; | |
| 195 | + | |
| 196 | + $select.parseRepeatAttr(attrs.repeat, groupByExp, groupFilterExp); //Result ready at $select.parserResult | |
| 197 | + | |
| 198 | + $select.disableChoiceExpression = attrs.uiDisableChoice; | |
| 199 | + $select.onHighlightCallback = attrs.onHighlight; | |
| 200 | + | |
| 201 | + $select.dropdownPosition = attrs.position ? attrs.position.toLowerCase() : uiSelectConfig.dropdownPosition; | |
| 202 | + | |
| 203 | + if(groupByExp) { | |
| 204 | + var groups = element.querySelectorAll('.ui-select-choices-group'); | |
| 205 | + if (groups.length !== 1) throw uiSelectMinErr('rows', "Expected 1 .ui-select-choices-group but got '{0}'.", groups.length); | |
| 206 | + groups.attr('ng-repeat', RepeatParser.getGroupNgRepeatExpression()); | |
| 207 | + } | |
| 208 | + | |
| 209 | + var choices = element.querySelectorAll('.ui-select-choices-row'); | |
| 210 | + if (choices.length !== 1) { | |
| 211 | + throw uiSelectMinErr('rows', "Expected 1 .ui-select-choices-row but got '{0}'.", choices.length); | |
| 212 | + } | |
| 213 | + | |
| 214 | + choices.attr('ng-repeat', $select.parserResult.repeatExpression(groupByExp)) | |
| 215 | + .attr('ng-if', '$select.open') //Prevent unnecessary watches when dropdown is closed | |
| 216 | + .attr('ng-click', '$select.select(' + $select.parserResult.itemName + ',false,$event)'); | |
| 217 | + | |
| 218 | + var rowsInner = element.querySelectorAll('.ui-select-choices-row-inner'); | |
| 219 | + if (rowsInner.length !== 1) throw uiSelectMinErr('rows', "Expected 1 .ui-select-choices-row-inner but got '{0}'.", rowsInner.length); | |
| 220 | + rowsInner.attr('uis-transclude-append', ''); //Adding uisTranscludeAppend directive to row element after choices element has ngRepeat | |
| 221 | + | |
| 222 | + $compile(element, transcludeFn)(scope); //Passing current transcludeFn to be able to append elements correctly from uisTranscludeAppend | |
| 223 | + | |
| 224 | + scope.$watch('$select.search', function(newValue) { | |
| 225 | + if(newValue && !$select.open && $select.multiple) $select.activate(false, true); | |
| 226 | + $select.activeIndex = $select.tagging.isActivated ? -1 : 0; | |
| 227 | + $select.refresh(attrs.refresh); | |
| 228 | + }); | |
| 229 | + | |
| 230 | + attrs.$observe('refreshDelay', function() { | |
| 231 | + // $eval() is needed otherwise we get a string instead of a number | |
| 232 | + var refreshDelay = scope.$eval(attrs.refreshDelay); | |
| 233 | + $select.refreshDelay = refreshDelay !== undefined ? refreshDelay : uiSelectConfig.refreshDelay; | |
| 234 | + }); | |
| 235 | + }; | |
| 236 | + } | |
| 237 | + }; | |
| 238 | +}]); | |
| 239 | + | |
| 240 | +/** | |
| 241 | + * Contains ui-select "intelligence". | |
| 242 | + * | |
| 243 | + * The goal is to limit dependency on the DOM whenever possible and | |
| 244 | + * put as much logic in the controller (instead of the link functions) as possible so it can be easily tested. | |
| 245 | + */ | |
| 246 | +uis.controller('uiSelectCtrl', | |
| 247 | + ['$scope', '$element', '$timeout', '$filter', 'uisRepeatParser', 'uiSelectMinErr', 'uiSelectConfig', '$parse', | |
| 248 | + function($scope, $element, $timeout, $filter, RepeatParser, uiSelectMinErr, uiSelectConfig, $parse) { | |
| 249 | + | |
| 250 | + var ctrl = this; | |
| 251 | + | |
| 252 | + var EMPTY_SEARCH = ''; | |
| 253 | + | |
| 254 | + ctrl.placeholder = uiSelectConfig.placeholder; | |
| 255 | + ctrl.searchEnabled = uiSelectConfig.searchEnabled; | |
| 256 | + ctrl.sortable = uiSelectConfig.sortable; | |
| 257 | + ctrl.refreshDelay = uiSelectConfig.refreshDelay; | |
| 258 | + | |
| 259 | + ctrl.removeSelected = false; //If selected item(s) should be removed from dropdown list | |
| 260 | + ctrl.closeOnSelect = true; //Initialized inside uiSelect directive link function | |
| 261 | + ctrl.search = EMPTY_SEARCH; | |
| 262 | + | |
| 263 | + ctrl.activeIndex = 0; //Dropdown of choices | |
| 264 | + ctrl.items = []; //All available choices | |
| 265 | + | |
| 266 | + ctrl.open = false; | |
| 267 | + ctrl.focus = false; | |
| 268 | + ctrl.disabled = false; | |
| 269 | + ctrl.selected = undefined; | |
| 270 | + | |
| 271 | + ctrl.dropdownPosition = 'auto'; | |
| 272 | + | |
| 273 | + ctrl.focusser = undefined; //Reference to input element used to handle focus events | |
| 274 | + ctrl.resetSearchInput = true; | |
| 275 | + ctrl.multiple = undefined; // Initialized inside uiSelect directive link function | |
| 276 | + ctrl.disableChoiceExpression = undefined; // Initialized inside uiSelectChoices directive link function | |
| 277 | + ctrl.tagging = {isActivated: false, fct: undefined}; | |
| 278 | + ctrl.taggingTokens = {isActivated: false, tokens: undefined}; | |
| 279 | + ctrl.lockChoiceExpression = undefined; // Initialized inside uiSelectMatch directive link function | |
| 280 | + ctrl.clickTriggeredSelect = false; | |
| 281 | + ctrl.$filter = $filter; | |
| 282 | + | |
| 283 | + ctrl.searchInput = $element.querySelectorAll('input.ui-select-search'); | |
| 284 | + if (ctrl.searchInput.length !== 1) { | |
| 285 | + throw uiSelectMinErr('searchInput', "Expected 1 input.ui-select-search but got '{0}'.", ctrl.searchInput.length); | |
| 286 | + } | |
| 287 | + | |
| 288 | + ctrl.isEmpty = function() { | |
| 289 | + return angular.isUndefined(ctrl.selected) || ctrl.selected === null || ctrl.selected === ''; | |
| 290 | + }; | |
| 291 | + | |
| 292 | + // Most of the time the user does not want to empty the search input when in typeahead mode | |
| 293 | + function _resetSearchInput() { | |
| 294 | + if (ctrl.resetSearchInput || (ctrl.resetSearchInput === undefined && uiSelectConfig.resetSearchInput)) { | |
| 295 | + ctrl.search = EMPTY_SEARCH; | |
| 296 | + //reset activeIndex | |
| 297 | + if (ctrl.selected && ctrl.items.length && !ctrl.multiple) { | |
| 298 | + ctrl.activeIndex = ctrl.items.indexOf(ctrl.selected); | |
| 299 | + } | |
| 300 | + } | |
| 301 | + } | |
| 302 | + | |
| 303 | + function _groupsFilter(groups, groupNames) { | |
| 304 | + var i, j, result = []; | |
| 305 | + for(i = 0; i < groupNames.length ;i++){ | |
| 306 | + for(j = 0; j < groups.length ;j++){ | |
| 307 | + if(groups[j].name == [groupNames[i]]){ | |
| 308 | + result.push(groups[j]); | |
| 309 | + } | |
| 310 | + } | |
| 311 | + } | |
| 312 | + return result; | |
| 313 | + } | |
| 314 | + | |
| 315 | + // When the user clicks on ui-select, displays the dropdown list | |
| 316 | + ctrl.activate = function(initSearchValue, avoidReset) { | |
| 317 | + if (!ctrl.disabled && !ctrl.open) { | |
| 318 | + if(!avoidReset) _resetSearchInput(); | |
| 319 | + | |
| 320 | + $scope.$broadcast('uis:activate'); | |
| 321 | + | |
| 322 | + ctrl.open = true; | |
| 323 | + | |
| 324 | + ctrl.activeIndex = ctrl.activeIndex >= ctrl.items.length ? 0 : ctrl.activeIndex; | |
| 325 | + | |
| 326 | + // ensure that the index is set to zero for tagging variants | |
| 327 | + // that where first option is auto-selected | |
| 328 | + if ( ctrl.activeIndex === -1 && ctrl.taggingLabel !== false ) { | |
| 329 | + ctrl.activeIndex = 0; | |
| 330 | + } | |
| 331 | + | |
| 332 | + // Give it time to appear before focus | |
| 333 | + $timeout(function() { | |
| 334 | + ctrl.search = initSearchValue || ctrl.search; | |
| 335 | + ctrl.searchInput[0].focus(); | |
| 336 | + if(!ctrl.tagging.isActivated && ctrl.items.length > 1) { | |
| 337 | + _ensureHighlightVisible(); | |
| 338 | + } | |
| 339 | + }); | |
| 340 | + } | |
| 341 | + }; | |
| 342 | + | |
| 343 | + ctrl.findGroupByName = function(name) { | |
| 344 | + return ctrl.groups && ctrl.groups.filter(function(group) { | |
| 345 | + return group.name === name; | |
| 346 | + })[0]; | |
| 347 | + }; | |
| 348 | + | |
| 349 | + ctrl.parseRepeatAttr = function(repeatAttr, groupByExp, groupFilterExp) { | |
| 350 | + function updateGroups(items) { | |
| 351 | + var groupFn = $scope.$eval(groupByExp); | |
| 352 | + ctrl.groups = []; | |
| 353 | + angular.forEach(items, function(item) { | |
| 354 | + var groupName = angular.isFunction(groupFn) ? groupFn(item) : item[groupFn]; | |
| 355 | + var group = ctrl.findGroupByName(groupName); | |
| 356 | + if(group) { | |
| 357 | + group.items.push(item); | |
| 358 | + } | |
| 359 | + else { | |
| 360 | + ctrl.groups.push({name: groupName, items: [item]}); | |
| 361 | + } | |
| 362 | + }); | |
| 363 | + if(groupFilterExp){ | |
| 364 | + var groupFilterFn = $scope.$eval(groupFilterExp); | |
| 365 | + if( angular.isFunction(groupFilterFn)){ | |
| 366 | + ctrl.groups = groupFilterFn(ctrl.groups); | |
| 367 | + } else if(angular.isArray(groupFilterFn)){ | |
| 368 | + ctrl.groups = _groupsFilter(ctrl.groups, groupFilterFn); | |
| 369 | + } | |
| 370 | + } | |
| 371 | + ctrl.items = []; | |
| 372 | + ctrl.groups.forEach(function(group) { | |
| 373 | + ctrl.items = ctrl.items.concat(group.items); | |
| 374 | + }); | |
| 375 | + } | |
| 376 | + | |
| 377 | + function setPlainItems(items) { | |
| 378 | + ctrl.items = items; | |
| 379 | + } | |
| 380 | + | |
| 381 | + ctrl.setItemsFn = groupByExp ? updateGroups : setPlainItems; | |
| 382 | + | |
| 383 | + ctrl.parserResult = RepeatParser.parse(repeatAttr); | |
| 384 | + | |
| 385 | + ctrl.isGrouped = !!groupByExp; | |
| 386 | + ctrl.itemProperty = ctrl.parserResult.itemName; | |
| 387 | + | |
| 388 | + //If collection is an Object, convert it to Array | |
| 389 | + | |
| 390 | + var originalSource = ctrl.parserResult.source; | |
| 391 | + | |
| 392 | + //When an object is used as source, we better create an array and use it as 'source' | |
| 393 | + var createArrayFromObject = function(){ | |
| 394 | + var origSrc = originalSource($scope); | |
| 395 | + $scope.$uisSource = Object.keys(origSrc).map(function(v){ | |
| 396 | + var result = {}; | |
| 397 | + result[ctrl.parserResult.keyName] = v; | |
| 398 | + result.value = origSrc[v]; | |
| 399 | + return result; | |
| 400 | + }); | |
| 401 | + }; | |
| 402 | + | |
| 403 | + if (ctrl.parserResult.keyName){ // Check for (key,value) syntax | |
| 404 | + createArrayFromObject(); | |
| 405 | + ctrl.parserResult.source = $parse('$uisSource' + ctrl.parserResult.filters); | |
| 406 | + $scope.$watch(originalSource, function(newVal, oldVal){ | |
| 407 | + if (newVal !== oldVal) createArrayFromObject(); | |
| 408 | + }, true); | |
| 409 | + } | |
| 410 | + | |
| 411 | + ctrl.refreshItems = function (data){ | |
| 412 | + data = data || ctrl.parserResult.source($scope); | |
| 413 | + var selectedItems = ctrl.selected; | |
| 414 | + //TODO should implement for single mode removeSelected | |
| 415 | + if (ctrl.isEmpty() || (angular.isArray(selectedItems) && !selectedItems.length) || !ctrl.removeSelected) { | |
| 416 | + ctrl.setItemsFn(data); | |
| 417 | + }else{ | |
| 418 | + if ( data !== undefined ) { | |
| 419 | + var filteredItems = data.filter(function(i) {return selectedItems && selectedItems.indexOf(i) < 0;}); | |
| 420 | + ctrl.setItemsFn(filteredItems); | |
| 421 | + } | |
| 422 | + } | |
| 423 | + if (ctrl.dropdownPosition === 'auto' || ctrl.dropdownPosition === 'up'){ | |
| 424 | + $scope.calculateDropdownPos(); | |
| 425 | + } | |
| 426 | + }; | |
| 427 | + | |
| 428 | + // See https://github.com/angular/angular.js/blob/v1.2.15/src/ng/directive/ngRepeat.js#L259 | |
| 429 | + $scope.$watchCollection(ctrl.parserResult.source, function(items) { | |
| 430 | + if (items === undefined || items === null) { | |
| 431 | + // If the user specifies undefined or null => reset the collection | |
| 432 | + // Special case: items can be undefined if the user did not initialized the collection on the scope | |
| 433 | + // i.e $scope.addresses = [] is missing | |
| 434 | + ctrl.items = []; | |
| 435 | + } else { | |
| 436 | + if (!angular.isArray(items)) { | |
| 437 | + throw uiSelectMinErr('items', "Expected an array but got '{0}'.", items); | |
| 438 | + } else { | |
| 439 | + //Remove already selected items (ex: while searching) | |
| 440 | + //TODO Should add a test | |
| 441 | + ctrl.refreshItems(items); | |
| 442 | + ctrl.ngModel.$modelValue = null; //Force scope model value and ngModel value to be out of sync to re-run formatters | |
| 443 | + } | |
| 444 | + } | |
| 445 | + }); | |
| 446 | + | |
| 447 | + }; | |
| 448 | + | |
| 449 | + var _refreshDelayPromise; | |
| 450 | + | |
| 451 | + /** | |
| 452 | + * Typeahead mode: lets the user refresh the collection using his own function. | |
| 453 | + * | |
| 454 | + * See Expose $select.search for external / remote filtering https://github.com/angular-ui/ui-select/pull/31 | |
| 455 | + */ | |
| 456 | + ctrl.refresh = function(refreshAttr) { | |
| 457 | + if (refreshAttr !== undefined) { | |
| 458 | + | |
| 459 | + // Debounce | |
| 460 | + // See https://github.com/angular-ui/bootstrap/blob/0.10.0/src/typeahead/typeahead.js#L155 | |
| 461 | + // FYI AngularStrap typeahead does not have debouncing: https://github.com/mgcrea/angular-strap/blob/v2.0.0-rc.4/src/typeahead/typeahead.js#L177 | |
| 462 | + if (_refreshDelayPromise) { | |
| 463 | + $timeout.cancel(_refreshDelayPromise); | |
| 464 | + } | |
| 465 | + _refreshDelayPromise = $timeout(function() { | |
| 466 | + $scope.$eval(refreshAttr); | |
| 467 | + }, ctrl.refreshDelay); | |
| 468 | + } | |
| 469 | + }; | |
| 470 | + | |
| 471 | + ctrl.isActive = function(itemScope) { | |
| 472 | + if ( !ctrl.open ) { | |
| 473 | + return false; | |
| 474 | + } | |
| 475 | + var itemIndex = ctrl.items.indexOf(itemScope[ctrl.itemProperty]); | |
| 476 | + var isActive = itemIndex === ctrl.activeIndex; | |
| 477 | + | |
| 478 | + if ( !isActive || ( itemIndex < 0 && ctrl.taggingLabel !== false ) ||( itemIndex < 0 && ctrl.taggingLabel === false) ) { | |
| 479 | + return false; | |
| 480 | + } | |
| 481 | + | |
| 482 | + if (isActive && !angular.isUndefined(ctrl.onHighlightCallback)) { | |
| 483 | + itemScope.$eval(ctrl.onHighlightCallback); | |
| 484 | + } | |
| 485 | + | |
| 486 | + return isActive; | |
| 487 | + }; | |
| 488 | + | |
| 489 | + ctrl.isDisabled = function(itemScope) { | |
| 490 | + | |
| 491 | + if (!ctrl.open) return; | |
| 492 | + | |
| 493 | + var itemIndex = ctrl.items.indexOf(itemScope[ctrl.itemProperty]); | |
| 494 | + var isDisabled = false; | |
| 495 | + var item; | |
| 496 | + | |
| 497 | + if (itemIndex >= 0 && !angular.isUndefined(ctrl.disableChoiceExpression)) { | |
| 498 | + item = ctrl.items[itemIndex]; | |
| 499 | + isDisabled = !!(itemScope.$eval(ctrl.disableChoiceExpression)); // force the boolean value | |
| 500 | + item._uiSelectChoiceDisabled = isDisabled; // store this for later reference | |
| 501 | + } | |
| 502 | + | |
| 503 | + return isDisabled; | |
| 504 | + }; | |
| 505 | + | |
| 506 | + | |
| 507 | + // When the user selects an item with ENTER or clicks the dropdown | |
| 508 | + ctrl.select = function(item, skipFocusser, $event) { | |
| 509 | + if (item === undefined || !item._uiSelectChoiceDisabled) { | |
| 510 | + | |
| 511 | + if ( ! ctrl.items && ! ctrl.search ) return; | |
| 512 | + | |
| 513 | + if (!item || !item._uiSelectChoiceDisabled) { | |
| 514 | + if(ctrl.tagging.isActivated) { | |
| 515 | + // if taggingLabel is disabled, we pull from ctrl.search val | |
| 516 | + if ( ctrl.taggingLabel === false ) { | |
| 517 | + if ( ctrl.activeIndex < 0 ) { | |
| 518 | + item = ctrl.tagging.fct !== undefined ? ctrl.tagging.fct(ctrl.search) : ctrl.search; | |
| 519 | + if (!item || angular.equals( ctrl.items[0], item ) ) { | |
| 520 | + return; | |
| 521 | + } | |
| 522 | + } else { | |
| 523 | + // keyboard nav happened first, user selected from dropdown | |
| 524 | + item = ctrl.items[ctrl.activeIndex]; | |
| 525 | + } | |
| 526 | + } else { | |
| 527 | + // tagging always operates at index zero, taggingLabel === false pushes | |
| 528 | + // the ctrl.search value without having it injected | |
| 529 | + if ( ctrl.activeIndex === 0 ) { | |
| 530 | + // ctrl.tagging pushes items to ctrl.items, so we only have empty val | |
| 531 | + // for `item` if it is a detected duplicate | |
| 532 | + if ( item === undefined ) return; | |
| 533 | + | |
| 534 | + // create new item on the fly if we don't already have one; | |
| 535 | + // use tagging function if we have one | |
| 536 | + if ( ctrl.tagging.fct !== undefined && typeof item === 'string' ) { | |
| 537 | + item = ctrl.tagging.fct(ctrl.search); | |
| 538 | + if (!item) return; | |
| 539 | + // if item type is 'string', apply the tagging label | |
| 540 | + } else if ( typeof item === 'string' ) { | |
| 541 | + // trim the trailing space | |
| 542 | + item = item.replace(ctrl.taggingLabel,'').trim(); | |
| 543 | + } | |
| 544 | + } | |
| 545 | + } | |
| 546 | + // search ctrl.selected for dupes potentially caused by tagging and return early if found | |
| 547 | + if ( ctrl.selected && angular.isArray(ctrl.selected) && ctrl.selected.filter( function (selection) { return angular.equals(selection, item); }).length > 0 ) { | |
| 548 | + ctrl.close(skipFocusser); | |
| 549 | + return; | |
| 550 | + } | |
| 551 | + } | |
| 552 | + | |
| 553 | + $scope.$broadcast('uis:select', item); | |
| 554 | + | |
| 555 | + var locals = {}; | |
| 556 | + locals[ctrl.parserResult.itemName] = item; | |
| 557 | + | |
| 558 | + $timeout(function(){ | |
| 559 | + ctrl.onSelectCallback($scope, { | |
| 560 | + $item: item, | |
| 561 | + $model: ctrl.parserResult.modelMapper($scope, locals) | |
| 562 | + }); | |
| 563 | + }); | |
| 564 | + | |
| 565 | + if (ctrl.closeOnSelect) { | |
| 566 | + ctrl.close(skipFocusser); | |
| 567 | + } | |
| 568 | + if ($event && $event.type === 'click') { | |
| 569 | + ctrl.clickTriggeredSelect = true; | |
| 570 | + } | |
| 571 | + } | |
| 572 | + } | |
| 573 | + }; | |
| 574 | + | |
| 575 | + // Closes the dropdown | |
| 576 | + ctrl.close = function(skipFocusser) { | |
| 577 | + if (!ctrl.open) return; | |
| 578 | + if (ctrl.ngModel && ctrl.ngModel.$setTouched) ctrl.ngModel.$setTouched(); | |
| 579 | + _resetSearchInput(); | |
| 580 | + ctrl.open = false; | |
| 581 | + | |
| 582 | + $scope.$broadcast('uis:close', skipFocusser); | |
| 583 | + | |
| 584 | + }; | |
| 585 | + | |
| 586 | + ctrl.setFocus = function(){ | |
| 587 | + if (!ctrl.focus) ctrl.focusInput[0].focus(); | |
| 588 | + }; | |
| 589 | + | |
| 590 | + ctrl.clear = function($event) { | |
| 591 | + ctrl.select(undefined); | |
| 592 | + $event.stopPropagation(); | |
| 593 | + $timeout(function() { | |
| 594 | + ctrl.focusser[0].focus(); | |
| 595 | + }, 0, false); | |
| 596 | + }; | |
| 597 | + | |
| 598 | + // Toggle dropdown | |
| 599 | + ctrl.toggle = function(e) { | |
| 600 | + if (ctrl.open) { | |
| 601 | + ctrl.close(); | |
| 602 | + e.preventDefault(); | |
| 603 | + e.stopPropagation(); | |
| 604 | + } else { | |
| 605 | + ctrl.activate(); | |
| 606 | + } | |
| 607 | + }; | |
| 608 | + | |
| 609 | + ctrl.isLocked = function(itemScope, itemIndex) { | |
| 610 | + var isLocked, item = ctrl.selected[itemIndex]; | |
| 611 | + | |
| 612 | + if (item && !angular.isUndefined(ctrl.lockChoiceExpression)) { | |
| 613 | + isLocked = !!(itemScope.$eval(ctrl.lockChoiceExpression)); // force the boolean value | |
| 614 | + item._uiSelectChoiceLocked = isLocked; // store this for later reference | |
| 615 | + } | |
| 616 | + | |
| 617 | + return isLocked; | |
| 618 | + }; | |
| 619 | + | |
| 620 | + var sizeWatch = null; | |
| 621 | + ctrl.sizeSearchInput = function() { | |
| 622 | + | |
| 623 | + var input = ctrl.searchInput[0], | |
| 624 | + container = ctrl.searchInput.parent().parent()[0], | |
| 625 | + calculateContainerWidth = function() { | |
| 626 | + // Return the container width only if the search input is visible | |
| 627 | + return container.clientWidth * !!input.offsetParent; | |
| 628 | + }, | |
| 629 | + updateIfVisible = function(containerWidth) { | |
| 630 | + if (containerWidth === 0) { | |
| 631 | + return false; | |
| 632 | + } | |
| 633 | + var inputWidth = containerWidth - input.offsetLeft - 10; | |
| 634 | + if (inputWidth < 50) inputWidth = containerWidth; | |
| 635 | + ctrl.searchInput.css('width', inputWidth+'px'); | |
| 636 | + return true; | |
| 637 | + }; | |
| 638 | + | |
| 639 | + ctrl.searchInput.css('width', '10px'); | |
| 640 | + $timeout(function() { //Give tags time to render correctly | |
| 641 | + if (sizeWatch === null && !updateIfVisible(calculateContainerWidth())) { | |
| 642 | + sizeWatch = $scope.$watch(calculateContainerWidth, function(containerWidth) { | |
| 643 | + if (updateIfVisible(containerWidth)) { | |
| 644 | + sizeWatch(); | |
| 645 | + sizeWatch = null; | |
| 646 | + } | |
| 647 | + }); | |
| 648 | + } | |
| 649 | + }); | |
| 650 | + }; | |
| 651 | + | |
| 652 | + function _handleDropDownSelection(key) { | |
| 653 | + var processed = true; | |
| 654 | + switch (key) { | |
| 655 | + case KEY.DOWN: | |
| 656 | + if (!ctrl.open && ctrl.multiple) ctrl.activate(false, true); //In case its the search input in 'multiple' mode | |
| 657 | + else if (ctrl.activeIndex < ctrl.items.length - 1) { ctrl.activeIndex++; } | |
| 658 | + break; | |
| 659 | + case KEY.UP: | |
| 660 | + if (!ctrl.open && ctrl.multiple) ctrl.activate(false, true); //In case its the search input in 'multiple' mode | |
| 661 | + else if (ctrl.activeIndex > 0 || (ctrl.search.length === 0 && ctrl.tagging.isActivated && ctrl.activeIndex > -1)) { ctrl.activeIndex--; } | |
| 662 | + break; | |
| 663 | + case KEY.TAB: | |
| 664 | + if (!ctrl.multiple || ctrl.open) ctrl.select(ctrl.items[ctrl.activeIndex], true); | |
| 665 | + break; | |
| 666 | + case KEY.ENTER: | |
| 667 | + if(ctrl.open && (ctrl.tagging.isActivated || ctrl.activeIndex >= 0)){ | |
| 668 | + ctrl.select(ctrl.items[ctrl.activeIndex]); // Make sure at least one dropdown item is highlighted before adding if not in tagging mode | |
| 669 | + } else { | |
| 670 | + ctrl.activate(false, true); //In case its the search input in 'multiple' mode | |
| 671 | + } | |
| 672 | + break; | |
| 673 | + case KEY.ESC: | |
| 674 | + ctrl.close(); | |
| 675 | + break; | |
| 676 | + default: | |
| 677 | + processed = false; | |
| 678 | + } | |
| 679 | + return processed; | |
| 680 | + } | |
| 681 | + | |
| 682 | + // Bind to keyboard shortcuts | |
| 683 | + ctrl.searchInput.on('keydown', function(e) { | |
| 684 | + | |
| 685 | + var key = e.which; | |
| 686 | + | |
| 687 | + // if(~[KEY.ESC,KEY.TAB].indexOf(key)){ | |
| 688 | + // //TODO: SEGURO? | |
| 689 | + // ctrl.close(); | |
| 690 | + // } | |
| 691 | + | |
| 692 | + $scope.$apply(function() { | |
| 693 | + | |
| 694 | + var tagged = false; | |
| 695 | + | |
| 696 | + if (ctrl.items.length > 0 || ctrl.tagging.isActivated) { | |
| 697 | + _handleDropDownSelection(key); | |
| 698 | + if ( ctrl.taggingTokens.isActivated ) { | |
| 699 | + for (var i = 0; i < ctrl.taggingTokens.tokens.length; i++) { | |
| 700 | + if ( ctrl.taggingTokens.tokens[i] === KEY.MAP[e.keyCode] ) { | |
| 701 | + // make sure there is a new value to push via tagging | |
| 702 | + if ( ctrl.search.length > 0 ) { | |
| 703 | + tagged = true; | |
| 704 | + } | |
| 705 | + } | |
| 706 | + } | |
| 707 | + if ( tagged ) { | |
| 708 | + $timeout(function() { | |
| 709 | + ctrl.searchInput.triggerHandler('tagged'); | |
| 710 | + var newItem = ctrl.search.replace(KEY.MAP[e.keyCode],'').trim(); | |
| 711 | + if ( ctrl.tagging.fct ) { | |
| 712 | + newItem = ctrl.tagging.fct( newItem ); | |
| 713 | + } | |
| 714 | + if (newItem) ctrl.select(newItem, true); | |
| 715 | + }); | |
| 716 | + } | |
| 717 | + } | |
| 718 | + } | |
| 719 | + | |
| 720 | + }); | |
| 721 | + | |
| 722 | + if(KEY.isVerticalMovement(key) && ctrl.items.length > 0){ | |
| 723 | + _ensureHighlightVisible(); | |
| 724 | + } | |
| 725 | + | |
| 726 | + if (key === KEY.ENTER || key === KEY.ESC) { | |
| 727 | + e.preventDefault(); | |
| 728 | + e.stopPropagation(); | |
| 729 | + } | |
| 730 | + | |
| 731 | + }); | |
| 732 | + | |
| 733 | + // If tagging try to split by tokens and add items | |
| 734 | + ctrl.searchInput.on('paste', function (e) { | |
| 735 | + var data = e.originalEvent.clipboardData.getData('text/plain'); | |
| 736 | + if (data && data.length > 0 && ctrl.taggingTokens.isActivated && ctrl.tagging.fct) { | |
| 737 | + var items = data.split(ctrl.taggingTokens.tokens[0]); // split by first token only | |
| 738 | + if (items && items.length > 0) { | |
| 739 | + angular.forEach(items, function (item) { | |
| 740 | + var newItem = ctrl.tagging.fct(item); | |
| 741 | + if (newItem) { | |
| 742 | + ctrl.select(newItem, true); | |
| 743 | + } | |
| 744 | + }); | |
| 745 | + e.preventDefault(); | |
| 746 | + e.stopPropagation(); | |
| 747 | + } | |
| 748 | + } | |
| 749 | + }); | |
| 750 | + | |
| 751 | + ctrl.searchInput.on('tagged', function() { | |
| 752 | + $timeout(function() { | |
| 753 | + _resetSearchInput(); | |
| 754 | + }); | |
| 755 | + }); | |
| 756 | + | |
| 757 | + // See https://github.com/ivaynberg/select2/blob/3.4.6/select2.js#L1431 | |
| 758 | + function _ensureHighlightVisible() { | |
| 759 | + var container = $element.querySelectorAll('.ui-select-choices-content'); | |
| 760 | + var choices = container.querySelectorAll('.ui-select-choices-row'); | |
| 761 | + if (choices.length < 1) { | |
| 762 | + throw uiSelectMinErr('choices', "Expected multiple .ui-select-choices-row but got '{0}'.", choices.length); | |
| 763 | + } | |
| 764 | + | |
| 765 | + if (ctrl.activeIndex < 0) { | |
| 766 | + return; | |
| 767 | + } | |
| 768 | + | |
| 769 | + var highlighted = choices[ctrl.activeIndex]; | |
| 770 | + var posY = highlighted.offsetTop + highlighted.clientHeight - container[0].scrollTop; | |
| 771 | + var height = container[0].offsetHeight; | |
| 772 | + | |
| 773 | + if (posY > height) { | |
| 774 | + container[0].scrollTop += posY - height; | |
| 775 | + } else if (posY < highlighted.clientHeight) { | |
| 776 | + if (ctrl.isGrouped && ctrl.activeIndex === 0) | |
| 777 | + container[0].scrollTop = 0; //To make group header visible when going all the way up | |
| 778 | + else | |
| 779 | + container[0].scrollTop -= highlighted.clientHeight - posY; | |
| 780 | + } | |
| 781 | + } | |
| 782 | + | |
| 783 | + $scope.$on('$destroy', function() { | |
| 784 | + ctrl.searchInput.off('keyup keydown tagged blur paste'); | |
| 785 | + }); | |
| 786 | + | |
| 787 | +}]); | |
| 788 | + | |
| 789 | +uis.directive('uiSelect', | |
| 790 | + ['$document', 'uiSelectConfig', 'uiSelectMinErr', 'uisOffset', '$compile', '$parse', '$timeout', | |
| 791 | + function($document, uiSelectConfig, uiSelectMinErr, uisOffset, $compile, $parse, $timeout) { | |
| 792 | + | |
| 793 | + return { | |
| 794 | + restrict: 'EA', | |
| 795 | + templateUrl: function(tElement, tAttrs) { | |
| 796 | + var theme = tAttrs.theme || uiSelectConfig.theme; | |
| 797 | + return theme + (angular.isDefined(tAttrs.multiple) ? '/select-multiple.tpl.html' : '/select.tpl.html'); | |
| 798 | + }, | |
| 799 | + replace: true, | |
| 800 | + transclude: true, | |
| 801 | + require: ['uiSelect', '^ngModel'], | |
| 802 | + scope: true, | |
| 803 | + | |
| 804 | + controller: 'uiSelectCtrl', | |
| 805 | + controllerAs: '$select', | |
| 806 | + compile: function(tElement, tAttrs) { | |
| 807 | + | |
| 808 | + //Multiple or Single depending if multiple attribute presence | |
| 809 | + if (angular.isDefined(tAttrs.multiple)) | |
| 810 | + tElement.append('<ui-select-multiple/>').removeAttr('multiple'); | |
| 811 | + else | |
| 812 | + tElement.append('<ui-select-single/>'); | |
| 813 | + | |
| 814 | + if (tAttrs.inputId) | |
| 815 | + tElement.querySelectorAll('input.ui-select-search')[0].id = tAttrs.inputId; | |
| 816 | + | |
| 817 | + return function(scope, element, attrs, ctrls, transcludeFn) { | |
| 818 | + | |
| 819 | + var $select = ctrls[0]; | |
| 820 | + var ngModel = ctrls[1]; | |
| 821 | + | |
| 822 | + $select.generatedId = uiSelectConfig.generateId(); | |
| 823 | + $select.baseTitle = attrs.title || 'Select box'; | |
| 824 | + $select.focusserTitle = $select.baseTitle + ' focus'; | |
| 825 | + $select.focusserId = 'focusser-' + $select.generatedId; | |
| 826 | + | |
| 827 | + $select.closeOnSelect = function() { | |
| 828 | + if (angular.isDefined(attrs.closeOnSelect)) { | |
| 829 | + return $parse(attrs.closeOnSelect)(); | |
| 830 | + } else { | |
| 831 | + return uiSelectConfig.closeOnSelect; | |
| 832 | + } | |
| 833 | + }(); | |
| 834 | + | |
| 835 | + $select.onSelectCallback = $parse(attrs.onSelect); | |
| 836 | + $select.onRemoveCallback = $parse(attrs.onRemove); | |
| 837 | + | |
| 838 | + //Limit the number of selections allowed | |
| 839 | + $select.limit = (angular.isDefined(attrs.limit)) ? parseInt(attrs.limit, 10) : undefined; | |
| 840 | + | |
| 841 | + //Set reference to ngModel from uiSelectCtrl | |
| 842 | + $select.ngModel = ngModel; | |
| 843 | + | |
| 844 | + $select.choiceGrouped = function(group){ | |
| 845 | + return $select.isGrouped && group && group.name; | |
| 846 | + }; | |
| 847 | + | |
| 848 | + if(attrs.tabindex){ | |
| 849 | + attrs.$observe('tabindex', function(value) { | |
| 850 | + $select.focusInput.attr('tabindex', value); | |
| 851 | + element.removeAttr('tabindex'); | |
| 852 | + }); | |
| 853 | + } | |
| 854 | + | |
| 855 | + scope.$watch('searchEnabled', function() { | |
| 856 | + var searchEnabled = scope.$eval(attrs.searchEnabled); | |
| 857 | + $select.searchEnabled = searchEnabled !== undefined ? searchEnabled : uiSelectConfig.searchEnabled; | |
| 858 | + }); | |
| 859 | + | |
| 860 | + scope.$watch('sortable', function() { | |
| 861 | + var sortable = scope.$eval(attrs.sortable); | |
| 862 | + $select.sortable = sortable !== undefined ? sortable : uiSelectConfig.sortable; | |
| 863 | + }); | |
| 864 | + | |
| 865 | + attrs.$observe('disabled', function() { | |
| 866 | + // No need to use $eval() (thanks to ng-disabled) since we already get a boolean instead of a string | |
| 867 | + $select.disabled = attrs.disabled !== undefined ? attrs.disabled : false; | |
| 868 | + }); | |
| 869 | + | |
| 870 | + attrs.$observe('resetSearchInput', function() { | |
| 871 | + // $eval() is needed otherwise we get a string instead of a boolean | |
| 872 | + var resetSearchInput = scope.$eval(attrs.resetSearchInput); | |
| 873 | + $select.resetSearchInput = resetSearchInput !== undefined ? resetSearchInput : true; | |
| 874 | + }); | |
| 875 | + | |
| 876 | + attrs.$observe('tagging', function() { | |
| 877 | + if(attrs.tagging !== undefined) | |
| 878 | + { | |
| 879 | + // $eval() is needed otherwise we get a string instead of a boolean | |
| 880 | + var taggingEval = scope.$eval(attrs.tagging); | |
| 881 | + $select.tagging = {isActivated: true, fct: taggingEval !== true ? taggingEval : undefined}; | |
| 882 | + } | |
| 883 | + else | |
| 884 | + { | |
| 885 | + $select.tagging = {isActivated: false, fct: undefined}; | |
| 886 | + } | |
| 887 | + }); | |
| 888 | + | |
| 889 | + attrs.$observe('taggingLabel', function() { | |
| 890 | + if(attrs.tagging !== undefined ) | |
| 891 | + { | |
| 892 | + // check eval for FALSE, in this case, we disable the labels | |
| 893 | + // associated with tagging | |
| 894 | + if ( attrs.taggingLabel === 'false' ) { | |
| 895 | + $select.taggingLabel = false; | |
| 896 | + } | |
| 897 | + else | |
| 898 | + { | |
| 899 | + $select.taggingLabel = attrs.taggingLabel !== undefined ? attrs.taggingLabel : '(new)'; | |
| 900 | + } | |
| 901 | + } | |
| 902 | + }); | |
| 903 | + | |
| 904 | + attrs.$observe('taggingTokens', function() { | |
| 905 | + if (attrs.tagging !== undefined) { | |
| 906 | + var tokens = attrs.taggingTokens !== undefined ? attrs.taggingTokens.split('|') : [',','ENTER']; | |
| 907 | + $select.taggingTokens = {isActivated: true, tokens: tokens }; | |
| 908 | + } | |
| 909 | + }); | |
| 910 | + | |
| 911 | + //Automatically gets focus when loaded | |
| 912 | + if (angular.isDefined(attrs.autofocus)){ | |
| 913 | + $timeout(function(){ | |
| 914 | + $select.setFocus(); | |
| 915 | + }); | |
| 916 | + } | |
| 917 | + | |
| 918 | + //Gets focus based on scope event name (e.g. focus-on='SomeEventName') | |
| 919 | + if (angular.isDefined(attrs.focusOn)){ | |
| 920 | + scope.$on(attrs.focusOn, function() { | |
| 921 | + $timeout(function(){ | |
| 922 | + $select.setFocus(); | |
| 923 | + }); | |
| 924 | + }); | |
| 925 | + } | |
| 926 | + | |
| 927 | + function onDocumentClick(e) { | |
| 928 | + if (!$select.open) return; //Skip it if dropdown is close | |
| 929 | + | |
| 930 | + var contains = false; | |
| 931 | + | |
| 932 | + if (window.jQuery) { | |
| 933 | + // Firefox 3.6 does not support element.contains() | |
| 934 | + // See Node.contains https://developer.mozilla.org/en-US/docs/Web/API/Node.contains | |
| 935 | + contains = window.jQuery.contains(element[0], e.target); | |
| 936 | + } else { | |
| 937 | + contains = element[0].contains(e.target); | |
| 938 | + } | |
| 939 | + | |
| 940 | + if (!contains && !$select.clickTriggeredSelect) { | |
| 941 | + //Will lose focus only with certain targets | |
| 942 | + var focusableControls = ['input','button','textarea']; | |
| 943 | + var targetController = angular.element(e.target).controller('uiSelect'); //To check if target is other ui-select | |
| 944 | + var skipFocusser = targetController && targetController !== $select; //To check if target is other ui-select | |
| 945 | + if (!skipFocusser) skipFocusser = ~focusableControls.indexOf(e.target.tagName.toLowerCase()); //Check if target is input, button or textarea | |
| 946 | + $select.close(skipFocusser); | |
| 947 | + scope.$digest(); | |
| 948 | + } | |
| 949 | + $select.clickTriggeredSelect = false; | |
| 950 | + } | |
| 951 | + | |
| 952 | + // See Click everywhere but here event http://stackoverflow.com/questions/12931369 | |
| 953 | + $document.on('click', onDocumentClick); | |
| 954 | + | |
| 955 | + scope.$on('$destroy', function() { | |
| 956 | + $document.off('click', onDocumentClick); | |
| 957 | + }); | |
| 958 | + | |
| 959 | + // Move transcluded elements to their correct position in main template | |
| 960 | + transcludeFn(scope, function(clone) { | |
| 961 | + // See Transclude in AngularJS http://blog.omkarpatil.com/2012/11/transclude-in-angularjs.html | |
| 962 | + | |
| 963 | + // One day jqLite will be replaced by jQuery and we will be able to write: | |
| 964 | + // var transcludedElement = clone.filter('.my-class') | |
| 965 | + // instead of creating a hackish DOM element: | |
| 966 | + var transcluded = angular.element('<div>').append(clone); | |
| 967 | + | |
| 968 | + var transcludedMatch = transcluded.querySelectorAll('.ui-select-match'); | |
| 969 | + transcludedMatch.removeAttr('ui-select-match'); //To avoid loop in case directive as attr | |
| 970 | + transcludedMatch.removeAttr('data-ui-select-match'); // Properly handle HTML5 data-attributes | |
| 971 | + if (transcludedMatch.length !== 1) { | |
| 972 | + throw uiSelectMinErr('transcluded', "Expected 1 .ui-select-match but got '{0}'.", transcludedMatch.length); | |
| 973 | + } | |
| 974 | + element.querySelectorAll('.ui-select-match').replaceWith(transcludedMatch); | |
| 975 | + | |
| 976 | + var transcludedChoices = transcluded.querySelectorAll('.ui-select-choices'); | |
| 977 | + transcludedChoices.removeAttr('ui-select-choices'); //To avoid loop in case directive as attr | |
| 978 | + transcludedChoices.removeAttr('data-ui-select-choices'); // Properly handle HTML5 data-attributes | |
| 979 | + if (transcludedChoices.length !== 1) { | |
| 980 | + throw uiSelectMinErr('transcluded', "Expected 1 .ui-select-choices but got '{0}'.", transcludedChoices.length); | |
| 981 | + } | |
| 982 | + element.querySelectorAll('.ui-select-choices').replaceWith(transcludedChoices); | |
| 983 | + }); | |
| 984 | + | |
| 985 | + // Support for appending the select field to the body when its open | |
| 986 | + var appendToBody = scope.$eval(attrs.appendToBody); | |
| 987 | + if (appendToBody !== undefined ? appendToBody : uiSelectConfig.appendToBody) { | |
| 988 | + scope.$watch('$select.open', function(isOpen) { | |
| 989 | + if (isOpen) { | |
| 990 | + positionDropdown(); | |
| 991 | + } else { | |
| 992 | + resetDropdown(); | |
| 993 | + } | |
| 994 | + }); | |
| 995 | + | |
| 996 | + // Move the dropdown back to its original location when the scope is destroyed. Otherwise | |
| 997 | + // it might stick around when the user routes away or the select field is otherwise removed | |
| 998 | + scope.$on('$destroy', function() { | |
| 999 | + resetDropdown(); | |
| 1000 | + }); | |
| 1001 | + } | |
| 1002 | + | |
| 1003 | + // Hold on to a reference to the .ui-select-container element for appendToBody support | |
| 1004 | + var placeholder = null, | |
| 1005 | + originalWidth = ''; | |
| 1006 | + | |
| 1007 | + function positionDropdown() { | |
| 1008 | + // Remember the absolute position of the element | |
| 1009 | + var offset = uisOffset(element); | |
| 1010 | + | |
| 1011 | + // Clone the element into a placeholder element to take its original place in the DOM | |
| 1012 | + placeholder = angular.element('<div class="ui-select-placeholder"></div>'); | |
| 1013 | + placeholder[0].style.width = offset.width + 'px'; | |
| 1014 | + placeholder[0].style.height = offset.height + 'px'; | |
| 1015 | + element.after(placeholder); | |
| 1016 | + | |
| 1017 | + // Remember the original value of the element width inline style, so it can be restored | |
| 1018 | + // when the dropdown is closed | |
| 1019 | + originalWidth = element[0].style.width; | |
| 1020 | + | |
| 1021 | + // Now move the actual dropdown element to the end of the body | |
| 1022 | + $document.find('body').append(element); | |
| 1023 | + | |
| 1024 | + element[0].style.position = 'absolute'; | |
| 1025 | + element[0].style.left = offset.left + 'px'; | |
| 1026 | + element[0].style.top = offset.top + 'px'; | |
| 1027 | + element[0].style.width = offset.width + 'px'; | |
| 1028 | + } | |
| 1029 | + | |
| 1030 | + function resetDropdown() { | |
| 1031 | + if (placeholder === null) { | |
| 1032 | + // The dropdown has not actually been display yet, so there's nothing to reset | |
| 1033 | + return; | |
| 1034 | + } | |
| 1035 | + | |
| 1036 | + // Move the dropdown element back to its original location in the DOM | |
| 1037 | + placeholder.replaceWith(element); | |
| 1038 | + placeholder = null; | |
| 1039 | + | |
| 1040 | + element[0].style.position = ''; | |
| 1041 | + element[0].style.left = ''; | |
| 1042 | + element[0].style.top = ''; | |
| 1043 | + element[0].style.width = originalWidth; | |
| 1044 | + } | |
| 1045 | + | |
| 1046 | + // Hold on to a reference to the .ui-select-dropdown element for direction support. | |
| 1047 | + var dropdown = null, | |
| 1048 | + directionUpClassName = 'direction-up'; | |
| 1049 | + | |
| 1050 | + // Support changing the direction of the dropdown if there isn't enough space to render it. | |
| 1051 | + scope.$watch('$select.open', function() { | |
| 1052 | + | |
| 1053 | + if ($select.dropdownPosition === 'auto' || $select.dropdownPosition === 'up'){ | |
| 1054 | + scope.calculateDropdownPos(); | |
| 1055 | + } | |
| 1056 | + | |
| 1057 | + }); | |
| 1058 | + | |
| 1059 | + var setDropdownPosUp = function(offset, offsetDropdown){ | |
| 1060 | + | |
| 1061 | + offset = offset || uisOffset(element); | |
| 1062 | + offsetDropdown = offsetDropdown || uisOffset(dropdown); | |
| 1063 | + | |
| 1064 | + dropdown[0].style.position = 'absolute'; | |
| 1065 | + dropdown[0].style.top = (offsetDropdown.height * -1) + 'px'; | |
| 1066 | + element.addClass(directionUpClassName); | |
| 1067 | + | |
| 1068 | + }; | |
| 1069 | + | |
| 1070 | + var setDropdownPosDown = function(offset, offsetDropdown){ | |
| 1071 | + | |
| 1072 | + element.removeClass(directionUpClassName); | |
| 1073 | + | |
| 1074 | + offset = offset || uisOffset(element); | |
| 1075 | + offsetDropdown = offsetDropdown || uisOffset(dropdown); | |
| 1076 | + | |
| 1077 | + dropdown[0].style.position = ''; | |
| 1078 | + dropdown[0].style.top = ''; | |
| 1079 | + | |
| 1080 | + }; | |
| 1081 | + | |
| 1082 | + scope.calculateDropdownPos = function(){ | |
| 1083 | + | |
| 1084 | + if ($select.open) { | |
| 1085 | + dropdown = angular.element(element).querySelectorAll('.ui-select-dropdown'); | |
| 1086 | + if (dropdown.length === 0) { | |
| 1087 | + return; | |
| 1088 | + } | |
| 1089 | + | |
| 1090 | + // Hide the dropdown so there is no flicker until $timeout is done executing. | |
| 1091 | + dropdown[0].style.opacity = 0; | |
| 1092 | + | |
| 1093 | + // Delay positioning the dropdown until all choices have been added so its height is correct. | |
| 1094 | + $timeout(function(){ | |
| 1095 | + | |
| 1096 | + if ($select.dropdownPosition === 'up'){ | |
| 1097 | + //Go UP | |
| 1098 | + setDropdownPosUp(offset, offsetDropdown); | |
| 1099 | + | |
| 1100 | + }else{ //AUTO | |
| 1101 | + | |
| 1102 | + element.removeClass(directionUpClassName); | |
| 1103 | + | |
| 1104 | + var offset = uisOffset(element); | |
| 1105 | + var offsetDropdown = uisOffset(dropdown); | |
| 1106 | + | |
| 1107 | + //https://code.google.com/p/chromium/issues/detail?id=342307#c4 | |
| 1108 | + var scrollTop = $document[0].documentElement.scrollTop || $document[0].body.scrollTop; //To make it cross browser (blink, webkit, IE, Firefox). | |
| 1109 | + | |
| 1110 | + // Determine if the direction of the dropdown needs to be changed. | |
| 1111 | + if (offset.top + offset.height + offsetDropdown.height > scrollTop + $document[0].documentElement.clientHeight) { | |
| 1112 | + //Go UP | |
| 1113 | + setDropdownPosUp(offset, offsetDropdown); | |
| 1114 | + }else{ | |
| 1115 | + //Go DOWN | |
| 1116 | + setDropdownPosDown(offset, offsetDropdown); | |
| 1117 | + } | |
| 1118 | + | |
| 1119 | + } | |
| 1120 | + | |
| 1121 | + // Display the dropdown once it has been positioned. | |
| 1122 | + dropdown[0].style.opacity = 1; | |
| 1123 | + }); | |
| 1124 | + } else { | |
| 1125 | + if (dropdown === null || dropdown.length === 0) { | |
| 1126 | + return; | |
| 1127 | + } | |
| 1128 | + | |
| 1129 | + // Reset the position of the dropdown. | |
| 1130 | + dropdown[0].style.position = ''; | |
| 1131 | + dropdown[0].style.top = ''; | |
| 1132 | + element.removeClass(directionUpClassName); | |
| 1133 | + } | |
| 1134 | + }; | |
| 1135 | + }; | |
| 1136 | + } | |
| 1137 | + }; | |
| 1138 | +}]); | |
| 1139 | + | |
| 1140 | +uis.directive('uiSelectMatch', ['uiSelectConfig', function(uiSelectConfig) { | |
| 1141 | + return { | |
| 1142 | + restrict: 'EA', | |
| 1143 | + require: '^uiSelect', | |
| 1144 | + replace: true, | |
| 1145 | + transclude: true, | |
| 1146 | + templateUrl: function(tElement) { | |
| 1147 | + // Gets theme attribute from parent (ui-select) | |
| 1148 | + var theme = tElement.parent().attr('theme') || uiSelectConfig.theme; | |
| 1149 | + var multi = tElement.parent().attr('multiple'); | |
| 1150 | + return theme + (multi ? '/match-multiple.tpl.html' : '/match.tpl.html'); | |
| 1151 | + }, | |
| 1152 | + link: function(scope, element, attrs, $select) { | |
| 1153 | + $select.lockChoiceExpression = attrs.uiLockChoice; | |
| 1154 | + attrs.$observe('placeholder', function(placeholder) { | |
| 1155 | + $select.placeholder = placeholder !== undefined ? placeholder : uiSelectConfig.placeholder; | |
| 1156 | + }); | |
| 1157 | + | |
| 1158 | + function setAllowClear(allow) { | |
| 1159 | + $select.allowClear = (angular.isDefined(allow)) ? (allow === '') ? true : (allow.toLowerCase() === 'true') : false; | |
| 1160 | + } | |
| 1161 | + | |
| 1162 | + attrs.$observe('allowClear', setAllowClear); | |
| 1163 | + setAllowClear(attrs.allowClear); | |
| 1164 | + | |
| 1165 | + if($select.multiple){ | |
| 1166 | + $select.sizeSearchInput(); | |
| 1167 | + } | |
| 1168 | + | |
| 1169 | + } | |
| 1170 | + }; | |
| 1171 | +}]); | |
| 1172 | + | |
| 1173 | +uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelectMinErr, $timeout) { | |
| 1174 | + return { | |
| 1175 | + restrict: 'EA', | |
| 1176 | + require: ['^uiSelect', '^ngModel'], | |
| 1177 | + | |
| 1178 | + controller: ['$scope','$timeout', function($scope, $timeout){ | |
| 1179 | + | |
| 1180 | + var ctrl = this, | |
| 1181 | + $select = $scope.$select, | |
| 1182 | + ngModel; | |
| 1183 | + | |
| 1184 | + //Wait for link fn to inject it | |
| 1185 | + $scope.$evalAsync(function(){ ngModel = $scope.ngModel; }); | |
| 1186 | + | |
| 1187 | + ctrl.activeMatchIndex = -1; | |
| 1188 | + | |
| 1189 | + ctrl.updateModel = function(){ | |
| 1190 | + ngModel.$setViewValue(Date.now()); //Set timestamp as a unique string to force changes | |
| 1191 | + ctrl.refreshComponent(); | |
| 1192 | + }; | |
| 1193 | + | |
| 1194 | + ctrl.refreshComponent = function(){ | |
| 1195 | + //Remove already selected items | |
| 1196 | + //e.g. When user clicks on a selection, the selected array changes and | |
| 1197 | + //the dropdown should remove that item | |
| 1198 | + $select.refreshItems(); | |
| 1199 | + $select.sizeSearchInput(); | |
| 1200 | + }; | |
| 1201 | + | |
| 1202 | + // Remove item from multiple select | |
| 1203 | + ctrl.removeChoice = function(index){ | |
| 1204 | + | |
| 1205 | + var removedChoice = $select.selected[index]; | |
| 1206 | + | |
| 1207 | + // if the choice is locked, can't remove it | |
| 1208 | + if(removedChoice._uiSelectChoiceLocked) return; | |
| 1209 | + | |
| 1210 | + var locals = {}; | |
| 1211 | + locals[$select.parserResult.itemName] = removedChoice; | |
| 1212 | + | |
| 1213 | + $select.selected.splice(index, 1); | |
| 1214 | + ctrl.activeMatchIndex = -1; | |
| 1215 | + $select.sizeSearchInput(); | |
| 1216 | + | |
| 1217 | + // Give some time for scope propagation. | |
| 1218 | + $timeout(function(){ | |
| 1219 | + $select.onRemoveCallback($scope, { | |
| 1220 | + $item: removedChoice, | |
| 1221 | + $model: $select.parserResult.modelMapper($scope, locals) | |
| 1222 | + }); | |
| 1223 | + }); | |
| 1224 | + | |
| 1225 | + ctrl.updateModel(); | |
| 1226 | + | |
| 1227 | + }; | |
| 1228 | + | |
| 1229 | + ctrl.getPlaceholder = function(){ | |
| 1230 | + //Refactor single? | |
| 1231 | + if($select.selected && $select.selected.length) return; | |
| 1232 | + return $select.placeholder; | |
| 1233 | + }; | |
| 1234 | + | |
| 1235 | + | |
| 1236 | + }], | |
| 1237 | + controllerAs: '$selectMultiple', | |
| 1238 | + | |
| 1239 | + link: function(scope, element, attrs, ctrls) { | |
| 1240 | + | |
| 1241 | + var $select = ctrls[0]; | |
| 1242 | + var ngModel = scope.ngModel = ctrls[1]; | |
| 1243 | + var $selectMultiple = scope.$selectMultiple; | |
| 1244 | + | |
| 1245 | + //$select.selected = raw selected objects (ignoring any property binding) | |
| 1246 | + | |
| 1247 | + $select.multiple = true; | |
| 1248 | + $select.removeSelected = true; | |
| 1249 | + | |
| 1250 | + //Input that will handle focus | |
| 1251 | + $select.focusInput = $select.searchInput; | |
| 1252 | + | |
| 1253 | + //From view --> model | |
| 1254 | + ngModel.$parsers.unshift(function () { | |
| 1255 | + var locals = {}, | |
| 1256 | + result, | |
| 1257 | + resultMultiple = []; | |
| 1258 | + for (var j = $select.selected.length - 1; j >= 0; j--) { | |
| 1259 | + locals = {}; | |
| 1260 | + locals[$select.parserResult.itemName] = $select.selected[j]; | |
| 1261 | + result = $select.parserResult.modelMapper(scope, locals); | |
| 1262 | + resultMultiple.unshift(result); | |
| 1263 | + } | |
| 1264 | + return resultMultiple; | |
| 1265 | + }); | |
| 1266 | + | |
| 1267 | + // From model --> view | |
| 1268 | + ngModel.$formatters.unshift(function (inputValue) { | |
| 1269 | + var data = $select.parserResult.source (scope, { $select : {search:''}}), //Overwrite $search | |
| 1270 | + locals = {}, | |
| 1271 | + result; | |
| 1272 | + if (!data) return inputValue; | |
| 1273 | + var resultMultiple = []; | |
| 1274 | + var checkFnMultiple = function(list, value){ | |
| 1275 | + if (!list || !list.length) return; | |
| 1276 | + for (var p = list.length - 1; p >= 0; p--) { | |
| 1277 | + locals[$select.parserResult.itemName] = list[p]; | |
| 1278 | + result = $select.parserResult.modelMapper(scope, locals); | |
| 1279 | + if($select.parserResult.trackByExp){ | |
| 1280 | + var matches = /\.(.+)/.exec($select.parserResult.trackByExp); | |
| 1281 | + if(matches.length>0 && result[matches[1]] == value[matches[1]]){ | |
| 1282 | + resultMultiple.unshift(list[p]); | |
| 1283 | + return true; | |
| 1284 | + } | |
| 1285 | + } | |
| 1286 | + if (angular.equals(result,value)){ | |
| 1287 | + resultMultiple.unshift(list[p]); | |
| 1288 | + return true; | |
| 1289 | + } | |
| 1290 | + } | |
| 1291 | + return false; | |
| 1292 | + }; | |
| 1293 | + if (!inputValue) return resultMultiple; //If ngModel was undefined | |
| 1294 | + for (var k = inputValue.length - 1; k >= 0; k--) { | |
| 1295 | + //Check model array of currently selected items | |
| 1296 | + if (!checkFnMultiple($select.selected, inputValue[k])){ | |
| 1297 | + //Check model array of all items available | |
| 1298 | + if (!checkFnMultiple(data, inputValue[k])){ | |
| 1299 | + //If not found on previous lists, just add it directly to resultMultiple | |
| 1300 | + resultMultiple.unshift(inputValue[k]); | |
| 1301 | + } | |
| 1302 | + } | |
| 1303 | + } | |
| 1304 | + return resultMultiple; | |
| 1305 | + }); | |
| 1306 | + | |
| 1307 | + //Watch for external model changes | |
| 1308 | + scope.$watchCollection(function(){ return ngModel.$modelValue; }, function(newValue, oldValue) { | |
| 1309 | + if (oldValue != newValue){ | |
| 1310 | + ngModel.$modelValue = null; //Force scope model value and ngModel value to be out of sync to re-run formatters | |
| 1311 | + $selectMultiple.refreshComponent(); | |
| 1312 | + } | |
| 1313 | + }); | |
| 1314 | + | |
| 1315 | + ngModel.$render = function() { | |
| 1316 | + // Make sure that model value is array | |
| 1317 | + if(!angular.isArray(ngModel.$viewValue)){ | |
| 1318 | + // Have tolerance for null or undefined values | |
| 1319 | + if(angular.isUndefined(ngModel.$viewValue) || ngModel.$viewValue === null){ | |
| 1320 | + $select.selected = []; | |
| 1321 | + } else { | |
| 1322 | + throw uiSelectMinErr('multiarr', "Expected model value to be array but got '{0}'", ngModel.$viewValue); | |
| 1323 | + } | |
| 1324 | + } | |
| 1325 | + $select.selected = ngModel.$viewValue; | |
| 1326 | + scope.$evalAsync(); //To force $digest | |
| 1327 | + }; | |
| 1328 | + | |
| 1329 | + scope.$on('uis:select', function (event, item) { | |
| 1330 | + if($select.selected.length >= $select.limit) { | |
| 1331 | + return; | |
| 1332 | + } | |
| 1333 | + $select.selected.push(item); | |
| 1334 | + $selectMultiple.updateModel(); | |
| 1335 | + }); | |
| 1336 | + | |
| 1337 | + scope.$on('uis:activate', function () { | |
| 1338 | + $selectMultiple.activeMatchIndex = -1; | |
| 1339 | + }); | |
| 1340 | + | |
| 1341 | + scope.$watch('$select.disabled', function(newValue, oldValue) { | |
| 1342 | + // As the search input field may now become visible, it may be necessary to recompute its size | |
| 1343 | + if (oldValue && !newValue) $select.sizeSearchInput(); | |
| 1344 | + }); | |
| 1345 | + | |
| 1346 | + $select.searchInput.on('keydown', function(e) { | |
| 1347 | + var key = e.which; | |
| 1348 | + scope.$apply(function() { | |
| 1349 | + var processed = false; | |
| 1350 | + // var tagged = false; //Checkme | |
| 1351 | + if(KEY.isHorizontalMovement(key)){ | |
| 1352 | + processed = _handleMatchSelection(key); | |
| 1353 | + } | |
| 1354 | + if (processed && key != KEY.TAB) { | |
| 1355 | + //TODO Check si el tab selecciona aun correctamente | |
| 1356 | + //Crear test | |
| 1357 | + e.preventDefault(); | |
| 1358 | + e.stopPropagation(); | |
| 1359 | + } | |
| 1360 | + }); | |
| 1361 | + }); | |
| 1362 | + function _getCaretPosition(el) { | |
| 1363 | + if(angular.isNumber(el.selectionStart)) return el.selectionStart; | |
| 1364 | + // selectionStart is not supported in IE8 and we don't want hacky workarounds so we compromise | |
| 1365 | + else return el.value.length; | |
| 1366 | + } | |
| 1367 | + // Handles selected options in "multiple" mode | |
| 1368 | + function _handleMatchSelection(key){ | |
| 1369 | + var caretPosition = _getCaretPosition($select.searchInput[0]), | |
| 1370 | + length = $select.selected.length, | |
| 1371 | + // none = -1, | |
| 1372 | + first = 0, | |
| 1373 | + last = length-1, | |
| 1374 | + curr = $selectMultiple.activeMatchIndex, | |
| 1375 | + next = $selectMultiple.activeMatchIndex+1, | |
| 1376 | + prev = $selectMultiple.activeMatchIndex-1, | |
| 1377 | + newIndex = curr; | |
| 1378 | + | |
| 1379 | + if(caretPosition > 0 || ($select.search.length && key == KEY.RIGHT)) return false; | |
| 1380 | + | |
| 1381 | + $select.close(); | |
| 1382 | + | |
| 1383 | + function getNewActiveMatchIndex(){ | |
| 1384 | + switch(key){ | |
| 1385 | + case KEY.LEFT: | |
| 1386 | + // Select previous/first item | |
| 1387 | + if(~$selectMultiple.activeMatchIndex) return prev; | |
| 1388 | + // Select last item | |
| 1389 | + else return last; | |
| 1390 | + break; | |
| 1391 | + case KEY.RIGHT: | |
| 1392 | + // Open drop-down | |
| 1393 | + if(!~$selectMultiple.activeMatchIndex || curr === last){ | |
| 1394 | + $select.activate(); | |
| 1395 | + return false; | |
| 1396 | + } | |
| 1397 | + // Select next/last item | |
| 1398 | + else return next; | |
| 1399 | + break; | |
| 1400 | + case KEY.BACKSPACE: | |
| 1401 | + // Remove selected item and select previous/first | |
| 1402 | + if(~$selectMultiple.activeMatchIndex){ | |
| 1403 | + $selectMultiple.removeChoice(curr); | |
| 1404 | + return prev; | |
| 1405 | + } | |
| 1406 | + // Select last item | |
| 1407 | + else return last; | |
| 1408 | + break; | |
| 1409 | + case KEY.DELETE: | |
| 1410 | + // Remove selected item and select next item | |
| 1411 | + if(~$selectMultiple.activeMatchIndex){ | |
| 1412 | + $selectMultiple.removeChoice($selectMultiple.activeMatchIndex); | |
| 1413 | + return curr; | |
| 1414 | + } | |
| 1415 | + else return false; | |
| 1416 | + } | |
| 1417 | + } | |
| 1418 | + | |
| 1419 | + newIndex = getNewActiveMatchIndex(); | |
| 1420 | + | |
| 1421 | + if(!$select.selected.length || newIndex === false) $selectMultiple.activeMatchIndex = -1; | |
| 1422 | + else $selectMultiple.activeMatchIndex = Math.min(last,Math.max(first,newIndex)); | |
| 1423 | + | |
| 1424 | + return true; | |
| 1425 | + } | |
| 1426 | + | |
| 1427 | + $select.searchInput.on('keyup', function(e) { | |
| 1428 | + | |
| 1429 | + if ( ! KEY.isVerticalMovement(e.which) ) { | |
| 1430 | + scope.$evalAsync( function () { | |
| 1431 | + $select.activeIndex = $select.taggingLabel === false ? -1 : 0; | |
| 1432 | + }); | |
| 1433 | + } | |
| 1434 | + // Push a "create new" item into array if there is a search string | |
| 1435 | + if ( $select.tagging.isActivated && $select.search.length > 0 ) { | |
| 1436 | + | |
| 1437 | + // return early with these keys | |
| 1438 | + if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.ESC || KEY.isVerticalMovement(e.which) ) { | |
| 1439 | + return; | |
| 1440 | + } | |
| 1441 | + // always reset the activeIndex to the first item when tagging | |
| 1442 | + $select.activeIndex = $select.taggingLabel === false ? -1 : 0; | |
| 1443 | + // taggingLabel === false bypasses all of this | |
| 1444 | + if ($select.taggingLabel === false) return; | |
| 1445 | + | |
| 1446 | + var items = angular.copy( $select.items ); | |
| 1447 | + var stashArr = angular.copy( $select.items ); | |
| 1448 | + var newItem; | |
| 1449 | + var item; | |
| 1450 | + var hasTag = false; | |
| 1451 | + var dupeIndex = -1; | |
| 1452 | + var tagItems; | |
| 1453 | + var tagItem; | |
| 1454 | + | |
| 1455 | + // case for object tagging via transform `$select.tagging.fct` function | |
| 1456 | + if ( $select.tagging.fct !== undefined) { | |
| 1457 | + tagItems = $select.$filter('filter')(items,{'isTag': true}); | |
| 1458 | + if ( tagItems.length > 0 ) { | |
| 1459 | + tagItem = tagItems[0]; | |
| 1460 | + } | |
| 1461 | + // remove the first element, if it has the `isTag` prop we generate a new one with each keyup, shaving the previous | |
| 1462 | + if ( items.length > 0 && tagItem ) { | |
| 1463 | + hasTag = true; | |
| 1464 | + items = items.slice(1,items.length); | |
| 1465 | + stashArr = stashArr.slice(1,stashArr.length); | |
| 1466 | + } | |
| 1467 | + newItem = $select.tagging.fct($select.search); | |
| 1468 | + newItem.isTag = true; | |
| 1469 | + // verify the the tag doesn't match the value of an existing item | |
| 1470 | + if ( stashArr.filter( function (origItem) { return angular.equals( origItem, $select.tagging.fct($select.search) ); } ).length > 0 ) { | |
| 1471 | + return; | |
| 1472 | + } | |
| 1473 | + newItem.isTag = true; | |
| 1474 | + // handle newItem string and stripping dupes in tagging string context | |
| 1475 | + } else { | |
| 1476 | + // find any tagging items already in the $select.items array and store them | |
| 1477 | + tagItems = $select.$filter('filter')(items,function (item) { | |
| 1478 | + return item.match($select.taggingLabel); | |
| 1479 | + }); | |
| 1480 | + if ( tagItems.length > 0 ) { | |
| 1481 | + tagItem = tagItems[0]; | |
| 1482 | + } | |
| 1483 | + item = items[0]; | |
| 1484 | + // remove existing tag item if found (should only ever be one tag item) | |
| 1485 | + if ( item !== undefined && items.length > 0 && tagItem ) { | |
| 1486 | + hasTag = true; | |
| 1487 | + items = items.slice(1,items.length); | |
| 1488 | + stashArr = stashArr.slice(1,stashArr.length); | |
| 1489 | + } | |
| 1490 | + newItem = $select.search+' '+$select.taggingLabel; | |
| 1491 | + if ( _findApproxDupe($select.selected, $select.search) > -1 ) { | |
| 1492 | + return; | |
| 1493 | + } | |
| 1494 | + // verify the the tag doesn't match the value of an existing item from | |
| 1495 | + // the searched data set or the items already selected | |
| 1496 | + if ( _findCaseInsensitiveDupe(stashArr.concat($select.selected)) ) { | |
| 1497 | + // if there is a tag from prev iteration, strip it / queue the change | |
| 1498 | + // and return early | |
| 1499 | + if ( hasTag ) { | |
| 1500 | + items = stashArr; | |
| 1501 | + scope.$evalAsync( function () { | |
| 1502 | + $select.activeIndex = 0; | |
| 1503 | + $select.items = items; | |
| 1504 | + }); | |
| 1505 | + } | |
| 1506 | + return; | |
| 1507 | + } | |
| 1508 | + if ( _findCaseInsensitiveDupe(stashArr) ) { | |
| 1509 | + // if there is a tag from prev iteration, strip it | |
| 1510 | + if ( hasTag ) { | |
| 1511 | + $select.items = stashArr.slice(1,stashArr.length); | |
| 1512 | + } | |
| 1513 | + return; | |
| 1514 | + } | |
| 1515 | + } | |
| 1516 | + if ( hasTag ) dupeIndex = _findApproxDupe($select.selected, newItem); | |
| 1517 | + // dupe found, shave the first item | |
| 1518 | + if ( dupeIndex > -1 ) { | |
| 1519 | + items = items.slice(dupeIndex+1,items.length-1); | |
| 1520 | + } else { | |
| 1521 | + items = []; | |
| 1522 | + items.push(newItem); | |
| 1523 | + items = items.concat(stashArr); | |
| 1524 | + } | |
| 1525 | + scope.$evalAsync( function () { | |
| 1526 | + $select.activeIndex = 0; | |
| 1527 | + $select.items = items; | |
| 1528 | + }); | |
| 1529 | + } | |
| 1530 | + }); | |
| 1531 | + function _findCaseInsensitiveDupe(arr) { | |
| 1532 | + if ( arr === undefined || $select.search === undefined ) { | |
| 1533 | + return false; | |
| 1534 | + } | |
| 1535 | + var hasDupe = arr.filter( function (origItem) { | |
| 1536 | + if ( $select.search.toUpperCase() === undefined || origItem === undefined ) { | |
| 1537 | + return false; | |
| 1538 | + } | |
| 1539 | + return origItem.toUpperCase() === $select.search.toUpperCase(); | |
| 1540 | + }).length > 0; | |
| 1541 | + | |
| 1542 | + return hasDupe; | |
| 1543 | + } | |
| 1544 | + function _findApproxDupe(haystack, needle) { | |
| 1545 | + var dupeIndex = -1; | |
| 1546 | + if(angular.isArray(haystack)) { | |
| 1547 | + var tempArr = angular.copy(haystack); | |
| 1548 | + for (var i = 0; i <tempArr.length; i++) { | |
| 1549 | + // handle the simple string version of tagging | |
| 1550 | + if ( $select.tagging.fct === undefined ) { | |
| 1551 | + // search the array for the match | |
| 1552 | + if ( tempArr[i]+' '+$select.taggingLabel === needle ) { | |
| 1553 | + dupeIndex = i; | |
| 1554 | + } | |
| 1555 | + // handle the object tagging implementation | |
| 1556 | + } else { | |
| 1557 | + var mockObj = tempArr[i]; | |
| 1558 | + mockObj.isTag = true; | |
| 1559 | + if ( angular.equals(mockObj, needle) ) { | |
| 1560 | + dupeIndex = i; | |
| 1561 | + } | |
| 1562 | + } | |
| 1563 | + } | |
| 1564 | + } | |
| 1565 | + return dupeIndex; | |
| 1566 | + } | |
| 1567 | + | |
| 1568 | + $select.searchInput.on('blur', function() { | |
| 1569 | + $timeout(function() { | |
| 1570 | + $selectMultiple.activeMatchIndex = -1; | |
| 1571 | + }); | |
| 1572 | + }); | |
| 1573 | + | |
| 1574 | + } | |
| 1575 | + }; | |
| 1576 | +}]); | |
| 1577 | + | |
| 1578 | +uis.directive('uiSelectSingle', ['$timeout','$compile', function($timeout, $compile) { | |
| 1579 | + return { | |
| 1580 | + restrict: 'EA', | |
| 1581 | + require: ['^uiSelect', '^ngModel'], | |
| 1582 | + link: function(scope, element, attrs, ctrls) { | |
| 1583 | + | |
| 1584 | + var $select = ctrls[0]; | |
| 1585 | + var ngModel = ctrls[1]; | |
| 1586 | + | |
| 1587 | + //From view --> model | |
| 1588 | + ngModel.$parsers.unshift(function (inputValue) { | |
| 1589 | + var locals = {}, | |
| 1590 | + result; | |
| 1591 | + locals[$select.parserResult.itemName] = inputValue; | |
| 1592 | + result = $select.parserResult.modelMapper(scope, locals); | |
| 1593 | + return result; | |
| 1594 | + }); | |
| 1595 | + | |
| 1596 | + //From model --> view | |
| 1597 | + ngModel.$formatters.unshift(function (inputValue) { | |
| 1598 | + var data = $select.parserResult.source (scope, { $select : {search:''}}), //Overwrite $search | |
| 1599 | + locals = {}, | |
| 1600 | + result; | |
| 1601 | + if (data){ | |
| 1602 | + var checkFnSingle = function(d){ | |
| 1603 | + locals[$select.parserResult.itemName] = d; | |
| 1604 | + result = $select.parserResult.modelMapper(scope, locals); | |
| 1605 | + return result == inputValue; | |
| 1606 | + }; | |
| 1607 | + //If possible pass same object stored in $select.selected | |
| 1608 | + if ($select.selected && checkFnSingle($select.selected)) { | |
| 1609 | + return $select.selected; | |
| 1610 | + } | |
| 1611 | + for (var i = data.length - 1; i >= 0; i--) { | |
| 1612 | + if (checkFnSingle(data[i])) return data[i]; | |
| 1613 | + } | |
| 1614 | + } | |
| 1615 | + return inputValue; | |
| 1616 | + }); | |
| 1617 | + | |
| 1618 | + //Update viewValue if model change | |
| 1619 | + scope.$watch('$select.selected', function(newValue) { | |
| 1620 | + if (ngModel.$viewValue !== newValue) { | |
| 1621 | + ngModel.$setViewValue(newValue); | |
| 1622 | + } | |
| 1623 | + }); | |
| 1624 | + | |
| 1625 | + ngModel.$render = function() { | |
| 1626 | + $select.selected = ngModel.$viewValue; | |
| 1627 | + }; | |
| 1628 | + | |
| 1629 | + scope.$on('uis:select', function (event, item) { | |
| 1630 | + $select.selected = item; | |
| 1631 | + }); | |
| 1632 | + | |
| 1633 | + scope.$on('uis:close', function (event, skipFocusser) { | |
| 1634 | + $timeout(function(){ | |
| 1635 | + $select.focusser.prop('disabled', false); | |
| 1636 | + if (!skipFocusser) $select.focusser[0].focus(); | |
| 1637 | + },0,false); | |
| 1638 | + }); | |
| 1639 | + | |
| 1640 | + scope.$on('uis:activate', function () { | |
| 1641 | + focusser.prop('disabled', true); //Will reactivate it on .close() | |
| 1642 | + }); | |
| 1643 | + | |
| 1644 | + //Idea from: https://github.com/ivaynberg/select2/blob/79b5bf6db918d7560bdd959109b7bcfb47edaf43/select2.js#L1954 | |
| 1645 | + 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' />"); | |
| 1646 | + $compile(focusser)(scope); | |
| 1647 | + $select.focusser = focusser; | |
| 1648 | + | |
| 1649 | + //Input that will handle focus | |
| 1650 | + $select.focusInput = focusser; | |
| 1651 | + | |
| 1652 | + element.parent().append(focusser); | |
| 1653 | + focusser.bind("focus", function(){ | |
| 1654 | + scope.$evalAsync(function(){ | |
| 1655 | + $select.focus = true; | |
| 1656 | + }); | |
| 1657 | + }); | |
| 1658 | + focusser.bind("blur", function(){ | |
| 1659 | + scope.$evalAsync(function(){ | |
| 1660 | + $select.focus = false; | |
| 1661 | + }); | |
| 1662 | + }); | |
| 1663 | + focusser.bind("keydown", function(e){ | |
| 1664 | + | |
| 1665 | + if (e.which === KEY.BACKSPACE) { | |
| 1666 | + e.preventDefault(); | |
| 1667 | + e.stopPropagation(); | |
| 1668 | + $select.select(undefined); | |
| 1669 | + scope.$apply(); | |
| 1670 | + return; | |
| 1671 | + } | |
| 1672 | + | |
| 1673 | + if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.ESC) { | |
| 1674 | + return; | |
| 1675 | + } | |
| 1676 | + | |
| 1677 | + if (e.which == KEY.DOWN || e.which == KEY.UP || e.which == KEY.ENTER || e.which == KEY.SPACE){ | |
| 1678 | + e.preventDefault(); | |
| 1679 | + e.stopPropagation(); | |
| 1680 | + $select.activate(); | |
| 1681 | + } | |
| 1682 | + | |
| 1683 | + scope.$digest(); | |
| 1684 | + }); | |
| 1685 | + | |
| 1686 | + focusser.bind("keyup input", function(e){ | |
| 1687 | + | |
| 1688 | + if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.ESC || e.which == KEY.ENTER || e.which === KEY.BACKSPACE) { | |
| 1689 | + return; | |
| 1690 | + } | |
| 1691 | + | |
| 1692 | + $select.activate(focusser.val()); //User pressed some regular key, so we pass it to the search input | |
| 1693 | + focusser.val(''); | |
| 1694 | + scope.$digest(); | |
| 1695 | + | |
| 1696 | + }); | |
| 1697 | + | |
| 1698 | + | |
| 1699 | + } | |
| 1700 | + }; | |
| 1701 | +}]); | |
| 1702 | +// Make multiple matches sortable | |
| 1703 | +uis.directive('uiSelectSort', ['$timeout', 'uiSelectConfig', 'uiSelectMinErr', function($timeout, uiSelectConfig, uiSelectMinErr) { | |
| 1704 | + return { | |
| 1705 | + require: '^uiSelect', | |
| 1706 | + link: function(scope, element, attrs, $select) { | |
| 1707 | + if (scope[attrs.uiSelectSort] === null) { | |
| 1708 | + throw uiSelectMinErr('sort', "Expected a list to sort"); | |
| 1709 | + } | |
| 1710 | + | |
| 1711 | + var options = angular.extend({ | |
| 1712 | + axis: 'horizontal' | |
| 1713 | + }, | |
| 1714 | + scope.$eval(attrs.uiSelectSortOptions)); | |
| 1715 | + | |
| 1716 | + var axis = options.axis, | |
| 1717 | + draggingClassName = 'dragging', | |
| 1718 | + droppingClassName = 'dropping', | |
| 1719 | + droppingBeforeClassName = 'dropping-before', | |
| 1720 | + droppingAfterClassName = 'dropping-after'; | |
| 1721 | + | |
| 1722 | + scope.$watch(function(){ | |
| 1723 | + return $select.sortable; | |
| 1724 | + }, function(n){ | |
| 1725 | + if (n) { | |
| 1726 | + element.attr('draggable', true); | |
| 1727 | + } else { | |
| 1728 | + element.removeAttr('draggable'); | |
| 1729 | + } | |
| 1730 | + }); | |
| 1731 | + | |
| 1732 | + element.on('dragstart', function(e) { | |
| 1733 | + element.addClass(draggingClassName); | |
| 1734 | + | |
| 1735 | + (e.dataTransfer || e.originalEvent.dataTransfer).setData('text/plain', scope.$index); | |
| 1736 | + }); | |
| 1737 | + | |
| 1738 | + element.on('dragend', function() { | |
| 1739 | + element.removeClass(draggingClassName); | |
| 1740 | + }); | |
| 1741 | + | |
| 1742 | + var move = function(from, to) { | |
| 1743 | + /*jshint validthis: true */ | |
| 1744 | + this.splice(to, 0, this.splice(from, 1)[0]); | |
| 1745 | + }; | |
| 1746 | + | |
| 1747 | + var dragOverHandler = function(e) { | |
| 1748 | + e.preventDefault(); | |
| 1749 | + | |
| 1750 | + var offset = axis === 'vertical' ? e.offsetY || e.layerY || (e.originalEvent ? e.originalEvent.offsetY : 0) : e.offsetX || e.layerX || (e.originalEvent ? e.originalEvent.offsetX : 0); | |
| 1751 | + | |
| 1752 | + if (offset < (this[axis === 'vertical' ? 'offsetHeight' : 'offsetWidth'] / 2)) { | |
| 1753 | + element.removeClass(droppingAfterClassName); | |
| 1754 | + element.addClass(droppingBeforeClassName); | |
| 1755 | + | |
| 1756 | + } else { | |
| 1757 | + element.removeClass(droppingBeforeClassName); | |
| 1758 | + element.addClass(droppingAfterClassName); | |
| 1759 | + } | |
| 1760 | + }; | |
| 1761 | + | |
| 1762 | + var dropTimeout; | |
| 1763 | + | |
| 1764 | + var dropHandler = function(e) { | |
| 1765 | + e.preventDefault(); | |
| 1766 | + | |
| 1767 | + var droppedItemIndex = parseInt((e.dataTransfer || e.originalEvent.dataTransfer).getData('text/plain'), 10); | |
| 1768 | + | |
| 1769 | + // prevent event firing multiple times in firefox | |
| 1770 | + $timeout.cancel(dropTimeout); | |
| 1771 | + dropTimeout = $timeout(function() { | |
| 1772 | + _dropHandler(droppedItemIndex); | |
| 1773 | + }, 20); | |
| 1774 | + }; | |
| 1775 | + | |
| 1776 | + var _dropHandler = function(droppedItemIndex) { | |
| 1777 | + var theList = scope.$eval(attrs.uiSelectSort), | |
| 1778 | + itemToMove = theList[droppedItemIndex], | |
| 1779 | + newIndex = null; | |
| 1780 | + | |
| 1781 | + if (element.hasClass(droppingBeforeClassName)) { | |
| 1782 | + if (droppedItemIndex < scope.$index) { | |
| 1783 | + newIndex = scope.$index - 1; | |
| 1784 | + } else { | |
| 1785 | + newIndex = scope.$index; | |
| 1786 | + } | |
| 1787 | + } else { | |
| 1788 | + if (droppedItemIndex < scope.$index) { | |
| 1789 | + newIndex = scope.$index; | |
| 1790 | + } else { | |
| 1791 | + newIndex = scope.$index + 1; | |
| 1792 | + } | |
| 1793 | + } | |
| 1794 | + | |
| 1795 | + move.apply(theList, [droppedItemIndex, newIndex]); | |
| 1796 | + | |
| 1797 | + scope.$apply(function() { | |
| 1798 | + scope.$emit('uiSelectSort:change', { | |
| 1799 | + array: theList, | |
| 1800 | + item: itemToMove, | |
| 1801 | + from: droppedItemIndex, | |
| 1802 | + to: newIndex | |
| 1803 | + }); | |
| 1804 | + }); | |
| 1805 | + | |
| 1806 | + element.removeClass(droppingClassName); | |
| 1807 | + element.removeClass(droppingBeforeClassName); | |
| 1808 | + element.removeClass(droppingAfterClassName); | |
| 1809 | + | |
| 1810 | + element.off('drop', dropHandler); | |
| 1811 | + }; | |
| 1812 | + | |
| 1813 | + element.on('dragenter', function() { | |
| 1814 | + if (element.hasClass(draggingClassName)) { | |
| 1815 | + return; | |
| 1816 | + } | |
| 1817 | + | |
| 1818 | + element.addClass(droppingClassName); | |
| 1819 | + | |
| 1820 | + element.on('dragover', dragOverHandler); | |
| 1821 | + element.on('drop', dropHandler); | |
| 1822 | + }); | |
| 1823 | + | |
| 1824 | + element.on('dragleave', function(e) { | |
| 1825 | + if (e.target != element) { | |
| 1826 | + return; | |
| 1827 | + } | |
| 1828 | + element.removeClass(droppingClassName); | |
| 1829 | + element.removeClass(droppingBeforeClassName); | |
| 1830 | + element.removeClass(droppingAfterClassName); | |
| 1831 | + | |
| 1832 | + element.off('dragover', dragOverHandler); | |
| 1833 | + element.off('drop', dropHandler); | |
| 1834 | + }); | |
| 1835 | + } | |
| 1836 | + }; | |
| 1837 | +}]); | |
| 1838 | + | |
| 1839 | +/** | |
| 1840 | + * Parses "repeat" attribute. | |
| 1841 | + * | |
| 1842 | + * Taken from AngularJS ngRepeat source code | |
| 1843 | + * See https://github.com/angular/angular.js/blob/v1.2.15/src/ng/directive/ngRepeat.js#L211 | |
| 1844 | + * | |
| 1845 | + * Original discussion about parsing "repeat" attribute instead of fully relying on ng-repeat: | |
| 1846 | + * https://github.com/angular-ui/ui-select/commit/5dd63ad#commitcomment-5504697 | |
| 1847 | + */ | |
| 1848 | + | |
| 1849 | +uis.service('uisRepeatParser', ['uiSelectMinErr','$parse', function(uiSelectMinErr, $parse) { | |
| 1850 | + var self = this; | |
| 1851 | + | |
| 1852 | + /** | |
| 1853 | + * Example: | |
| 1854 | + * expression = "address in addresses | filter: {street: $select.search} track by $index" | |
| 1855 | + * itemName = "address", | |
| 1856 | + * source = "addresses | filter: {street: $select.search}", | |
| 1857 | + * trackByExp = "$index", | |
| 1858 | + */ | |
| 1859 | + self.parse = function(expression) { | |
| 1860 | + | |
| 1861 | + | |
| 1862 | + var match; | |
| 1863 | + var isObjectCollection = /\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)/.test(expression); | |
| 1864 | + // If an array is used as collection | |
| 1865 | + | |
| 1866 | + // if (isObjectCollection){ | |
| 1867 | + //00000000000000000000000000000111111111000000000000000222222222222220033333333333333333333330000444444444444444444000000000000000556666660000077777777777755000000000000000000000088888880000000 | |
| 1868 | + match = expression.match(/^\s*(?:([\s\S]+?)\s+as\s+)?(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+(([\w\.]+)?\s*(|\s*[\s\S]+?))?(?:\s+track\s+by\s+([\s\S]+?))?\s*$/); | |
| 1869 | + | |
| 1870 | + // 1 Alias | |
| 1871 | + // 2 Item | |
| 1872 | + // 3 Key on (key,value) | |
| 1873 | + // 4 Value on (key,value) | |
| 1874 | + // 5 Collection expresion (only used when using an array collection) | |
| 1875 | + // 6 Object that will be converted to Array when using (key,value) syntax | |
| 1876 | + // 7 Filters that will be applied to #6 when using (key,value) syntax | |
| 1877 | + // 8 Track by | |
| 1878 | + | |
| 1879 | + if (!match) { | |
| 1880 | + throw uiSelectMinErr('iexp', "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.", | |
| 1881 | + expression); | |
| 1882 | + } | |
| 1883 | + if (!match[6] && isObjectCollection) { | |
| 1884 | + throw uiSelectMinErr('iexp', "Expected expression in form of '_item_ as (_key_, _item_) in _ObjCollection_ [ track by _id_]' but got '{0}'.", | |
| 1885 | + expression); | |
| 1886 | + } | |
| 1887 | + | |
| 1888 | + return { | |
| 1889 | + itemName: match[4] || match[2], // (lhs) Left-hand side, | |
| 1890 | + keyName: match[3], //for (key, value) syntax | |
| 1891 | + source: $parse(!match[3] ? match[5] : match[6]), | |
| 1892 | + sourceName: match[6], | |
| 1893 | + filters: match[7], | |
| 1894 | + trackByExp: match[8], | |
| 1895 | + modelMapper: $parse(match[1] || match[4] || match[2]), | |
| 1896 | + repeatExpression: function (grouped) { | |
| 1897 | + var expression = this.itemName + ' in ' + (grouped ? '$group.items' : '$select.items'); | |
| 1898 | + if (this.trackByExp) { | |
| 1899 | + expression += ' track by ' + this.trackByExp; | |
| 1900 | + } | |
| 1901 | + return expression; | |
| 1902 | + } | |
| 1903 | + }; | |
| 1904 | + | |
| 1905 | + }; | |
| 1906 | + | |
| 1907 | + self.getGroupNgRepeatExpression = function() { | |
| 1908 | + return '$group in $select.groups'; | |
| 1909 | + }; | |
| 1910 | + | |
| 1911 | +}]); | |
| 1912 | + | |
| 1913 | +}()); | |
| 1914 | +angular.module("ui.select").run(["$templateCache", function($templateCache) {$templateCache.put("bootstrap/choices.tpl.html","<ul class=\"ui-select-choices ui-select-choices-content ui-select-dropdown dropdown-menu\" role=\"listbox\" ng-show=\"$select.items.length > 0\"><li class=\"ui-select-choices-group\" id=\"ui-select-choices-{{ $select.generatedId }}\"><div class=\"divider\" ng-show=\"$select.isGrouped && $index > 0\"></div><div ng-show=\"$select.isGrouped\" class=\"ui-select-choices-group-label dropdown-header\" ng-bind=\"$group.name\"></div><div id=\"ui-select-choices-row-{{ $select.generatedId }}-{{$index}}\" class=\"ui-select-choices-row\" ng-class=\"{active: $select.isActive(this), disabled: $select.isDisabled(this)}\" role=\"option\"><a href=\"javascript:void(0)\" class=\"ui-select-choices-row-inner\"></a></div></li></ul>"); | |
| 1915 | +$templateCache.put("bootstrap/match-multiple.tpl.html","<span class=\"ui-select-match\"><span ng-repeat=\"$item in $select.selected\"><span class=\"ui-select-match-item btn btn-default btn-xs\" tabindex=\"-1\" type=\"button\" ng-disabled=\"$select.disabled\" ng-click=\"$selectMultiple.activeMatchIndex = $index;\" ng-class=\"{\'btn-primary\':$selectMultiple.activeMatchIndex === $index, \'select-locked\':$select.isLocked(this, $index)}\" ui-select-sort=\"$select.selected\"><span class=\"close ui-select-match-close\" ng-hide=\"$select.disabled\" ng-click=\"$selectMultiple.removeChoice($index)\"> ×</span> <span uis-transclude-append=\"\"></span></span></span></span>"); | |
| 1916 | +$templateCache.put("bootstrap/match.tpl.html","<div class=\"ui-select-match\" ng-hide=\"$select.open\" ng-disabled=\"$select.disabled\" ng-class=\"{\'btn-default-focus\':$select.focus}\"><span tabindex=\"-1\" class=\"btn btn-default form-control ui-select-toggle\" aria-label=\"{{ $select.baseTitle }} activate\" ng-disabled=\"$select.disabled\" ng-click=\"$select.activate()\" style=\"outline: 0;\"><span ng-show=\"$select.isEmpty()\" class=\"ui-select-placeholder text-muted\">{{$select.placeholder}}</span> <span ng-hide=\"$select.isEmpty()\" class=\"ui-select-match-text pull-left\" ng-class=\"{\'ui-select-allow-clear\': $select.allowClear && !$select.isEmpty()}\" ng-transclude=\"\"></span> <i class=\"caret pull-right\" ng-click=\"$select.toggle($event)\"></i> <a ng-show=\"$select.allowClear && !$select.isEmpty()\" aria-label=\"{{ $select.baseTitle }} clear\" style=\"margin-right: 10px\" ng-click=\"$select.clear($event)\" class=\"btn btn-xs btn-link pull-right\"><i class=\"glyphicon glyphicon-remove\" aria-hidden=\"true\"></i></a></span></div>"); | |
| 1917 | +$templateCache.put("bootstrap/select-multiple.tpl.html","<div class=\"ui-select-container ui-select-multiple ui-select-bootstrap dropdown form-control\" ng-class=\"{open: $select.open}\"><div><div class=\"ui-select-match\"></div><input type=\"text\" autocomplete=\"false\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" class=\"ui-select-search input-xs\" placeholder=\"{{$selectMultiple.getPlaceholder()}}\" ng-disabled=\"$select.disabled\" ng-hide=\"$select.disabled\" ng-click=\"$select.activate()\" ng-model=\"$select.search\" role=\"combobox\" aria-label=\"{{ $select.baseTitle }}\" ondrop=\"return false;\"></div><div class=\"ui-select-choices\"></div></div>"); | |
| 1918 | +$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><input type=\"text\" autocomplete=\"false\" tabindex=\"-1\" aria-expanded=\"true\" aria-label=\"{{ $select.baseTitle }}\" aria-owns=\"ui-select-choices-{{ $select.generatedId }}\" aria-activedescendant=\"ui-select-choices-row-{{ $select.generatedId }}-{{ $select.activeIndex }}\" class=\"form-control ui-select-search\" placeholder=\"{{$select.placeholder}}\" ng-model=\"$select.search\" ng-show=\"$select.searchEnabled && $select.open\"><div class=\"ui-select-choices\"></div></div>"); | |
| 1919 | +$templateCache.put("selectize/choices.tpl.html","<div ng-show=\"$select.open\" class=\"ui-select-choices ui-select-dropdown selectize-dropdown single\"><div class=\"ui-select-choices-content selectize-dropdown-content\"><div class=\"ui-select-choices-group optgroup\" role=\"listbox\"><div ng-show=\"$select.isGrouped\" class=\"ui-select-choices-group-label optgroup-header\" ng-bind=\"$group.name\"></div><div role=\"option\" class=\"ui-select-choices-row\" ng-class=\"{active: $select.isActive(this), disabled: $select.isDisabled(this)}\"><div class=\"option ui-select-choices-row-inner\" data-selectable=\"\"></div></div></div></div></div>"); | |
| 1920 | +$templateCache.put("selectize/match.tpl.html","<div ng-hide=\"($select.open || $select.isEmpty())\" class=\"ui-select-match\" ng-transclude=\"\"></div>"); | |
| 1921 | +$templateCache.put("selectize/select.tpl.html","<div class=\"ui-select-container selectize-control single\" ng-class=\"{\'open\': $select.open}\"><div class=\"selectize-input\" ng-class=\"{\'focus\': $select.open, \'disabled\': $select.disabled, \'selectize-focus\' : $select.focus}\" ng-click=\"$select.activate()\"><div class=\"ui-select-match\"></div><input type=\"text\" autocomplete=\"false\" tabindex=\"-1\" class=\"ui-select-search ui-select-toggle\" ng-click=\"$select.toggle($event)\" placeholder=\"{{$select.placeholder}}\" ng-model=\"$select.search\" ng-hide=\"!$select.searchEnabled || ($select.selected && !$select.open)\" ng-disabled=\"$select.disabled\" aria-label=\"{{ $select.baseTitle }}\"></div><div class=\"ui-select-choices\"></div></div>"); | |
| 1922 | +$templateCache.put("select2/choices.tpl.html","<ul class=\"ui-select-choices ui-select-choices-content select2-results\"><li class=\"ui-select-choices-group\" ng-class=\"{\'select2-result-with-children\': $select.choiceGrouped($group) }\"><div ng-show=\"$select.choiceGrouped($group)\" class=\"ui-select-choices-group-label select2-result-label\" ng-bind=\"$group.name\"></div><ul role=\"listbox\" id=\"ui-select-choices-{{ $select.generatedId }}\" ng-class=\"{\'select2-result-sub\': $select.choiceGrouped($group), \'select2-result-single\': !$select.choiceGrouped($group) }\"><li role=\"option\" id=\"ui-select-choices-row-{{ $select.generatedId }}-{{$index}}\" class=\"ui-select-choices-row\" ng-class=\"{\'select2-highlighted\': $select.isActive(this), \'select2-disabled\': $select.isDisabled(this)}\"><div class=\"select2-result-label ui-select-choices-row-inner\"></div></li></ul></li></ul>"); | |
| 1923 | +$templateCache.put("select2/match-multiple.tpl.html","<span class=\"ui-select-match\"><li class=\"ui-select-match-item select2-search-choice\" ng-repeat=\"$item in $select.selected\" ng-class=\"{\'select2-search-choice-focus\':$selectMultiple.activeMatchIndex === $index, \'select2-locked\':$select.isLocked(this, $index)}\" ui-select-sort=\"$select.selected\"><span uis-transclude-append=\"\"></span> <a href=\"javascript:;\" class=\"ui-select-match-close select2-search-choice-close\" ng-click=\"$selectMultiple.removeChoice($index)\" tabindex=\"-1\"></a></li></span>"); | |
| 1924 | +$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>"); | |
| 1925 | +$templateCache.put("select2/select-multiple.tpl.html","<div class=\"ui-select-container ui-select-multiple select2 select2-container select2-container-multi\" ng-class=\"{\'select2-container-active select2-dropdown-open open\': $select.open, \'select2-container-disabled\': $select.disabled}\"><ul class=\"select2-choices\"><span class=\"ui-select-match\"></span><li class=\"select2-search-field\"><input type=\"text\" autocomplete=\"false\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" role=\"combobox\" aria-expanded=\"true\" aria-owns=\"ui-select-choices-{{ $select.generatedId }}\" aria-label=\"{{ $select.baseTitle }}\" aria-activedescendant=\"ui-select-choices-row-{{ $select.generatedId }}-{{ $select.activeIndex }}\" class=\"select2-input ui-select-search\" placeholder=\"{{$selectMultiple.getPlaceholder()}}\" ng-disabled=\"$select.disabled\" ng-hide=\"$select.disabled\" ng-model=\"$select.search\" ng-click=\"$select.activate()\" style=\"width: 34px;\" ondrop=\"return false;\"></li></ul><div class=\"ui-select-dropdown select2-drop select2-with-searchbox select2-drop-active\" ng-class=\"{\'select2-display-none\': !$select.open}\"><div class=\"ui-select-choices\"></div></div></div>"); | |
| 1926 | +$templateCache.put("select2/select.tpl.html","<div class=\"ui-select-container select2 select2-container\" ng-class=\"{\'select2-container-active select2-dropdown-open open\': $select.open, \'select2-container-disabled\': $select.disabled, \'select2-container-active\': $select.focus, \'select2-allowclear\': $select.allowClear && !$select.isEmpty()}\"><div class=\"ui-select-match\"></div><div class=\"ui-select-dropdown select2-drop select2-with-searchbox select2-drop-active\" ng-class=\"{\'select2-display-none\': !$select.open}\"><div class=\"select2-search\" ng-show=\"$select.searchEnabled\"><input type=\"text\" autocomplete=\"false\" autocorrect=\"false\" autocapitalize=\"off\" spellcheck=\"false\" role=\"combobox\" aria-expanded=\"true\" aria-owns=\"ui-select-choices-{{ $select.generatedId }}\" aria-label=\"{{ $select.baseTitle }}\" aria-activedescendant=\"ui-select-choices-row-{{ $select.generatedId }}-{{ $select.activeIndex }}\" class=\"ui-select-search select2-input\" ng-model=\"$select.search\"></div><div class=\"ui-select-choices\"></div></div></div>");}]); | |
| 0 | 1927 | \ No newline at end of file | ... | ... |
src/main/resources/static/assets/bower_components/angular-ui-select/dist/select.min.css
0 → 100644
| 1 | +/*! | |
| 2 | + * ui-select | |
| 3 | + * http://github.com/angular-ui/ui-select | |
| 4 | + * Version: 0.13.2 - 2015-10-09T15:34:24.045Z | |
| 5 | + * License: MIT | |
| 6 | + */.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}.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[theme=select2].direction-up .ui-select-match{border-radius:0 0 4px 4px}.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[theme=select2].direction-up .ui-select-dropdown .select2-search{margin-top:4px}.ui-select-container[theme=select2].direction-up.select2-dropdown-open .ui-select-match{border-bottom-color:#5897fb}.selectize-input.selectize-focus{border-color:#007FBB!important}.selectize-control>.selectize-dropdown,.selectize-control>.selectize-input>input{width:100%}.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}.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-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{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-before:before{content:"";position:absolute;top:0;right:100%;height:100%;margin-right:2px;border-left:1px solid #428bca}.ui-select-multiple .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>a{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>a:focus,.ui-select-bootstrap .ui-select-choices-row>a:hover{text-decoration:none;color:#262626;background-color:#f5f5f5}.ui-select-bootstrap .ui-select-choices-row.active>a{color:#fff;text-decoration:none;outline:0;background-color:#428bca}.ui-select-bootstrap .ui-select-choices-row.active.disabled>a,.ui-select-bootstrap .ui-select-choices-row.disabled>a{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)} | |
| 0 | 7 | \ No newline at end of file | ... | ... |
src/main/resources/static/assets/bower_components/angular-ui-select/dist/select.min.js
0 → 100644
| 1 | +/*! | |
| 2 | + * ui-select | |
| 3 | + * http://github.com/angular-ui/ui-select | |
| 4 | + * Version: 0.13.2 - 2015-10-09T15:34:24.040Z | |
| 5 | + * License: MIT | |
| 6 | + */ | |
| 7 | +!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 i=t.which;switch(i){case e.COMMAND:case e.SHIFT:case e.CTRL:case e.ALT:return!0}return t.metaKey?!0:!1},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)}};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],i=t.matches||t.webkitMatchesSelector||t.mozMatchesSelector||t.msMatchesSelector;t;){if(i.bind(t)(e))return t;t=t.parentElement}return!1});var t=0,i=angular.module("ui.select",[]).constant("uiSelectConfig",{theme:"bootstrap",searchEnabled:!0,sortable:!1,placeholder:"",refreshDelay:1e3,closeOnSelect:!0,dropdownPosition:"auto",generateId:function(){return t++},appendToBody:!1}).service("uiSelectMinErr",function(){var e=angular.$$minErr("ui.select");return function(){var t=e.apply(this,arguments),i=t.message.replace(new RegExp("\nhttp://errors.angularjs.org/.*"),"");return new Error(i)}}).directive("uisTranscludeAppend",function(){return{link:function(e,t,i,s,c){c(e,function(e){t.append(e)})}}}).filter("highlight",function(){function e(e){return e.replace(/([.?*+^$[\]\\(){}|-])/g,"\\$1")}return function(t,i){return i&&t?t.replace(new RegExp(e(i),"gi"),'<span class="ui-select-highlight">$&</span>'):t}}).factory("uisOffset",["$document","$window",function(e,t){return function(i){var s=i[0].getBoundingClientRect();return{width:s.width||i.prop("offsetWidth"),height:s.height||i.prop("offsetHeight"),top:s.top+(t.pageYOffset||e[0].documentElement.scrollTop),left:s.left+(t.pageXOffset||e[0].documentElement.scrollLeft)}}}]);i.directive("uiSelectChoices",["uiSelectConfig","uisRepeatParser","uiSelectMinErr","$compile",function(e,t,i,s){return{restrict:"EA",require:"^uiSelect",replace:!0,transclude:!0,templateUrl:function(t){var i=t.parent().attr("theme")||e.theme;return i+"/choices.tpl.html"},compile:function(c,l){if(!l.repeat)throw i("repeat","Expected 'repeat' expression.");return function(c,l,n,a,r){var o=n.groupBy,u=n.groupFilter;if(a.parseRepeatAttr(n.repeat,o,u),a.disableChoiceExpression=n.uiDisableChoice,a.onHighlightCallback=n.onHighlight,a.dropdownPosition=n.position?n.position.toLowerCase():e.dropdownPosition,o){var d=l.querySelectorAll(".ui-select-choices-group");if(1!==d.length)throw i("rows","Expected 1 .ui-select-choices-group but got '{0}'.",d.length);d.attr("ng-repeat",t.getGroupNgRepeatExpression())}var p=l.querySelectorAll(".ui-select-choices-row");if(1!==p.length)throw i("rows","Expected 1 .ui-select-choices-row but got '{0}'.",p.length);p.attr("ng-repeat",a.parserResult.repeatExpression(o)).attr("ng-if","$select.open").attr("ng-click","$select.select("+a.parserResult.itemName+",false,$event)");var h=l.querySelectorAll(".ui-select-choices-row-inner");if(1!==h.length)throw i("rows","Expected 1 .ui-select-choices-row-inner but got '{0}'.",h.length);h.attr("uis-transclude-append",""),s(l,r)(c),c.$watch("$select.search",function(e){e&&!a.open&&a.multiple&&a.activate(!1,!0),a.activeIndex=a.tagging.isActivated?-1:0,a.refresh(n.refresh)}),n.$observe("refreshDelay",function(){var t=c.$eval(n.refreshDelay);a.refreshDelay=void 0!==t?t:e.refreshDelay})}}}}]),i.controller("uiSelectCtrl",["$scope","$element","$timeout","$filter","uisRepeatParser","uiSelectMinErr","uiSelectConfig","$parse",function(t,i,s,c,l,n,a,r){function o(){(h.resetSearchInput||void 0===h.resetSearchInput&&a.resetSearchInput)&&(h.search=g,h.selected&&h.items.length&&!h.multiple&&(h.activeIndex=h.items.indexOf(h.selected)))}function u(e,t){var i,s,c=[];for(i=0;i<t.length;i++)for(s=0;s<e.length;s++)e[s].name==[t[i]]&&c.push(e[s]);return c}function d(t){var i=!0;switch(t){case e.DOWN:!h.open&&h.multiple?h.activate(!1,!0):h.activeIndex<h.items.length-1&&h.activeIndex++;break;case e.UP:!h.open&&h.multiple?h.activate(!1,!0):(h.activeIndex>0||0===h.search.length&&h.tagging.isActivated&&h.activeIndex>-1)&&h.activeIndex--;break;case e.TAB:(!h.multiple||h.open)&&h.select(h.items[h.activeIndex],!0);break;case e.ENTER:h.open&&(h.tagging.isActivated||h.activeIndex>=0)?h.select(h.items[h.activeIndex]):h.activate(!1,!0);break;case e.ESC:h.close();break;default:i=!1}return i}function p(){var e=i.querySelectorAll(".ui-select-choices-content"),t=e.querySelectorAll(".ui-select-choices-row");if(t.length<1)throw n("choices","Expected multiple .ui-select-choices-row but got '{0}'.",t.length);if(!(h.activeIndex<0)){var s=t[h.activeIndex],c=s.offsetTop+s.clientHeight-e[0].scrollTop,l=e[0].offsetHeight;c>l?e[0].scrollTop+=c-l:c<s.clientHeight&&(h.isGrouped&&0===h.activeIndex?e[0].scrollTop=0:e[0].scrollTop-=s.clientHeight-c)}}var h=this,g="";if(h.placeholder=a.placeholder,h.searchEnabled=a.searchEnabled,h.sortable=a.sortable,h.refreshDelay=a.refreshDelay,h.removeSelected=!1,h.closeOnSelect=!0,h.search=g,h.activeIndex=0,h.items=[],h.open=!1,h.focus=!1,h.disabled=!1,h.selected=void 0,h.dropdownPosition="auto",h.focusser=void 0,h.resetSearchInput=!0,h.multiple=void 0,h.disableChoiceExpression=void 0,h.tagging={isActivated:!1,fct:void 0},h.taggingTokens={isActivated:!1,tokens:void 0},h.lockChoiceExpression=void 0,h.clickTriggeredSelect=!1,h.$filter=c,h.searchInput=i.querySelectorAll("input.ui-select-search"),1!==h.searchInput.length)throw n("searchInput","Expected 1 input.ui-select-search but got '{0}'.",h.searchInput.length);h.isEmpty=function(){return angular.isUndefined(h.selected)||null===h.selected||""===h.selected},h.activate=function(e,i){h.disabled||h.open||(i||o(),t.$broadcast("uis:activate"),h.open=!0,h.activeIndex=h.activeIndex>=h.items.length?0:h.activeIndex,-1===h.activeIndex&&h.taggingLabel!==!1&&(h.activeIndex=0),s(function(){h.search=e||h.search,h.searchInput[0].focus(),!h.tagging.isActivated&&h.items.length>1&&p()}))},h.findGroupByName=function(e){return h.groups&&h.groups.filter(function(t){return t.name===e})[0]},h.parseRepeatAttr=function(e,i,s){function c(e){var c=t.$eval(i);if(h.groups=[],angular.forEach(e,function(e){var t=angular.isFunction(c)?c(e):e[c],i=h.findGroupByName(t);i?i.items.push(e):h.groups.push({name:t,items:[e]})}),s){var l=t.$eval(s);angular.isFunction(l)?h.groups=l(h.groups):angular.isArray(l)&&(h.groups=u(h.groups,l))}h.items=[],h.groups.forEach(function(e){h.items=h.items.concat(e.items)})}function a(e){h.items=e}h.setItemsFn=i?c:a,h.parserResult=l.parse(e),h.isGrouped=!!i,h.itemProperty=h.parserResult.itemName;var o=h.parserResult.source,d=function(){var e=o(t);t.$uisSource=Object.keys(e).map(function(t){var i={};return i[h.parserResult.keyName]=t,i.value=e[t],i})};h.parserResult.keyName&&(d(),h.parserResult.source=r("$uisSource"+h.parserResult.filters),t.$watch(o,function(e,t){e!==t&&d()},!0)),h.refreshItems=function(e){e=e||h.parserResult.source(t);var i=h.selected;if(h.isEmpty()||angular.isArray(i)&&!i.length||!h.removeSelected)h.setItemsFn(e);else if(void 0!==e){var s=e.filter(function(e){return i&&i.indexOf(e)<0});h.setItemsFn(s)}("auto"===h.dropdownPosition||"up"===h.dropdownPosition)&&t.calculateDropdownPos()},t.$watchCollection(h.parserResult.source,function(e){if(void 0===e||null===e)h.items=[];else{if(!angular.isArray(e))throw n("items","Expected an array but got '{0}'.",e);h.refreshItems(e),h.ngModel.$modelValue=null}})};var f;h.refresh=function(e){void 0!==e&&(f&&s.cancel(f),f=s(function(){t.$eval(e)},h.refreshDelay))},h.isActive=function(e){if(!h.open)return!1;var t=h.items.indexOf(e[h.itemProperty]),i=t===h.activeIndex;return!i||0>t&&h.taggingLabel!==!1||0>t&&h.taggingLabel===!1?!1:(i&&!angular.isUndefined(h.onHighlightCallback)&&e.$eval(h.onHighlightCallback),i)},h.isDisabled=function(e){if(h.open){var t,i=h.items.indexOf(e[h.itemProperty]),s=!1;return i>=0&&!angular.isUndefined(h.disableChoiceExpression)&&(t=h.items[i],s=!!e.$eval(h.disableChoiceExpression),t._uiSelectChoiceDisabled=s),s}},h.select=function(e,i,c){if(void 0===e||!e._uiSelectChoiceDisabled){if(!h.items&&!h.search)return;if(!e||!e._uiSelectChoiceDisabled){if(h.tagging.isActivated){if(h.taggingLabel===!1)if(h.activeIndex<0){if(e=void 0!==h.tagging.fct?h.tagging.fct(h.search):h.search,!e||angular.equals(h.items[0],e))return}else e=h.items[h.activeIndex];else if(0===h.activeIndex){if(void 0===e)return;if(void 0!==h.tagging.fct&&"string"==typeof e){if(e=h.tagging.fct(h.search),!e)return}else"string"==typeof e&&(e=e.replace(h.taggingLabel,"").trim())}if(h.selected&&angular.isArray(h.selected)&&h.selected.filter(function(t){return angular.equals(t,e)}).length>0)return h.close(i),void 0}t.$broadcast("uis:select",e);var l={};l[h.parserResult.itemName]=e,s(function(){h.onSelectCallback(t,{$item:e,$model:h.parserResult.modelMapper(t,l)})}),h.closeOnSelect&&h.close(i),c&&"click"===c.type&&(h.clickTriggeredSelect=!0)}}},h.close=function(e){h.open&&(h.ngModel&&h.ngModel.$setTouched&&h.ngModel.$setTouched(),o(),h.open=!1,t.$broadcast("uis:close",e))},h.setFocus=function(){h.focus||h.focusInput[0].focus()},h.clear=function(e){h.select(void 0),e.stopPropagation(),s(function(){h.focusser[0].focus()},0,!1)},h.toggle=function(e){h.open?(h.close(),e.preventDefault(),e.stopPropagation()):h.activate()},h.isLocked=function(e,t){var i,s=h.selected[t];return s&&!angular.isUndefined(h.lockChoiceExpression)&&(i=!!e.$eval(h.lockChoiceExpression),s._uiSelectChoiceLocked=i),i};var v=null;h.sizeSearchInput=function(){var e=h.searchInput[0],i=h.searchInput.parent().parent()[0],c=function(){return i.clientWidth*!!e.offsetParent},l=function(t){if(0===t)return!1;var i=t-e.offsetLeft-10;return 50>i&&(i=t),h.searchInput.css("width",i+"px"),!0};h.searchInput.css("width","10px"),s(function(){null!==v||l(c())||(v=t.$watch(c,function(e){l(e)&&(v(),v=null)}))})},h.searchInput.on("keydown",function(i){var c=i.which;t.$apply(function(){var t=!1;if((h.items.length>0||h.tagging.isActivated)&&(d(c),h.taggingTokens.isActivated)){for(var l=0;l<h.taggingTokens.tokens.length;l++)h.taggingTokens.tokens[l]===e.MAP[i.keyCode]&&h.search.length>0&&(t=!0);t&&s(function(){h.searchInput.triggerHandler("tagged");var t=h.search.replace(e.MAP[i.keyCode],"").trim();h.tagging.fct&&(t=h.tagging.fct(t)),t&&h.select(t,!0)})}}),e.isVerticalMovement(c)&&h.items.length>0&&p(),(c===e.ENTER||c===e.ESC)&&(i.preventDefault(),i.stopPropagation())}),h.searchInput.on("paste",function(e){var t=e.originalEvent.clipboardData.getData("text/plain");if(t&&t.length>0&&h.taggingTokens.isActivated&&h.tagging.fct){var i=t.split(h.taggingTokens.tokens[0]);i&&i.length>0&&(angular.forEach(i,function(e){var t=h.tagging.fct(e);t&&h.select(t,!0)}),e.preventDefault(),e.stopPropagation())}}),h.searchInput.on("tagged",function(){s(function(){o()})}),t.$on("$destroy",function(){h.searchInput.off("keyup keydown tagged blur paste")})}]),i.directive("uiSelect",["$document","uiSelectConfig","uiSelectMinErr","uisOffset","$compile","$parse","$timeout",function(e,t,i,s,c,l,n){return{restrict:"EA",templateUrl:function(e,i){var s=i.theme||t.theme;return s+(angular.isDefined(i.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){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 i=["input","button","textarea"],s=angular.element(e.target).controller("uiSelect"),l=s&&s!==g;l||(l=~i.indexOf(e.target.tagName.toLowerCase())),g.close(l),c.$digest()}g.clickTriggeredSelect=!1}}function p(){var t=s(a);m=angular.element('<div class="ui-select-placeholder"></div>'),m[0].style.width=t.width+"px",m[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!==m&&(m.replaceWith(a),m=null,a[0].style.position="",a[0].style.left="",a[0].style.top="",a[0].style.width=$)}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)?l(r.closeOnSelect)():t.closeOnSelect}(),g.onSelectCallback=l(r.onSelect),g.onRemoveCallback=l(r.onRemove),g.limit=angular.isDefined(r.limit)?parseInt(r.limit,10):void 0,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("searchEnabled",function(){var e=c.$eval(r.searchEnabled);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("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("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&&(g.taggingLabel="false"===r.taggingLabel?!1: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}}}),angular.isDefined(r.autofocus)&&n(function(){g.setFocus()}),angular.isDefined(r.focusOn)&&c.$on(r.focusOn,function(){n(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),s=t.querySelectorAll(".ui-select-match");if(s.removeAttr("ui-select-match"),s.removeAttr("data-ui-select-match"),1!==s.length)throw i("transcluded","Expected 1 .ui-select-match but got '{0}'.",s.length);a.querySelectorAll(".ui-select-match").replaceWith(s);var c=t.querySelectorAll(".ui-select-choices");if(c.removeAttr("ui-select-choices"),c.removeAttr("data-ui-select-choices"),1!==c.length)throw i("transcluded","Expected 1 .ui-select-choices but got '{0}'.",c.length);a.querySelectorAll(".ui-select-choices").replaceWith(c)});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 m=null,$="",b=null,w="direction-up";c.$watch("$select.open",function(){("auto"===g.dropdownPosition||"up"===g.dropdownPosition)&&c.calculateDropdownPos()});var x=function(e,t){e=e||s(a),t=t||s(b),b[0].style.position="absolute",b[0].style.top=-1*t.height+"px",a.addClass(w)},y=function(e,t){a.removeClass(w),e=e||s(a),t=t||s(b),b[0].style.position="",b[0].style.top=""};c.calculateDropdownPos=function(){if(g.open){if(b=angular.element(a).querySelectorAll(".ui-select-dropdown"),0===b.length)return;b[0].style.opacity=0,n(function(){if("up"===g.dropdownPosition)x(t,i);else{a.removeClass(w);var t=s(a),i=s(b),c=e[0].documentElement.scrollTop||e[0].body.scrollTop;t.top+t.height+i.height>c+e[0].documentElement.clientHeight?x(t,i):y(t,i)}b[0].style.opacity=1})}else{if(null===b||0===b.length)return;b[0].style.position="",b[0].style.top="",a.removeClass(w)}}}}}}]),i.directive("uiSelectMatch",["uiSelectConfig",function(e){return{restrict:"EA",require:"^uiSelect",replace:!0,transclude:!0,templateUrl:function(t){var i=t.parent().attr("theme")||e.theme,s=t.parent().attr("multiple");return i+(s?"/match-multiple.tpl.html":"/match.tpl.html")},link:function(t,i,s,c){function l(e){c.allowClear=angular.isDefined(e)?""===e?!0:"true"===e.toLowerCase():!1}c.lockChoiceExpression=s.uiLockChoice,s.$observe("placeholder",function(t){c.placeholder=void 0!==t?t:e.placeholder}),s.$observe("allowClear",l),l(s.allowClear),c.multiple&&c.sizeSearchInput()}}}]),i.directive("uiSelectMultiple",["uiSelectMinErr","$timeout",function(t,i){return{restrict:"EA",require:["^uiSelect","^ngModel"],controller:["$scope","$timeout",function(e,t){var i,s=this,c=e.$select;e.$evalAsync(function(){i=e.ngModel}),s.activeMatchIndex=-1,s.updateModel=function(){i.$setViewValue(Date.now()),s.refreshComponent()},s.refreshComponent=function(){c.refreshItems(),c.sizeSearchInput()},s.removeChoice=function(i){var l=c.selected[i];if(!l._uiSelectChoiceLocked){var n={};n[c.parserResult.itemName]=l,c.selected.splice(i,1),s.activeMatchIndex=-1,c.sizeSearchInput(),t(function(){c.onRemoveCallback(e,{$item:l,$model:c.parserResult.modelMapper(e,n)})}),s.updateModel()}},s.getPlaceholder=function(){return c.selected&&c.selected.length?void 0:c.placeholder}}],controllerAs:"$selectMultiple",link:function(s,c,l,n){function a(e){return angular.isNumber(e.selectionStart)?e.selectionStart:e.value.length}function r(t){function i(){switch(t){case e.LEFT:return~h.activeMatchIndex?u:n;case e.RIGHT:return~h.activeMatchIndex&&r!==n?o:(d.activate(),!1);case e.BACKSPACE:return~h.activeMatchIndex?(h.removeChoice(r),u):n;case e.DELETE:return~h.activeMatchIndex?(h.removeChoice(h.activeMatchIndex),r):!1}}var s=a(d.searchInput[0]),c=d.selected.length,l=0,n=c-1,r=h.activeMatchIndex,o=h.activeMatchIndex+1,u=h.activeMatchIndex-1,p=r;return s>0||d.search.length&&t==e.RIGHT?!1:(d.close(),p=i(),h.activeMatchIndex=d.selected.length&&p!==!1?Math.min(n,Math.max(l,p)):-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 i=-1;if(angular.isArray(e))for(var s=angular.copy(e),c=0;c<s.length;c++)if(void 0===d.tagging.fct)s[c]+" "+d.taggingLabel===t&&(i=c);else{var l=s[c];l.isTag=!0,angular.equals(l,t)&&(i=c)}return i}var d=n[0],p=s.ngModel=n[1],h=s.$selectMultiple;d.multiple=!0,d.removeSelected=!0,d.focusInput=d.searchInput,p.$parsers.unshift(function(){for(var e,t={},i=[],c=d.selected.length-1;c>=0;c--)t={},t[d.parserResult.itemName]=d.selected[c],e=d.parserResult.modelMapper(s,t),i.unshift(e);return i}),p.$formatters.unshift(function(e){var t,i=d.parserResult.source(s,{$select:{search:""}}),c={};if(!i)return e;var l=[],n=function(e,i){if(e&&e.length){for(var n=e.length-1;n>=0;n--){if(c[d.parserResult.itemName]=e[n],t=d.parserResult.modelMapper(s,c),d.parserResult.trackByExp){var a=/\.(.+)/.exec(d.parserResult.trackByExp);if(a.length>0&&t[a[1]]==i[a[1]])return l.unshift(e[n]),!0}if(angular.equals(t,i))return l.unshift(e[n]),!0}return!1}};if(!e)return l;for(var a=e.length-1;a>=0;a--)n(d.selected,e[a])||n(i,e[a])||l.unshift(e[a]);return l}),s.$watchCollection(function(){return p.$modelValue},function(e,t){t!=e&&(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);d.selected=[]}d.selected=p.$viewValue,s.$evalAsync()},s.$on("uis:select",function(e,t){d.selected.length>=d.limit||(d.selected.push(t),h.updateModel())}),s.$on("uis:activate",function(){h.activeMatchIndex=-1}),s.$watch("$select.disabled",function(e,t){t&&!e&&d.sizeSearchInput()}),d.searchInput.on("keydown",function(t){var i=t.which;s.$apply(function(){var s=!1;e.isHorizontalMovement(i)&&(s=r(i)),s&&i!=e.TAB&&(t.preventDefault(),t.stopPropagation())})}),d.searchInput.on("keyup",function(t){if(e.isVerticalMovement(t.which)||s.$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 i,c,l,n,a=angular.copy(d.items),r=angular.copy(d.items),p=!1,h=-1;if(void 0!==d.tagging.fct){if(l=d.$filter("filter")(a,{isTag:!0}),l.length>0&&(n=l[0]),a.length>0&&n&&(p=!0,a=a.slice(1,a.length),r=r.slice(1,r.length)),i=d.tagging.fct(d.search),i.isTag=!0,r.filter(function(e){return angular.equals(e,d.tagging.fct(d.search))}).length>0)return;i.isTag=!0}else{if(l=d.$filter("filter")(a,function(e){return e.match(d.taggingLabel)}),l.length>0&&(n=l[0]),c=a[0],void 0!==c&&a.length>0&&n&&(p=!0,a=a.slice(1,a.length),r=r.slice(1,r.length)),i=d.search+" "+d.taggingLabel,u(d.selected,d.search)>-1)return;if(o(r.concat(d.selected)))return p&&(a=r,s.$evalAsync(function(){d.activeIndex=0,d.items=a})),void 0;if(o(r))return p&&(d.items=r.slice(1,r.length)),void 0}p&&(h=u(d.selected,i)),h>-1?a=a.slice(h+1,a.length-1):(a=[],a.push(i),a=a.concat(r)),s.$evalAsync(function(){d.activeIndex=0,d.items=a})}}),d.searchInput.on("blur",function(){i(function(){h.activeMatchIndex=-1})})}}}]),i.directive("uiSelectSingle",["$timeout","$compile",function(t,i){return{restrict:"EA",require:["^uiSelect","^ngModel"],link:function(s,c,l,n){var a=n[0],r=n[1];r.$parsers.unshift(function(e){var t,i={};return i[a.parserResult.itemName]=e,t=a.parserResult.modelMapper(s,i)}),r.$formatters.unshift(function(e){var t,i=a.parserResult.source(s,{$select:{search:""}}),c={};if(i){var l=function(i){return c[a.parserResult.itemName]=i,t=a.parserResult.modelMapper(s,c),t==e};if(a.selected&&l(a.selected))return a.selected;for(var n=i.length-1;n>=0;n--)if(l(i[n]))return i[n]}return e}),s.$watch("$select.selected",function(e){r.$viewValue!==e&&r.$setViewValue(e)}),r.$render=function(){a.selected=r.$viewValue},s.$on("uis:select",function(e,t){a.selected=t}),s.$on("uis:close",function(e,i){t(function(){a.focusser.prop("disabled",!1),i||a.focusser[0].focus()},0,!1)}),s.$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' />");i(o)(s),a.focusser=o,a.focusInput=o,c.parent().append(o),o.bind("focus",function(){s.$evalAsync(function(){a.focus=!0})}),o.bind("blur",function(){s.$evalAsync(function(){a.focus=!1})}),o.bind("keydown",function(t){return t.which===e.BACKSPACE?(t.preventDefault(),t.stopPropagation(),a.select(void 0),s.$apply(),void 0):(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()),s.$digest()),void 0)}),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(""),s.$digest())})}}}]),i.directive("uiSelectSort",["$timeout","uiSelectConfig","uiSelectMinErr",function(e,t,i){return{require:"^uiSelect",link:function(t,s,c,l){if(null===t[c.uiSelectSort])throw i("sort","Expected a list to sort");var n=angular.extend({axis:"horizontal"},t.$eval(c.uiSelectSortOptions)),a=n.axis,r="dragging",o="dropping",u="dropping-before",d="dropping-after";t.$watch(function(){return l.sortable},function(e){e?s.attr("draggable",!0):s.removeAttr("draggable")}),s.on("dragstart",function(e){s.addClass(r),(e.dataTransfer||e.originalEvent.dataTransfer).setData("text/plain",t.$index)}),s.on("dragend",function(){s.removeClass(r)});var p,h=function(e,t){this.splice(t,0,this.splice(e,1)[0])},g=function(e){e.preventDefault();var t="vertical"===a?e.offsetY||e.layerY||(e.originalEvent?e.originalEvent.offsetY:0):e.offsetX||e.layerX||(e.originalEvent?e.originalEvent.offsetX:0);t<this["vertical"===a?"offsetHeight":"offsetWidth"]/2?(s.removeClass(d),s.addClass(u)):(s.removeClass(u),s.addClass(d))},f=function(t){t.preventDefault();var i=parseInt((t.dataTransfer||t.originalEvent.dataTransfer).getData("text/plain"),10);e.cancel(p),p=e(function(){v(i)},20)},v=function(e){var i=t.$eval(c.uiSelectSort),l=i[e],n=null;n=s.hasClass(u)?e<t.$index?t.$index-1:t.$index:e<t.$index?t.$index:t.$index+1,h.apply(i,[e,n]),t.$apply(function(){t.$emit("uiSelectSort:change",{array:i,item:l,from:e,to:n})}),s.removeClass(o),s.removeClass(u),s.removeClass(d),s.off("drop",f)};s.on("dragenter",function(){s.hasClass(r)||(s.addClass(o),s.on("dragover",g),s.on("drop",f))}),s.on("dragleave",function(e){e.target==s&&(s.removeClass(o),s.removeClass(u),s.removeClass(d),s.off("dragover",g),s.off("drop",f))})}}}]),i.service("uisRepeatParser",["uiSelectMinErr","$parse",function(e,t){var i=this;i.parse=function(i){var s,c=/\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)/.test(i);if(s=i.match(/^\s*(?:([\s\S]+?)\s+as\s+)?(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+(([\w\.]+)?\s*(|\s*[\s\S]+?))?(?:\s+track\s+by\s+([\s\S]+?))?\s*$/),!s)throw e("iexp","Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",i);if(!s[6]&&c)throw e("iexp","Expected expression in form of '_item_ as (_key_, _item_) in _ObjCollection_ [ track by _id_]' but got '{0}'.",i);return{itemName:s[4]||s[2],keyName:s[3],source:t(s[3]?s[6]:s[5]),sourceName:s[6],filters:s[7],trackByExp:s[8],modelMapper:t(s[1]||s[4]||s[2]),repeatExpression:function(e){var t=this.itemName+" in "+(e?"$group.items":"$select.items");return this.trackByExp&&(t+=" track by "+this.trackByExp),t}}},i.getGroupNgRepeatExpression=function(){return"$group in $select.groups"}}])}(),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" role="listbox" ng-show="$select.items.length > 0"><li class="ui-select-choices-group" id="ui-select-choices-{{ $select.generatedId }}"><div class="divider" ng-show="$select.isGrouped && $index > 0"></div><div ng-show="$select.isGrouped" class="ui-select-choices-group-label dropdown-header" ng-bind="$group.name"></div><div id="ui-select-choices-row-{{ $select.generatedId }}-{{$index}}" class="ui-select-choices-row" ng-class="{active: $select.isActive(this), disabled: $select.isDisabled(this)}" role="option"><a href="javascript:void(0)" class="ui-select-choices-row-inner"></a></div></li></ul>'),e.put("bootstrap/match-multiple.tpl.html",'<span class="ui-select-match"><span ng-repeat="$item in $select.selected"><span class="ui-select-match-item btn btn-default btn-xs" tabindex="-1" type="button" ng-disabled="$select.disabled" ng-click="$selectMultiple.activeMatchIndex = $index;" ng-class="{\'btn-primary\':$selectMultiple.activeMatchIndex === $index, \'select-locked\':$select.isLocked(this, $index)}" ui-select-sort="$select.selected"><span class="close ui-select-match-close" ng-hide="$select.disabled" ng-click="$selectMultiple.removeChoice($index)"> ×</span> <span uis-transclude-append=""></span></span></span></span>'),e.put("bootstrap/match.tpl.html",'<div class="ui-select-match" ng-hide="$select.open" ng-disabled="$select.disabled" ng-class="{\'btn-default-focus\':$select.focus}"><span tabindex="-1" class="btn btn-default form-control ui-select-toggle" aria-label="{{ $select.baseTitle }} activate" ng-disabled="$select.disabled" ng-click="$select.activate()" style="outline: 0;"><span ng-show="$select.isEmpty()" class="ui-select-placeholder text-muted">{{$select.placeholder}}</span> <span ng-hide="$select.isEmpty()" class="ui-select-match-text pull-left" ng-class="{\'ui-select-allow-clear\': $select.allowClear && !$select.isEmpty()}" ng-transclude=""></span> <i class="caret pull-right" ng-click="$select.toggle($event)"></i> <a ng-show="$select.allowClear && !$select.isEmpty()" aria-label="{{ $select.baseTitle }} clear" style="margin-right: 10px" ng-click="$select.clear($event)" class="btn btn-xs btn-link pull-right"><i class="glyphicon glyphicon-remove" aria-hidden="true"></i></a></span></div>'),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="text" autocomplete="false" autocorrect="off" autocapitalize="off" spellcheck="false" class="ui-select-search input-xs" placeholder="{{$selectMultiple.getPlaceholder()}}" ng-disabled="$select.disabled" ng-hide="$select.disabled" ng-click="$select.activate()" ng-model="$select.search" role="combobox" aria-label="{{ $select.baseTitle }}" ondrop="return false;"></div><div class="ui-select-choices"></div></div>'),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><input type="text" autocomplete="false" tabindex="-1" aria-expanded="true" aria-label="{{ $select.baseTitle }}" aria-owns="ui-select-choices-{{ $select.generatedId }}" aria-activedescendant="ui-select-choices-row-{{ $select.generatedId }}-{{ $select.activeIndex }}" class="form-control ui-select-search" placeholder="{{$select.placeholder}}" ng-model="$select.search" ng-show="$select.searchEnabled && $select.open"><div class="ui-select-choices"></div></div>'),e.put("selectize/choices.tpl.html",'<div ng-show="$select.open" class="ui-select-choices ui-select-dropdown selectize-dropdown single"><div class="ui-select-choices-content selectize-dropdown-content"><div class="ui-select-choices-group optgroup" role="listbox"><div ng-show="$select.isGrouped" class="ui-select-choices-group-label optgroup-header" ng-bind="$group.name"></div><div role="option" class="ui-select-choices-row" ng-class="{active: $select.isActive(this), disabled: $select.isDisabled(this)}"><div class="option ui-select-choices-row-inner" data-selectable=""></div></div></div></div></div>'),e.put("selectize/match.tpl.html",'<div ng-hide="($select.open || $select.isEmpty())" class="ui-select-match" ng-transclude=""></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.activate()"><div class="ui-select-match"></div><input type="text" autocomplete="false" tabindex="-1" class="ui-select-search ui-select-toggle" ng-click="$select.toggle($event)" placeholder="{{$select.placeholder}}" ng-model="$select.search" ng-hide="!$select.searchEnabled || ($select.selected && !$select.open)" ng-disabled="$select.disabled" aria-label="{{ $select.baseTitle }}"></div><div class="ui-select-choices"></div></div>'),e.put("select2/choices.tpl.html",'<ul class="ui-select-choices ui-select-choices-content select2-results"><li class="ui-select-choices-group" ng-class="{\'select2-result-with-children\': $select.choiceGrouped($group) }"><div ng-show="$select.choiceGrouped($group)" class="ui-select-choices-group-label select2-result-label" ng-bind="$group.name"></div><ul role="listbox" id="ui-select-choices-{{ $select.generatedId }}" ng-class="{\'select2-result-sub\': $select.choiceGrouped($group), \'select2-result-single\': !$select.choiceGrouped($group) }"><li role="option" id="ui-select-choices-row-{{ $select.generatedId }}-{{$index}}" class="ui-select-choices-row" ng-class="{\'select2-highlighted\': $select.isActive(this), \'select2-disabled\': $select.isDisabled(this)}"><div class="select2-result-label ui-select-choices-row-inner"></div></li></ul></li></ul>'),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" 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/select-multiple.tpl.html",'<div class="ui-select-container ui-select-multiple select2 select2-container select2-container-multi" ng-class="{\'select2-container-active select2-dropdown-open open\': $select.open, \'select2-container-disabled\': $select.disabled}"><ul class="select2-choices"><span class="ui-select-match"></span><li class="select2-search-field"><input type="text" autocomplete="false" autocorrect="off" autocapitalize="off" spellcheck="false" role="combobox" aria-expanded="true" aria-owns="ui-select-choices-{{ $select.generatedId }}" aria-label="{{ $select.baseTitle }}" aria-activedescendant="ui-select-choices-row-{{ $select.generatedId }}-{{ $select.activeIndex }}" class="select2-input ui-select-search" placeholder="{{$selectMultiple.getPlaceholder()}}" ng-disabled="$select.disabled" ng-hide="$select.disabled" ng-model="$select.search" ng-click="$select.activate()" style="width: 34px;" ondrop="return false;"></li></ul><div class="ui-select-dropdown select2-drop select2-with-searchbox select2-drop-active" ng-class="{\'select2-display-none\': !$select.open}"><div class="ui-select-choices"></div></div></div>'),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="select2-search" ng-show="$select.searchEnabled"><input type="text" autocomplete="false" autocorrect="false" autocapitalize="off" spellcheck="false" role="combobox" aria-expanded="true" aria-owns="ui-select-choices-{{ $select.generatedId }}" aria-label="{{ $select.baseTitle }}" aria-activedescendant="ui-select-choices-row-{{ $select.generatedId }}-{{ $select.activeIndex }}" class="ui-select-search select2-input" ng-model="$select.search"></div><div class="ui-select-choices"></div></div></div>') | |
| 8 | +}]); | |
| 0 | 9 | \ No newline at end of file | ... | ... |
src/main/resources/static/assets/bower_components/angular-ui-select/package.json
0 → 100644
| 1 | +{ | |
| 2 | + "name": "ui-select", | |
| 3 | + "main": "dist/select.js", | |
| 4 | + "author": "http://github.com/angular-ui/ui-select/graphs/contributors", | |
| 5 | + "homepage": "http://github.com/angular-ui/ui-select", | |
| 6 | + "repository": { | |
| 7 | + "url": "git://github.com/angular-ui/ui-select.git" | |
| 8 | + }, | |
| 9 | + "version": "0.13.2", | |
| 10 | + "devDependencies": { | |
| 11 | + "bower": "~1.3", | |
| 12 | + "del": "~0.1.1", | |
| 13 | + "event-stream": "~3.1.0", | |
| 14 | + "gulp": "~3.8.5", | |
| 15 | + "gulp-angular-templatecache": "~1.2.1", | |
| 16 | + "gulp-concat": "~2.1.7", | |
| 17 | + "gulp-header": "~1.0.2", | |
| 18 | + "gulp-footer": "~1.0.5", | |
| 19 | + "gulp-jshint": "1.6.4", | |
| 20 | + "gulp-minify-css": "~0.3.6", | |
| 21 | + "gulp-minify-html": "~0.1.0", | |
| 22 | + "gulp-plumber": "^0.6.3", | |
| 23 | + "gulp-rename": "~0.2.2", | |
| 24 | + "gulp-uglify": "~0.3.1", | |
| 25 | + "gulp-util": "^2.2.19", | |
| 26 | + "jshint-stylish": "~0.3.0", | |
| 27 | + "karma": "^0.12.16", | |
| 28 | + "karma-chrome-launcher": "^0.1.3", | |
| 29 | + "karma-firefox-launcher": "~0.1", | |
| 30 | + "karma-jasmine": "~0.2", | |
| 31 | + "karma-ng-html2js-preprocessor": "^0.1.0", | |
| 32 | + "karma-phantomjs-launcher": "~0.1.4", | |
| 33 | + "karma-coverage": "~0.2" | |
| 34 | + }, | |
| 35 | + "scripts": { | |
| 36 | + "test": "gulp test" | |
| 37 | + }, | |
| 38 | + "license": "MIT" | |
| 39 | +} | ... | ... |
src/main/resources/static/index.html
| ... | ... | @@ -36,6 +36,10 @@ |
| 36 | 36 | |
| 37 | 37 | <!-- table 表格控件 --> |
| 38 | 38 | <link rel="stylesheet" href="http://api.map.baidu.com/library/DrawingManager/1.4/src/DrawingManager_min.css" type="text/css" /> |
| 39 | + | |
| 40 | +<!-- schedule计划调度AngularJS模块主css --> | |
| 41 | +<link rel="stylesheet" href="/pages/scheduleApp/module/main.css" type="text/css"/> | |
| 42 | + | |
| 39 | 43 | <style type="text/css"> |
| 40 | 44 | .searchForm{ |
| 41 | 45 | ... | ... |
src/main/resources/static/pages/scheduleApp/bower.json
src/main/resources/static/pages/scheduleApp/module/basicInfo/busInfoManage/busInfoManage.js
| 1 | 1 | // 车辆基础信息维护 service controller等写在一起 |
| 2 | 2 | |
| 3 | -angular.module('ScheduleApp').factory('BusInfoManageService', ['$resource', function($resource) { | |
| 4 | - // TODO:测试 | |
| 5 | - var pageInfo = { | |
| 6 | - totalItems : 64, | |
| 7 | - currentPage : 4, | |
| 8 | - infos: [] | |
| 3 | +angular.module('ScheduleApp').factory('BusInfoManageService', ['BusInfoManageService_g', function(service) { | |
| 4 | + /** 车辆类型常量 */ | |
| 5 | + var carTypes = [ | |
| 6 | + {type: "营运车"}, | |
| 7 | + {type: "包车"}, | |
| 8 | + {type: "学校班车"}, | |
| 9 | + {type: "公司班车"}, | |
| 10 | + {type: "待报废车"}, | |
| 11 | + {type: "备车"} | |
| 12 | + ]; | |
| 13 | + /** 机动车类型常量 */ | |
| 14 | + var vehicleStates = [ | |
| 15 | + {type: "非机动车"}, | |
| 16 | + {type: "机动一队"}, | |
| 17 | + {type: "机动二队"}, | |
| 18 | + {type: "机动三队"}, | |
| 19 | + {type: "备车"}, | |
| 20 | + {type: "抢修车"} | |
| 21 | + ]; | |
| 22 | + /** 营运状态类型常量 */ | |
| 23 | + var operatorsStates = [ | |
| 24 | + {type: "营运"}, | |
| 25 | + {type: "停运"}, | |
| 26 | + {type: "挂失"}, | |
| 27 | + {type: "迁出(过户)"}, | |
| 28 | + {type: "迁出(转籍)"}, | |
| 29 | + {type: "报废"}, | |
| 30 | + {type: "歇业"}, | |
| 31 | + {type: "注销"}, | |
| 32 | + {type: "其他"} | |
| 33 | + ]; | |
| 34 | + /** 设备厂商名字 */ | |
| 35 | + var supplierNames = [ | |
| 36 | + {name: "巴士拓华"}, | |
| 37 | + {name: "博康"} | |
| 38 | + ]; | |
| 39 | + /** 公司字典 */ | |
| 40 | + var gses = [ | |
| 41 | + {gsdm: "55", gsmc: "上南公司"}, | |
| 42 | + {gsdm: "22", gsmc: "金高公司"}, | |
| 43 | + {gsdm: "05", gsmc: "杨高公司"}, | |
| 44 | + {gsdm: "26", gsmc: "南汇公司"} | |
| 45 | + ]; | |
| 46 | + | |
| 47 | + /** 当前的查询条件信息 */ | |
| 48 | + var currentSearchCondition = { | |
| 49 | + "carCode_like" : "", | |
| 50 | + "insideCode_like" : "", | |
| 51 | + "equipmentCode_like" : "", | |
| 52 | + "carPlate_like" : "" | |
| 9 | 53 | }; |
| 10 | 54 | |
| 55 | + /** 当前第几页 */ | |
| 56 | + var currentPageNo = 1; | |
| 11 | 57 | return { |
| 12 | - pi: function() { | |
| 13 | - console.log("pi"); | |
| 14 | - return pageInfo; | |
| 58 | + /** | |
| 59 | + * 获取公司字典。 | |
| 60 | + */ | |
| 61 | + getGses: function() { | |
| 62 | + return gses; | |
| 63 | + }, | |
| 64 | + /** | |
| 65 | + * 获取设备厂商名字。 | |
| 66 | + */ | |
| 67 | + getSupplierNames: function() { | |
| 68 | + return supplierNames; | |
| 69 | + }, | |
| 70 | + /** | |
| 71 | + * 获取营运状态类型。 | |
| 72 | + */ | |
| 73 | + getOperatorsStates: function() { | |
| 74 | + return operatorsStates; | |
| 75 | + }, | |
| 76 | + /** | |
| 77 | + * 获取机动车类型。 | |
| 78 | + */ | |
| 79 | + getVehicleStates: function() { | |
| 80 | + return vehicleStates; | |
| 81 | + }, | |
| 82 | + /** | |
| 83 | + * 获取车辆类型。 | |
| 84 | + */ | |
| 85 | + getCarTypes: function() { | |
| 86 | + return carTypes; | |
| 87 | + }, | |
| 88 | + /** | |
| 89 | + * 获取查询条件信息, | |
| 90 | + * 用于给controller用来和页面数据绑定。 | |
| 91 | + */ | |
| 92 | + getSearchCondition: function() { | |
| 93 | + return currentSearchCondition; | |
| 94 | + }, | |
| 95 | + /** | |
| 96 | + * 重置查询条件信息。 | |
| 97 | + */ | |
| 98 | + resetSearchCondition: function() { | |
| 99 | + var key; | |
| 100 | + for (key in currentSearchCondition) { | |
| 101 | + currentSearchCondition[key] = ""; | |
| 102 | + } | |
| 103 | + }, | |
| 104 | + /** | |
| 105 | + * 设置当前页码。 | |
| 106 | + * @param cpn 从1开始,后台是从0开始的 | |
| 107 | + */ | |
| 108 | + setCurrentPageNo: function(cpn) { | |
| 109 | + currentPageNo = cpn; | |
| 110 | + }, | |
| 111 | + /** | |
| 112 | + * 组装查询参数,返回一个promise查询结果。 | |
| 113 | + * @param params 查询参数 | |
| 114 | + * @return 返回一个 promise | |
| 115 | + */ | |
| 116 | + getPage: function() { | |
| 117 | + var params = currentSearchCondition; // 查询条件 | |
| 118 | + params.page = currentPageNo - 1; // 服务端页码从0开始 | |
| 119 | + return service.list(params).$promise; | |
| 15 | 120 | }, |
| 16 | - setCP: function(cp) { | |
| 17 | - console.log("setCP"); | |
| 18 | - pageInfo.currentPage = cp; | |
| 121 | + /** | |
| 122 | + * 获取明细信息。 | |
| 123 | + * @param id 车辆id | |
| 124 | + * @return 返沪一个 promise | |
| 125 | + */ | |
| 126 | + getDetail: function(id) { | |
| 127 | + var params = {id: id}; | |
| 128 | + return service.get(params).$promise; | |
| 19 | 129 | } |
| 20 | 130 | }; |
| 21 | - | |
| 22 | - //return $resource( // TODO:后面再改 | |
| 23 | - // '/cci', | |
| 24 | - // {}, | |
| 25 | - // { | |
| 26 | - // list: { | |
| 27 | - // method: 'GET' | |
| 28 | - // } | |
| 29 | - // } | |
| 30 | - //); | |
| 31 | 131 | }]); |
| 32 | 132 | |
| 33 | 133 | angular.module('ScheduleApp').controller('BusInfoManageCtrl', ['BusInfoManageService','$state', function(busInfoManageService, $state) { |
| 34 | - // TODO:测试state变换 | |
| 35 | 134 | var self = this; |
| 36 | - self.testgo = function() { | |
| 135 | + | |
| 136 | + // 切换到form状态 | |
| 137 | + self.goForm = function() { | |
| 37 | 138 | //alert("切换"); |
| 38 | - $state.go("form"); | |
| 139 | + $state.go("busInfoManage_form"); | |
| 39 | 140 | } |
| 40 | 141 | |
| 41 | 142 | |
| 42 | 143 | }]); |
| 43 | 144 | |
| 44 | -angular.module('ScheduleApp').controller('BusInfoManageListCtrl', ['BusInfoManageService', function(busInfoManageService) { | |
| 45 | - // TODO:模拟数据 | |
| 145 | +angular.module('ScheduleApp').controller('BusInfoManageListCtrl', ['BusInfoManageService','$scope', function(service, $scope) { | |
| 46 | 146 | var self = this; |
| 47 | - self.pi = busInfoManageService.pi(); | |
| 48 | - //self.totalItems = pi.totalItems; | |
| 49 | - //self.currentPage = pi.currentPage; | |
| 50 | - //self.infos = pi.infos; | |
| 147 | + self.pageInfo = { | |
| 148 | + totalItems : 0, | |
| 149 | + currentPage : 1, | |
| 150 | + infos: [] | |
| 151 | + }; | |
| 152 | + | |
| 153 | + // 初始创建的时候,获取一次列表数据 | |
| 154 | + service.getPage().then( | |
| 155 | + function(result) { | |
| 156 | + self.pageInfo.totalItems = result.totalElements; | |
| 157 | + self.pageInfo.currentPage = result.number + 1; | |
| 158 | + self.pageInfo.infos = result.content; | |
| 159 | + service.setCurrentPageNo(result.number + 1); | |
| 160 | + }, | |
| 161 | + function(result) { | |
| 162 | + alert("出错啦!"); | |
| 163 | + } | |
| 164 | + ); | |
| 165 | + | |
| 166 | + //$scope.$watch("ctrl.pageInfo.currentPage", function() { | |
| 167 | + // alert("dfdfdf"); | |
| 168 | + //}); | |
| 169 | + | |
| 170 | + // 翻页的时候调用 | |
| 51 | 171 | self.pageChanaged = function() { |
| 52 | - console.log("页面跳转到:" + busInfoManageService.pi().currentPage); | |
| 53 | - } | |
| 172 | + service.setCurrentPageNo(self.pageInfo.currentPage); | |
| 173 | + service.getPage().then( | |
| 174 | + function(result) { | |
| 175 | + self.pageInfo.totalItems = result.totalElements; | |
| 176 | + self.pageInfo.currentPage = result.number + 1; | |
| 177 | + self.pageInfo.infos = result.content; | |
| 178 | + service.setCurrentPageNo(result.number + 1); | |
| 179 | + }, | |
| 180 | + function(result) { | |
| 181 | + alert("出错啦!"); | |
| 182 | + } | |
| 183 | + ); | |
| 184 | + }; | |
| 185 | + // 获取查询条件数据 | |
| 186 | + self.searchCondition = function() { | |
| 187 | + return service.getSearchCondition(); | |
| 188 | + }; | |
| 189 | + // 重置查询条件 | |
| 190 | + self.resetSearchCondition = function() { | |
| 191 | + return service.resetSearchCondition(); | |
| 192 | + }; | |
| 54 | 193 | }]); |
| 55 | 194 | |
| 56 | -angular.module('ScheduleApp').controller('BusInfoManageFormCtrl', ['BusInfoManageService', function(busInfoManageService) { | |
| 195 | +angular.module('ScheduleApp').controller('BusInfoManageFormCtrl', ['BusInfoManageService', '$scope', function(busInfoManageService, $scope) { | |
| 57 | 196 | var self = this; |
| 58 | 197 | |
| 59 | - // 绑定一个当前的输入对象 | |
| 60 | - self.busInfo = {}; | |
| 198 | + // 报废日期 日期控件开关 | |
| 199 | + self.scrapDateOpen = false; | |
| 200 | + self.scrapDate_open = function() { | |
| 201 | + self.scrapDateOpen = true; | |
| 202 | + }; | |
| 203 | + | |
| 204 | + // 启用日期 日期控件开关 | |
| 205 | + self.openDateOpen = false; | |
| 206 | + self.openDate_open = function() { | |
| 207 | + self.openDateOpen = true; | |
| 208 | + }; | |
| 209 | + // 取消日期 日期控件开关 | |
| 210 | + self.closeDateOpen = false; | |
| 211 | + self.closeDate_open = function() { | |
| 212 | + self.closeDateOpen = true; | |
| 213 | + }; | |
| 214 | + | |
| 215 | + // 欲保存的busInfo信息,绑定 | |
| 216 | + self.busInfoForSave = {}; | |
| 217 | + | |
| 218 | + // 车辆类型 selectedItem | |
| 219 | + self.busInfoForSave.carType_Selected = null; | |
| 220 | + self.carTypes = busInfoManageService.getCarTypes(); | |
| 221 | + | |
| 222 | + // 机动车类型 selectedItem | |
| 223 | + self.busInfoForSave.vehicleStats_Selected = null; | |
| 224 | + self.vehicleStates = busInfoManageService.getVehicleStates(); | |
| 225 | + | |
| 226 | + // 营运状态类型 selectedItem | |
| 227 | + self.busInfoForSave.operatorsState_Selected = null; | |
| 228 | + self.operatorsStates = busInfoManageService.getOperatorsStates(); | |
| 229 | + | |
| 230 | + // 设备厂商 selectedItem | |
| 231 | + self.busInfoForSave.supplierName_selected = null; | |
| 232 | + self.supplierNames = busInfoManageService.getSupplierNames(); | |
| 233 | + | |
| 234 | + // 公司 selectedItem | |
| 235 | + self.busInfoForSave.gs_selected = null; | |
| 236 | + self.gses = busInfoManageService.getGses(); | |
| 237 | + self.gs_selected_change = function($item, $model) { | |
| 238 | + self.busInfoForSave.businessCode = $item.gsdm; | |
| 239 | + self.busInfoForSave.company = $item.gsmc; | |
| 240 | + }; | |
| 241 | + self.gs_selected_remove = function() { | |
| 242 | + self.busInfoForSave.businessCode = null; | |
| 243 | + self.busInfoForSave.company = null; | |
| 244 | + }; | |
| 61 | 245 | |
| 62 | 246 | // 提交方法 |
| 63 | 247 | self.submit = function() { |
| 248 | + console.log(self.busInfoForSave); | |
| 64 | 249 | alert("form submit 测试!"); |
| 65 | 250 | }; |
| 66 | 251 | |
| 67 | - | |
| 68 | 252 | }]); |
| 69 | 253 | |
| 70 | -angular.module('ScheduleApp').controller('BusInfoManageDetailCtrl', ['BusInfoManageService', function(busInfoManageService) { | |
| 254 | +angular.module('ScheduleApp').controller('BusInfoManageDetailCtrl', ['BusInfoManageService', '$stateParams', function(service, $stateParams) { | |
| 255 | + var self = this; | |
| 256 | + self.title = ""; | |
| 257 | + self.busInfoForDetail = {}; | |
| 258 | + self.busInfoForDetail.id = $stateParams.id; | |
| 259 | + | |
| 260 | + // 当转向到此页面时,就获取明细信息并绑定 | |
| 261 | + service.getDetail($stateParams.id).then( | |
| 262 | + function(result) { | |
| 263 | + var key; | |
| 264 | + for (key in result) { | |
| 265 | + self.busInfoForDetail[key] = result[key]; | |
| 266 | + } | |
| 71 | 267 | |
| 268 | + self.title = "车辆 " + self.busInfoForDetail.insideCode + " 详细信息"; | |
| 269 | + }, | |
| 270 | + function(result) { | |
| 271 | + alert("出错啦!"); | |
| 272 | + } | |
| 273 | + ); | |
| 72 | 274 | }]); |
| 73 | 275 | \ No newline at end of file | ... | ... |
src/main/resources/static/pages/scheduleApp/module/basicInfo/busInfoManage/detail.html
| 1 | +<div class="page-head"> | |
| 2 | + <div class="page-title"> | |
| 3 | + <h1>车辆详细信息</h1> | |
| 4 | + </div> | |
| 5 | +</div> | |
| 6 | + | |
| 7 | +<ul class="page-breadcrumb breadcrumb"> | |
| 8 | + <li> | |
| 9 | + <a href="/pages/home.html" data-pjax>首页</a> | |
| 10 | + <i class="fa fa-circle"></i> | |
| 11 | + </li> | |
| 12 | + <li> | |
| 13 | + <span class="active">基础信息</span> | |
| 14 | + <i class="fa fa-circle"></i> | |
| 15 | + </li> | |
| 16 | + <li> | |
| 17 | + <a ui-sref="busInfoManage">车辆信息管理</a> | |
| 18 | + <i class="fa fa-circle"></i> | |
| 19 | + </li> | |
| 20 | + <li> | |
| 21 | + <span class="active">车辆详细信息</span> | |
| 22 | + </li> | |
| 23 | +</ul> | |
| 24 | + | |
| 25 | +<div class="portlet light bordered" ng-controller="BusInfoManageDetailCtrl as ctrl"> | |
| 26 | + <div class="portlet-title"> | |
| 27 | + <div class="caption"> | |
| 28 | + <i class="icon-equalizer font-red-sunglo"></i> <span | |
| 29 | + class="caption-subject font-red-sunglo bold uppercase" | |
| 30 | + ng-bind="ctrl.title"></span> | |
| 31 | + </div> | |
| 32 | + </div> | |
| 33 | + | |
| 34 | + <div class="portlet-body form"> | |
| 35 | + <form class="form-horizontal" novalidate name="myForm"> | |
| 36 | + <!--<div class="alert alert-danger display-hide">--> | |
| 37 | + <!--<button class="close" data-close="alert"></button>--> | |
| 38 | + <!--您的输入有误,请检查下面的输入项--> | |
| 39 | + <!--</div>--> | |
| 40 | + | |
| 41 | + | |
| 42 | + <!-- 其他信息放置在这里 --> | |
| 43 | + <div class="form-body"> | |
| 44 | + <div class="form-group has-success has-feedback"> | |
| 45 | + <label class="col-md-2 control-label">内部编号*:</label> | |
| 46 | + <div class="col-md-3"> | |
| 47 | + <input type="text" class="form-control" | |
| 48 | + name="insideCode" ng-model="ctrl.busInfoForDetail.insideCode" readonly/> | |
| 49 | + </div> | |
| 50 | + </div> | |
| 51 | + | |
| 52 | + <div class="form-group has-success has-feedback"> | |
| 53 | + <label class="col-md-2 control-label">所属公司*:</label> | |
| 54 | + <div class="col-md-3"> | |
| 55 | + <input type="text" class="form-control" name="company" | |
| 56 | + ng-model="ctrl.busInfoForDetail.company" readonly/> | |
| 57 | + </div> | |
| 58 | + </div> | |
| 59 | + | |
| 60 | + <div class="form-group"> | |
| 61 | + <label class="col-md-2 control-label">分公司:</label> | |
| 62 | + <div class="col-md-3"> | |
| 63 | + <input type="text" class="form-control" name="brancheCompany" | |
| 64 | + ng-model="ctrl.busInfoForDetail.brancheCompany" readonly/> | |
| 65 | + </div> | |
| 66 | + </div> | |
| 67 | + | |
| 68 | + <div class="form-group has-success has-feedback"> | |
| 69 | + <label class="col-md-2 control-label">车辆编码*:</label> | |
| 70 | + <div class="col-md-3"> | |
| 71 | + <input type="text" class="form-control" | |
| 72 | + name="carCode" ng-model="ctrl.busInfoForDetail.carCode" readonly/> | |
| 73 | + </div> | |
| 74 | + </div> | |
| 75 | + | |
| 76 | + <div class="form-group has-success has-feedback"> | |
| 77 | + <label class="col-md-2 control-label">车牌号*:</label> | |
| 78 | + <div class="col-md-3"> | |
| 79 | + <input type="text" class="form-control" | |
| 80 | + name="carPlate" ng-model="ctrl.busInfoForDetail.carPlate" readonly/> | |
| 81 | + </div> | |
| 82 | + </div> | |
| 83 | + | |
| 84 | + <div class="form-group has-success has-feedback"> | |
| 85 | + <label class="col-md-2 control-label">设备供应厂商*:</label> | |
| 86 | + <div class="col-md-3"> | |
| 87 | + <input type="text" class="form-control" | |
| 88 | + name="supplierName" ng-model="ctrl.busInfoForDetail.supplierName" readonly/> | |
| 89 | + </div> | |
| 90 | + </div> | |
| 91 | + | |
| 92 | + <div class="form-group has-success has-feedback"> | |
| 93 | + <label class="col-md-2 control-label">终端号*:</label> | |
| 94 | + <div class="col-md-3"> | |
| 95 | + <input type="text" class="form-control" | |
| 96 | + name="equipmentCode" ng-model="ctrl.busInfoForDetail.equipmentCode" readonly/> | |
| 97 | + </div> | |
| 98 | + </div> | |
| 99 | + | |
| 100 | + <div class="form-group"> | |
| 101 | + <label class="col-md-2 control-label">车型类别:</label> | |
| 102 | + <div class="col-md-4"> | |
| 103 | + <input type="text" class="form-control" ng-model="ctrl.busInfoForDetail.carClass" readonly/> | |
| 104 | + </div> | |
| 105 | + </div> | |
| 106 | + <div class="form-group"> | |
| 107 | + <label class="col-md-2 control-label">技术速度:</label> | |
| 108 | + <div class="col-md-4"> | |
| 109 | + <input type="text" class="form-control" ng-model="ctrl.busInfoForDetail.speed" readonly/> | |
| 110 | + </div> | |
| 111 | + </div> | |
| 112 | + <div class="form-group"> | |
| 113 | + <label class="col-md-2 control-label">座位数:</label> | |
| 114 | + <div class="col-md-4"> | |
| 115 | + <input type="text" class="form-control" ng-model="ctrl.busInfoForDetail.carSeatnNumber" readonly/> | |
| 116 | + </div> | |
| 117 | + </div> | |
| 118 | + <div class="form-group"> | |
| 119 | + <label class="col-md-2 control-label">载客标准:</label> | |
| 120 | + <div class="col-md-4"> | |
| 121 | + <input type="text" class="form-control" ng-model="ctrl.busInfoForDetail.carStandard" readonly/> | |
| 122 | + </div> | |
| 123 | + </div> | |
| 124 | + <div class="form-group"> | |
| 125 | + <label class="col-md-2 control-label">标准油耗/开空调:</label> | |
| 126 | + <div class="col-md-4"> | |
| 127 | + <input type="text" class="form-control" ng-model="ctrl.busInfoForDetail.kburnStandard" readonly/> | |
| 128 | + </div> | |
| 129 | + </div> | |
| 130 | + <div class="form-group"> | |
| 131 | + <label class="col-md-2 control-label">标准油耗/关空调:</label> | |
| 132 | + <div class="col-md-4"> | |
| 133 | + <input type="text" class="form-control" ng-model="ctrl.busInfoForDetail.gburnStandard" readonly/> | |
| 134 | + </div> | |
| 135 | + </div> | |
| 136 | + <div class="form-group"> | |
| 137 | + <label class="col-md-2 control-label">报废号:</label> | |
| 138 | + <div class="col-md-4"> | |
| 139 | + <input type="text" class="form-control" ng-model="ctrl.busInfoForDetail.scrapCode" readonly/> | |
| 140 | + </div> | |
| 141 | + </div> | |
| 142 | + | |
| 143 | + <!-- TODO --> | |
| 144 | + <div class="form-group"> | |
| 145 | + <label class="col-md-2 control-label">报废日期:</label> | |
| 146 | + <div class="col-md-4"> | |
| 147 | + <input type="text" class="form-control" | |
| 148 | + name="scrapDate" uib-datepicker-popup="yyyy年MM月dd日" | |
| 149 | + ng-model="ctrl.busInfoForDetail.scrapDate" readonly/> | |
| 150 | + </div> | |
| 151 | + </div> | |
| 152 | + <div class="form-group"> | |
| 153 | + <label class="col-md-2 control-label">厂牌型号1:</label> | |
| 154 | + <div class="col-md-4"> | |
| 155 | + <input type="text" class="form-control" ng-model="ctrl.busInfoForDetail.makeCodeOne" readonly/> | |
| 156 | + </div> | |
| 157 | + </div> | |
| 158 | + <div class="form-group"> | |
| 159 | + <label class="col-md-2 control-label">厂牌型号2:</label> | |
| 160 | + <div class="col-md-4"> | |
| 161 | + <input type="text" class="form-control" ng-model="ctrl.busInfoForDetail.makeCodeTwo" readonly/> | |
| 162 | + </div> | |
| 163 | + </div> | |
| 164 | + <div class="form-group"> | |
| 165 | + <label class="col-md-2 control-label">车辆等级标准:</label> | |
| 166 | + <div class="col-md-4"> | |
| 167 | + <input type="text" class="form-control" ng-model="ctrl.busInfoForDetail.carGride" readonly/> | |
| 168 | + </div> | |
| 169 | + </div> | |
| 170 | + <div class="form-group"> | |
| 171 | + <label class="col-md-2 control-label">出厂排放标准:</label> | |
| 172 | + <div class="col-md-4"> | |
| 173 | + <input type="text" class="form-control" ng-model="ctrl.busInfoForDetail.emissionsStandard" readonly/> | |
| 174 | + </div> | |
| 175 | + </div> | |
| 176 | + <div class="form-group"> | |
| 177 | + <label class="col-md-2 control-label">发动机号码1:</label> | |
| 178 | + <div class="col-md-4"> | |
| 179 | + <input type="text" class="form-control" ng-model="ctrl.busInfoForDetail.engineCodeOne" readonly/> | |
| 180 | + </div> | |
| 181 | + </div> | |
| 182 | + <div class="form-group"> | |
| 183 | + <label class="col-md-2 control-label">发动机号码2:</label> | |
| 184 | + <div class="col-md-4"> | |
| 185 | + <input type="text" class="form-control" ng-model="ctrl.busInfoForDetail.engineCodeTwo" readonly/> | |
| 186 | + </div> | |
| 187 | + </div> | |
| 188 | + <div class="form-group"> | |
| 189 | + <label class="col-md-2 control-label">车架号码1:</label> | |
| 190 | + <div class="col-md-4"> | |
| 191 | + <input type="text" class="form-control" ng-model="ctrl.busInfoForDetail.carNumberOne" readonly/> | |
| 192 | + </div> | |
| 193 | + </div> | |
| 194 | + <div class="form-group"> | |
| 195 | + <label class="col-md-2 control-label">车架号码2:</label> | |
| 196 | + <div class="col-md-4"> | |
| 197 | + <input type="text" class="form-control" ng-model="ctrl.busInfoForDetail.carNumberTwo" readonly/> | |
| 198 | + </div> | |
| 199 | + </div> | |
| 200 | + | |
| 201 | + <div class="form-group"> | |
| 202 | + <label class="col-md-2 control-label">启用日期:</label> | |
| 203 | + <div class="col-md-4"> | |
| 204 | + <input type="text" class="form-control" | |
| 205 | + name="openDate" uib-datepicker-popup="yyyy年MM月dd日" | |
| 206 | + ng-model="ctrl.busInfoForDetail.openDate" readonly/> | |
| 207 | + </div> | |
| 208 | + </div> | |
| 209 | + <div class="form-group"> | |
| 210 | + <label class="col-md-2 control-label">取消日期:</label> | |
| 211 | + <div class="col-md-4"> | |
| 212 | + <input type="text" class="form-control" | |
| 213 | + name="closeDate" uib-datepicker-popup="yyyy年MM月dd日" | |
| 214 | + ng-model="ctrl.busInfoForDetail.closeDate" readonly/> | |
| 215 | + </div> | |
| 216 | + </div> | |
| 217 | + | |
| 218 | + <div class="form-group"> | |
| 219 | + <label class="col-md-2 control-label">是否空调车:</label> | |
| 220 | + <div class="col-md-3"> | |
| 221 | + <label class="radio-inline"> | |
| 222 | + <input type="radio" name="hvacCar" ng-value="true" ng-model="ctrl.busInfoForDetail.hvacCar" disabled/>是 | |
| 223 | + </label> | |
| 224 | + <label class="radio-inline"> | |
| 225 | + <input type="radio" name="hvacCar" ng-value="false" ng-model="ctrl.busInfoForDetail.hvacCar" disabled/>否 | |
| 226 | + </label> | |
| 227 | + </div> | |
| 228 | + </div> | |
| 229 | + | |
| 230 | + <div class="form-group"> | |
| 231 | + <label class="col-md-2 control-label">有无人售票:</label> | |
| 232 | + <div class="col-md-3"> | |
| 233 | + <label class="radio-inline"> | |
| 234 | + <input type="radio" name="ticketType" ng-value="true" ng-model="ctrl.busInfoForDetail.ticketType" disabled/>是 | |
| 235 | + </label> | |
| 236 | + <label class="radio-inline"> | |
| 237 | + <input type="radio" name="ticketType" ng-value="false" ng-model="ctrl.busInfoForDetail.ticketType" disabled/>否 | |
| 238 | + </label> | |
| 239 | + </div> | |
| 240 | + </div> | |
| 241 | + | |
| 242 | + <div class="form-group"> | |
| 243 | + <label class="col-md-2 control-label">是否有LED服务屏:</label> | |
| 244 | + <div class="col-md-3"> | |
| 245 | + <label class="radio-inline"> | |
| 246 | + <input type="radio" name="ledScreen" ng-value="true" ng-model="ctrl.busInfoForDetail.ledScreen" disabled/>是 | |
| 247 | + </label> | |
| 248 | + <label class="radio-inline"> | |
| 249 | + <input type="radio" name="ledScreen" ng-value="false" ng-model="ctrl.busInfoForDetail.ledScreen" disabled/>否 | |
| 250 | + </label> | |
| 251 | + </div> | |
| 252 | + </div> | |
| 253 | + | |
| 254 | + <div class="form-group"> | |
| 255 | + <label class="col-md-2 control-label">是否有TV视屏:</label> | |
| 256 | + <div class="col-md-3"> | |
| 257 | + <label class="radio-inline"> | |
| 258 | + <input type="radio" name="tvVideoType" ng-value="true" ng-model="ctrl.busInfoForDetail.tvVideoType" disabled/>是 | |
| 259 | + </label> | |
| 260 | + <label class="radio-inline"> | |
| 261 | + <input type="radio" name="tvVideoType" ng-value="false" ng-model="ctrl.busInfoForDetail.tvVideoType" disabled/>否 | |
| 262 | + </label> | |
| 263 | + </div> | |
| 264 | + </div> | |
| 265 | + | |
| 266 | + <div class="form-group"> | |
| 267 | + <label class="col-md-2 control-label">车辆类型:</label> | |
| 268 | + <div class="col-md-3"> | |
| 269 | + <input type="text" class="form-control" | |
| 270 | + name="carType" ng-model="ctrl.busInfoForDetail.carType" readonly/> | |
| 271 | + </div> | |
| 272 | + </div> | |
| 273 | + | |
| 274 | + <div class="form-group"> | |
| 275 | + <label class="col-md-2 control-label">是否机动车:</label> | |
| 276 | + <div class="col-md-3"> | |
| 277 | + <input type="text" class="form-control" | |
| 278 | + name="vehicleStats" ng-model="ctrl.busInfoForDetail.vehicleStats" readonly/> | |
| 279 | + </div> | |
| 280 | + </div> | |
| 281 | + | |
| 282 | + <div class="form-group"> | |
| 283 | + <label class="col-md-2 control-label">营运状态:</label> | |
| 284 | + <div class="col-md-3"> | |
| 285 | + <input type="text" class="form-control" | |
| 286 | + name="operatorsState" ng-model="ctrl.busInfoForDetail.operatorsState" readonly/> | |
| 287 | + </div> | |
| 288 | + </div> | |
| 289 | + | |
| 290 | + <div class="form-group"> | |
| 291 | + <label class="col-md-2 control-label">修改时间:</label> | |
| 292 | + <div class="col-md-3"> | |
| 293 | + <input type="text" class="form-control" | |
| 294 | + name="updateDate" uib-datepicker-popup="yyyy年MM月dd日 HH:mm:ss" | |
| 295 | + ng-model="ctrl.busInfoForDetail.updateDate" readonly/> | |
| 296 | + </div> | |
| 297 | + </div> | |
| 298 | + | |
| 299 | + <div class="form-group"> | |
| 300 | + <label class="col-md-2 control-label">是否电车:</label> | |
| 301 | + <div class="col-md-3"> | |
| 302 | + <label class="radio-inline"> | |
| 303 | + <input type="radio" name="sfdc" ng-value="true" ng-model="ctrl.busInfoForDetail.sfdc" disabled/>是 | |
| 304 | + </label> | |
| 305 | + <label class="radio-inline"> | |
| 306 | + <input type="radio" name="sfdc" ng-value="true" ng-model="ctrl.busInfoForDetail.sfdc" disabled/>否 | |
| 307 | + </label> | |
| 308 | + </div> | |
| 309 | + </div> | |
| 310 | + | |
| 311 | + | |
| 312 | + <div class="form-group"> | |
| 313 | + <label class="col-md-2 control-label">备注:</label> | |
| 314 | + <div class="col-md-10"> | |
| 315 | + <textarea rows="3" class="form-control" ng-model="ctrl.busInfoForDetail.descriptions" readonly></textarea> | |
| 316 | + </div> | |
| 317 | + </div> | |
| 318 | + | |
| 319 | + | |
| 320 | + <!-- 其他form-group --> | |
| 321 | + | |
| 322 | + </div> | |
| 323 | + | |
| 324 | + </form> | |
| 325 | + | |
| 326 | + </div> | |
| 327 | +</div> | |
| 0 | 328 | \ No newline at end of file | ... | ... |
src/main/resources/static/pages/scheduleApp/module/basicInfo/busInfoManage/form.html
| 1 | -<!-- 导航式布局到时候再加 --> | |
| 1 | +<div class="page-head"> | |
| 2 | + <div class="page-title"> | |
| 3 | + <h1>添加车辆信息</h1> | |
| 4 | + </div> | |
| 5 | +</div> | |
| 6 | + | |
| 7 | +<ul class="page-breadcrumb breadcrumb"> | |
| 8 | + <li> | |
| 9 | + <a href="/pages/home.html" data-pjax>首页</a> | |
| 10 | + <i class="fa fa-circle"></i> | |
| 11 | + </li> | |
| 12 | + <li> | |
| 13 | + <span class="active">基础信息</span> | |
| 14 | + <i class="fa fa-circle"></i> | |
| 15 | + </li> | |
| 16 | + <li> | |
| 17 | + <a ui-sref="busInfoManage">车辆信息管理</a> | |
| 18 | + <i class="fa fa-circle"></i> | |
| 19 | + </li> | |
| 20 | + <li> | |
| 21 | + <span class="active">添加车辆信息</span> | |
| 22 | + </li> | |
| 23 | +</ul> | |
| 2 | 24 | |
| 3 | 25 | <div class="portlet light bordered" ng-controller="BusInfoManageFormCtrl as ctrl"> |
| 4 | 26 | <div class="portlet-title"> |
| ... | ... | @@ -9,7 +31,7 @@ |
| 9 | 31 | </div> |
| 10 | 32 | |
| 11 | 33 | <div class="portlet-body form"> |
| 12 | - <form ng-submit="ctrl.submit()" class="form-horizontal" name="myForm"> | |
| 34 | + <form ng-submit="ctrl.submit()" class="form-horizontal" novalidate name="myForm"> | |
| 13 | 35 | <!--<div class="alert alert-danger display-hide">--> |
| 14 | 36 | <!--<button class="close" data-close="alert"></button>--> |
| 15 | 37 | <!--您的输入有误,请检查下面的输入项--> |
| ... | ... | @@ -18,224 +40,414 @@ |
| 18 | 40 | |
| 19 | 41 | <!-- 其他信息放置在这里 --> |
| 20 | 42 | <div class="form-body"> |
| 21 | - <!-- 测试form验证 --> | |
| 22 | - <div class="form-group"> | |
| 23 | - <label class="col-md-2 control-label">内部编号:</label> | |
| 24 | - <div class="col-md-10"> | |
| 25 | - <input type="text" class="form-control" name="insideCode" ng-model="ctrl.busInfo.insideCode" | |
| 26 | - required ng-maxlength="8"/> | |
| 27 | - <span ng-show="myForm.insideCode.$error.required"> | |
| 28 | - 内部编号必须填写 | |
| 29 | - </span> | |
| 30 | - <span ng-show="myForm.insideCode.$error.maxlength"> | |
| 31 | - 内部编号长度不能超过8位 | |
| 32 | - </span> | |
| 33 | - | |
| 43 | + <div class="form-group has-success has-feedback"> | |
| 44 | + <label class="col-md-2 control-label">内部编号*:</label> | |
| 45 | + <div class="col-md-3"> | |
| 46 | + <input type="text" class="form-control" | |
| 47 | + name="insideCode" ng-model="ctrl.busInfoForSave.insideCode" | |
| 48 | + required ng-maxlength="8" placeholder="请输入车辆内部编码"/> | |
| 49 | + </div> | |
| 50 | + <!-- 隐藏块,显示验证信息 --> | |
| 51 | + <div class="alert alert-danger well-sm" ng-show="myForm.insideCode.$error.required"> | |
| 52 | + 内部编号必须填写 | |
| 53 | + </div> | |
| 54 | + <div class="alert alert-danger well-sm" ng-show="myForm.insideCode.$error.maxlength"> | |
| 55 | + 内部编号长度不能超过8位 | |
| 34 | 56 | </div> |
| 35 | 57 | </div> |
| 36 | - <div class="form-group"> | |
| 37 | - <label class="col-md-2 control-label">所属公司:</label> | |
| 38 | - <div class="col-md-10"> | |
| 39 | - <input type="text" class="form-control"/> | |
| 58 | + | |
| 59 | + <div class="form-group has-success has-feedback"> | |
| 60 | + <label class="col-md-2 control-label">所属公司*:</label> | |
| 61 | + <div class="col-md-3"> | |
| 62 | + <div class="input-group"> | |
| 63 | + <ui-select ng-model="ctrl.busInfoForSave.gs_selected" | |
| 64 | + on-select="ctrl.gs_selected_change($item, $model)" | |
| 65 | + theme="bootstrap" name="gs" required> | |
| 66 | + <ui-select-match placeholder="请选择所属公司...">{{$select.selected.gsmc}}</ui-select-match> | |
| 67 | + <ui-select-choices repeat="item in ctrl.gses"> | |
| 68 | + <span ng-bind="item.gsmc"></span> | |
| 69 | + </ui-select-choices> | |
| 70 | + </ui-select> | |
| 71 | + <span class="input-group-btn"> | |
| 72 | + <button type="button" ng-click="ctrl.gs_selected_remove()" class="btn btn-default"> | |
| 73 | + <span class="glyphicon glyphicon-trash"></span> | |
| 74 | + </button> | |
| 75 | + </span> | |
| 76 | + </div> | |
| 77 | + </div> | |
| 78 | + <!-- 隐藏块,显示验证信息 --> | |
| 79 | + <div class="alert alert-danger well-sm" ng-show="myForm.gs.$error.required"> | |
| 80 | + 内部编号必须填写 | |
| 40 | 81 | </div> |
| 41 | 82 | </div> |
| 83 | + | |
| 84 | + <!-- TODO --> | |
| 42 | 85 | <div class="form-group"> |
| 43 | 86 | <label class="col-md-2 control-label">分公司:</label> |
| 44 | - <div class="col-md-10"> | |
| 45 | - <input type="text" class="form-control"/> | |
| 87 | + <div class="col-md-3"> | |
| 88 | + <select name="brancheCompanyCode" class="form-control"> | |
| 89 | + <option value="">请选择...</option> | |
| 90 | + <option value="1">分公司1</option> | |
| 91 | + <option value="2">分公司1</option> | |
| 92 | + <option value="3">分公司1</option> | |
| 93 | + <option value="4">分公司1</option> | |
| 94 | + </select> | |
| 46 | 95 | </div> |
| 47 | 96 | </div> |
| 48 | - <div class="form-group"> | |
| 49 | - <label class="col-md-2 control-label">车辆编码:</label> | |
| 50 | - <div class="col-md-10"> | |
| 51 | - <input type="text" class="form-control"/> | |
| 97 | + | |
| 98 | + <div class="form-group has-success has-feedback"> | |
| 99 | + <label class="col-md-2 control-label">车辆编码*:</label> | |
| 100 | + <div class="col-md-3"> | |
| 101 | + <input type="text" class="form-control" | |
| 102 | + name="carCode" ng-model="ctrl.busInfoForSave.carCode" | |
| 103 | + required placeholder="请输入车辆编码"/> | |
| 104 | + </div> | |
| 105 | + <!-- 隐藏块,显示验证信息 --> | |
| 106 | + <div class="alert alert-danger well-sm" ng-show="myForm.carCode.$error.required"> | |
| 107 | + 车辆编码必须填写 | |
| 52 | 108 | </div> |
| 53 | 109 | </div> |
| 54 | - <div class="form-group"> | |
| 55 | - <label class="col-md-2 control-label">车牌号:</label> | |
| 56 | - <div class="col-md-10"> | |
| 57 | - <input type="text" class="form-control"/> | |
| 110 | + | |
| 111 | + <div class="form-group has-success has-feedback"> | |
| 112 | + <label class="col-md-2 control-label">车牌号*:</label> | |
| 113 | + <div class="col-md-3"> | |
| 114 | + <input type="text" class="form-control" | |
| 115 | + name="carPlate" ng-model="ctrl.busInfoForSave.carPlate" | |
| 116 | + required placeholder="请输入车牌号"/> | |
| 117 | + </div> | |
| 118 | + <!-- 隐藏快,显示验证信息 --> | |
| 119 | + <div class="alert alert-danger well-sm" ng-show="myForm.carPlate.$error.required"> | |
| 120 | + 车牌号必须填写 | |
| 58 | 121 | </div> |
| 59 | 122 | </div> |
| 60 | - <div class="form-group"> | |
| 61 | - <label class="col-md-2 control-label">设备供应厂商:</label> | |
| 62 | - <div class="col-md-10"> | |
| 63 | - <input type="text" class="form-control"/> | |
| 123 | + | |
| 124 | + <div class="form-group has-success has-feedback"> | |
| 125 | + <label class="col-md-2 control-label">设备供应厂商*:</label> | |
| 126 | + <div class="col-md-3"> | |
| 127 | + <div class="input-group"> | |
| 128 | + <ui-select ng-model="ctrl.busInfoForSave.supplierName_Selected" | |
| 129 | + theme="bootstrap" name="supplierName" required> | |
| 130 | + <ui-select-match placeholder="请选择设备厂商...">{{$select.selected.name}}</ui-select-match> | |
| 131 | + <ui-select-choices repeat="item in ctrl.supplierNames"> | |
| 132 | + <span ng-bind="item.name"></span> | |
| 133 | + </ui-select-choices> | |
| 134 | + </ui-select> | |
| 135 | + <span class="input-group-btn"> | |
| 136 | + <button type="button" ng-click="ctrl.busInfoForSave.supplierName_Selected = null" class="btn btn-default"> | |
| 137 | + <span class="glyphicon glyphicon-trash"></span> | |
| 138 | + </button> | |
| 139 | + </span> | |
| 140 | + </div> | |
| 141 | + </div> | |
| 142 | + <!-- 隐藏快,显示验证信息 --> | |
| 143 | + <div class="alert alert-danger well-sm" ng-show="myForm.supplierName.$error.required"> | |
| 144 | + 设备供应厂商必须选择 | |
| 64 | 145 | </div> |
| 65 | 146 | </div> |
| 66 | - <div class="form-group"> | |
| 67 | - <label class="col-md-2 control-label">终端号:</label> | |
| 68 | - <div class="col-md-10"> | |
| 69 | - <input type="text" class="form-control"/> | |
| 147 | + | |
| 148 | + <div class="form-group has-success has-feedback"> | |
| 149 | + <label class="col-md-2 control-label">终端号*:</label> | |
| 150 | + <div class="col-md-3"> | |
| 151 | + <input type="text" class="form-control" | |
| 152 | + name="equipmentCode" ng-model="ctrl.busInfoForSave.equipmentCode" | |
| 153 | + required placeholder="请输入设备终端号"/> | |
| 154 | + </div> | |
| 155 | + <!-- 隐藏块,显示验证信息 --> | |
| 156 | + <div class="alert alert-danger well-sm" ng-show="myForm.equipmentCode.$error.required"> | |
| 157 | + 设备终端号必须填写 | |
| 70 | 158 | </div> |
| 71 | 159 | </div> |
| 72 | 160 | |
| 73 | 161 | <div class="form-group"> |
| 74 | 162 | <label class="col-md-2 control-label">车型类别:</label> |
| 75 | - <div class="col-md-10"> | |
| 76 | - <input type="text" class="form-control"/> | |
| 163 | + <div class="col-md-4"> | |
| 164 | + <input type="text" class="form-control" ng-model="ctrl.busInfoForSave.carClass" | |
| 165 | + placeholder="请输入车型类别"/> | |
| 77 | 166 | </div> |
| 78 | 167 | </div> |
| 79 | 168 | <div class="form-group"> |
| 80 | 169 | <label class="col-md-2 control-label">技术速度:</label> |
| 81 | - <div class="col-md-10"> | |
| 82 | - <input type="text" class="form-control"/> | |
| 170 | + <div class="col-md-4"> | |
| 171 | + <input type="text" class="form-control" ng-model="ctrl.busInfoForSave.speed" | |
| 172 | + placeholder="请输入技术速度"/> | |
| 83 | 173 | </div> |
| 84 | 174 | </div> |
| 85 | 175 | <div class="form-group"> |
| 86 | 176 | <label class="col-md-2 control-label">座位数:</label> |
| 87 | - <div class="col-md-10"> | |
| 88 | - <input type="text" class="form-control"/> | |
| 177 | + <div class="col-md-4"> | |
| 178 | + <input type="text" class="form-control" ng-model="ctrl.busInfoForSave.carSeatnNumber" | |
| 179 | + placeholder="请输入座位数"/> | |
| 89 | 180 | </div> |
| 90 | 181 | </div> |
| 91 | 182 | <div class="form-group"> |
| 92 | 183 | <label class="col-md-2 control-label">载客标准:</label> |
| 93 | - <div class="col-md-10"> | |
| 94 | - <input type="text" class="form-control"/> | |
| 184 | + <div class="col-md-4"> | |
| 185 | + <input type="text" class="form-control" ng-model="ctrl.busInfoForSave.carStandard" | |
| 186 | + placeholder="请输入载客标准"/> | |
| 95 | 187 | </div> |
| 96 | 188 | </div> |
| 97 | 189 | <div class="form-group"> |
| 98 | 190 | <label class="col-md-2 control-label">标准油耗/开空调:</label> |
| 99 | - <div class="col-md-10"> | |
| 100 | - <input type="text" class="form-control"/> | |
| 191 | + <div class="col-md-4"> | |
| 192 | + <input type="text" class="form-control" ng-model="ctrl.busInfoForSave.kburnStandard" | |
| 193 | + placeholder="请输入标准油耗/开空调"/> | |
| 101 | 194 | </div> |
| 102 | 195 | </div> |
| 103 | 196 | <div class="form-group"> |
| 104 | 197 | <label class="col-md-2 control-label">标准油耗/关空调:</label> |
| 105 | - <div class="col-md-10"> | |
| 106 | - <input type="text" class="form-control"/> | |
| 198 | + <div class="col-md-4"> | |
| 199 | + <input type="text" class="form-control" ng-model="ctrl.busInfoForSave.gburnStandard" | |
| 200 | + placeholder="请输入标准油耗/关空调"/> | |
| 107 | 201 | </div> |
| 108 | 202 | </div> |
| 109 | 203 | <div class="form-group"> |
| 110 | 204 | <label class="col-md-2 control-label">报废号:</label> |
| 111 | - <div class="col-md-10"> | |
| 112 | - <input type="text" class="form-control"/> | |
| 205 | + <div class="col-md-4"> | |
| 206 | + <input type="text" class="form-control" ng-model="ctrl.busInfoForSave.scrapCode" | |
| 207 | + placeholder="请输入报废号"/> | |
| 113 | 208 | </div> |
| 114 | 209 | </div> |
| 210 | + | |
| 115 | 211 | <div class="form-group"> |
| 116 | 212 | <label class="col-md-2 control-label">报废日期:</label> |
| 117 | - <div class="col-md-10"> | |
| 118 | - <input type="text" class="form-control"/> | |
| 213 | + <div class="col-md-4"> | |
| 214 | + <div class="input-group"> | |
| 215 | + <input type="text" class="form-control" | |
| 216 | + name="scrapDate" placeholder="请选择报废日期..." | |
| 217 | + uib-datepicker-popup="yyyy年MM月dd日" | |
| 218 | + is-open="ctrl.scrapDateOpen" | |
| 219 | + ng-model="ctrl.busInfoForSave.scrapDate"/> | |
| 220 | + <span class="input-group-btn"> | |
| 221 | + <button type="button" class="btn btn-default" ng-click="ctrl.scrapDate_open()"> | |
| 222 | + <i class="glyphicon glyphicon-calendar"></i> | |
| 223 | + </button> | |
| 224 | + </span> | |
| 225 | + </div> | |
| 119 | 226 | </div> |
| 120 | 227 | </div> |
| 121 | 228 | <div class="form-group"> |
| 122 | 229 | <label class="col-md-2 control-label">厂牌型号1:</label> |
| 123 | - <div class="col-md-10"> | |
| 124 | - <input type="text" class="form-control"/> | |
| 230 | + <div class="col-md-4"> | |
| 231 | + <input type="text" class="form-control" ng-model="ctrl.busInfoForSave.makeCodeOne" | |
| 232 | + placeholder="请输入厂牌型号1"/> | |
| 125 | 233 | </div> |
| 126 | 234 | </div> |
| 127 | 235 | <div class="form-group"> |
| 128 | 236 | <label class="col-md-2 control-label">厂牌型号2:</label> |
| 129 | - <div class="col-md-10"> | |
| 130 | - <input type="text" class="form-control"/> | |
| 237 | + <div class="col-md-4"> | |
| 238 | + <input type="text" class="form-control" ng-model="ctrl.busInfoForSave.makeCodeTwo" | |
| 239 | + placeholder="请输入厂牌型号2"/> | |
| 131 | 240 | </div> |
| 132 | 241 | </div> |
| 133 | 242 | <div class="form-group"> |
| 134 | 243 | <label class="col-md-2 control-label">车辆等级标准:</label> |
| 135 | - <div class="col-md-10"> | |
| 136 | - <input type="text" class="form-control"/> | |
| 244 | + <div class="col-md-4"> | |
| 245 | + <input type="text" class="form-control" ng-model="ctrl.busInfoForSave.carGride" | |
| 246 | + placeholder="请输入车辆等级标准"/> | |
| 137 | 247 | </div> |
| 138 | 248 | </div> |
| 139 | 249 | <div class="form-group"> |
| 140 | 250 | <label class="col-md-2 control-label">出厂排放标准:</label> |
| 141 | - <div class="col-md-10"> | |
| 142 | - <input type="text" class="form-control"/> | |
| 251 | + <div class="col-md-4"> | |
| 252 | + <input type="text" class="form-control" ng-model="ctrl.busInfoForSave.emissionsStandard" | |
| 253 | + placeholder="请输入出场排放标准"/> | |
| 143 | 254 | </div> |
| 144 | 255 | </div> |
| 145 | 256 | <div class="form-group"> |
| 146 | 257 | <label class="col-md-2 control-label">发动机号码1:</label> |
| 147 | - <div class="col-md-10"> | |
| 148 | - <input type="text" class="form-control"/> | |
| 258 | + <div class="col-md-4"> | |
| 259 | + <input type="text" class="form-control" ng-model="ctrl.busInfoForSave.engineCodeOne" | |
| 260 | + placeholder="请输入发动机号码1"/> | |
| 149 | 261 | </div> |
| 150 | 262 | </div> |
| 151 | 263 | <div class="form-group"> |
| 152 | 264 | <label class="col-md-2 control-label">发动机号码2:</label> |
| 153 | - <div class="col-md-10"> | |
| 154 | - <input type="text" class="form-control"/> | |
| 265 | + <div class="col-md-4"> | |
| 266 | + <input type="text" class="form-control" ng-model="ctrl.busInfoForSave.engineCodeTwo" | |
| 267 | + placeholder="请输入发动机号码2"/> | |
| 155 | 268 | </div> |
| 156 | 269 | </div> |
| 157 | 270 | <div class="form-group"> |
| 158 | 271 | <label class="col-md-2 control-label">车架号码1:</label> |
| 159 | - <div class="col-md-10"> | |
| 160 | - <input type="text" class="form-control"/> | |
| 272 | + <div class="col-md-4"> | |
| 273 | + <input type="text" class="form-control" ng-model="ctrl.busInfoForSave.carNumberOne" | |
| 274 | + placeholder="请输入车架号码1"/> | |
| 161 | 275 | </div> |
| 162 | 276 | </div> |
| 163 | 277 | <div class="form-group"> |
| 164 | 278 | <label class="col-md-2 control-label">车架号码2:</label> |
| 165 | - <div class="col-md-10"> | |
| 166 | - <input type="text" class="form-control"/> | |
| 279 | + <div class="col-md-4"> | |
| 280 | + <input type="text" class="form-control" ng-model="ctrl.busInfoForSave.carNumberTwo" | |
| 281 | + placeholder="请输入车架号码2"/> | |
| 167 | 282 | </div> |
| 168 | 283 | </div> |
| 169 | 284 | <div class="form-group"> |
| 170 | 285 | <label class="col-md-2 control-label">启用日期:</label> |
| 171 | - <div class="col-md-10"> | |
| 172 | - <input type="text" class="form-control"/> | |
| 286 | + <div class="col-md-4"> | |
| 287 | + <div class="input-group"> | |
| 288 | + <input type="text" class="form-control" | |
| 289 | + name="openDate" placeholder="请选择启用日期..." | |
| 290 | + uib-datepicker-popup="yyyy年MM月dd日" | |
| 291 | + is-open="ctrl.openDateOpen" | |
| 292 | + ng-model="ctrl.busInfoForSave.openDate"/> | |
| 293 | + <span class="input-group-btn"> | |
| 294 | + <button type="button" class="btn btn-default" ng-click="ctrl.openDate_open()"> | |
| 295 | + <i class="glyphicon glyphicon-calendar"></i> | |
| 296 | + </button> | |
| 297 | + </span> | |
| 298 | + </div> | |
| 173 | 299 | </div> |
| 174 | 300 | </div> |
| 175 | 301 | <div class="form-group"> |
| 176 | 302 | <label class="col-md-2 control-label">取消日期:</label> |
| 177 | - <div class="col-md-10"> | |
| 178 | - <input type="text" class="form-control"/> | |
| 303 | + <div class="col-md-4"> | |
| 304 | + <div class="input-group"> | |
| 305 | + <input type="text" class="form-control" | |
| 306 | + name="closeDate" placeholder="请选择取消日期..." | |
| 307 | + uib-datepicker-popup="yyyy年MM月dd日" | |
| 308 | + is-open="ctrl.closeDateOpen" | |
| 309 | + ng-model="ctrl.busInfoForSave.closeDate"/> | |
| 310 | + <span class="input-group-btn"> | |
| 311 | + <button type="button" class="btn btn-default" ng-click="ctrl.closeDate_open()"> | |
| 312 | + <i class="glyphicon glyphicon-calendar"></i> | |
| 313 | + </button> | |
| 314 | + </span> | |
| 315 | + </div> | |
| 179 | 316 | </div> |
| 180 | 317 | </div> |
| 318 | + | |
| 181 | 319 | <div class="form-group"> |
| 182 | 320 | <label class="col-md-2 control-label">是否空调车:</label> |
| 183 | - <div class="col-md-10"> | |
| 184 | - <input type="text" class="form-control"/> | |
| 321 | + <div class="col-md-3"> | |
| 322 | + <label class="radio-inline"> | |
| 323 | + <input type="radio" name="hvacCar" | |
| 324 | + ng-value="true" ng-model="ctrl.busInfoForSave.hvacCar"/>是 | |
| 325 | + </label> | |
| 326 | + <label class="radio-inline"> | |
| 327 | + <input type="radio" name="hvacCar" | |
| 328 | + ng-value="false" ng-model="ctrl.busInfoForSave.hvacCar"/>否 | |
| 329 | + </label> | |
| 185 | 330 | </div> |
| 186 | 331 | </div> |
| 332 | + | |
| 187 | 333 | <div class="form-group"> |
| 188 | 334 | <label class="col-md-2 control-label">有无人售票:</label> |
| 189 | - <div class="col-md-10"> | |
| 190 | - <input type="text" class="form-control"/> | |
| 335 | + <div class="col-md-3"> | |
| 336 | + <label class="radio-inline"> | |
| 337 | + <input type="radio" name="ticketType" | |
| 338 | + ng-value="true" ng-model="ctrl.busInfoForSave.ticketType"/>是 | |
| 339 | + </label> | |
| 340 | + <label class="radio-inline"> | |
| 341 | + <input type="radio" name="ticketType" | |
| 342 | + ng-value="false" ng-model="ctrl.busInfoForSave.ticketType"/>否 | |
| 343 | + </label> | |
| 191 | 344 | </div> |
| 192 | 345 | </div> |
| 346 | + | |
| 193 | 347 | <div class="form-group"> |
| 194 | 348 | <label class="col-md-2 control-label">是否有LED服务屏:</label> |
| 195 | - <div class="col-md-10"> | |
| 196 | - <input type="text" class="form-control"/> | |
| 349 | + <div class="col-md-3"> | |
| 350 | + <label class="radio-inline"> | |
| 351 | + <input type="radio" name="ledScreen" | |
| 352 | + ng-value="true" ng-model="ctrl.busInfoForSave.ledScreen"/>是 | |
| 353 | + </label> | |
| 354 | + <label class="radio-inline"> | |
| 355 | + <input type="radio" name="ledScreen" | |
| 356 | + ng-value="false" ng-model="ctrl.busInfoForSave.ledScreen"/>否 | |
| 357 | + </label> | |
| 197 | 358 | </div> |
| 198 | 359 | </div> |
| 360 | + | |
| 199 | 361 | <div class="form-group"> |
| 200 | 362 | <label class="col-md-2 control-label">是否有TV视屏:</label> |
| 201 | - <div class="col-md-10"> | |
| 202 | - <input type="text" class="form-control"/> | |
| 363 | + <div class="col-md-3"> | |
| 364 | + <label class="radio-inline"> | |
| 365 | + <input type="radio" name="tvVideoType" | |
| 366 | + ng-value="true" ng-model="ctrl.busInfoForSave.tvVideoType"/>是 | |
| 367 | + </label> | |
| 368 | + <label class="radio-inline"> | |
| 369 | + <input type="radio" name="tvVideoType" | |
| 370 | + ng-value="false" ng-model="ctrl.busInfoForSave.tvVideoType"/>否 | |
| 371 | + </label> | |
| 203 | 372 | </div> |
| 204 | 373 | </div> |
| 374 | + | |
| 205 | 375 | <div class="form-group"> |
| 206 | 376 | <label class="col-md-2 control-label">车辆类型:</label> |
| 207 | - <div class="col-md-10"> | |
| 208 | - <input type="text" class="form-control"/> | |
| 377 | + <div class="col-md-3"> | |
| 378 | + <div class="input-group"> | |
| 379 | + <ui-select ng-model="ctrl.busInfoForSave.carType_Selected" theme="bootstrap"> | |
| 380 | + <ui-select-match placeholder="请选择车辆类型...">{{$select.selected.type}}</ui-select-match> | |
| 381 | + <ui-select-choices repeat="item in ctrl.carTypes"> | |
| 382 | + <span ng-bind="item.type"></span> | |
| 383 | + </ui-select-choices> | |
| 384 | + </ui-select> | |
| 385 | + <span class="input-group-btn"> | |
| 386 | + <button type="button" ng-click="ctrl.busInfoForSave.carType_Selected = null" class="btn btn-default"> | |
| 387 | + <span class="glyphicon glyphicon-trash"></span> | |
| 388 | + </button> | |
| 389 | + </span> | |
| 390 | + </div> | |
| 209 | 391 | </div> |
| 210 | 392 | </div> |
| 393 | + | |
| 211 | 394 | <div class="form-group"> |
| 212 | 395 | <label class="col-md-2 control-label">是否机动车:</label> |
| 213 | - <div class="col-md-10"> | |
| 214 | - <input type="text" class="form-control"/> | |
| 396 | + <div class="col-md-3"> | |
| 397 | + <div class="input-group"> | |
| 398 | + <ui-select ng-model="ctrl.busInfoForSave.vehicleStats_Selected" theme="bootstrap"> | |
| 399 | + <ui-select-match placeholder="请选择机动车类型...">{{$select.selected.type}}</ui-select-match> | |
| 400 | + <ui-select-choices repeat="item in ctrl.vehicleStates"> | |
| 401 | + <span ng-bind="item.type"></span> | |
| 402 | + </ui-select-choices> | |
| 403 | + </ui-select> | |
| 404 | + <span class="input-group-btn"> | |
| 405 | + <button type="button" ng-click="ctrl.busInfoForSave.vehicleStats_Selected = null" class="btn btn-default"> | |
| 406 | + <span class="glyphicon glyphicon-trash"></span> | |
| 407 | + </button> | |
| 408 | + </span> | |
| 409 | + </div> | |
| 215 | 410 | </div> |
| 216 | 411 | </div> |
| 412 | + | |
| 217 | 413 | <div class="form-group"> |
| 218 | 414 | <label class="col-md-2 control-label">营运状态:</label> |
| 219 | - <div class="col-md-10"> | |
| 220 | - <input type="text" class="form-control"/> | |
| 221 | - </div> | |
| 222 | - </div> | |
| 223 | - <div class="form-group"> | |
| 224 | - <label class="col-md-2 control-label">修改日期:</label> | |
| 225 | - <div class="col-md-10"> | |
| 226 | - <input type="text" class="form-control"/> | |
| 415 | + <div class="col-md-3"> | |
| 416 | + <div class="input-group"> | |
| 417 | + <ui-select ng-model="ctrl.busInfoForSave.operatorsState_Selected" theme="bootstrap"> | |
| 418 | + <ui-select-match placeholder="请选择营运状态...">{{$select.selected.type}}</ui-select-match> | |
| 419 | + <ui-select-choices repeat="item in ctrl.operatorsStates"> | |
| 420 | + <span ng-bind="item.type"></span> | |
| 421 | + </ui-select-choices> | |
| 422 | + </ui-select> | |
| 423 | + <span class="input-group-btn"> | |
| 424 | + <button type="button" ng-click="ctrl.busInfoForSave.operatorsState_Selected = null" class="btn btn-default"> | |
| 425 | + <span class="glyphicon glyphicon-trash"></span> | |
| 426 | + </button> | |
| 427 | + </span> | |
| 428 | + </div> | |
| 227 | 429 | </div> |
| 228 | 430 | </div> |
| 431 | + | |
| 229 | 432 | <div class="form-group"> |
| 230 | 433 | <label class="col-md-2 control-label">是否电车:</label> |
| 231 | - <div class="col-md-10"> | |
| 232 | - <input type="text" class="form-control"/> | |
| 434 | + <div class="col-md-3"> | |
| 435 | + <label class="radio-inline"> | |
| 436 | + <input type="radio" name="sfdc" | |
| 437 | + ng-value="true" ng-model="ctrl.busInfoForSave.sfdc"/>是 | |
| 438 | + </label> | |
| 439 | + <label class="radio-inline"> | |
| 440 | + <input type="radio" name="sfdc" | |
| 441 | + ng-value="false" ng-model="ctrl.busInfoForSave.sfdc"/>否 | |
| 442 | + </label> | |
| 233 | 443 | </div> |
| 234 | 444 | </div> |
| 445 | + | |
| 235 | 446 | <div class="form-group"> |
| 236 | 447 | <label class="col-md-2 control-label">备注:</label> |
| 237 | 448 | <div class="col-md-10"> |
| 238 | - <textarea rows="3" class="form-control"></textarea> | |
| 449 | + <textarea rows="3" class="form-control" name="descriptions" | |
| 450 | + ng-model="ctrl.busInfoForSave.descriptions"></textarea> | |
| 239 | 451 | </div> |
| 240 | 452 | </div> |
| 241 | 453 | |
| ... | ... | @@ -247,7 +459,7 @@ |
| 247 | 459 | <div class="form-actions"> |
| 248 | 460 | <div class="row"> |
| 249 | 461 | <div class="col-md-offset-3 col-md-4"> |
| 250 | - <button type="submit" class="btn green" ><i class="fa fa-check"></i> 提交</button> | |
| 462 | + <button type="submit" class="btn green" ng-disabled="!myForm.$valid"><i class="fa fa-check"></i> 提交</button> | |
| 251 | 463 | <a type="button" class="btn default" ui-sref="busInfoManage" ><i class="fa fa-times"></i> 取消</a> |
| 252 | 464 | </div> |
| 253 | 465 | </div> |
| ... | ... | @@ -258,20 +470,4 @@ |
| 258 | 470 | </div> |
| 259 | 471 | |
| 260 | 472 | |
| 261 | - | |
| 262 | - | |
| 263 | - | |
| 264 | - | |
| 265 | - | |
| 266 | - | |
| 267 | - | |
| 268 | - | |
| 269 | - | |
| 270 | - | |
| 271 | - | |
| 272 | - | |
| 273 | - | |
| 274 | - | |
| 275 | - | |
| 276 | - | |
| 277 | 473 | </div> |
| 278 | 474 | \ No newline at end of file | ... | ... |
src/main/resources/static/pages/scheduleApp/module/basicInfo/busInfoManage/index.html
| ... | ... | @@ -27,7 +27,7 @@ |
| 27 | 27 | <span class="caption-subject bold uppercase">车辆信息表</span> |
| 28 | 28 | </div> |
| 29 | 29 | <div class="actions"> |
| 30 | - <a href="javascirpt:" class="btn btn-circle blue" ng-click="ctrl.testgo()"> | |
| 30 | + <a href="javascirpt:" class="btn btn-circle blue" ng-click="ctrl.goForm()"> | |
| 31 | 31 | <i class="fa fa-plus"></i> |
| 32 | 32 | 添加车辆信息 |
| 33 | 33 | </a> |
| ... | ... | @@ -58,7 +58,7 @@ |
| 58 | 58 | </div> |
| 59 | 59 | |
| 60 | 60 | <div class="portlet-body"> |
| 61 | - <div ui-view="list"></div> | |
| 61 | + <div ui-view="busInfoManage_list"></div> | |
| 62 | 62 | </div> |
| 63 | 63 | </div> |
| 64 | 64 | </div> | ... | ... |
src/main/resources/static/pages/scheduleApp/module/basicInfo/busInfoManage/list.html
| ... | ... | @@ -2,11 +2,11 @@ |
| 2 | 2 | <div ng-controller="BusInfoManageListCtrl as ctrl"> |
| 3 | 3 | <table class="table table-striped table-bordered table-hover table-checkable order-column"> |
| 4 | 4 | <thead> |
| 5 | - <tr> | |
| 5 | + <tr role="row" class="heading"> | |
| 6 | 6 | <th> |
| 7 | 7 | <input type="checkbox" class="group-checkable"/> |
| 8 | 8 | </th> |
| 9 | - <th>序号</th> | |
| 9 | + <th width="50">序号</th> | |
| 10 | 10 | <th>车辆编号</th> |
| 11 | 11 | <th>内部编号</th> |
| 12 | 12 | <th>设备编号</th> |
| ... | ... | @@ -14,16 +14,63 @@ |
| 14 | 14 | <th>所在公司</th> |
| 15 | 15 | <th>所在分公司</th> |
| 16 | 16 | <th>是否电车</th> |
| 17 | - <th>操作</th> | |
| 17 | + <th width="14%">操作</th> | |
| 18 | + </tr> | |
| 19 | + <tr role="row" class="filter"> | |
| 20 | + <td></td> | |
| 21 | + <td></td> | |
| 22 | + <td> | |
| 23 | + <input type="text" class="form-control form-filter input-sm" ng-model="ctrl.searchCondition().carCode_like"/> | |
| 24 | + </td> | |
| 25 | + <td> | |
| 26 | + <input type="text" class="form-control form-filter input-sm" ng-model="ctrl.searchCondition().insideCode_like"/> | |
| 27 | + </td> | |
| 28 | + <td> | |
| 29 | + <input type="text" class="form-control form-filter input-sm" ng-model="ctrl.searchCondition().equipmentCode_like"/> | |
| 30 | + </td> | |
| 31 | + <td> | |
| 32 | + <input type="text" class="form-control form-filter input-sm" ng-model="ctrl.searchCondition().carPlate_like"/> | |
| 33 | + </td> | |
| 34 | + <td> | |
| 35 | + <select class="form-control form-filter " > | |
| 36 | + <option value="">请选择...</option> | |
| 37 | + <option value="55">上南公司</option> | |
| 38 | + <option value="22">金高公司</option> | |
| 39 | + <option value="05">杨高公司</option> | |
| 40 | + <option value="26">南汇公司</option> | |
| 41 | + </select> | |
| 42 | + </td> | |
| 43 | + <td> | |
| 44 | + <select class="form-control form-filter " > | |
| 45 | + <option value="">请选择...</option> | |
| 46 | + </select> | |
| 47 | + </td> | |
| 48 | + <td> | |
| 49 | + <select class="form-control form-filter " > | |
| 50 | + <option value="">请选择...</option> | |
| 51 | + <option value="1">是</option> | |
| 52 | + <option value="0">否</option> | |
| 53 | + </select> | |
| 54 | + </td> | |
| 55 | + <td> | |
| 56 | + <button class="btn btn-sm green btn-outline filter-submit margin-bottom" | |
| 57 | + ng-click="ctrl.pageChanaged()"> | |
| 58 | + <i class="fa fa-search"></i> 搜索</button> | |
| 59 | + | |
| 60 | + <button class="btn btn-sm red btn-outline filter-cancel" | |
| 61 | + ng-click="ctrl.resetSearchCondition()"> | |
| 62 | + <i class="fa fa-times"></i> 重置</button> | |
| 63 | + </td> | |
| 64 | + | |
| 18 | 65 | </tr> |
| 19 | 66 | </thead> |
| 20 | 67 | <tbody> |
| 21 | - <tr ng-repeat="info in ctrl.infos" class="odd gradeX"> | |
| 68 | + <tr ng-repeat="info in ctrl.pageInfo.infos" class="odd gradeX"> | |
| 22 | 69 | <td> |
| 23 | 70 | <input type="checkbox"/> |
| 24 | 71 | </td> |
| 25 | 72 | <td> |
| 26 | - <span>todo</span> | |
| 73 | + <span ng-bind="$index + 1"></span> | |
| 27 | 74 | </td> |
| 28 | 75 | <td> |
| 29 | 76 | <span ng-bind="info.carCode"></span> |
| ... | ... | @@ -44,10 +91,13 @@ |
| 44 | 91 | <span ng-bind="info.brancheCompany"></span> |
| 45 | 92 | </td> |
| 46 | 93 | <td> |
| 47 | - <span>todo</span> | |
| 94 | + <span ng-bind="info.sfdc"></span> | |
| 48 | 95 | </td> |
| 49 | 96 | <td> |
| 50 | - <span>todo</span> | |
| 97 | + <!--<a href="details.html?lineId={{obj.id}}" class="btn default blue-stripe btn-sm"> 详细 </a>--> | |
| 98 | + <!--<a href="edit.html?lineId={{obj.id}}" class="btn default blue-stripe btn-sm"> 修改 </a>--> | |
| 99 | + <a ui-sref="busInfoManage_detail({id: info.id})" class="btn default blue-stripe btn-sm"> 详细 </a> | |
| 100 | + <a href="#" class="btn default blue-stripe btn-sm"> 修改 </a> | |
| 51 | 101 | </td> |
| 52 | 102 | </tr> |
| 53 | 103 | </tbody> |
| ... | ... | @@ -55,11 +105,16 @@ |
| 55 | 105 | </table> |
| 56 | 106 | |
| 57 | 107 | <div style="text-align: right;"> |
| 58 | - <uib-pagination total-items="ctrl.pi.totalItems" | |
| 59 | - ng-model="ctrl.pi.currentPage" | |
| 60 | - ng-change="ctrl.pageChanged()" | |
| 108 | + <uib-pagination total-items="ctrl.pageInfo.totalItems" | |
| 109 | + ng-model="ctrl.pageInfo.currentPage" | |
| 110 | + ng-change="ctrl.pageChanaged()" | |
| 111 | + rotate="false" | |
| 112 | + max-size="10" | |
| 113 | + boundary-links="true" | |
| 114 | + first-text="首页" | |
| 61 | 115 | previous-text="上一页" |
| 62 | - next-text="下一页"> | |
| 116 | + next-text="下一页" | |
| 117 | + last-text="尾页"> | |
| 63 | 118 | </uib-pagination> |
| 64 | 119 | </div> |
| 65 | 120 | </div> | ... | ... |
src/main/resources/static/pages/scheduleApp/module/main.css
0 → 100644
| 1 | +form input.ng-invalid.ng-dirty.ng-invalid-required { | |
| 2 | + background-color: #FFC0CB; | |
| 3 | +} | |
| 4 | +form input.ng-valid.ng-dirty.ng-valid-required { | |
| 5 | + background-color: #78FA89; | |
| 6 | +} | |
| 7 | + | |
| 8 | +/*.ng-invalid.ng-dirty {*/ | |
| 9 | + /*background-color: #FFC0CB;*/ | |
| 10 | +/*}*/ | |
| 11 | +/*.ng-valid.ng-dirty {*/ | |
| 12 | + /*background-color: #78FA89;*/ | |
| 13 | +/*}*/ | |
| 14 | + | |
| 15 | +.ui-select-container.ng-invalid.ng-dirty.ng-invalid-required .form-control { | |
| 16 | + background-color: #FFC0CB; | |
| 17 | +} | |
| 18 | +.ui-select-container.ng-valid.ng-dirty.ng-valid-required .form-control { | |
| 19 | + background-color: #78FA89; | |
| 20 | +} | |
| 0 | 21 | \ No newline at end of file | ... | ... |
src/main/resources/static/pages/scheduleApp/module/main.js
| ... | ... | @@ -51,7 +51,7 @@ ScheduleApp.config(['$stateProvider', '$urlRouterProvider', function($stateProvi |
| 51 | 51 | "": { |
| 52 | 52 | templateUrl: 'pages/scheduleApp/module/basicInfo/busInfoManage/index.html' |
| 53 | 53 | }, |
| 54 | - "list@busInfoManage": { | |
| 54 | + "busInfoManage_list@busInfoManage": { | |
| 55 | 55 | templateUrl: 'pages/scheduleApp/module/basicInfo/busInfoManage/list.html' |
| 56 | 56 | } |
| 57 | 57 | }, |
| ... | ... | @@ -68,23 +68,8 @@ ScheduleApp.config(['$stateProvider', '$urlRouterProvider', function($stateProvi |
| 68 | 68 | }] |
| 69 | 69 | } |
| 70 | 70 | }) |
| 71 | - .state("busInfoManage.list", { | |
| 72 | - url: 'list', | |
| 73 | - templateUrl: 'pages/scheduleApp/module/basicInfo/busInfoManage/list.html', | |
| 74 | - resolve: { | |
| 75 | - deps: ['$ocLazyLoad', function($ocLazyLoad) { | |
| 76 | - return $ocLazyLoad.load({ | |
| 77 | - name: 'busInfoManage_list_module', | |
| 78 | - insertBefore: '#ng_load_plugins_before', // 动态载入模块时放置的位置 | |
| 79 | - files: [ | |
| 80 | - "pages/scheduleApp/module/basicInfo/busInfoManage/busInfoManage.js" | |
| 81 | - ] | |
| 82 | - }); | |
| 83 | - }] | |
| 84 | - } | |
| 85 | - }) | |
| 86 | - .state("form", { | |
| 87 | - url: '/form', | |
| 71 | + .state("busInfoManage_form", { | |
| 72 | + url: '/busInfoManage_form', | |
| 88 | 73 | views: { |
| 89 | 74 | "": {templateUrl: 'pages/scheduleApp/module/basicInfo/busInfoManage/form.html'} |
| 90 | 75 | }, |
| ... | ... | @@ -94,14 +79,16 @@ ScheduleApp.config(['$stateProvider', '$urlRouterProvider', function($stateProvi |
| 94 | 79 | name: 'busInfoManage_form_module', |
| 95 | 80 | insertBefore: '#ng_load_plugins_before', // 动态载入模块时放置的位置 |
| 96 | 81 | files: [ |
| 82 | + "assets/bower_components/angular-ui-select/dist/select.min.css", | |
| 83 | + "assets/bower_components/angular-ui-select/dist/select.min.js", | |
| 97 | 84 | "pages/scheduleApp/module/basicInfo/busInfoManage/busInfoManage.js" |
| 98 | 85 | ] |
| 99 | 86 | }); |
| 100 | 87 | }] |
| 101 | 88 | } |
| 102 | 89 | }) |
| 103 | - .state("busInfoManage.detail", { | |
| 104 | - url: 'detail', | |
| 90 | + .state("busInfoManage_detail", { | |
| 91 | + url: '/busInfoManage_detail/:id', | |
| 105 | 92 | views: { |
| 106 | 93 | "": {templateUrl: 'pages/scheduleApp/module/basicInfo/busInfoManage/detail.html'} |
| 107 | 94 | }, |
| ... | ... | @@ -243,6 +230,27 @@ ScheduleApp.config(['$stateProvider', '$urlRouterProvider', function($stateProvi |
| 243 | 230 | }) |
| 244 | 231 | }]); |
| 245 | 232 | |
| 233 | +// 全局service放置在此处, | |
| 234 | +// 一般这种服务会被其他模块调用的,所以干脆放到main.js里 | |
| 235 | + | |
| 236 | +// 车辆信息service | |
| 237 | +angular.module('ScheduleApp').factory('BusInfoManageService_g', ['$resource', function($resource) { | |
| 238 | + return $resource( | |
| 239 | + '/cars/:id', | |
| 240 | + {order: 'carCode', direction: 'ASC', id: '@id'}, | |
| 241 | + { | |
| 242 | + list: { | |
| 243 | + method: 'GET', | |
| 244 | + params: { | |
| 245 | + page: 0 | |
| 246 | + } | |
| 247 | + }, | |
| 248 | + get: { | |
| 249 | + method: 'GET' | |
| 250 | + } | |
| 251 | + } | |
| 252 | + ); | |
| 253 | +}]); | |
| 246 | 254 | |
| 247 | 255 | |
| 248 | 256 | ... | ... |