Commit 40fbec4fb9bbfc06185afe1b90f6fe4074e23c5c

Authored by 徐烜
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 \ No newline at end of file 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 [![Build Status](https://travis-ci.org/angular-ui/ui-select.svg?branch=master)](https://travis-ci.org/angular-ui/ui-select)
  2 +
  3 +[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/angular-ui/ui-select?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
  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)\">&nbsp;&times;</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 \ No newline at end of file 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 \ No newline at end of file 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)">&nbsp;&times;</span> <span uis-transclude-append=""></span></span></span></span>'),e.put("bootstrap/match.tpl.html",'<div class="ui-select-match" ng-hide="$select.open" 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 \ No newline at end of file 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,6 +36,10 @@
36 36
37 <!-- table 表格控件 --> 37 <!-- table 表格控件 -->
38 <link rel="stylesheet" href="http://api.map.baidu.com/library/DrawingManager/1.4/src/DrawingManager_min.css" type="text/css" /> 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 <style type="text/css"> 43 <style type="text/css">
40 .searchForm{ 44 .searchForm{
41 45
src/main/resources/static/pages/scheduleApp/bower.json
@@ -15,6 +15,7 @@ @@ -15,6 +15,7 @@
15 "angular-bootstrap": "0.14.0", 15 "angular-bootstrap": "0.14.0",
16 "angular-route": "1.4.x", 16 "angular-route": "1.4.x",
17 "angular-ui-router": "0.2.15", 17 "angular-ui-router": "0.2.15",
  18 + "angular-ui-select": "0.13.2",
18 "angular-resource": "1.4.x" 19 "angular-resource": "1.4.x"
19 } 20 }
20 } 21 }
src/main/resources/static/pages/scheduleApp/module/basicInfo/busInfoManage/busInfoManage.js
1 // 车辆基础信息维护 service controller等写在一起 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 return { 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 angular.module('ScheduleApp').controller('BusInfoManageCtrl', ['BusInfoManageService','$state', function(busInfoManageService, $state) { 133 angular.module('ScheduleApp').controller('BusInfoManageCtrl', ['BusInfoManageService','$state', function(busInfoManageService, $state) {
34 - // TODO:测试state变换  
35 var self = this; 134 var self = this;
36 - self.testgo = function() { 135 +
  136 + // 切换到form状态
  137 + self.goForm = function() {
37 //alert("切换"); 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 var self = this; 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 self.pageChanaged = function() { 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 var self = this; 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 self.submit = function() { 247 self.submit = function() {
  248 + console.log(self.busInfoForSave);
64 alert("form submit 测试!"); 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 \ No newline at end of file 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 \ No newline at end of file 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 <div class="portlet light bordered" ng-controller="BusInfoManageFormCtrl as ctrl"> 25 <div class="portlet light bordered" ng-controller="BusInfoManageFormCtrl as ctrl">
4 <div class="portlet-title"> 26 <div class="portlet-title">
@@ -9,7 +31,7 @@ @@ -9,7 +31,7 @@
9 </div> 31 </div>
10 32
11 <div class="portlet-body form"> 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 <!--<div class="alert alert-danger display-hide">--> 35 <!--<div class="alert alert-danger display-hide">-->
14 <!--<button class="close" data-close="alert"></button>--> 36 <!--<button class="close" data-close="alert"></button>-->
15 <!--您的输入有误,请检查下面的输入项--> 37 <!--您的输入有误,请检查下面的输入项-->
@@ -18,224 +40,414 @@ @@ -18,224 +40,414 @@
18 40
19 <!-- 其他信息放置在这里 --> 41 <!-- 其他信息放置在这里 -->
20 <div class="form-body"> 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 </div> 56 </div>
35 </div> 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 </div> 81 </div>
41 </div> 82 </div>
  83 +
  84 + <!-- TODO -->
42 <div class="form-group"> 85 <div class="form-group">
43 <label class="col-md-2 control-label">分公司:</label> 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 </div> 95 </div>
47 </div> 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 </div> 108 </div>
53 </div> 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 </div> 121 </div>
59 </div> 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 </div> 145 </div>
65 </div> 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 </div> 158 </div>
71 </div> 159 </div>
72 160
73 <div class="form-group"> 161 <div class="form-group">
74 <label class="col-md-2 control-label">车型类别:</label> 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 </div> 166 </div>
78 </div> 167 </div>
79 <div class="form-group"> 168 <div class="form-group">
80 <label class="col-md-2 control-label">技术速度:</label> 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 </div> 173 </div>
84 </div> 174 </div>
85 <div class="form-group"> 175 <div class="form-group">
86 <label class="col-md-2 control-label">座位数:</label> 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 </div> 180 </div>
90 </div> 181 </div>
91 <div class="form-group"> 182 <div class="form-group">
92 <label class="col-md-2 control-label">载客标准:</label> 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 </div> 187 </div>
96 </div> 188 </div>
97 <div class="form-group"> 189 <div class="form-group">
98 <label class="col-md-2 control-label">标准油耗/开空调:</label> 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 </div> 194 </div>
102 </div> 195 </div>
103 <div class="form-group"> 196 <div class="form-group">
104 <label class="col-md-2 control-label">标准油耗/关空调:</label> 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 </div> 201 </div>
108 </div> 202 </div>
109 <div class="form-group"> 203 <div class="form-group">
110 <label class="col-md-2 control-label">报废号:</label> 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 </div> 208 </div>
114 </div> 209 </div>
  210 +
115 <div class="form-group"> 211 <div class="form-group">
116 <label class="col-md-2 control-label">报废日期:</label> 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 </div> 226 </div>
120 </div> 227 </div>
121 <div class="form-group"> 228 <div class="form-group">
122 <label class="col-md-2 control-label">厂牌型号1:</label> 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 </div> 233 </div>
126 </div> 234 </div>
127 <div class="form-group"> 235 <div class="form-group">
128 <label class="col-md-2 control-label">厂牌型号2:</label> 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 </div> 240 </div>
132 </div> 241 </div>
133 <div class="form-group"> 242 <div class="form-group">
134 <label class="col-md-2 control-label">车辆等级标准:</label> 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 </div> 247 </div>
138 </div> 248 </div>
139 <div class="form-group"> 249 <div class="form-group">
140 <label class="col-md-2 control-label">出厂排放标准:</label> 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 </div> 254 </div>
144 </div> 255 </div>
145 <div class="form-group"> 256 <div class="form-group">
146 <label class="col-md-2 control-label">发动机号码1:</label> 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 </div> 261 </div>
150 </div> 262 </div>
151 <div class="form-group"> 263 <div class="form-group">
152 <label class="col-md-2 control-label">发动机号码2:</label> 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 </div> 268 </div>
156 </div> 269 </div>
157 <div class="form-group"> 270 <div class="form-group">
158 <label class="col-md-2 control-label">车架号码1:</label> 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 </div> 275 </div>
162 </div> 276 </div>
163 <div class="form-group"> 277 <div class="form-group">
164 <label class="col-md-2 control-label">车架号码2:</label> 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 </div> 282 </div>
168 </div> 283 </div>
169 <div class="form-group"> 284 <div class="form-group">
170 <label class="col-md-2 control-label">启用日期:</label> 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 </div> 299 </div>
174 </div> 300 </div>
175 <div class="form-group"> 301 <div class="form-group">
176 <label class="col-md-2 control-label">取消日期:</label> 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 </div> 316 </div>
180 </div> 317 </div>
  318 +
181 <div class="form-group"> 319 <div class="form-group">
182 <label class="col-md-2 control-label">是否空调车:</label> 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 </div> 330 </div>
186 </div> 331 </div>
  332 +
187 <div class="form-group"> 333 <div class="form-group">
188 <label class="col-md-2 control-label">有无人售票:</label> 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 </div> 344 </div>
192 </div> 345 </div>
  346 +
193 <div class="form-group"> 347 <div class="form-group">
194 <label class="col-md-2 control-label">是否有LED服务屏:</label> 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 </div> 358 </div>
198 </div> 359 </div>
  360 +
199 <div class="form-group"> 361 <div class="form-group">
200 <label class="col-md-2 control-label">是否有TV视屏:</label> 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 </div> 372 </div>
204 </div> 373 </div>
  374 +
205 <div class="form-group"> 375 <div class="form-group">
206 <label class="col-md-2 control-label">车辆类型:</label> 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 </div> 391 </div>
210 </div> 392 </div>
  393 +
211 <div class="form-group"> 394 <div class="form-group">
212 <label class="col-md-2 control-label">是否机动车:</label> 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 </div> 410 </div>
216 </div> 411 </div>
  412 +
217 <div class="form-group"> 413 <div class="form-group">
218 <label class="col-md-2 control-label">营运状态:</label> 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 </div> 429 </div>
228 </div> 430 </div>
  431 +
229 <div class="form-group"> 432 <div class="form-group">
230 <label class="col-md-2 control-label">是否电车:</label> 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 </div> 443 </div>
234 </div> 444 </div>
  445 +
235 <div class="form-group"> 446 <div class="form-group">
236 <label class="col-md-2 control-label">备注:</label> 447 <label class="col-md-2 control-label">备注:</label>
237 <div class="col-md-10"> 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 </div> 451 </div>
240 </div> 452 </div>
241 453
@@ -247,7 +459,7 @@ @@ -247,7 +459,7 @@
247 <div class="form-actions"> 459 <div class="form-actions">
248 <div class="row"> 460 <div class="row">
249 <div class="col-md-offset-3 col-md-4"> 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 <a type="button" class="btn default" ui-sref="busInfoManage" ><i class="fa fa-times"></i> 取消</a> 463 <a type="button" class="btn default" ui-sref="busInfoManage" ><i class="fa fa-times"></i> 取消</a>
252 </div> 464 </div>
253 </div> 465 </div>
@@ -258,20 +470,4 @@ @@ -258,20 +470,4 @@
258 </div> 470 </div>
259 471
260 472
261 -  
262 -  
263 -  
264 -  
265 -  
266 -  
267 -  
268 -  
269 -  
270 -  
271 -  
272 -  
273 -  
274 -  
275 -  
276 -  
277 </div> 473 </div>
278 \ No newline at end of file 474 \ No newline at end of file
src/main/resources/static/pages/scheduleApp/module/basicInfo/busInfoManage/index.html
@@ -27,7 +27,7 @@ @@ -27,7 +27,7 @@
27 <span class="caption-subject bold uppercase">车辆信息表</span> 27 <span class="caption-subject bold uppercase">车辆信息表</span>
28 </div> 28 </div>
29 <div class="actions"> 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 <i class="fa fa-plus"></i> 31 <i class="fa fa-plus"></i>
32 添加车辆信息 32 添加车辆信息
33 </a> 33 </a>
@@ -58,7 +58,7 @@ @@ -58,7 +58,7 @@
58 </div> 58 </div>
59 59
60 <div class="portlet-body"> 60 <div class="portlet-body">
61 - <div ui-view="list"></div> 61 + <div ui-view="busInfoManage_list"></div>
62 </div> 62 </div>
63 </div> 63 </div>
64 </div> 64 </div>
src/main/resources/static/pages/scheduleApp/module/basicInfo/busInfoManage/list.html
@@ -2,11 +2,11 @@ @@ -2,11 +2,11 @@
2 <div ng-controller="BusInfoManageListCtrl as ctrl"> 2 <div ng-controller="BusInfoManageListCtrl as ctrl">
3 <table class="table table-striped table-bordered table-hover table-checkable order-column"> 3 <table class="table table-striped table-bordered table-hover table-checkable order-column">
4 <thead> 4 <thead>
5 - <tr> 5 + <tr role="row" class="heading">
6 <th> 6 <th>
7 <input type="checkbox" class="group-checkable"/> 7 <input type="checkbox" class="group-checkable"/>
8 </th> 8 </th>
9 - <th>序号</th> 9 + <th width="50">序号</th>
10 <th>车辆编号</th> 10 <th>车辆编号</th>
11 <th>内部编号</th> 11 <th>内部编号</th>
12 <th>设备编号</th> 12 <th>设备编号</th>
@@ -14,16 +14,63 @@ @@ -14,16 +14,63 @@
14 <th>所在公司</th> 14 <th>所在公司</th>
15 <th>所在分公司</th> 15 <th>所在分公司</th>
16 <th>是否电车</th> 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 </tr> 65 </tr>
19 </thead> 66 </thead>
20 <tbody> 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 <td> 69 <td>
23 <input type="checkbox"/> 70 <input type="checkbox"/>
24 </td> 71 </td>
25 <td> 72 <td>
26 - <span>todo</span> 73 + <span ng-bind="$index + 1"></span>
27 </td> 74 </td>
28 <td> 75 <td>
29 <span ng-bind="info.carCode"></span> 76 <span ng-bind="info.carCode"></span>
@@ -44,10 +91,13 @@ @@ -44,10 +91,13 @@
44 <span ng-bind="info.brancheCompany"></span> 91 <span ng-bind="info.brancheCompany"></span>
45 </td> 92 </td>
46 <td> 93 <td>
47 - <span>todo</span> 94 + <span ng-bind="info.sfdc"></span>
48 </td> 95 </td>
49 <td> 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 </td> 101 </td>
52 </tr> 102 </tr>
53 </tbody> 103 </tbody>
@@ -55,11 +105,16 @@ @@ -55,11 +105,16 @@
55 </table> 105 </table>
56 106
57 <div style="text-align: right;"> 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 previous-text="上一页" 115 previous-text="上一页"
62 - next-text="下一页"> 116 + next-text="下一页"
  117 + last-text="尾页">
63 </uib-pagination> 118 </uib-pagination>
64 </div> 119 </div>
65 </div> 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 \ No newline at end of file 21 \ No newline at end of file
src/main/resources/static/pages/scheduleApp/module/main.js
@@ -51,7 +51,7 @@ ScheduleApp.config([&#39;$stateProvider&#39;, &#39;$urlRouterProvider&#39;, function($stateProvi @@ -51,7 +51,7 @@ ScheduleApp.config([&#39;$stateProvider&#39;, &#39;$urlRouterProvider&#39;, function($stateProvi
51 "": { 51 "": {
52 templateUrl: 'pages/scheduleApp/module/basicInfo/busInfoManage/index.html' 52 templateUrl: 'pages/scheduleApp/module/basicInfo/busInfoManage/index.html'
53 }, 53 },
54 - "list@busInfoManage": { 54 + "busInfoManage_list@busInfoManage": {
55 templateUrl: 'pages/scheduleApp/module/basicInfo/busInfoManage/list.html' 55 templateUrl: 'pages/scheduleApp/module/basicInfo/busInfoManage/list.html'
56 } 56 }
57 }, 57 },
@@ -68,23 +68,8 @@ ScheduleApp.config([&#39;$stateProvider&#39;, &#39;$urlRouterProvider&#39;, function($stateProvi @@ -68,23 +68,8 @@ ScheduleApp.config([&#39;$stateProvider&#39;, &#39;$urlRouterProvider&#39;, 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 views: { 73 views: {
89 "": {templateUrl: 'pages/scheduleApp/module/basicInfo/busInfoManage/form.html'} 74 "": {templateUrl: 'pages/scheduleApp/module/basicInfo/busInfoManage/form.html'}
90 }, 75 },
@@ -94,14 +79,16 @@ ScheduleApp.config([&#39;$stateProvider&#39;, &#39;$urlRouterProvider&#39;, function($stateProvi @@ -94,14 +79,16 @@ ScheduleApp.config([&#39;$stateProvider&#39;, &#39;$urlRouterProvider&#39;, function($stateProvi
94 name: 'busInfoManage_form_module', 79 name: 'busInfoManage_form_module',
95 insertBefore: '#ng_load_plugins_before', // 动态载入模块时放置的位置 80 insertBefore: '#ng_load_plugins_before', // 动态载入模块时放置的位置
96 files: [ 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 "pages/scheduleApp/module/basicInfo/busInfoManage/busInfoManage.js" 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 views: { 92 views: {
106 "": {templateUrl: 'pages/scheduleApp/module/basicInfo/busInfoManage/detail.html'} 93 "": {templateUrl: 'pages/scheduleApp/module/basicInfo/busInfoManage/detail.html'}
107 }, 94 },
@@ -243,6 +230,27 @@ ScheduleApp.config([&#39;$stateProvider&#39;, &#39;$urlRouterProvider&#39;, function($stateProvi @@ -243,6 +230,27 @@ ScheduleApp.config([&#39;$stateProvider&#39;, &#39;$urlRouterProvider&#39;, 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