├── .babelrc ├── .gitignore ├── LICENSE ├── README.md ├── bower.json ├── dist ├── ionic-modal-select.js ├── ionic-modal-select.js.map ├── ionic-modal-select.min.js └── ionic-modal-select.min.js.map ├── gulpfile.js ├── package.json ├── src ├── ionic-modal-select.js ├── main.js ├── modal-template-multiple.html └── modal-template.html ├── tests ├── compile-directive.tests.js └── my.conf.js ├── webpack.config.js └── webpack.config.production.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015"] 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ModalSelectExample/* 2 | node_modules/* 3 | bower_components/* 4 | 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 INMAGIK srl 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, 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, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ionic-modal-select 2 | 3 | Modal select for Ionic Framework based on [$ionicModal](http://ionicframework.com/docs/api/service/$ionicModal/) 4 | 5 | See all docs and examples on the [project site](http://inmagik.github.io/ionic-modal-select). 6 | 7 | We also have a simple [Codepen demo](http://codepen.io/bianchimro/pen/epYYQO?editors=101). 8 | 9 | ![animated example](https://dl.dropboxusercontent.com/u/6178230/screenshots/ionic-modal-picker.gif) 10 | 11 | ## IMPORTANT NOTICE 12 | 13 | **In order to survive, this project needs**: 14 | * proper testing: see [issue #26](https://github.com/inmagik/ionic-modal-select/issues/26) 15 | * co-maintainers: see [issue #54](https://github.com/inmagik/ionic-modal-select/issues/54) 16 | 17 | Any help on this is greatly appreciated. Comment directly those issues or contact me directly at mauro.bianchi at inmagik.com if you are interested in helping with this. 18 | 19 | ## Features 20 | 21 | * supports long list of object via collection-repeat 22 | * optional search bar 23 | * supports unsetting the chosen value (optional) 24 | * customizable modal classes, modal header and footer classes 25 | * customizable buttons text 26 | * multiple selectable options (experimental) 27 | 28 | ## Usage 29 | 30 | Get the files from github or install from bower: 31 | ``` 32 | bower install ionic-modal-select 33 | ``` 34 | 35 | 36 | Include `ionic-modal-select.js` or its minified version in your index.html: 37 | 38 | ```html 39 | 40 | 41 | 42 | ``` 43 | 44 | 45 | Add the module `ionic-modal-select` to your application dependencies: 46 | 47 | ```javascript 48 | 49 | angular.module('starter', ['ionic', 'ionic-modal-select']) 50 | 51 | ``` 52 | 53 | And you're ready to go. 54 | 55 | 56 | ## Directives 57 | 58 | ### modal-select 59 | 60 | This directive will transform the element into a modal select: when clicking the element a select dialog will be open, with options presented in a clickable list. Once the user clicks on an option, it will be set on the bound model. 61 | 62 | For this to work the following conditions must apply: 63 | 64 | * The element you use this directive must be clickable. 65 | * The directive requires ngModel to be set on the element 66 | * The directive expects an inner element of class "option" to define the options template 67 | 68 | The final value bound to your model will be determined as follow: 69 | 70 | * if you set the attribute `option-getter` will be set as `getterFunction(selectedItem)` 71 | * if you set the attribute `option-property` will be set as `selectedItem[propertyName]` 72 | * otherwise it will be set as the full object 73 | 74 | 75 | In case of "multiple" selection mode, the user is allowed to select multiple options and 76 | the bound ng-model will be a list containing the selected options, with the same logic 77 | of getting the value. 78 | 79 | 80 | #### Options 81 | 82 | option|meaning|accepted values|default 83 | ---|---|---|--- 84 | `options`|List of options to choose from|Array|| 85 | `options-expression`|The expression indicating how to enumerate a the options collection, of the format `variable in expression` – where variable is the user defined loop variable and expression is a scope expression giving the collection to enumerate. For example: `album in artist.albums or album in artist.albums | orderBy:'name'`.|expression|| 86 | `option-getter`|Optional method to get the value from the chosen item|function|not set| 87 | `option-property`|Optional property name to get as model value from the chosen item|string|not set| 88 | `multiple`|If set (to any value) enables "multiple" selection mode that allows the user to select more than one option. For each option, a checkbox will be rendered. *This feature is still experimental*. |string|not set| 89 | `modal-class`|The class for the modal (set on ``|string|'' 90 | `selected-class`|The class applied to the currently selected option (if any) in the modal list|string|'option-selected' 91 | `on-select`|Callback triggered on object select. Takes two arguments, `newValue` and `oldValue` with obvious meaning.|function call with arguments `newValue` and `oldValue`|not set 92 | `on-reset`|Callback triggered when value is resetted using the relevant ui interface. Takes no arguments.|function call|not set 93 | `on-close`|Callback triggered when modal is closed (in any way, uses 'modal.hidden' ionic event). Takes no arguments.|function call|not set 94 | `modal-title`|The title shown on the modal header|string|'Select an option' 95 | `header-footer-class`|The class for header and footer of the modal|string|'bar-stable' 96 | `cancel-button`|Text of the button for closing the modal without changing the value|string|'Cancel' 97 | `reset-button`|Text of the button for unsetting value in the modal dialog|string|'Reset' 98 | `ok-button`|Text of the button to accept the multiple selection. *Appears only when multiple true*. |string|'Cancel' 99 | `hide-reset`|Hides the button for unsetting value in the modal dialog|string. Set to 'true' for hiding the button|false 100 | `use-collection-repeat`|Forces use of collection-repeat or ng-repeat for rendering options in the modal.| string "true", "false" | not set (automatically set according to number of options and `short-list-break` attribute) 101 | `short-list-break`|The maximum number of item in list to be rendered with `ng-repeat`.(if `use-collection-repeat` is not set) If the list has a number of options greater than this attribute it will be rendered with ionic `collection-repeat` directive instead. (see also `load-list-message` option)|integer|10 102 | `load-list-message`|Message to be shown when loading a long list of options in the modal|string|'Loading' 103 | `has-search`|Whether to show a search bar to filter options.|set to "true" for showing the search bar|undefined 104 | `search-placeholder`|String placeholder in search bar.|string|'Search' 105 | `sub-header-class`|Class to be applied to the subheader containing the search bar (makes sense only if `has-search="true`) |string|'bar-stable' 106 | `cancel-search-button`|Text for the button for clearing search text (makes sense only if `has-search="true`) |string|'Clear' 107 | `clear-search-on-select`|Tells the directive to not clear the search bar content after user selection. Set to `false` to prevent clearing the search text.|boolean|true 108 | `search-properties`|Array of properties for the search. For example: In your controller `$scope.searchProperties = ['property1', 'property2'];` and in template attributes `search-properties="searchProperties"`|Array 109 | 110 | 111 | ### Passing in options 112 | 113 | The `modal-select` directive must be provided with a set of options to choose from 114 | 115 | This can be done in two ways: 116 | 117 | * via the `options` attribute, that accepts an array of values or objects. The directive will watch for changes in this array and modify its options accordingly. 118 | * via the `options-expression` attribute, that accepts an expression similar to what you would use with ionic `collection-repeat` directive, of the format `variable in expression` – where variable is the user defined loop variable and expression is a scope expression giving the collection to enumerate. For example: `album in artist.albums or album in artist.albums | orderBy:'name'`. This allows you to apply ordering or filtering without acting on the original array. 119 | 120 | 121 | ### Options templates 122 | 123 | This directive expects to find a single inner element of class "option" that is used to define the template of the options that can be selected. Options will be rendered as items into a list in the modal (The content of each option, rendered with your template, is wrapped in an element of class 'item item-text wrap' and the original ".option" element is removed). 124 | 125 | For example: 126 | ```html 127 | 133 | ``` 134 | 135 | Will be rendered in the modal as : 136 | 137 | ```html 138 |
139 | {{option}} 140 |
141 | ``` 142 | 143 | ## Multiple selection mode 144 | From version 1.3.1, setting `multiple` attribute to any value other than "undefined" will enable the multiple selection on the widget. In this case, the user is allowed to select more than one option and options will be rendered with checkboxes in the selection modal. *This feature is still experimental*. 145 | 146 | 147 | ## Search bar 148 | From version 1.1.0 you can include a search bar into the modal for filtering options by simply adding the attribute `has-search="true"` to your `modal-select` element. 149 | 150 | Filtering is implemented with the angular `filter` filter, which searches recursively in all properties of the objects passed in as options. This means that you cannot search on "computed properties" right now. For example if you are using a custom setter you will be only able to search the original properties of the options. 151 | 152 | 153 | ### Examples 154 | #### Simplest one. 155 | This example shows a modal for choosing a number between 1 and 5. 156 | 157 | In your controller: 158 | 159 | ```js 160 | $scope.selectables = [1,2,3,4,5]; 161 | ``` 162 | In your template: 163 | 164 | ```html 165 | 171 | ``` 172 | 173 | #### Including a search bar 174 | To include a search bar in the previous example, just add `has-search="true"`: 175 | 176 | ```html 177 | 183 | ``` 184 | 185 | 186 | #### Objects as options 187 | In the following example we use some objects as options. 188 | 189 | 190 | In your controller: 191 | 192 | ```js 193 | $scope.selectables = [ 194 | { name: "Mauro", role : "navigator"}, 195 | { name: "Silvia", role : "chef"}, 196 | { name: "Merlino", role : "canaglia"} 197 | ]; 198 | ``` 199 | 200 | We'll explore different possibilities we have with this options. 201 | 202 | ##### 1. Setting the full object 203 | 204 | If we do not set `option-getter` or `option-property` attributes, the model is assigned to the full option object when an option is selected. 205 | 206 | ```html 207 | 213 | ``` 214 | 215 | 216 | 217 | 218 | ##### 2. Setting a property 219 | If `option-property` attribute is set to a string, the bound model assigned that property of the option object when an option is selected. For example if we set `option-getter="name"`, we get back the 'name' property of our options. 220 | 221 | ```html 222 | 228 | ``` 229 | 230 | ##### 3. Custom setter 231 | If a function call is passed via `option-getter` attribute, the bound model assignment is done by calling this function with the selected option as the only argument (named 'option'). For example if we do this in our controller: 232 | 233 | ```javascript 234 | $scope.getOption = function(option){ 235 | return option.name + ":" + option.role; 236 | }; 237 | ``` 238 | 239 | ```html 240 | 246 | ``` 247 | 248 | ##### 4. Specify the properties for search 249 | Specify in the array the properties' name for search `$scope.search_properties = ['propertie_1', 'propertie_2', '...'];`: 250 | ```javascript 251 | $scope.search_properties = ['name']; 252 | ``` 253 | ```html 254 | 260 | ``` 261 | 262 | We get back the phrase "Mauro:navigator", "Silvia:chef" or "Merlino:canaglia" if we click the previous defined options. 263 | 264 | 265 | ##### More examples [on the project site](http://inmagik.github.io/ionic-modal-select). 266 | 267 | 268 | ## Maintenance and support 269 | This project is maintained by [INMAGIK](https://www.inmagik.com). 270 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ionic-modal-select", 3 | "version": "1.3.1-alpha.0", 4 | "homepage": "https://github.com/inmagik/ionic-modal-select", 5 | "authors": [ 6 | "Mauro Bianchi " 7 | ], 8 | "description": "Modal select for ionic framework", 9 | "main": [ 10 | "dist/ionic-modal-select.js" 11 | ], 12 | "keywords": [ 13 | "ionic", 14 | "modal", 15 | "select" 16 | ], 17 | "license": "MIT", 18 | "ignore": [ 19 | "**/.*", 20 | "node_modules", 21 | "bower_components", 22 | "test", 23 | "tests" 24 | ], 25 | "devDependencies": { 26 | "ionic": "~1.1.1", 27 | "angular-mocks": "1.4.3" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /dist/ionic-modal-select.js: -------------------------------------------------------------------------------- 1 | /******/ (function(modules) { // webpackBootstrap 2 | /******/ // The module cache 3 | /******/ var installedModules = {}; 4 | /******/ 5 | /******/ // The require function 6 | /******/ function __webpack_require__(moduleId) { 7 | /******/ 8 | /******/ // Check if module is in cache 9 | /******/ if(installedModules[moduleId]) 10 | /******/ return installedModules[moduleId].exports; 11 | /******/ 12 | /******/ // Create a new module (and put it into the cache) 13 | /******/ var module = installedModules[moduleId] = { 14 | /******/ exports: {}, 15 | /******/ id: moduleId, 16 | /******/ loaded: false 17 | /******/ }; 18 | /******/ 19 | /******/ // Execute the module function 20 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 21 | /******/ 22 | /******/ // Flag the module as loaded 23 | /******/ module.loaded = true; 24 | /******/ 25 | /******/ // Return the exports of the module 26 | /******/ return module.exports; 27 | /******/ } 28 | /******/ 29 | /******/ 30 | /******/ // expose the modules object (__webpack_modules__) 31 | /******/ __webpack_require__.m = modules; 32 | /******/ 33 | /******/ // expose the module cache 34 | /******/ __webpack_require__.c = installedModules; 35 | /******/ 36 | /******/ // __webpack_public_path__ 37 | /******/ __webpack_require__.p = ""; 38 | /******/ 39 | /******/ // Load entry module and return exports 40 | /******/ return __webpack_require__(0); 41 | /******/ }) 42 | /************************************************************************/ 43 | /******/ ([ 44 | /* 0 */ 45 | /***/ function(module, exports, __webpack_require__) { 46 | 47 | "use strict"; 48 | 49 | __webpack_require__(1); 50 | 51 | /***/ }, 52 | /* 1 */ 53 | /***/ function(module, exports, __webpack_require__) { 54 | 55 | 'use strict'; 56 | 57 | compile.$inject = ["$compile"]; 58 | modalSelect.$inject = ["$ionicModal", "$timeout", "$filter", "$parse", "$templateCache"]; 59 | var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; }; 60 | 61 | /*! 62 | * Copyright 2015 Inmagik SRL. 63 | * http://www.inmagik.com/ 64 | * 65 | * ionic-modal-select, v1.3.2 66 | * Modal select directive for Ionic framework. 67 | * 68 | * By @bianchimro 69 | * 70 | * Licensed under the MIT license. Please see LICENSE for more information. 71 | * 72 | */ 73 | 74 | angular.module('ionic-modal-select', []).directive('compile', compile).directive('modalSelect', modalSelect); 75 | 76 | function compile($compile) { 77 | return function (scope, iElement, iAttrs) { 78 | var x = scope.$watch(function (scope) { 79 | // watch the 'compile' expression for changes 80 | return scope.$eval(iAttrs.compile); 81 | }, function (value) { 82 | // when the 'compile' expression changes 83 | // assign it into the current DOM 84 | iElement.html(value); 85 | 86 | // compile the new DOM and link it to the current 87 | // scope. 88 | // NOTE: we only compile .childNodes so that 89 | // we don't get into infinite loop compiling ourselves 90 | $compile(iElement.contents())(scope); 91 | 92 | //deactivate watch if "compile-once" is set to "true" 93 | if (iAttrs.compileOnce === 'true') { 94 | x(); 95 | } 96 | }); 97 | }; 98 | } 99 | 100 | function modalSelect($ionicModal, $timeout, $filter, $parse, $templateCache) { 101 | 102 | var modalTemplateMultiple = __webpack_require__(2); 103 | var modalTemplate = __webpack_require__(3); 104 | 105 | return { 106 | restrict: 'A', 107 | require: 'ngModel', 108 | scope: { 109 | initialOptions: "=options", 110 | optionGetter: "&", 111 | searchFilters: "=searchFilters", 112 | searchProperties: '=', 113 | onSelect: "&", 114 | onSearch: "&", 115 | onReset: "&", 116 | onClose: "&" 117 | }, 118 | link: function link(scope, iElement, iAttrs, ngModelController, transclude) { 119 | 120 | var shortList = true; 121 | var shortListBreak = iAttrs.shortListBreak ? parseInt(iAttrs.shortListBreak) : 10; 122 | var setFromProperty = iAttrs.optionProperty; 123 | var onOptionSelect = iAttrs.optionGetter; 124 | var clearSearchOnSelect = iAttrs.clearSearchOnSelect !== "false" ? true : false; 125 | var searchProperties = scope.searchProperties ? scope.searchProperties : false; 126 | 127 | //multiple values settings. 128 | var multiple = iAttrs.multiple ? true : false; 129 | if (multiple) { 130 | scope.isChecked = {}; 131 | } 132 | var multipleNullValue = iAttrs.multipleNullValue ? scope.$eval(iAttrs.multipleNullValue) : []; 133 | 134 | scope.ui = { 135 | modalTitle: iAttrs.modalTitle || 'Select an option', 136 | okButton: iAttrs.okButton || 'OK', 137 | hideReset: iAttrs.hideReset !== "true" ? false : true, 138 | resetButton: iAttrs.resetButton || 'Reset', 139 | cancelButton: iAttrs.cancelButton || 'Cancel', 140 | loadListMessage: iAttrs.loadListMessage || 'Loading', 141 | modalClass: iAttrs.modalClass || '', 142 | headerFooterClass: iAttrs.headerFooterClass || 'bar-stable', 143 | value: null, 144 | selectedClass: iAttrs.selectedClass || 'option-selected', 145 | itemClass: iAttrs.itemClass || 'item item-text-wrap', 146 | searchTemplate: iAttrs.searchTemplate || (multiple ? modalTemplateMultiple : modalTemplate), 147 | 148 | //search stuff 149 | hasSearch: iAttrs.hasSearch !== "true" ? false : true, 150 | searchValue: '', 151 | searchPlaceholder: iAttrs.searchPlaceholder || 'Search', 152 | subHeaderClass: iAttrs.subHeaderClass || 'bar-stable', 153 | cancelSearchButton: iAttrs.cancelSearchButton || 'Clear' 154 | 155 | }; 156 | 157 | var allOptions = []; 158 | scope.options = []; 159 | 160 | if (iAttrs.optionsExpression) { 161 | var optionsExpression = iAttrs.optionsExpression; 162 | var match = optionsExpression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/); 163 | if (!match) { 164 | throw new Error("collection-repeat expected expression in form of '_item_ in " + "_collection_[ track by _id_]' but got '" + iAttrs.optionsExpression + "'."); 165 | } 166 | //var keyExpr = match[1]; 167 | var listExpr = match[2]; 168 | var listGetter = $parse(listExpr); 169 | var s = iElement.scope(); 170 | 171 | scope.$watch(function () { 172 | return listGetter(s); 173 | }, function (nv, ov) { 174 | initialOptionsSetup(nv); 175 | updateListMode(); 176 | }, true); 177 | } else { 178 | scope.$watchCollection('initialOptions', function (nv) { 179 | initialOptionsSetup(nv); 180 | updateListMode(); 181 | }); 182 | } 183 | 184 | //#TODO: this is due to different single vs multiple template 185 | //but adds lots of complexity here and in search 186 | function initialOptionsSetup(nv) { 187 | nv = nv || []; 188 | if (!multiple) { 189 | allOptions = angular.copy(nv); 190 | scope.options = angular.copy(nv); 191 | } else { 192 | allOptions = nv.map(function (item, idx) { 193 | return [idx, angular.copy(item)]; 194 | }); 195 | scope.options = angular.copy(allOptions); 196 | } 197 | } 198 | 199 | // getting options template 200 | var opt = iElement[0].querySelector('.option'); 201 | if (!opt) { 202 | throw new Error({ 203 | name: 'modalSelectError:noOptionTemplate', 204 | message: 'When using modalSelect directive you must include an element with class "option"\n\t\t\t\t\t\t to provide a template for your select options.', 205 | toString: function toString() { 206 | return this.name + " " + this.message; 207 | } 208 | }); 209 | } 210 | scope.inner = angular.element(opt).html(); 211 | 212 | //add support for .remove for older devices 213 | if (!('remove' in Element.prototype)) { 214 | Element.prototype.remove = function () { 215 | this.parentNode.removeChild(this); 216 | }; 217 | } 218 | 219 | angular.element(opt).remove(); 220 | 221 | var notFound = iElement[0].querySelector('.not-found'); 222 | if (notFound) { 223 | scope.notFound = angular.element(notFound).html(); 224 | angular.element(notFound).remove(); 225 | } 226 | 227 | function updateListMode() { 228 | //shortList controls wether using ng-repeat instead of collection-repeat 229 | if (iAttrs.useCollectionRepeat === "true") { 230 | shortList = false; 231 | } else if (iAttrs.useCollectionRepeat === "false") { 232 | shortList = true; 233 | } else { 234 | if (typeof scope.options !== "undefined") { 235 | shortList = !!(scope.options.length < shortListBreak); 236 | } 237 | } 238 | 239 | scope.ui.shortList = shortList; 240 | } 241 | 242 | ngModelController.$render = function () { 243 | scope.ui.value = ngModelController.$viewValue; 244 | }; 245 | 246 | var getSelectedValue = scope.getSelectedValue = function (option) { 247 | var val = null; 248 | if (option === null || option === undefined) { 249 | return option; 250 | } 251 | if (onOptionSelect) { 252 | return scope.optionGetter({ option: option }); 253 | } 254 | if (setFromProperty) { 255 | val = option[setFromProperty]; 256 | } else { 257 | val = option; 258 | } 259 | return val; 260 | }; 261 | 262 | scope.setOption = function (option) { 263 | var oldValue = ngModelController.$viewValue; 264 | var val = getSelectedValue(option); 265 | ngModelController.$setViewValue(val); 266 | ngModelController.$render(); 267 | 268 | if (scope.onSelect) { 269 | scope.onSelect({ newValue: val, oldValue: oldValue }); 270 | } 271 | scope.modal.hide().then(function () { 272 | scope.showList = false; 273 | if (scope.ui.hasSearch) { 274 | if (clearSearchOnSelect) { 275 | scope.ui.searchValue = ''; 276 | } 277 | } 278 | }); 279 | }; 280 | 281 | // Filter object {id: , active: } 282 | // Used as auxiliary query params when querying server for search results 283 | scope.setFilter = function (filterId) { 284 | angular.forEach(scope.searchFilters, function (filter) { 285 | if (filter.id == filterId) { 286 | filter.active = !filter.active; 287 | } else { 288 | filter.active = false; 289 | } 290 | }); 291 | 292 | // Trigger another search when the search filters change 293 | if (scope.onSearch) { 294 | scope.onSearch({ query: scope.ui.searchValue }); 295 | } 296 | }; 297 | 298 | scope.unsetValue = function () { 299 | $timeout(function () { 300 | ngModelController.$setViewValue(""); 301 | ngModelController.$render(); 302 | scope.modal.hide(); 303 | scope.showList = false; 304 | if (scope.onReset && angular.isFunction(scope.onReset)) { 305 | scope.onReset(); 306 | } 307 | }); 308 | }; 309 | 310 | scope.setValues = function () { 311 | var checkedItems = []; 312 | angular.forEach(scope.isChecked, function (v, k) { 313 | if (v) { 314 | checkedItems.push(allOptions[k][1]); 315 | } 316 | }); 317 | var oldValues = ngModelController.$viewValue; 318 | var vals = checkedItems.map(function (item) { 319 | return getSelectedValue(item); 320 | }); 321 | ngModelController.$setViewValue(vals); 322 | ngModelController.$render(); 323 | 324 | if (scope.onSelect) { 325 | scope.onSelect({ newValue: vals, oldValue: oldValues }); 326 | } 327 | scope.modal.hide().then(function () { 328 | scope.showList = false; 329 | if (scope.ui.hasSearch) { 330 | if (clearSearchOnSelect) { 331 | scope.ui.searchValue = ''; 332 | } 333 | } 334 | }); 335 | }; 336 | 337 | scope.unsetValues = function () { 338 | $timeout(function () { 339 | ngModelController.$setViewValue(multipleNullValue); 340 | ngModelController.$render(); 341 | scope.isChecked = {}; 342 | scope.modal.hide(); 343 | scope.showList = false; 344 | if (scope.onReset && angular.isFunction(scope.onReset)) { 345 | scope.onReset(); 346 | } 347 | }); 348 | }; 349 | 350 | scope.closeModal = function () { 351 | scope.modal.hide().then(function () { 352 | scope.showList = false; 353 | }); 354 | }; 355 | 356 | scope.compareValues = function (a, b) { 357 | return angular.equals(a, b); 358 | }; 359 | 360 | //loading the modal 361 | var modalTpl = null; 362 | if (iAttrs.searchTemplate) { 363 | scope.modal = $ionicModal.fromTemplate($templateCache.get(iAttrs.searchTemplate), { scope: scope }); 364 | } else { 365 | modalTpl = multiple ? modalTemplateMultiple : modalTemplate; 366 | scope.modal = $ionicModal.fromTemplate(modalTpl, { scope: scope }); 367 | } 368 | 369 | var hiddenCb = null; 370 | scope.$on('$destroy', function () { 371 | if (hiddenCb) { 372 | hiddenCb(); 373 | hiddenCb = null; 374 | } 375 | scope.modal.remove(); 376 | }); 377 | 378 | if (scope.onClose && angular.isFunction(scope.onClose)) { 379 | hiddenCb = scope.$on('modal.hidden', function () { 380 | scope.onClose(); 381 | }); 382 | } 383 | 384 | iElement.on('click', function () { 385 | if (shortList) { 386 | scope.showList = true; 387 | scope.modal.show(); 388 | } else { 389 | scope.modal.show().then(function () { 390 | scope.showList = true; 391 | scope.ui.shortList = shortList; 392 | }); 393 | } 394 | }); 395 | 396 | //filter function 397 | if (scope.ui.hasSearch) { 398 | scope.$watch('ui.searchValue', function (nv) { 399 | var whatToSearch; 400 | if (!multiple) { 401 | whatToSearch = allOptions; 402 | } else { 403 | whatToSearch = allOptions.map(function (item) { 404 | return item[1]; 405 | }); 406 | } 407 | 408 | if (iAttrs.onSearch) { 409 | scope.onSearch({ query: nv }); 410 | } else { 411 | var filteredOpts = $filter('filter')(whatToSearch, nv, function (actual, expected) { 412 | if (!actual) { 413 | // if actual is an empty string, empty object, null, or undefined 414 | return false; 415 | } 416 | if (searchProperties) { 417 | if ((typeof actual === 'undefined' ? 'undefined' : _typeof(actual)) == 'object') { 418 | for (var i = 0; i < searchProperties.length; i++) { 419 | if (actual[searchProperties[i]] && actual[searchProperties[i]].toLowerCase().indexOf(expected.toLowerCase()) >= 0) { 420 | return true; 421 | } 422 | } 423 | } 424 | return false; 425 | } else { 426 | if (actual.toString().toLowerCase().indexOf(expected.toLowerCase()) >= 0) { 427 | return true; 428 | } 429 | } 430 | return false; 431 | }); 432 | 433 | var oldLen = scope.options.length; 434 | if (!multiple) { 435 | scope.options = filteredOpts; 436 | } else { 437 | //#TODO: lots of loops here! 438 | var newOpts = []; 439 | angular.forEach(filteredOpts, function (item) { 440 | var originalItem = allOptions.find(function (it) { 441 | return it[1] == item; 442 | }); 443 | if (originalItem) { 444 | newOpts.push(originalItem); 445 | } 446 | }); 447 | scope.options = newOpts; 448 | } 449 | if (oldLen != scope.options.length) { 450 | //#todo: should resize scroll or scroll up here 451 | } 452 | } 453 | }); 454 | scope.clearSearch = function () { 455 | scope.ui.searchValue = ''; 456 | }; 457 | } 458 | 459 | scope.copyOpt = function (option) { 460 | return angular.copy(option); 461 | }; 462 | 463 | //#TODO ?: WRAP INTO $timeout? 464 | ngModelController.$render(); 465 | } 466 | }; 467 | } 468 | 469 | /***/ }, 470 | /* 2 */ 471 | /***/ function(module, exports) { 472 | 473 | module.exports = " \n\n \n

{{::ui.modalTitle}}

\n
\n\n
\n \n \n
\n\n \n
\n

{{::ui.loadListMessage}}

\n

\n \n

\n
\n\n
\n \n \n \n\n \n
\n
\n \n \n
\n
\n
\n
\n \n
\n \n \n
\n \n
\n \n
\n
\n" 474 | 475 | /***/ }, 476 | /* 3 */ 477 | /***/ function(module, exports) { 478 | 479 | module.exports = " \n\n \n

{{::ui.modalTitle}}

\n
\n\n
\n \n \n
\n\n \n
\n

{{::ui.loadListMessage}}

\n

\n \n

\n
\n
\n
\n
\n \n
\n
\n
\n
\n
\n
\n \n
\n
\n
\n \n \n\n
\n
\n
\n\n
\n\n \n \n \n \n\n
\n" 480 | 481 | /***/ } 482 | /******/ ]); 483 | //# sourceMappingURL=ionic-modal-select.js.map -------------------------------------------------------------------------------- /dist/ionic-modal-select.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack:///webpack/bootstrap 8415b3f4e7fb1256b4c4","webpack:///./src/main.js","webpack:///./src/ionic-modal-select.js","webpack:///./src/modal-template-multiple.html","webpack:///./src/modal-template.html"],"names":[],"mappings":";AAAA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,uBAAe;AACf;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;;;;;;ACtCA;;AAAA,wB;;;;;;ACAA;;;;AAEA,KAAI,UAAU,OAAO,WAAW,cAAc,OAAO,OAAO,aAAa,WAAW,UAAU,KAAK,EAAE,OAAO,OAAO,SAAS,UAAU,KAAK,EAAE,OAAO,OAAO,OAAO,WAAW,cAAc,IAAI,gBAAgB,SAAS,WAAW,OAAO;;;;;;;;;;;;;;;AAW1O,SAAQ,OAAO,sBAAsB,IACpC,UAAU,WAAW,SACrB,UAAU,eAAe;;AAG1B,UAAS,QAAQ,UAAU;EAC1B,OAAO,UAAS,OAAO,UAAU,QAAQ;GACxC,IAAI,IAAI,MAAM,OACb,UAAS,OAAO;;IAEf,OAAO,MAAM,MAAM,OAAO;MAE3B,UAAS,OAAO;;;IAGf,SAAS,KAAK;;;;;;IAMd,SAAS,SAAS,YAAY;;;IAG9B,IAAI,OAAO,gBAAgB,QAAQ;KAClC;;;;;;AAQL,UAAS,YAAY,aAAa,UAAU,SAAS,QAAQ,gBAAiB;;EAE5E,IAAM,wBAAwB,oBAAQ;EACtC,IAAM,gBAAgB,oBAAQ;;EAE9B,OAAO;GACN,UAAU;GACV,SAAU;GACV,OAAO;IACN,gBAAe;IACf,cAAa;IACb,eAAe;IACf,kBAAiB;IACjB,UAAU;IACV,UAAU;IACV,SAAS;IACT,SAAS;;GAEV,MAAM,cAAU,OAAO,UAAU,QAAQ,mBAAmB,YAAY;;IAEvE,IAAI,YAAY;IAChB,IAAI,iBAAiB,OAAO,iBAAiB,SAAS,OAAO,kBAAkB;IAC/E,IAAI,kBAAiB,OAAO;IAC5B,IAAI,iBAAiB,OAAO;IAC5B,IAAI,sBAAsB,OAAO,wBAAwB,UAAU,OAAO;IAC1E,IAAI,mBAAmB,MAAM,mBAAoB,MAAM,mBAAmB;;;IAG1E,IAAI,WAAW,OAAO,WAAY,OAAO;IACzC,IAAI,UAAU;KACZ,MAAM,YAAY;;IAEpB,IAAI,oBAAoB,OAAO,oBAAoB,MAAM,MAAM,OAAO,qBAAqB;;IAE3F,MAAM,KAAK;KACV,YAAa,OAAO,cAAc;KAClC,UAAW,OAAO,YAAY;KAC9B,WAAY,OAAO,cAAe,SAAS,QAAQ;KACnD,aAAc,OAAO,eAAe;KACpC,cAAe,OAAO,gBAAgB;KACtC,iBAAkB,OAAO,mBAAmB;KAC5C,YAAa,OAAO,cAAc;KAClC,mBAAoB,OAAO,qBAAqB;KAChD,OAAS;KACT,eAAgB,OAAO,iBAAiB;KACxC,WAAW,OAAO,aAAa;KAC/B,gBAAgB,OAAO,mBAAmB,WAAW,wBAAwB;;;KAG7E,WAAY,OAAO,cAAe,SAAS,QAAQ;KACnD,aAAc;KACd,mBAAoB,OAAO,qBAAqB;KAChD,gBAAiB,OAAO,kBAAkB;KAC1C,oBAAqB,OAAO,sBAAsB;;;;IAInD,IAAI,aAAa;IACjB,MAAM,UAAU;;IAEhB,IAAI,OAAO,mBAAmB;KAC5B,IAAI,oBAAoB,OAAO;KAC/B,IAAI,QAAQ,kBAAkB,MAAM;KACpC,IAAI,CAAC,OAAO;MACV,MAAM,IAAI,MAAM,iEACP,4CAA4C,OAAO,oBAAoB;;;KAGlF,IAAI,WAAW,MAAM;KACrB,IAAI,aAAa,OAAO;KACxB,IAAI,IAAI,SAAS;;KAEjB,MAAM,OACJ,YAAM;MACJ,OAAO,WAAW;QAEpB,UAAC,IAAI,IAAO;MACV,oBAAoB;MACpB;QAEF;WAGG;KACL,MAAM,iBAAiB,kBAAkB,UAAS,IAAG;MACnD,oBAAoB;MACpB;;;;;;IAMJ,SAAS,oBAAoB,IAAG;KAC9B,KAAK,MAAM;KACX,IAAK,CAAC,UAAW;MACf,aAAa,QAAQ,KAAK;MAC1B,MAAM,UAAU,QAAQ,KAAK;YACxB;MACL,aAAa,GAAG,IAAI,UAAC,MAAM,KAAP;OAAA,OAAe,CAAC,KAAK,QAAQ,KAAK;;MACtD,MAAM,UAAU,QAAQ,KAAK;;;;;IAKjC,IAAI,MAAM,SAAS,GAAG,cAAc;IACpC,IAAI,CAAC,KAAK;KACT,MAAM,IAAI,MAAM;MACf,MAAK;MACL;MAEA,UAAS,oBAAU;OAClB,OAAO,KAAK,OAAO,MAAM,KAAK;;;;IAIjC,MAAM,QAAQ,QAAQ,QAAQ,KAAK;;;IAGnC,IAAI,EAAE,YAAY,QAAQ,YAAY;KACrC,QAAQ,UAAU,SAAS,YAAW;MACrC,KAAK,WAAW,YAAY;;;;IAI9B,QAAQ,QAAQ,KAAK;;IAErB,IAAI,WAAW,SAAS,GAAG,cAAc;IACzC,IAAG,UAAU;KACZ,MAAM,WAAW,QAAQ,QAAQ,UAAU;KAC3C,QAAQ,QAAQ,UAAU;;;IAG3B,SAAS,iBAAgB;;KAExB,IAAI,OAAO,wBAAwB,QAAQ;MAC1C,YAAY;YACN,IAAI,OAAO,wBAAwB,SAAS;MAClD,YAAY;YACN;MACN,IAAI,OAAO,MAAM,YAAY,aAAY;OACxC,YAAY,CAAC,EAAE,MAAM,QAAQ,SAAS;;;;KAIxC,MAAM,GAAG,YAAY;;;IAGtB,kBAAkB,UAAU,YAAU;KACrC,MAAM,GAAG,QAAQ,kBAAkB;;;IAGpC,IAAI,mBAAmB,MAAM,mBAAmB,UAAS,QAAO;KAC/D,IAAI,MAAM;KACV,IAAI,WAAW,QAAQ,WAAW,WAAW;MAC5C,OAAO;;KAER,IAAI,gBAAgB;MACnB,OAAO,MAAM,aAAa,EAAC,QAAO;;KAEnC,IAAI,iBAAiB;MACpB,MAAM,OAAO;YACP;MACN,MAAM;;KAEP,OAAO;;;IAGR,MAAM,YAAY,UAAS,QAAO;KACjC,IAAI,WAAW,kBAAkB;KACjC,IAAI,MAAM,iBAAiB;KAC3B,kBAAkB,cAAc;KAChC,kBAAkB;;KAElB,IAAI,MAAM,UAAU;MACnB,MAAM,SAAS,EAAE,UAAU,KAAK,UAAU;;KAE3C,MAAM,MAAM,OAAO,KAAK,YAAU;MACjC,MAAM,WAAW;MACjB,IAAI,MAAM,GAAG,WAAW;OACvB,IAAG,qBAAqB;QACvB,MAAM,GAAG,cAAc;;;;;;;;IAQ3B,MAAM,YAAY,UAAS,UAAU;KACpC,QAAQ,QAAQ,MAAM,eAAe,UAAS,QAAQ;MACrD,IAAG,OAAO,MAAM,UAAU;OACzB,OAAO,SAAS,CAAC,OAAO;aAClB;OACN,OAAO,SAAS;;;;;KAKlB,IAAG,MAAM,UAAU;MAClB,MAAM,SAAS,EAAC,OAAO,MAAM,GAAG;;;;IAIlC,MAAM,aAAa,YAAU;KAC5B,SAAS,YAAU;MAClB,kBAAkB,cAAc;MAChC,kBAAkB;MAClB,MAAM,MAAM;MACZ,MAAM,WAAW;MACjB,IAAI,MAAM,WAAW,QAAQ,WAAW,MAAM,UAAU;OACvD,MAAM;;;;;IAKT,MAAM,YAAY,YAAU;KAC1B,IAAI,eAAe;KACnB,QAAQ,QAAQ,MAAM,WAAW,UAAS,GAAG,GAAE;MAC7C,IAAG,GAAE;OACH,aAAa,KAAK,WAAW,GAAG;;;KAGpC,IAAI,YAAY,kBAAkB;KAClC,IAAI,OAAO,aAAa,IAAI,UAAS,MAAK;MACxC,OAAO,iBAAiB;;KAE1B,kBAAkB,cAAc;KAChC,kBAAkB;;KAElB,IAAI,MAAM,UAAU;MAClB,MAAM,SAAS,EAAE,UAAU,MAAM,UAAU;;KAE7C,MAAM,MAAM,OAAO,KAAK,YAAU;MAChC,MAAM,WAAW;MACjB,IAAI,MAAM,GAAG,WAAW;OACtB,IAAG,qBAAoB;QACrB,MAAM,GAAG,cAAc;;;;;;IAO/B,MAAM,cAAc,YAAU;KAC5B,SAAS,YAAU;MACjB,kBAAkB,cAAc;MAChC,kBAAkB;MAClB,MAAM,YAAY;MAClB,MAAM,MAAM;MACZ,MAAM,WAAW;MACjB,IAAI,MAAM,WAAW,QAAQ,WAAW,MAAM,UAAU;OACtD,MAAM;;;;;IAKZ,MAAM,aAAa,YAAU;KAC5B,MAAM,MAAM,OAAO,KAAK,YAAU;MACjC,MAAM,WAAW;;;;IAKnB,MAAM,gBAAgB,UAAS,GAAG,GAAE;KACnC,OAAO,QAAQ,OAAO,GAAG;;;;IAI1B,IAAI,WAAW;IACf,IAAG,OAAO,gBAAgB;KACzB,MAAM,QAAQ,YAAY,aACzB,eAAe,IAAI,OAAO,iBAC1B,EAAE,OAAO;WAEJ;KACN,WAAW,WAAW,wBAAwB;KAC9C,MAAM,QAAQ,YAAY,aACzB,UACA,EAAE,OAAO;;;IAIX,IAAI,WAAW;IACf,MAAM,IAAI,YAAY,YAAU;KAC/B,IAAG,UAAS;MACV;MACA,WAAW;;KAEb,MAAM,MAAM;;;IAGb,IAAI,MAAM,WAAW,QAAQ,WAAW,MAAM,UAAU;KACvD,WAAW,MAAM,IAAI,gBAAgB,YAAU;MAC9C,MAAM;;;;IAIR,SAAS,GAAG,SAAS,YAAU;KAC9B,IAAI,WAAW;MACd,MAAM,WAAW;MACjB,MAAM,MAAM;YACN;MACN,MAAM,MAAM,OACV,KAAK,YAAU;OACf,MAAM,WAAW;OACjB,MAAM,GAAG,YAAY;;;;;;IAOzB,IAAI,MAAM,GAAG,WAAW;KACvB,MAAM,OAAO,kBAAkB,UAAS,IAAG;MAC1C,IAAI;MACJ,IAAK,CAAC,UAAY;OAChB,eAAe;aACV;OACL,eAAe,WAAW,IAAI,UAAS,MAAK;QAC1C,OAAO,KAAK;;;;MAIhB,IAAG,OAAO,UAAU;OAClB,MAAM,SAAS,EAAC,OAAO;aAClB;OACL,IAAI,eAAe,QAAQ,UAAU,cAAc,IAAI,UAAS,QAAQ,UAAU;QAClF,IAAG,CAAC,QAAO;;SAEV,OAAO;;QAER,IAAI,kBAAiB;SACpB,IAAI,QAAO,WAAP,oCAAO,YAAU,UAAS;UAC7B,KAAK,IAAI,IAAI,GAAG,IAAI,iBAAiB,QAAQ,KAAI;WAChD,IAAI,OAAO,iBAAiB,OAAO,OAAO,iBAAiB,IAAI,cAAc,QAAQ,SAAS,kBAAkB,GAAE;YACjH,OAAO;;;;SAIV,OAAO;eACD;SACN,IAAG,OAAO,WAAW,cAAc,QAAQ,SAAS,kBAAkB,GAAE;UACvE,OAAO;;;QAGT,OAAO;;;OAGR,IAAI,SAAS,MAAM,QAAQ;OAC3B,IAAK,CAAC,UAAU;QACd,MAAM,UAAU;cAEX;;QAEL,IAAI,UAAU;QACd,QAAQ,QAAQ,cAAc,UAAS,MAAK;SAC1C,IAAI,eAAe,WAAW,KAAK,UAAS,IAAG;UAC7C,OAAO,GAAG,MAAM;;SAElB,IAAI,cAAc;UAChB,QAAQ,KAAK;;;QAGjB,MAAM,UAAU;;OAElB,IAAG,UAAU,MAAM,QAAQ,QAAO;;;;;KAKpC,MAAM,cAAc,YAAU;MAC7B,MAAM,GAAG,cAAc;;;;IAIzB,MAAM,UAAU,kBAAU;KACzB,OAAO,QAAQ,KAAK;;;;IAIrB,kBAAkB;;;;;;;;;AC1atB,wLAAuL,iBAAiB,2SAA2S,wBAAwB,oJAAoJ,yBAAyB,mFAAmF,6BAA6B,kGAAkG,mCAAmC,sBAAsB,wkDAAwkD,iBAAiB,mRAAmR,gBAAgB,sD;;;;;;ACA/zF,wLAAuL,iBAAiB,2SAA2S,wBAAwB,oJAAoJ,yBAAyB,mFAAmF,6BAA6B,sGAAsG,uCAAuC,sBAAsB,8TAA8T,IAAI,gBAAgB,aAAa,oBAAoB,sDAAsD,2KAA2K,GAAG,oBAAoB,sDAAsD,maAAma,IAAI,gBAAgB,aAAa,oBAAoB,sDAAsD,0hBAA0hB,iBAAiB,gIAAgI,gBAAgB,wD","file":"ionic-modal-select.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId])\n \t\t\treturn installedModules[moduleId].exports;\n\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\texports: {},\n \t\t\tid: moduleId,\n \t\t\tloaded: false\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.loaded = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(0);\n\n\n\n/** WEBPACK FOOTER **\n ** webpack/bootstrap 8415b3f4e7fb1256b4c4\n **/","import \"./ionic-modal-select.js\";\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/main.js\n **/","/*!\n * Copyright 2015 Inmagik SRL.\n * http://www.inmagik.com/\n *\n * ionic-modal-select, v1.3.2\n * Modal select directive for Ionic framework.\n *\n * By @bianchimro\n *\n * Licensed under the MIT license. Please see LICENSE for more information.\n *\n */\n\nangular.module('ionic-modal-select', [])\n.directive('compile', compile)\n.directive('modalSelect', modalSelect);\n\n\nfunction compile($compile) {\n\treturn function(scope, iElement, iAttrs) {\n\t\tvar x = scope.$watch(\n\t\t\tfunction(scope) {\n\t\t\t\t// watch the 'compile' expression for changes\n\t\t\t\treturn scope.$eval(iAttrs.compile);\n\t\t\t},\n\t\t\tfunction(value) {\n\t\t\t\t// when the 'compile' expression changes\n\t\t\t\t// assign it into the current DOM\n\t\t\t\tiElement.html(value);\n\n\t\t\t\t// compile the new DOM and link it to the current\n\t\t\t\t// scope.\n\t\t\t\t// NOTE: we only compile .childNodes so that\n\t\t\t\t// we don't get into infinite loop compiling ourselves\n\t\t\t\t$compile(iElement.contents())(scope);\n\n\t\t\t\t//deactivate watch if \"compile-once\" is set to \"true\"\n\t\t\t\tif (iAttrs.compileOnce === 'true') {\n\t\t\t\t\tx();\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\t};\n}\n\n\nfunction modalSelect($ionicModal, $timeout, $filter, $parse, $templateCache ) {\n\n\t\tconst modalTemplateMultiple = require('raw!./modal-template-multiple.html');\n\t\tconst modalTemplate = require('raw!./modal-template.html');\n\n\t\treturn {\n\t\t\trestrict: 'A',\n\t\t\trequire : 'ngModel',\n\t\t\tscope: {\n\t\t\t\tinitialOptions:\"=options\",\n\t\t\t\toptionGetter:\"&\",\n\t\t\t\tsearchFilters: \"=searchFilters\",\n\t\t\t\tsearchProperties:'=',\n\t\t\t\tonSelect: \"&\",\n\t\t\t\tonSearch: \"&\",\n\t\t\t\tonReset: \"&\",\n\t\t\t\tonClose: \"&\",\n\t\t\t},\n\t\t\tlink: function (scope, iElement, iAttrs, ngModelController, transclude) {\n\n\t\t\t\tvar shortList = true;\n\t\t\t\tvar shortListBreak = iAttrs.shortListBreak ? parseInt(iAttrs.shortListBreak) : 10;\n\t\t\t\tvar setFromProperty= iAttrs.optionProperty;\n\t\t\t\tvar onOptionSelect = iAttrs.optionGetter;\n\t\t\t\tvar clearSearchOnSelect = iAttrs.clearSearchOnSelect !== \"false\" ? true : false;\n\t\t\t\tvar searchProperties = scope.searchProperties ? scope.searchProperties : false;\n\n\t\t\t\t//multiple values settings.\n\t\t\t\tvar multiple = iAttrs.multiple ? true : false;\n\t\t\t\tif (multiple) {\n\t\t\t\t\t\tscope.isChecked = {};\n\t\t\t\t}\n\t\t\t\tvar multipleNullValue = iAttrs.multipleNullValue ? scope.$eval(iAttrs.multipleNullValue) : [];\n\n\t\t\t\tscope.ui = {\n\t\t\t\t\tmodalTitle : iAttrs.modalTitle || 'Select an option',\n\t\t\t\t\tokButton : iAttrs.okButton || 'OK',\n\t\t\t\t\thideReset : iAttrs.hideReset !== \"true\" ? false : true,\n\t\t\t\t\tresetButton : iAttrs.resetButton || 'Reset',\n\t\t\t\t\tcancelButton : iAttrs.cancelButton || 'Cancel',\n\t\t\t\t\tloadListMessage : iAttrs.loadListMessage || 'Loading',\n\t\t\t\t\tmodalClass : iAttrs.modalClass || '',\n\t\t\t\t\theaderFooterClass : iAttrs.headerFooterClass || 'bar-stable',\n\t\t\t\t\tvalue : null,\n\t\t\t\t\tselectedClass : iAttrs.selectedClass || 'option-selected',\n\t\t\t\t\titemClass: iAttrs.itemClass || 'item item-text-wrap',\n\t\t\t\t\tsearchTemplate: iAttrs.searchTemplate || (multiple ? modalTemplateMultiple : modalTemplate),\n\n\t\t\t\t\t//search stuff\n\t\t\t\t\thasSearch : iAttrs.hasSearch !== \"true\" ? false : true,\n\t\t\t\t\tsearchValue : '',\n\t\t\t\t\tsearchPlaceholder : iAttrs.searchPlaceholder || 'Search',\n\t\t\t\t\tsubHeaderClass : iAttrs.subHeaderClass || 'bar-stable',\n\t\t\t\t\tcancelSearchButton : iAttrs.cancelSearchButton || 'Clear'\n\n\t\t\t\t};\n\n\t\t\t\tvar allOptions = [];\n\t\t\t\tscope.options = [];\n\n\t\t\t\tif (iAttrs.optionsExpression) {\n\t\t\t\t\t\tvar optionsExpression = iAttrs.optionsExpression;\n\t\t\t\t\t\tvar match = optionsExpression.match(/^\\s*([\\s\\S]+?)\\s+in\\s+([\\s\\S]+?)(?:\\s+track\\s+by\\s+([\\s\\S]+?))?\\s*$/);\n\t\t\t\t\t\tif (!match) {\n\t\t\t\t\t\t\t\tthrow new Error(\"collection-repeat expected expression in form of '_item_ in \" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"_collection_[ track by _id_]' but got '\" + iAttrs.optionsExpression + \"'.\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\t//var keyExpr = match[1];\n\t\t\t\t\t\tvar listExpr = match[2];\n\t\t\t\t\t\tvar listGetter = $parse(listExpr);\n\t\t\t\t\t\tvar s = iElement.scope();\n\n\t\t\t\t\t\tscope.$watch(\n\t\t\t\t\t\t\t\t() => {\n\t\t\t\t\t\t\t\t\t\treturn listGetter(s);\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t(nv, ov) => {\n\t\t\t\t\t\t\t\t\t\tinitialOptionsSetup(nv);\n\t\t\t\t\t\t\t\t\t\tupdateListMode();\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\ttrue\n\t\t\t\t\t\t);\n\n\t\t\t\t} else {\n\t\t\t\t\t\tscope.$watchCollection('initialOptions', function(nv){\n\t\t\t\t\t\t\t\tinitialOptionsSetup(nv);\n\t\t\t\t\t\t\t\tupdateListMode();\n\t\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t//#TODO: this is due to different single vs multiple template\n\t\t\t\t//but adds lots of complexity here and in search\n\t\t\t\tfunction initialOptionsSetup(nv){\n\t\t\t\t\t\tnv = nv || [];\n\t\t\t\t\t\tif ( !multiple ) {\n\t\t\t\t\t\t\t\tallOptions = angular.copy(nv);\n\t\t\t\t\t\t\t\tscope.options = angular.copy(nv);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tallOptions = nv.map((item, idx) => [idx, angular.copy(item)] );\n\t\t\t\t\t\t\t\tscope.options = angular.copy(allOptions);\n\t\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// getting options template\n\t\t\t\tvar opt = iElement[0].querySelector('.option');\n\t\t\t\tif (!opt) {\n\t\t\t\t\tthrow new Error({\n\t\t\t\t\t\tname:'modalSelectError:noOptionTemplate',\n\t\t\t\t\t\tmessage:`When using modalSelect directive you must include an element with class \"option\"\n\t\t\t\t\t\t to provide a template for your select options.`,\n\t\t\t\t\t\ttoString:function(){\n\t\t\t\t\t\t\treturn this.name + \" \" + this.message;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tscope.inner = angular.element(opt).html();\n\n\t\t\t\t//add support for .remove for older devices\n\t\t\t\tif (!('remove' in Element.prototype)) {\n\t\t\t\t\tElement.prototype.remove = function() {\n\t\t\t\t\t\tthis.parentNode.removeChild(this);\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tangular.element(opt).remove();\n\n\t\t\t\tvar notFound = iElement[0].querySelector('.not-found');\n\t\t\t\tif(notFound) {\n\t\t\t\t\tscope.notFound = angular.element(notFound).html();\n\t\t\t\t\tangular.element(notFound).remove();\n\t\t\t\t}\n\n\t\t\t\tfunction updateListMode(){\n\t\t\t\t\t//shortList controls wether using ng-repeat instead of collection-repeat\n\t\t\t\t\tif (iAttrs.useCollectionRepeat === \"true\") {\n\t\t\t\t\t\tshortList = false;\n\t\t\t\t\t} else if (iAttrs.useCollectionRepeat === \"false\") {\n\t\t\t\t\t\tshortList = true;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (typeof(scope.options) !==\"undefined\"){\n\t\t\t\t\t\t\tshortList = !!(scope.options.length < shortListBreak);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tscope.ui.shortList = shortList;\n\t\t\t\t}\n\n\t\t\t\tngModelController.$render = function(){\n\t\t\t\t\tscope.ui.value = ngModelController.$viewValue;\n\t\t\t\t};\n\n\t\t\t\tvar getSelectedValue = scope.getSelectedValue = function(option){\n\t\t\t\t\tvar val = null;\n\t\t\t\t\tif (option === null || option === undefined) {\n\t\t\t\t\t\treturn option;\n\t\t\t\t\t}\n\t\t\t\t\tif (onOptionSelect) {\n\t\t\t\t\t\treturn scope.optionGetter({option:option});\n\t\t\t\t\t}\n\t\t\t\t\tif (setFromProperty) {\n\t\t\t\t\t\tval = option[setFromProperty];\n\t\t\t\t\t} else {\n\t\t\t\t\t\tval = option;\n\t\t\t\t\t}\n\t\t\t\t\treturn val;\n\t\t\t\t};\n\n\t\t\t\tscope.setOption = function(option){\n\t\t\t\t\tvar oldValue = ngModelController.$viewValue;\n\t\t\t\t\tvar val = getSelectedValue(option);\n\t\t\t\t\tngModelController.$setViewValue(val);\n\t\t\t\t\tngModelController.$render();\n\n\t\t\t\t\tif (scope.onSelect) {\n\t\t\t\t\t\tscope.onSelect({ newValue: val, oldValue: oldValue });\n\t\t\t\t\t}\n\t\t\t\t\tscope.modal.hide().then(function(){\n\t\t\t\t\t\tscope.showList = false;\n\t\t\t\t\t\tif (scope.ui.hasSearch) {\n\t\t\t\t\t\t\tif(clearSearchOnSelect) {\n\t\t\t\t\t\t\t\tscope.ui.searchValue = '';\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t};\n\n\t\t\t\t// Filter object {id: , active: }\n\t\t\t\t// Used as auxiliary query params when querying server for search results\n\t\t\t\tscope.setFilter = function(filterId) {\n\t\t\t\t\tangular.forEach(scope.searchFilters, function(filter) {\n\t\t\t\t\t\tif(filter.id == filterId) {\n\t\t\t\t\t\t\tfilter.active = !filter.active;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tfilter.active = false;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\n\t\t\t\t\t// Trigger another search when the search filters change\n\t\t\t\t\tif(scope.onSearch) {\n\t\t\t\t\t\tscope.onSearch({query: scope.ui.searchValue});\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\tscope.unsetValue = function(){\n\t\t\t\t\t$timeout(function(){\n\t\t\t\t\t\tngModelController.$setViewValue(\"\");\n\t\t\t\t\t\tngModelController.$render();\n\t\t\t\t\t\tscope.modal.hide();\n\t\t\t\t\t\tscope.showList = false;\n\t\t\t\t\t\tif (scope.onReset && angular.isFunction(scope.onReset)) {\n\t\t\t\t\t\t\tscope.onReset();\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t};\n\n\t\t\t\tscope.setValues = function(){\n\t\t\t\t\t\tvar checkedItems = [];\n\t\t\t\t\t\tangular.forEach(scope.isChecked, function(v, k){\n\t\t\t\t\t\t\t\tif(v){\n\t\t\t\t\t\t\t\t\t\tcheckedItems.push(allOptions[k][1])\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t\tvar oldValues = ngModelController.$viewValue;\n\t\t\t\t\t\tvar vals = checkedItems.map(function(item){\n\t\t\t\t\t\t\t\treturn getSelectedValue(item);\n\t\t\t\t\t\t});\n\t\t\t\t\t\tngModelController.$setViewValue(vals);\n\t\t\t\t\t\tngModelController.$render();\n\n\t\t\t\t\t\tif (scope.onSelect) {\n\t\t\t\t\t\t\t\tscope.onSelect({ newValue: vals, oldValue: oldValues });\n\t\t\t\t\t\t}\n\t\t\t\t\t\tscope.modal.hide().then(function(){\n\t\t\t\t\t\t\t\tscope.showList = false;\n\t\t\t\t\t\t\t\tif (scope.ui.hasSearch) {\n\t\t\t\t\t\t\t\t\t if(clearSearchOnSelect){\n\t\t\t\t\t\t\t\t\t\t\t\tscope.ui.searchValue = '';\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\n\t\t\t\t};\n\n\t\t\t\tscope.unsetValues = function(){\n\t\t\t\t\t\t$timeout(function(){\n\t\t\t\t\t\t\t\tngModelController.$setViewValue(multipleNullValue);\n\t\t\t\t\t\t\t\tngModelController.$render();\n\t\t\t\t\t\t\t\tscope.isChecked = {};\n\t\t\t\t\t\t\t\tscope.modal.hide();\n\t\t\t\t\t\t\t\tscope.showList = false;\n\t\t\t\t\t\t\t\tif (scope.onReset && angular.isFunction(scope.onReset)) {\n\t\t\t\t\t\t\t\t\t\tscope.onReset();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t};\n\n\t\t\t\tscope.closeModal = function(){\n\t\t\t\t\tscope.modal.hide().then(function(){\n\t\t\t\t\t\tscope.showList = false;\n\t\t\t\t\t});\n\t\t\t\t};\n\n\n\t\t\t\tscope.compareValues = function(a, b){\n\t\t\t\t\treturn angular.equals(a, b);\n\t\t\t\t};\n\n\t\t\t\t//loading the modal\n\t\t\t\tvar modalTpl = null;\n\t\t\t\tif(iAttrs.searchTemplate) {\n\t\t\t\t\tscope.modal = $ionicModal.fromTemplate(\n\t\t\t\t\t\t$templateCache.get(iAttrs.searchTemplate),\n\t\t\t\t\t\t{ scope: scope }\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tmodalTpl = multiple ? modalTemplateMultiple : modalTemplate;\n\t\t\t\t\tscope.modal = $ionicModal.fromTemplate(\n\t\t\t\t\t\tmodalTpl,\n\t\t\t\t\t\t{ scope: scope }\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tlet hiddenCb = null;\n\t\t\t\tscope.$on('$destroy', function(){\n\t\t\t\t\tif(hiddenCb){\n\t\t\t\t\t\t\thiddenCb();\n\t\t\t\t\t\t\thiddenCb = null;\n\t\t\t\t\t}\n\t\t\t\t\tscope.modal.remove();\n\t\t\t\t});\n\n\t\t\t\tif (scope.onClose && angular.isFunction(scope.onClose)) {\n\t\t\t\t\thiddenCb = scope.$on('modal.hidden', function(){\n\t\t\t\t\t\tscope.onClose();\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tiElement.on('click', function(){\n\t\t\t\t\tif (shortList) {\n\t\t\t\t\t\tscope.showList = true;\n\t\t\t\t\t\tscope.modal.show();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tscope.modal.show()\n\t\t\t\t\t\t\t.then(function(){\n\t\t\t\t\t\t\t\tscope.showList = true;\n\t\t\t\t\t\t\t\tscope.ui.shortList = shortList;\n\t\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t});\n\n\n\t\t\t\t//filter function\n\t\t\t\tif (scope.ui.hasSearch) {\n\t\t\t\t\tscope.$watch('ui.searchValue', function(nv){\n\t\t\t\t\t\tvar whatToSearch;\n\t\t\t\t\t\tif ( !multiple ) {\n\t\t\t\t\t\t\t\twhatToSearch = allOptions;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\twhatToSearch = allOptions.map(function(item){\n\t\t\t\t\t\t\t\t\t\treturn item[1];\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif(iAttrs.onSearch) {\n\t\t\t\t\t\t\t\tscope.onSearch({query: nv});\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tvar filteredOpts = $filter('filter')(whatToSearch, nv, function(actual, expected) {\n\t\t\t\t\t\t\t\tif(!actual){\n\t\t\t\t\t\t\t\t\t// if actual is an empty string, empty object, null, or undefined\n\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (searchProperties){\n\t\t\t\t\t\t\t\t\tif (typeof actual == 'object'){\n\t\t\t\t\t\t\t\t\t\tfor (var i = 0; i < searchProperties.length; i++){\n\t\t\t\t\t\t\t\t\t\t\tif (actual[searchProperties[i]] && actual[searchProperties[i]].toLowerCase().indexOf(expected.toLowerCase()) >= 0){\n\t\t\t\t\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tif(actual.toString().toLowerCase().indexOf(expected.toLowerCase()) >= 0){\n\t\t\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tvar oldLen = scope.options.length;\n\t\t\t\t\t\t\tif ( !multiple ){\n\t\t\t\t\t\t\t\t\tscope.options = filteredOpts;\n\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t//#TODO: lots of loops here!\n\t\t\t\t\t\t\t\t\tvar newOpts = [];\n\t\t\t\t\t\t\t\t\tangular.forEach(filteredOpts, function(item){\n\t\t\t\t\t\t\t\t\t\t\tvar originalItem = allOptions.find(function(it){\n\t\t\t\t\t\t\t\t\t\t\t\t\treturn it[1] == item;\n\t\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t\t\tif( originalItem ){\n\t\t\t\t\t\t\t\t\t\t\t\t\tnewOpts.push(originalItem);\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\tscope.options = newOpts;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(oldLen != scope.options.length){\n\t\t\t\t\t\t\t\t//#todo: should resize scroll or scroll up here\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\tscope.clearSearch = function(){\n\t\t\t\t\t\tscope.ui.searchValue = '';\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tscope.copyOpt = option => {\n\t\t\t\t\treturn angular.copy(option);\n\t\t\t\t}\n\n\t\t\t\t//#TODO ?: WRAP INTO $timeout?\n\t\t\t\tngModelController.$render();\n\n\t\t\t}\n\t\t};\n\t}\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/ionic-modal-select.js\n **/","module.exports = \" \\n\\n \\n

{{::ui.modalTitle}}

\\n
\\n\\n
\\n \\n \\n
\\n\\n \\n
\\n

{{::ui.loadListMessage}}

\\n

\\n \\n

\\n
\\n\\n
\\n \\n \\n \\n\\n \\n
\\n
\\n \\n \\n
\\n
\\n
\\n
\\n \\n
\\n \\n \\n
\\n \\n
\\n \\n
\\n
\\n\"\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./~/raw-loader!./src/modal-template-multiple.html\n ** module id = 2\n ** module chunks = 0\n **/","module.exports = \" \\n\\n \\n

{{::ui.modalTitle}}

\\n
\\n\\n
\\n \\n \\n
\\n\\n \\n
\\n

{{::ui.loadListMessage}}

\\n

\\n \\n

\\n
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n \\n \\n\\n
\\n
\\n
\\n\\n
\\n\\n \\n \\n \\n \\n\\n
\\n\"\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./~/raw-loader!./src/modal-template.html\n ** module id = 3\n ** module chunks = 0\n **/"],"sourceRoot":""} -------------------------------------------------------------------------------- /dist/ionic-modal-select.min.js: -------------------------------------------------------------------------------- 1 | !function(e){function n(o){if(t[o])return t[o].exports;var i=t[o]={exports:{},id:o,loaded:!1};return e[o].call(i.exports,i,i.exports,n),i.loaded=!0,i.exports}var t={};return n.m=e,n.c=t,n.p="",n(0)}([function(e,n,t){"use strict";t(1)},function(e,n,t){"use strict";function o(e){return function(n,t,o){var i=n.$watch(function(e){return e.$eval(o.compile)},function(s){t.html(s),e(t.contents())(n),"true"===o.compileOnce&&i()})}}function i(e,n,o,i,a){var l=t(2),r=t(3);return{restrict:"A",require:"ngModel",scope:{initialOptions:"=options",optionGetter:"&",searchFilters:"=searchFilters",searchProperties:"=",onSelect:"&",onSearch:"&",onReset:"&",onClose:"&"},link:function(t,c,u,d,p){function h(e){e=e||[],w?(V=e.map(function(e,n){return[n,angular.copy(e)]}),t.options=angular.copy(V)):(V=angular.copy(e),t.options=angular.copy(e))}function m(){"true"===u.useCollectionRepeat?f=!1:"false"===u.useCollectionRepeat?f=!0:"undefined"!=typeof t.options&&(f=!!(t.options.length=0)return!0;return!1}return e.toString().toLowerCase().indexOf(n.toLowerCase())>=0}),a=t.options.length;if(w){var l=[];angular.forEach(i,function(e){var n=V.find(function(n){return n[1]==e});n&&l.push(n)}),t.options=l}else t.options=i;a!=t.options.length}}),t.clearSearch=function(){t.ui.searchValue=""}),t.copyOpt=function(e){return angular.copy(e)},d.$render()}}}o.$inject=["$compile"],i.$inject=["$ionicModal","$timeout","$filter","$parse","$templateCache"];var s="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol?"symbol":typeof e};/*! 2 | * Copyright 2015 Inmagik SRL. 3 | * http://www.inmagik.com/ 4 | * 5 | * ionic-modal-select, v1.3.2 6 | * Modal select directive for Ionic framework. 7 | * 8 | * By @bianchimro 9 | * 10 | * Licensed under the MIT license. Please see LICENSE for more information. 11 | * 12 | */ 13 | angular.module("ionic-modal-select",[]).directive("compile",o).directive("modalSelect",i)},function(e,n){e.exports=' \n\n \n

{{::ui.modalTitle}}

\n
\n\n
\n \n \n
\n\n \n
\n

{{::ui.loadListMessage}}

\n

\n \n

\n
\n\n
\n \n \n \n\n \n
\n
\n \n \n
\n
\n
\n
\n \n
\n \n \n
\n \n
\n \n
\n
\n'},function(e,n){e.exports=' \n\n \n

{{::ui.modalTitle}}

\n
\n\n
\n \n \n
\n\n \n
\n

{{::ui.loadListMessage}}

\n

\n \n

\n
\n
\n
\n
\n \n
\n
\n
\n
\n
\n
\n \n
\n
\n
\n \n \n\n
\n
\n
\n\n
\n\n \n \n \n \n\n
\n'}]); 14 | //# sourceMappingURL=ionic-modal-select.min.js.map -------------------------------------------------------------------------------- /dist/ionic-modal-select.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack:///ionic-modal-select.min.js","webpack:///webpack/bootstrap 1241f30cc22c1b6fab5d","webpack:///./src/main.js","webpack:///./src/ionic-modal-select.js","webpack:///./src/modal-template-multiple.html","webpack:///./src/modal-template.html"],"names":["modules","__webpack_require__","moduleId","installedModules","exports","module","id","loaded","call","m","c","p","compile","$compile","scope","iElement","iAttrs","x","$watch","$eval","value","html","contents","compileOnce","modalSelect","$ionicModal","$timeout","$filter","$parse","$templateCache","modalTemplateMultiple","modalTemplate","restrict","require","initialOptions","optionGetter","searchFilters","searchProperties","onSelect","onSearch","onReset","onClose","link","ngModelController","transclude","initialOptionsSetup","nv","multiple","allOptions","map","item","idx","angular","copy","options","updateListMode","useCollectionRepeat","shortList","length","shortListBreak","ui","parseInt","setFromProperty","optionProperty","onOptionSelect","clearSearchOnSelect","isChecked","multipleNullValue","modalTitle","okButton","hideReset","resetButton","cancelButton","loadListMessage","modalClass","headerFooterClass","selectedClass","itemClass","searchTemplate","hasSearch","searchValue","searchPlaceholder","subHeaderClass","cancelSearchButton","optionsExpression","match","Error","listExpr","listGetter","s","ov","$watchCollection","opt","querySelector","name","message","toString","this","inner","element","Element","prototype","remove","parentNode","removeChild","notFound","$render","$viewValue","getSelectedValue","option","val","undefined","setOption","oldValue","$setViewValue","newValue","modal","hide","then","showList","setFilter","filterId","forEach","filter","active","query","unsetValue","isFunction","setValues","checkedItems","v","k","push","oldValues","vals","unsetValues","closeModal","compareValues","a","b","equals","modalTpl","fromTemplate","get","hiddenCb","$on","on","show","whatToSearch","filteredOpts","actual","expected","_typeof","i","toLowerCase","indexOf","oldLen","newOpts","originalItem","find","it","clearSearch","copyOpt","$inject","Symbol","iterator","obj","constructor","directive"],"mappings":"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","file":"ionic-modal-select.min.js","sourcesContent":["/******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId])\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\texports: {},\n/******/ \t\t\tid: moduleId,\n/******/ \t\t\tloaded: false\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.loaded = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(0);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t\"use strict\";\n\t\n\t__webpack_require__(1);\n\n/***/ },\n/* 1 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\tcompile.$inject = [\"$compile\"];\n\tmodalSelect.$inject = [\"$ionicModal\", \"$timeout\", \"$filter\", \"$parse\", \"$templateCache\"];\n\tvar _typeof = typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol ? \"symbol\" : typeof obj; };\n\t\n\t/*!\n\t * Copyright 2015 Inmagik SRL.\n\t * http://www.inmagik.com/\n\t *\n\t * ionic-modal-select, v1.3.2\n\t * Modal select directive for Ionic framework.\n\t *\n\t * By @bianchimro\n\t *\n\t * Licensed under the MIT license. Please see LICENSE for more information.\n\t *\n\t */\n\t\n\tangular.module('ionic-modal-select', []).directive('compile', compile).directive('modalSelect', modalSelect);\n\t\n\tfunction compile($compile) {\n\t\treturn function (scope, iElement, iAttrs) {\n\t\t\tvar x = scope.$watch(function (scope) {\n\t\t\t\t// watch the 'compile' expression for changes\n\t\t\t\treturn scope.$eval(iAttrs.compile);\n\t\t\t}, function (value) {\n\t\t\t\t// when the 'compile' expression changes\n\t\t\t\t// assign it into the current DOM\n\t\t\t\tiElement.html(value);\n\t\n\t\t\t\t// compile the new DOM and link it to the current\n\t\t\t\t// scope.\n\t\t\t\t// NOTE: we only compile .childNodes so that\n\t\t\t\t// we don't get into infinite loop compiling ourselves\n\t\t\t\t$compile(iElement.contents())(scope);\n\t\n\t\t\t\t//deactivate watch if \"compile-once\" is set to \"true\"\n\t\t\t\tif (iAttrs.compileOnce === 'true') {\n\t\t\t\t\tx();\n\t\t\t\t}\n\t\t\t});\n\t\t};\n\t}\n\t\n\tfunction modalSelect($ionicModal, $timeout, $filter, $parse, $templateCache) {\n\t\n\t\tvar modalTemplateMultiple = __webpack_require__(2);\n\t\tvar modalTemplate = __webpack_require__(3);\n\t\n\t\treturn {\n\t\t\trestrict: 'A',\n\t\t\trequire: 'ngModel',\n\t\t\tscope: {\n\t\t\t\tinitialOptions: \"=options\",\n\t\t\t\toptionGetter: \"&\",\n\t\t\t\tsearchFilters: \"=searchFilters\",\n\t\t\t\tsearchProperties: '=',\n\t\t\t\tonSelect: \"&\",\n\t\t\t\tonSearch: \"&\",\n\t\t\t\tonReset: \"&\",\n\t\t\t\tonClose: \"&\"\n\t\t\t},\n\t\t\tlink: function link(scope, iElement, iAttrs, ngModelController, transclude) {\n\t\n\t\t\t\tvar shortList = true;\n\t\t\t\tvar shortListBreak = iAttrs.shortListBreak ? parseInt(iAttrs.shortListBreak) : 10;\n\t\t\t\tvar setFromProperty = iAttrs.optionProperty;\n\t\t\t\tvar onOptionSelect = iAttrs.optionGetter;\n\t\t\t\tvar clearSearchOnSelect = iAttrs.clearSearchOnSelect !== \"false\" ? true : false;\n\t\t\t\tvar searchProperties = scope.searchProperties ? scope.searchProperties : false;\n\t\n\t\t\t\t//multiple values settings.\n\t\t\t\tvar multiple = iAttrs.multiple ? true : false;\n\t\t\t\tif (multiple) {\n\t\t\t\t\tscope.isChecked = {};\n\t\t\t\t}\n\t\t\t\tvar multipleNullValue = iAttrs.multipleNullValue ? scope.$eval(iAttrs.multipleNullValue) : [];\n\t\n\t\t\t\tscope.ui = {\n\t\t\t\t\tmodalTitle: iAttrs.modalTitle || 'Select an option',\n\t\t\t\t\tokButton: iAttrs.okButton || 'OK',\n\t\t\t\t\thideReset: iAttrs.hideReset !== \"true\" ? false : true,\n\t\t\t\t\tresetButton: iAttrs.resetButton || 'Reset',\n\t\t\t\t\tcancelButton: iAttrs.cancelButton || 'Cancel',\n\t\t\t\t\tloadListMessage: iAttrs.loadListMessage || 'Loading',\n\t\t\t\t\tmodalClass: iAttrs.modalClass || '',\n\t\t\t\t\theaderFooterClass: iAttrs.headerFooterClass || 'bar-stable',\n\t\t\t\t\tvalue: null,\n\t\t\t\t\tselectedClass: iAttrs.selectedClass || 'option-selected',\n\t\t\t\t\titemClass: iAttrs.itemClass || 'item item-text-wrap',\n\t\t\t\t\tsearchTemplate: iAttrs.searchTemplate || (multiple ? modalTemplateMultiple : modalTemplate),\n\t\n\t\t\t\t\t//search stuff\n\t\t\t\t\thasSearch: iAttrs.hasSearch !== \"true\" ? false : true,\n\t\t\t\t\tsearchValue: '',\n\t\t\t\t\tsearchPlaceholder: iAttrs.searchPlaceholder || 'Search',\n\t\t\t\t\tsubHeaderClass: iAttrs.subHeaderClass || 'bar-stable',\n\t\t\t\t\tcancelSearchButton: iAttrs.cancelSearchButton || 'Clear'\n\t\n\t\t\t\t};\n\t\n\t\t\t\tvar allOptions = [];\n\t\t\t\tscope.options = [];\n\t\n\t\t\t\tif (iAttrs.optionsExpression) {\n\t\t\t\t\tvar optionsExpression = iAttrs.optionsExpression;\n\t\t\t\t\tvar match = optionsExpression.match(/^\\s*([\\s\\S]+?)\\s+in\\s+([\\s\\S]+?)(?:\\s+track\\s+by\\s+([\\s\\S]+?))?\\s*$/);\n\t\t\t\t\tif (!match) {\n\t\t\t\t\t\tthrow new Error(\"collection-repeat expected expression in form of '_item_ in \" + \"_collection_[ track by _id_]' but got '\" + iAttrs.optionsExpression + \"'.\");\n\t\t\t\t\t}\n\t\t\t\t\t//var keyExpr = match[1];\n\t\t\t\t\tvar listExpr = match[2];\n\t\t\t\t\tvar listGetter = $parse(listExpr);\n\t\t\t\t\tvar s = iElement.scope();\n\t\n\t\t\t\t\tscope.$watch(function () {\n\t\t\t\t\t\treturn listGetter(s);\n\t\t\t\t\t}, function (nv, ov) {\n\t\t\t\t\t\tinitialOptionsSetup(nv);\n\t\t\t\t\t\tupdateListMode();\n\t\t\t\t\t}, true);\n\t\t\t\t} else {\n\t\t\t\t\tscope.$watchCollection('initialOptions', function (nv) {\n\t\t\t\t\t\tinitialOptionsSetup(nv);\n\t\t\t\t\t\tupdateListMode();\n\t\t\t\t\t});\n\t\t\t\t}\n\t\n\t\t\t\t//#TODO: this is due to different single vs multiple template\n\t\t\t\t//but adds lots of complexity here and in search\n\t\t\t\tfunction initialOptionsSetup(nv) {\n\t\t\t\t\tnv = nv || [];\n\t\t\t\t\tif (!multiple) {\n\t\t\t\t\t\tallOptions = angular.copy(nv);\n\t\t\t\t\t\tscope.options = angular.copy(nv);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tallOptions = nv.map(function (item, idx) {\n\t\t\t\t\t\t\treturn [idx, angular.copy(item)];\n\t\t\t\t\t\t});\n\t\t\t\t\t\tscope.options = angular.copy(allOptions);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\t// getting options template\n\t\t\t\tvar opt = iElement[0].querySelector('.option');\n\t\t\t\tif (!opt) {\n\t\t\t\t\tthrow new Error({\n\t\t\t\t\t\tname: 'modalSelectError:noOptionTemplate',\n\t\t\t\t\t\tmessage: 'When using modalSelect directive you must include an element with class \"option\"\\n\\t\\t\\t\\t\\t\\t to provide a template for your select options.',\n\t\t\t\t\t\ttoString: function toString() {\n\t\t\t\t\t\t\treturn this.name + \" \" + this.message;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tscope.inner = angular.element(opt).html();\n\t\n\t\t\t\t//add support for .remove for older devices\n\t\t\t\tif (!('remove' in Element.prototype)) {\n\t\t\t\t\tElement.prototype.remove = function () {\n\t\t\t\t\t\tthis.parentNode.removeChild(this);\n\t\t\t\t\t};\n\t\t\t\t}\n\t\n\t\t\t\tangular.element(opt).remove();\n\t\n\t\t\t\tvar notFound = iElement[0].querySelector('.not-found');\n\t\t\t\tif (notFound) {\n\t\t\t\t\tscope.notFound = angular.element(notFound).html();\n\t\t\t\t\tangular.element(notFound).remove();\n\t\t\t\t}\n\t\n\t\t\t\tfunction updateListMode() {\n\t\t\t\t\t//shortList controls wether using ng-repeat instead of collection-repeat\n\t\t\t\t\tif (iAttrs.useCollectionRepeat === \"true\") {\n\t\t\t\t\t\tshortList = false;\n\t\t\t\t\t} else if (iAttrs.useCollectionRepeat === \"false\") {\n\t\t\t\t\t\tshortList = true;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (typeof scope.options !== \"undefined\") {\n\t\t\t\t\t\t\tshortList = !!(scope.options.length < shortListBreak);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\n\t\t\t\t\tscope.ui.shortList = shortList;\n\t\t\t\t}\n\t\n\t\t\t\tngModelController.$render = function () {\n\t\t\t\t\tscope.ui.value = ngModelController.$viewValue;\n\t\t\t\t};\n\t\n\t\t\t\tvar getSelectedValue = scope.getSelectedValue = function (option) {\n\t\t\t\t\tvar val = null;\n\t\t\t\t\tif (option === null || option === undefined) {\n\t\t\t\t\t\treturn option;\n\t\t\t\t\t}\n\t\t\t\t\tif (onOptionSelect) {\n\t\t\t\t\t\treturn scope.optionGetter({ option: option });\n\t\t\t\t\t}\n\t\t\t\t\tif (setFromProperty) {\n\t\t\t\t\t\tval = option[setFromProperty];\n\t\t\t\t\t} else {\n\t\t\t\t\t\tval = option;\n\t\t\t\t\t}\n\t\t\t\t\treturn val;\n\t\t\t\t};\n\t\n\t\t\t\tscope.setOption = function (option) {\n\t\t\t\t\tvar oldValue = ngModelController.$viewValue;\n\t\t\t\t\tvar val = getSelectedValue(option);\n\t\t\t\t\tngModelController.$setViewValue(val);\n\t\t\t\t\tngModelController.$render();\n\t\n\t\t\t\t\tif (scope.onSelect) {\n\t\t\t\t\t\tscope.onSelect({ newValue: val, oldValue: oldValue });\n\t\t\t\t\t}\n\t\t\t\t\tscope.modal.hide().then(function () {\n\t\t\t\t\t\tscope.showList = false;\n\t\t\t\t\t\tif (scope.ui.hasSearch) {\n\t\t\t\t\t\t\tif (clearSearchOnSelect) {\n\t\t\t\t\t\t\t\tscope.ui.searchValue = '';\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t};\n\t\n\t\t\t\t// Filter object {id: , active: }\n\t\t\t\t// Used as auxiliary query params when querying server for search results\n\t\t\t\tscope.setFilter = function (filterId) {\n\t\t\t\t\tangular.forEach(scope.searchFilters, function (filter) {\n\t\t\t\t\t\tif (filter.id == filterId) {\n\t\t\t\t\t\t\tfilter.active = !filter.active;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tfilter.active = false;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\n\t\t\t\t\t// Trigger another search when the search filters change\n\t\t\t\t\tif (scope.onSearch) {\n\t\t\t\t\t\tscope.onSearch({ query: scope.ui.searchValue });\n\t\t\t\t\t}\n\t\t\t\t};\n\t\n\t\t\t\tscope.unsetValue = function () {\n\t\t\t\t\t$timeout(function () {\n\t\t\t\t\t\tngModelController.$setViewValue(\"\");\n\t\t\t\t\t\tngModelController.$render();\n\t\t\t\t\t\tscope.modal.hide();\n\t\t\t\t\t\tscope.showList = false;\n\t\t\t\t\t\tif (scope.onReset && angular.isFunction(scope.onReset)) {\n\t\t\t\t\t\t\tscope.onReset();\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t};\n\t\n\t\t\t\tscope.setValues = function () {\n\t\t\t\t\tvar checkedItems = [];\n\t\t\t\t\tangular.forEach(scope.isChecked, function (v, k) {\n\t\t\t\t\t\tif (v) {\n\t\t\t\t\t\t\tcheckedItems.push(allOptions[k][1]);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\tvar oldValues = ngModelController.$viewValue;\n\t\t\t\t\tvar vals = checkedItems.map(function (item) {\n\t\t\t\t\t\treturn getSelectedValue(item);\n\t\t\t\t\t});\n\t\t\t\t\tngModelController.$setViewValue(vals);\n\t\t\t\t\tngModelController.$render();\n\t\n\t\t\t\t\tif (scope.onSelect) {\n\t\t\t\t\t\tscope.onSelect({ newValue: vals, oldValue: oldValues });\n\t\t\t\t\t}\n\t\t\t\t\tscope.modal.hide().then(function () {\n\t\t\t\t\t\tscope.showList = false;\n\t\t\t\t\t\tif (scope.ui.hasSearch) {\n\t\t\t\t\t\t\tif (clearSearchOnSelect) {\n\t\t\t\t\t\t\t\tscope.ui.searchValue = '';\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t};\n\t\n\t\t\t\tscope.unsetValues = function () {\n\t\t\t\t\t$timeout(function () {\n\t\t\t\t\t\tngModelController.$setViewValue(multipleNullValue);\n\t\t\t\t\t\tngModelController.$render();\n\t\t\t\t\t\tscope.isChecked = {};\n\t\t\t\t\t\tscope.modal.hide();\n\t\t\t\t\t\tscope.showList = false;\n\t\t\t\t\t\tif (scope.onReset && angular.isFunction(scope.onReset)) {\n\t\t\t\t\t\t\tscope.onReset();\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t};\n\t\n\t\t\t\tscope.closeModal = function () {\n\t\t\t\t\tscope.modal.hide().then(function () {\n\t\t\t\t\t\tscope.showList = false;\n\t\t\t\t\t});\n\t\t\t\t};\n\t\n\t\t\t\tscope.compareValues = function (a, b) {\n\t\t\t\t\treturn angular.equals(a, b);\n\t\t\t\t};\n\t\n\t\t\t\t//loading the modal\n\t\t\t\tvar modalTpl = null;\n\t\t\t\tif (iAttrs.searchTemplate) {\n\t\t\t\t\tscope.modal = $ionicModal.fromTemplate($templateCache.get(iAttrs.searchTemplate), { scope: scope });\n\t\t\t\t} else {\n\t\t\t\t\tmodalTpl = multiple ? modalTemplateMultiple : modalTemplate;\n\t\t\t\t\tscope.modal = $ionicModal.fromTemplate(modalTpl, { scope: scope });\n\t\t\t\t}\n\t\n\t\t\t\tvar hiddenCb = null;\n\t\t\t\tscope.$on('$destroy', function () {\n\t\t\t\t\tif (hiddenCb) {\n\t\t\t\t\t\thiddenCb();\n\t\t\t\t\t\thiddenCb = null;\n\t\t\t\t\t}\n\t\t\t\t\tscope.modal.remove();\n\t\t\t\t});\n\t\n\t\t\t\tif (scope.onClose && angular.isFunction(scope.onClose)) {\n\t\t\t\t\thiddenCb = scope.$on('modal.hidden', function () {\n\t\t\t\t\t\tscope.onClose();\n\t\t\t\t\t});\n\t\t\t\t}\n\t\n\t\t\t\tiElement.on('click', function () {\n\t\t\t\t\tif (shortList) {\n\t\t\t\t\t\tscope.showList = true;\n\t\t\t\t\t\tscope.modal.show();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tscope.modal.show().then(function () {\n\t\t\t\t\t\t\tscope.showList = true;\n\t\t\t\t\t\t\tscope.ui.shortList = shortList;\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t});\n\t\n\t\t\t\t//filter function\n\t\t\t\tif (scope.ui.hasSearch) {\n\t\t\t\t\tscope.$watch('ui.searchValue', function (nv) {\n\t\t\t\t\t\tvar whatToSearch;\n\t\t\t\t\t\tif (!multiple) {\n\t\t\t\t\t\t\twhatToSearch = allOptions;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\twhatToSearch = allOptions.map(function (item) {\n\t\t\t\t\t\t\t\treturn item[1];\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tif (iAttrs.onSearch) {\n\t\t\t\t\t\t\tscope.onSearch({ query: nv });\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tvar filteredOpts = $filter('filter')(whatToSearch, nv, function (actual, expected) {\n\t\t\t\t\t\t\t\tif (!actual) {\n\t\t\t\t\t\t\t\t\t// if actual is an empty string, empty object, null, or undefined\n\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (searchProperties) {\n\t\t\t\t\t\t\t\t\tif ((typeof actual === 'undefined' ? 'undefined' : _typeof(actual)) == 'object') {\n\t\t\t\t\t\t\t\t\t\tfor (var i = 0; i < searchProperties.length; i++) {\n\t\t\t\t\t\t\t\t\t\t\tif (actual[searchProperties[i]] && actual[searchProperties[i]].toLowerCase().indexOf(expected.toLowerCase()) >= 0) {\n\t\t\t\t\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tif (actual.toString().toLowerCase().indexOf(expected.toLowerCase()) >= 0) {\n\t\t\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t});\n\t\n\t\t\t\t\t\t\tvar oldLen = scope.options.length;\n\t\t\t\t\t\t\tif (!multiple) {\n\t\t\t\t\t\t\t\tscope.options = filteredOpts;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t//#TODO: lots of loops here!\n\t\t\t\t\t\t\t\tvar newOpts = [];\n\t\t\t\t\t\t\t\tangular.forEach(filteredOpts, function (item) {\n\t\t\t\t\t\t\t\t\tvar originalItem = allOptions.find(function (it) {\n\t\t\t\t\t\t\t\t\t\treturn it[1] == item;\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\tif (originalItem) {\n\t\t\t\t\t\t\t\t\t\tnewOpts.push(originalItem);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\tscope.options = newOpts;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (oldLen != scope.options.length) {\n\t\t\t\t\t\t\t\t//#todo: should resize scroll or scroll up here\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\tscope.clearSearch = function () {\n\t\t\t\t\t\tscope.ui.searchValue = '';\n\t\t\t\t\t};\n\t\t\t\t}\n\t\n\t\t\t\tscope.copyOpt = function (option) {\n\t\t\t\t\treturn angular.copy(option);\n\t\t\t\t};\n\t\n\t\t\t\t//#TODO ?: WRAP INTO $timeout?\n\t\t\t\tngModelController.$render();\n\t\t\t}\n\t\t};\n\t}\n\n/***/ },\n/* 2 */\n/***/ function(module, exports) {\n\n\tmodule.exports = \" \\n\\n \\n

{{::ui.modalTitle}}

\\n
\\n\\n
\\n \\n \\n
\\n\\n \\n
\\n

{{::ui.loadListMessage}}

\\n

\\n \\n

\\n
\\n\\n
\\n \\n \\n \\n\\n \\n
\\n
\\n \\n \\n
\\n
\\n
\\n
\\n \\n
\\n \\n \\n
\\n \\n
\\n \\n
\\n
\\n\"\n\n/***/ },\n/* 3 */\n/***/ function(module, exports) {\n\n\tmodule.exports = \" \\n\\n \\n

{{::ui.modalTitle}}

\\n
\\n\\n
\\n \\n \\n
\\n\\n \\n
\\n

{{::ui.loadListMessage}}

\\n

\\n \\n

\\n
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n \\n \\n\\n
\\n
\\n
\\n\\n
\\n\\n \\n \\n \\n \\n\\n
\\n\"\n\n/***/ }\n/******/ ]);\n\n\n/** WEBPACK FOOTER **\n ** ionic-modal-select.min.js\n **/"," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId])\n \t\t\treturn installedModules[moduleId].exports;\n\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\texports: {},\n \t\t\tid: moduleId,\n \t\t\tloaded: false\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.loaded = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(0);\n\n\n\n/** WEBPACK FOOTER **\n ** webpack/bootstrap 1241f30cc22c1b6fab5d\n **/","import \"./ionic-modal-select.js\";\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/main.js\n **/","/*!\n * Copyright 2015 Inmagik SRL.\n * http://www.inmagik.com/\n *\n * ionic-modal-select, v1.3.2\n * Modal select directive for Ionic framework.\n *\n * By @bianchimro\n *\n * Licensed under the MIT license. Please see LICENSE for more information.\n *\n */\n\nangular.module('ionic-modal-select', [])\n.directive('compile', compile)\n.directive('modalSelect', modalSelect);\n\n\nfunction compile($compile) {\n\treturn function(scope, iElement, iAttrs) {\n\t\tvar x = scope.$watch(\n\t\t\tfunction(scope) {\n\t\t\t\t// watch the 'compile' expression for changes\n\t\t\t\treturn scope.$eval(iAttrs.compile);\n\t\t\t},\n\t\t\tfunction(value) {\n\t\t\t\t// when the 'compile' expression changes\n\t\t\t\t// assign it into the current DOM\n\t\t\t\tiElement.html(value);\n\n\t\t\t\t// compile the new DOM and link it to the current\n\t\t\t\t// scope.\n\t\t\t\t// NOTE: we only compile .childNodes so that\n\t\t\t\t// we don't get into infinite loop compiling ourselves\n\t\t\t\t$compile(iElement.contents())(scope);\n\n\t\t\t\t//deactivate watch if \"compile-once\" is set to \"true\"\n\t\t\t\tif (iAttrs.compileOnce === 'true') {\n\t\t\t\t\tx();\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\t};\n}\n\n\nfunction modalSelect($ionicModal, $timeout, $filter, $parse, $templateCache ) {\n\n\t\tconst modalTemplateMultiple = require('raw!./modal-template-multiple.html');\n\t\tconst modalTemplate = require('raw!./modal-template.html');\n\n\t\treturn {\n\t\t\trestrict: 'A',\n\t\t\trequire : 'ngModel',\n\t\t\tscope: {\n\t\t\t\tinitialOptions:\"=options\",\n\t\t\t\toptionGetter:\"&\",\n\t\t\t\tsearchFilters: \"=searchFilters\",\n\t\t\t\tsearchProperties:'=',\n\t\t\t\tonSelect: \"&\",\n\t\t\t\tonSearch: \"&\",\n\t\t\t\tonReset: \"&\",\n\t\t\t\tonClose: \"&\",\n\t\t\t},\n\t\t\tlink: function (scope, iElement, iAttrs, ngModelController, transclude) {\n\n\t\t\t\tvar shortList = true;\n\t\t\t\tvar shortListBreak = iAttrs.shortListBreak ? parseInt(iAttrs.shortListBreak) : 10;\n\t\t\t\tvar setFromProperty= iAttrs.optionProperty;\n\t\t\t\tvar onOptionSelect = iAttrs.optionGetter;\n\t\t\t\tvar clearSearchOnSelect = iAttrs.clearSearchOnSelect !== \"false\" ? true : false;\n\t\t\t\tvar searchProperties = scope.searchProperties ? scope.searchProperties : false;\n\n\t\t\t\t//multiple values settings.\n\t\t\t\tvar multiple = iAttrs.multiple ? true : false;\n\t\t\t\tif (multiple) {\n\t\t\t\t\t\tscope.isChecked = {};\n\t\t\t\t}\n\t\t\t\tvar multipleNullValue = iAttrs.multipleNullValue ? scope.$eval(iAttrs.multipleNullValue) : [];\n\n\t\t\t\tscope.ui = {\n\t\t\t\t\tmodalTitle : iAttrs.modalTitle || 'Select an option',\n\t\t\t\t\tokButton : iAttrs.okButton || 'OK',\n\t\t\t\t\thideReset : iAttrs.hideReset !== \"true\" ? false : true,\n\t\t\t\t\tresetButton : iAttrs.resetButton || 'Reset',\n\t\t\t\t\tcancelButton : iAttrs.cancelButton || 'Cancel',\n\t\t\t\t\tloadListMessage : iAttrs.loadListMessage || 'Loading',\n\t\t\t\t\tmodalClass : iAttrs.modalClass || '',\n\t\t\t\t\theaderFooterClass : iAttrs.headerFooterClass || 'bar-stable',\n\t\t\t\t\tvalue : null,\n\t\t\t\t\tselectedClass : iAttrs.selectedClass || 'option-selected',\n\t\t\t\t\titemClass: iAttrs.itemClass || 'item item-text-wrap',\n\t\t\t\t\tsearchTemplate: iAttrs.searchTemplate || (multiple ? modalTemplateMultiple : modalTemplate),\n\n\t\t\t\t\t//search stuff\n\t\t\t\t\thasSearch : iAttrs.hasSearch !== \"true\" ? false : true,\n\t\t\t\t\tsearchValue : '',\n\t\t\t\t\tsearchPlaceholder : iAttrs.searchPlaceholder || 'Search',\n\t\t\t\t\tsubHeaderClass : iAttrs.subHeaderClass || 'bar-stable',\n\t\t\t\t\tcancelSearchButton : iAttrs.cancelSearchButton || 'Clear'\n\n\t\t\t\t};\n\n\t\t\t\tvar allOptions = [];\n\t\t\t\tscope.options = [];\n\n\t\t\t\tif (iAttrs.optionsExpression) {\n\t\t\t\t\t\tvar optionsExpression = iAttrs.optionsExpression;\n\t\t\t\t\t\tvar match = optionsExpression.match(/^\\s*([\\s\\S]+?)\\s+in\\s+([\\s\\S]+?)(?:\\s+track\\s+by\\s+([\\s\\S]+?))?\\s*$/);\n\t\t\t\t\t\tif (!match) {\n\t\t\t\t\t\t\t\tthrow new Error(\"collection-repeat expected expression in form of '_item_ in \" +\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"_collection_[ track by _id_]' but got '\" + iAttrs.optionsExpression + \"'.\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\t//var keyExpr = match[1];\n\t\t\t\t\t\tvar listExpr = match[2];\n\t\t\t\t\t\tvar listGetter = $parse(listExpr);\n\t\t\t\t\t\tvar s = iElement.scope();\n\n\t\t\t\t\t\tscope.$watch(\n\t\t\t\t\t\t\t\t() => {\n\t\t\t\t\t\t\t\t\t\treturn listGetter(s);\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t(nv, ov) => {\n\t\t\t\t\t\t\t\t\t\tinitialOptionsSetup(nv);\n\t\t\t\t\t\t\t\t\t\tupdateListMode();\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\ttrue\n\t\t\t\t\t\t);\n\n\t\t\t\t} else {\n\t\t\t\t\t\tscope.$watchCollection('initialOptions', function(nv){\n\t\t\t\t\t\t\t\tinitialOptionsSetup(nv);\n\t\t\t\t\t\t\t\tupdateListMode();\n\t\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t//#TODO: this is due to different single vs multiple template\n\t\t\t\t//but adds lots of complexity here and in search\n\t\t\t\tfunction initialOptionsSetup(nv){\n\t\t\t\t\t\tnv = nv || [];\n\t\t\t\t\t\tif ( !multiple ) {\n\t\t\t\t\t\t\t\tallOptions = angular.copy(nv);\n\t\t\t\t\t\t\t\tscope.options = angular.copy(nv);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tallOptions = nv.map((item, idx) => [idx, angular.copy(item)] );\n\t\t\t\t\t\t\t\tscope.options = angular.copy(allOptions);\n\t\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// getting options template\n\t\t\t\tvar opt = iElement[0].querySelector('.option');\n\t\t\t\tif (!opt) {\n\t\t\t\t\tthrow new Error({\n\t\t\t\t\t\tname:'modalSelectError:noOptionTemplate',\n\t\t\t\t\t\tmessage:`When using modalSelect directive you must include an element with class \"option\"\n\t\t\t\t\t\t to provide a template for your select options.`,\n\t\t\t\t\t\ttoString:function(){\n\t\t\t\t\t\t\treturn this.name + \" \" + this.message;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tscope.inner = angular.element(opt).html();\n\n\t\t\t\t//add support for .remove for older devices\n\t\t\t\tif (!('remove' in Element.prototype)) {\n\t\t\t\t\tElement.prototype.remove = function() {\n\t\t\t\t\t\tthis.parentNode.removeChild(this);\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tangular.element(opt).remove();\n\n\t\t\t\tvar notFound = iElement[0].querySelector('.not-found');\n\t\t\t\tif(notFound) {\n\t\t\t\t\tscope.notFound = angular.element(notFound).html();\n\t\t\t\t\tangular.element(notFound).remove();\n\t\t\t\t}\n\n\t\t\t\tfunction updateListMode(){\n\t\t\t\t\t//shortList controls wether using ng-repeat instead of collection-repeat\n\t\t\t\t\tif (iAttrs.useCollectionRepeat === \"true\") {\n\t\t\t\t\t\tshortList = false;\n\t\t\t\t\t} else if (iAttrs.useCollectionRepeat === \"false\") {\n\t\t\t\t\t\tshortList = true;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (typeof(scope.options) !==\"undefined\"){\n\t\t\t\t\t\t\tshortList = !!(scope.options.length < shortListBreak);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tscope.ui.shortList = shortList;\n\t\t\t\t}\n\n\t\t\t\tngModelController.$render = function(){\n\t\t\t\t\tscope.ui.value = ngModelController.$viewValue;\n\t\t\t\t};\n\n\t\t\t\tvar getSelectedValue = scope.getSelectedValue = function(option){\n\t\t\t\t\tvar val = null;\n\t\t\t\t\tif (option === null || option === undefined) {\n\t\t\t\t\t\treturn option;\n\t\t\t\t\t}\n\t\t\t\t\tif (onOptionSelect) {\n\t\t\t\t\t\treturn scope.optionGetter({option:option});\n\t\t\t\t\t}\n\t\t\t\t\tif (setFromProperty) {\n\t\t\t\t\t\tval = option[setFromProperty];\n\t\t\t\t\t} else {\n\t\t\t\t\t\tval = option;\n\t\t\t\t\t}\n\t\t\t\t\treturn val;\n\t\t\t\t};\n\n\t\t\t\tscope.setOption = function(option){\n\t\t\t\t\tvar oldValue = ngModelController.$viewValue;\n\t\t\t\t\tvar val = getSelectedValue(option);\n\t\t\t\t\tngModelController.$setViewValue(val);\n\t\t\t\t\tngModelController.$render();\n\n\t\t\t\t\tif (scope.onSelect) {\n\t\t\t\t\t\tscope.onSelect({ newValue: val, oldValue: oldValue });\n\t\t\t\t\t}\n\t\t\t\t\tscope.modal.hide().then(function(){\n\t\t\t\t\t\tscope.showList = false;\n\t\t\t\t\t\tif (scope.ui.hasSearch) {\n\t\t\t\t\t\t\tif(clearSearchOnSelect) {\n\t\t\t\t\t\t\t\tscope.ui.searchValue = '';\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t};\n\n\t\t\t\t// Filter object {id: , active: }\n\t\t\t\t// Used as auxiliary query params when querying server for search results\n\t\t\t\tscope.setFilter = function(filterId) {\n\t\t\t\t\tangular.forEach(scope.searchFilters, function(filter) {\n\t\t\t\t\t\tif(filter.id == filterId) {\n\t\t\t\t\t\t\tfilter.active = !filter.active;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tfilter.active = false;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\n\t\t\t\t\t// Trigger another search when the search filters change\n\t\t\t\t\tif(scope.onSearch) {\n\t\t\t\t\t\tscope.onSearch({query: scope.ui.searchValue});\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\tscope.unsetValue = function(){\n\t\t\t\t\t$timeout(function(){\n\t\t\t\t\t\tngModelController.$setViewValue(\"\");\n\t\t\t\t\t\tngModelController.$render();\n\t\t\t\t\t\tscope.modal.hide();\n\t\t\t\t\t\tscope.showList = false;\n\t\t\t\t\t\tif (scope.onReset && angular.isFunction(scope.onReset)) {\n\t\t\t\t\t\t\tscope.onReset();\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t};\n\n\t\t\t\tscope.setValues = function(){\n\t\t\t\t\t\tvar checkedItems = [];\n\t\t\t\t\t\tangular.forEach(scope.isChecked, function(v, k){\n\t\t\t\t\t\t\t\tif(v){\n\t\t\t\t\t\t\t\t\t\tcheckedItems.push(allOptions[k][1])\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t\tvar oldValues = ngModelController.$viewValue;\n\t\t\t\t\t\tvar vals = checkedItems.map(function(item){\n\t\t\t\t\t\t\t\treturn getSelectedValue(item);\n\t\t\t\t\t\t});\n\t\t\t\t\t\tngModelController.$setViewValue(vals);\n\t\t\t\t\t\tngModelController.$render();\n\n\t\t\t\t\t\tif (scope.onSelect) {\n\t\t\t\t\t\t\t\tscope.onSelect({ newValue: vals, oldValue: oldValues });\n\t\t\t\t\t\t}\n\t\t\t\t\t\tscope.modal.hide().then(function(){\n\t\t\t\t\t\t\t\tscope.showList = false;\n\t\t\t\t\t\t\t\tif (scope.ui.hasSearch) {\n\t\t\t\t\t\t\t\t\t if(clearSearchOnSelect){\n\t\t\t\t\t\t\t\t\t\t\t\tscope.ui.searchValue = '';\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\n\t\t\t\t};\n\n\t\t\t\tscope.unsetValues = function(){\n\t\t\t\t\t\t$timeout(function(){\n\t\t\t\t\t\t\t\tngModelController.$setViewValue(multipleNullValue);\n\t\t\t\t\t\t\t\tngModelController.$render();\n\t\t\t\t\t\t\t\tscope.isChecked = {};\n\t\t\t\t\t\t\t\tscope.modal.hide();\n\t\t\t\t\t\t\t\tscope.showList = false;\n\t\t\t\t\t\t\t\tif (scope.onReset && angular.isFunction(scope.onReset)) {\n\t\t\t\t\t\t\t\t\t\tscope.onReset();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t};\n\n\t\t\t\tscope.closeModal = function(){\n\t\t\t\t\tscope.modal.hide().then(function(){\n\t\t\t\t\t\tscope.showList = false;\n\t\t\t\t\t});\n\t\t\t\t};\n\n\n\t\t\t\tscope.compareValues = function(a, b){\n\t\t\t\t\treturn angular.equals(a, b);\n\t\t\t\t};\n\n\t\t\t\t//loading the modal\n\t\t\t\tvar modalTpl = null;\n\t\t\t\tif(iAttrs.searchTemplate) {\n\t\t\t\t\tscope.modal = $ionicModal.fromTemplate(\n\t\t\t\t\t\t$templateCache.get(iAttrs.searchTemplate),\n\t\t\t\t\t\t{ scope: scope }\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tmodalTpl = multiple ? modalTemplateMultiple : modalTemplate;\n\t\t\t\t\tscope.modal = $ionicModal.fromTemplate(\n\t\t\t\t\t\tmodalTpl,\n\t\t\t\t\t\t{ scope: scope }\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tlet hiddenCb = null;\n\t\t\t\tscope.$on('$destroy', function(){\n\t\t\t\t\tif(hiddenCb){\n\t\t\t\t\t\t\thiddenCb();\n\t\t\t\t\t\t\thiddenCb = null;\n\t\t\t\t\t}\n\t\t\t\t\tscope.modal.remove();\n\t\t\t\t});\n\n\t\t\t\tif (scope.onClose && angular.isFunction(scope.onClose)) {\n\t\t\t\t\thiddenCb = scope.$on('modal.hidden', function(){\n\t\t\t\t\t\tscope.onClose();\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tiElement.on('click', function(){\n\t\t\t\t\tif (shortList) {\n\t\t\t\t\t\tscope.showList = true;\n\t\t\t\t\t\tscope.modal.show();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tscope.modal.show()\n\t\t\t\t\t\t\t.then(function(){\n\t\t\t\t\t\t\t\tscope.showList = true;\n\t\t\t\t\t\t\t\tscope.ui.shortList = shortList;\n\t\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t});\n\n\n\t\t\t\t//filter function\n\t\t\t\tif (scope.ui.hasSearch) {\n\t\t\t\t\tscope.$watch('ui.searchValue', function(nv){\n\t\t\t\t\t\tvar whatToSearch;\n\t\t\t\t\t\tif ( !multiple ) {\n\t\t\t\t\t\t\t\twhatToSearch = allOptions;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\twhatToSearch = allOptions.map(function(item){\n\t\t\t\t\t\t\t\t\t\treturn item[1];\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif(iAttrs.onSearch) {\n\t\t\t\t\t\t\t\tscope.onSearch({query: nv});\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tvar filteredOpts = $filter('filter')(whatToSearch, nv, function(actual, expected) {\n\t\t\t\t\t\t\t\tif(!actual){\n\t\t\t\t\t\t\t\t\t// if actual is an empty string, empty object, null, or undefined\n\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (searchProperties){\n\t\t\t\t\t\t\t\t\tif (typeof actual == 'object'){\n\t\t\t\t\t\t\t\t\t\tfor (var i = 0; i < searchProperties.length; i++){\n\t\t\t\t\t\t\t\t\t\t\tif (actual[searchProperties[i]] && actual[searchProperties[i]].toLowerCase().indexOf(expected.toLowerCase()) >= 0){\n\t\t\t\t\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tif(actual.toString().toLowerCase().indexOf(expected.toLowerCase()) >= 0){\n\t\t\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tvar oldLen = scope.options.length;\n\t\t\t\t\t\t\tif ( !multiple ){\n\t\t\t\t\t\t\t\t\tscope.options = filteredOpts;\n\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t//#TODO: lots of loops here!\n\t\t\t\t\t\t\t\t\tvar newOpts = [];\n\t\t\t\t\t\t\t\t\tangular.forEach(filteredOpts, function(item){\n\t\t\t\t\t\t\t\t\t\t\tvar originalItem = allOptions.find(function(it){\n\t\t\t\t\t\t\t\t\t\t\t\t\treturn it[1] == item;\n\t\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t\t\tif( originalItem ){\n\t\t\t\t\t\t\t\t\t\t\t\t\tnewOpts.push(originalItem);\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\tscope.options = newOpts;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(oldLen != scope.options.length){\n\t\t\t\t\t\t\t\t//#todo: should resize scroll or scroll up here\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\tscope.clearSearch = function(){\n\t\t\t\t\t\tscope.ui.searchValue = '';\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tscope.copyOpt = option => {\n\t\t\t\t\treturn angular.copy(option);\n\t\t\t\t}\n\n\t\t\t\t//#TODO ?: WRAP INTO $timeout?\n\t\t\t\tngModelController.$render();\n\n\t\t\t}\n\t\t};\n\t}\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/ionic-modal-select.js\n **/","module.exports = \" \\n\\n \\n

{{::ui.modalTitle}}

\\n
\\n\\n
\\n \\n \\n
\\n\\n \\n
\\n

{{::ui.loadListMessage}}

\\n

\\n \\n

\\n
\\n\\n
\\n \\n \\n \\n\\n \\n
\\n
\\n \\n \\n
\\n
\\n
\\n
\\n \\n
\\n \\n \\n
\\n \\n
\\n \\n
\\n
\\n\"\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./~/raw-loader!./src/modal-template-multiple.html\n ** module id = 2\n ** module chunks = 0\n **/","module.exports = \" \\n\\n \\n

{{::ui.modalTitle}}

\\n
\\n\\n
\\n \\n \\n
\\n\\n \\n
\\n

{{::ui.loadListMessage}}

\\n

\\n \\n

\\n
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n \\n \\n\\n
\\n
\\n
\\n\\n
\\n\\n \\n \\n \\n \\n\\n
\\n\"\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./~/raw-loader!./src/modal-template.html\n ** module id = 3\n ** module chunks = 0\n **/"],"sourceRoot":""} -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var concat = require('gulp-concat'); 3 | var minifyCss = require('gulp-minify-css'); 4 | var rename = require('gulp-rename'); 5 | var addsrc = require('gulp-add-src'); 6 | var replace = require('gulp-replace'); 7 | var uglify = require('gulp-uglify'); 8 | var order = require("gulp-order"); 9 | var plumber = require("gulp-plumber"); 10 | 11 | var webpackStream = require('webpack-stream'); 12 | var webpack = require("webpack"); 13 | // Import at the top of the file 14 | var karma = require('karma').Server; 15 | 16 | var paths = { 17 | es6: ['./src/*.js'], 18 | webpack: ['./src/main.js'], 19 | templates : ['./src/*.html'], 20 | output: './dist', 21 | }; 22 | 23 | var webPackConfig = require('./webpack.config'); 24 | var webPackConfigProduction = require('./webpack.config.production'); 25 | 26 | 27 | // use webpack.config.js to build modules 28 | gulp.task('webpack', () => { 29 | return gulp.src(paths.webpack) 30 | .pipe(plumber()) 31 | .pipe(webpackStream(webPackConfig)) 32 | .pipe(gulp.dest(paths.output)) 33 | }); 34 | 35 | gulp.task('webpack-production', () => { 36 | return gulp.src(paths.webpack) 37 | .pipe(plumber()) 38 | .pipe(webpackStream(webPackConfigProduction)) 39 | .pipe(gulp.dest(paths.output)) 40 | }); 41 | 42 | 43 | /** 44 | * Test task, run test once and exit 45 | */ 46 | gulp.task('test', function(done) { 47 | var config = { 48 | configFile: __dirname + '/tests/my.conf.js', 49 | singleRun: true 50 | }; 51 | var server = new karma(config); 52 | server.start(); 53 | }); 54 | 55 | 56 | gulp.task('watch', function() { 57 | gulp.watch([paths.es6, paths.templates], ['webpack', 'webpack-production']); 58 | }); 59 | 60 | gulp.task('default', ['webpack', 'webpack-production']); 61 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ionic-modal-select", 3 | "version": "1.3.1", 4 | "description": "Modal select for ionic", 5 | "scripts": {}, 6 | "author": "bianchimro@gmail.com", 7 | "license": "MIT", 8 | "devDependencies": { 9 | "babel-loader": "^6.2.5", 10 | "css-loader": "^0.25.0", 11 | "gulp": "^3.9.0", 12 | "gulp-add-src": "^0.2.0", 13 | "gulp-concat": "^2.6.0", 14 | "gulp-order": "^1.1.1", 15 | "gulp-plumber": "^1.1.0", 16 | "gulp-rename": "^1.2.2", 17 | "gulp-replace": "^0.5.4", 18 | "gulp-uglify": "^1.3.0", 19 | "html-loader": "^0.4.4", 20 | "jasmine-core": "^2.3.4", 21 | "karma": "^0.13.15", 22 | "karma-jasmine": "^0.3.6", 23 | "karma-phantomjs-launcher": "^0.2.1", 24 | "ng-annotate": "^1.2.1", 25 | "ng-annotate-loader": "^0.1.1", 26 | "phantomjs": "^1.9.18", 27 | "raw-loader": "^0.5.1", 28 | "webpack-stream": "^3.2.0" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/ionic-modal-select.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright 2015 Inmagik SRL. 3 | * http://www.inmagik.com/ 4 | * 5 | * ionic-modal-select, v1.3.2 6 | * Modal select directive for Ionic framework. 7 | * 8 | * By @bianchimro 9 | * 10 | * Licensed under the MIT license. Please see LICENSE for more information. 11 | * 12 | */ 13 | 14 | angular.module('ionic-modal-select', []) 15 | .directive('compile', compile) 16 | .directive('modalSelect', modalSelect); 17 | 18 | 19 | function compile($compile) { 20 | return function(scope, iElement, iAttrs) { 21 | var x = scope.$watch( 22 | function(scope) { 23 | // watch the 'compile' expression for changes 24 | return scope.$eval(iAttrs.compile); 25 | }, 26 | function(value) { 27 | // when the 'compile' expression changes 28 | // assign it into the current DOM 29 | iElement.html(value); 30 | 31 | // compile the new DOM and link it to the current 32 | // scope. 33 | // NOTE: we only compile .childNodes so that 34 | // we don't get into infinite loop compiling ourselves 35 | $compile(iElement.contents())(scope); 36 | 37 | //deactivate watch if "compile-once" is set to "true" 38 | if (iAttrs.compileOnce === 'true') { 39 | x(); 40 | } 41 | } 42 | ); 43 | }; 44 | } 45 | 46 | 47 | function modalSelect($ionicModal, $timeout, $filter, $parse, $templateCache ) { 48 | 49 | const modalTemplateMultiple = require('raw!./modal-template-multiple.html'); 50 | const modalTemplate = require('raw!./modal-template.html'); 51 | 52 | return { 53 | restrict: 'A', 54 | require : 'ngModel', 55 | scope: { 56 | initialOptions:"=options", 57 | optionGetter:"&", 58 | searchFilters: "=searchFilters", 59 | searchProperties:'=', 60 | onSelect: "&", 61 | onSearch: "&", 62 | onReset: "&", 63 | onClose: "&", 64 | }, 65 | link: function (scope, iElement, iAttrs, ngModelController, transclude) { 66 | 67 | var shortList = true; 68 | var shortListBreak = iAttrs.shortListBreak ? parseInt(iAttrs.shortListBreak) : 10; 69 | var setFromProperty= iAttrs.optionProperty; 70 | var onOptionSelect = iAttrs.optionGetter; 71 | var clearSearchOnSelect = iAttrs.clearSearchOnSelect !== "false" ? true : false; 72 | var searchProperties = scope.searchProperties ? scope.searchProperties : false; 73 | 74 | //multiple values settings. 75 | var multiple = iAttrs.multiple ? true : false; 76 | if (multiple) { 77 | scope.isChecked = {}; 78 | } 79 | var multipleNullValue = iAttrs.multipleNullValue ? scope.$eval(iAttrs.multipleNullValue) : []; 80 | 81 | scope.ui = { 82 | modalTitle : iAttrs.modalTitle || 'Select an option', 83 | okButton : iAttrs.okButton || 'OK', 84 | hideReset : iAttrs.hideReset !== "true" ? false : true, 85 | resetButton : iAttrs.resetButton || 'Reset', 86 | cancelButton : iAttrs.cancelButton || 'Cancel', 87 | loadListMessage : iAttrs.loadListMessage || 'Loading', 88 | modalClass : iAttrs.modalClass || '', 89 | headerFooterClass : iAttrs.headerFooterClass || 'bar-stable', 90 | value : null, 91 | selectedClass : iAttrs.selectedClass || 'option-selected', 92 | itemClass: iAttrs.itemClass || 'item item-text-wrap', 93 | searchTemplate: iAttrs.searchTemplate || (multiple ? modalTemplateMultiple : modalTemplate), 94 | 95 | //search stuff 96 | hasSearch : iAttrs.hasSearch !== "true" ? false : true, 97 | searchValue : '', 98 | searchPlaceholder : iAttrs.searchPlaceholder || 'Search', 99 | subHeaderClass : iAttrs.subHeaderClass || 'bar-stable', 100 | cancelSearchButton : iAttrs.cancelSearchButton || 'Clear' 101 | 102 | }; 103 | 104 | var allOptions = []; 105 | scope.options = []; 106 | 107 | if (iAttrs.optionsExpression) { 108 | var optionsExpression = iAttrs.optionsExpression; 109 | var match = optionsExpression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/); 110 | if (!match) { 111 | throw new Error("collection-repeat expected expression in form of '_item_ in " + 112 | "_collection_[ track by _id_]' but got '" + iAttrs.optionsExpression + "'."); 113 | } 114 | //var keyExpr = match[1]; 115 | var listExpr = match[2]; 116 | var listGetter = $parse(listExpr); 117 | var s = iElement.scope(); 118 | 119 | scope.$watch( 120 | () => { 121 | return listGetter(s); 122 | }, 123 | (nv, ov) => { 124 | initialOptionsSetup(nv); 125 | updateListMode(); 126 | }, 127 | true 128 | ); 129 | 130 | } else { 131 | scope.$watchCollection('initialOptions', function(nv){ 132 | initialOptionsSetup(nv); 133 | updateListMode(); 134 | }); 135 | } 136 | 137 | //#TODO: this is due to different single vs multiple template 138 | //but adds lots of complexity here and in search 139 | function initialOptionsSetup(nv){ 140 | nv = nv || []; 141 | if ( !multiple ) { 142 | allOptions = angular.copy(nv); 143 | scope.options = angular.copy(nv); 144 | } else { 145 | allOptions = nv.map((item, idx) => [idx, angular.copy(item)] ); 146 | scope.options = angular.copy(allOptions); 147 | } 148 | } 149 | 150 | // getting options template 151 | var opt = iElement[0].querySelector('.option'); 152 | if (!opt) { 153 | throw new Error({ 154 | name:'modalSelectError:noOptionTemplate', 155 | message:`When using modalSelect directive you must include an element with class "option" 156 | to provide a template for your select options.`, 157 | toString:function(){ 158 | return this.name + " " + this.message; 159 | } 160 | }); 161 | } 162 | scope.inner = angular.element(opt).html(); 163 | 164 | //add support for .remove for older devices 165 | if (!('remove' in Element.prototype)) { 166 | Element.prototype.remove = function() { 167 | this.parentNode.removeChild(this); 168 | }; 169 | } 170 | 171 | angular.element(opt).remove(); 172 | 173 | var notFound = iElement[0].querySelector('.not-found'); 174 | if(notFound) { 175 | scope.notFound = angular.element(notFound).html(); 176 | angular.element(notFound).remove(); 177 | } 178 | 179 | function updateListMode(){ 180 | //shortList controls wether using ng-repeat instead of collection-repeat 181 | if (iAttrs.useCollectionRepeat === "true") { 182 | shortList = false; 183 | } else if (iAttrs.useCollectionRepeat === "false") { 184 | shortList = true; 185 | } else { 186 | if (typeof(scope.options) !=="undefined"){ 187 | shortList = !!(scope.options.length < shortListBreak); 188 | } 189 | } 190 | 191 | scope.ui.shortList = shortList; 192 | } 193 | 194 | ngModelController.$render = function(){ 195 | scope.ui.value = ngModelController.$viewValue; 196 | }; 197 | 198 | var getSelectedValue = scope.getSelectedValue = function(option){ 199 | var val = null; 200 | if (option === null || option === undefined) { 201 | return option; 202 | } 203 | if (onOptionSelect) { 204 | return scope.optionGetter({option:option}); 205 | } 206 | if (setFromProperty) { 207 | val = option[setFromProperty]; 208 | } else { 209 | val = option; 210 | } 211 | return val; 212 | }; 213 | 214 | scope.setOption = function(option){ 215 | var oldValue = ngModelController.$viewValue; 216 | var val = getSelectedValue(option); 217 | ngModelController.$setViewValue(val); 218 | ngModelController.$render(); 219 | 220 | if (scope.onSelect) { 221 | scope.onSelect({ newValue: val, oldValue: oldValue }); 222 | } 223 | scope.modal.hide().then(function(){ 224 | scope.showList = false; 225 | if (scope.ui.hasSearch) { 226 | if(clearSearchOnSelect) { 227 | scope.ui.searchValue = ''; 228 | } 229 | } 230 | }); 231 | }; 232 | 233 | // Filter object {id: , active: } 234 | // Used as auxiliary query params when querying server for search results 235 | scope.setFilter = function(filterId) { 236 | angular.forEach(scope.searchFilters, function(filter) { 237 | if(filter.id == filterId) { 238 | filter.active = !filter.active; 239 | } else { 240 | filter.active = false; 241 | } 242 | }); 243 | 244 | // Trigger another search when the search filters change 245 | if(scope.onSearch) { 246 | scope.onSearch({query: scope.ui.searchValue}); 247 | } 248 | }; 249 | 250 | scope.unsetValue = function(){ 251 | $timeout(function(){ 252 | ngModelController.$setViewValue(""); 253 | ngModelController.$render(); 254 | scope.modal.hide(); 255 | scope.showList = false; 256 | if (scope.onReset && angular.isFunction(scope.onReset)) { 257 | scope.onReset(); 258 | } 259 | }); 260 | }; 261 | 262 | scope.setValues = function(){ 263 | var checkedItems = []; 264 | angular.forEach(scope.isChecked, function(v, k){ 265 | if(v){ 266 | checkedItems.push(allOptions[k][1]) 267 | } 268 | }); 269 | var oldValues = ngModelController.$viewValue; 270 | var vals = checkedItems.map(function(item){ 271 | return getSelectedValue(item); 272 | }); 273 | ngModelController.$setViewValue(vals); 274 | ngModelController.$render(); 275 | 276 | if (scope.onSelect) { 277 | scope.onSelect({ newValue: vals, oldValue: oldValues }); 278 | } 279 | scope.modal.hide().then(function(){ 280 | scope.showList = false; 281 | if (scope.ui.hasSearch) { 282 | if(clearSearchOnSelect){ 283 | scope.ui.searchValue = ''; 284 | } 285 | } 286 | }); 287 | 288 | }; 289 | 290 | scope.unsetValues = function(){ 291 | $timeout(function(){ 292 | ngModelController.$setViewValue(multipleNullValue); 293 | ngModelController.$render(); 294 | scope.isChecked = {}; 295 | scope.modal.hide(); 296 | scope.showList = false; 297 | if (scope.onReset && angular.isFunction(scope.onReset)) { 298 | scope.onReset(); 299 | } 300 | }); 301 | }; 302 | 303 | scope.closeModal = function(){ 304 | scope.modal.hide().then(function(){ 305 | scope.showList = false; 306 | }); 307 | }; 308 | 309 | 310 | scope.compareValues = function(a, b){ 311 | return angular.equals(a, b); 312 | }; 313 | 314 | //loading the modal 315 | var modalTpl = null; 316 | if(iAttrs.searchTemplate) { 317 | scope.modal = $ionicModal.fromTemplate( 318 | $templateCache.get(iAttrs.searchTemplate), 319 | { scope: scope } 320 | ); 321 | } else { 322 | modalTpl = multiple ? modalTemplateMultiple : modalTemplate; 323 | scope.modal = $ionicModal.fromTemplate( 324 | modalTpl, 325 | { scope: scope } 326 | ); 327 | } 328 | 329 | let hiddenCb = null; 330 | scope.$on('$destroy', function(){ 331 | if(hiddenCb){ 332 | hiddenCb(); 333 | hiddenCb = null; 334 | } 335 | scope.modal.remove(); 336 | }); 337 | 338 | if (scope.onClose && angular.isFunction(scope.onClose)) { 339 | hiddenCb = scope.$on('modal.hidden', function(){ 340 | scope.onClose(); 341 | }); 342 | } 343 | 344 | iElement.on('click', function(){ 345 | if (shortList) { 346 | scope.showList = true; 347 | scope.modal.show(); 348 | } else { 349 | scope.modal.show() 350 | .then(function(){ 351 | scope.showList = true; 352 | scope.ui.shortList = shortList; 353 | }); 354 | } 355 | }); 356 | 357 | 358 | //filter function 359 | if (scope.ui.hasSearch) { 360 | scope.$watch('ui.searchValue', function(nv){ 361 | var whatToSearch; 362 | if ( !multiple ) { 363 | whatToSearch = allOptions; 364 | } else { 365 | whatToSearch = allOptions.map(function(item){ 366 | return item[1]; 367 | }); 368 | } 369 | 370 | if(iAttrs.onSearch) { 371 | scope.onSearch({query: nv}); 372 | } else { 373 | var filteredOpts = $filter('filter')(whatToSearch, nv, function(actual, expected) { 374 | if(!actual){ 375 | // if actual is an empty string, empty object, null, or undefined 376 | return false; 377 | } 378 | if (searchProperties){ 379 | if (typeof actual == 'object'){ 380 | for (var i = 0; i < searchProperties.length; i++){ 381 | if (actual[searchProperties[i]] && actual[searchProperties[i]].toLowerCase().indexOf(expected.toLowerCase()) >= 0){ 382 | return true; 383 | } 384 | } 385 | } 386 | return false; 387 | } else { 388 | if(actual.toString().toLowerCase().indexOf(expected.toLowerCase()) >= 0){ 389 | return true; 390 | } 391 | } 392 | return false; 393 | }); 394 | 395 | var oldLen = scope.options.length; 396 | if ( !multiple ){ 397 | scope.options = filteredOpts; 398 | 399 | } else { 400 | //#TODO: lots of loops here! 401 | var newOpts = []; 402 | angular.forEach(filteredOpts, function(item){ 403 | var originalItem = allOptions.find(function(it){ 404 | return it[1] == item; 405 | }); 406 | if( originalItem ){ 407 | newOpts.push(originalItem); 408 | } 409 | }); 410 | scope.options = newOpts; 411 | } 412 | if(oldLen != scope.options.length){ 413 | //#todo: should resize scroll or scroll up here 414 | } 415 | } 416 | }); 417 | scope.clearSearch = function(){ 418 | scope.ui.searchValue = ''; 419 | }; 420 | } 421 | 422 | scope.copyOpt = option => { 423 | return angular.copy(option); 424 | } 425 | 426 | // init ischecked for multiple mode to synch with scope 427 | var initIsChecked = () =>{ 428 | if(multiple){ 429 | var values = ngModelController.$viewValue; 430 | if(!values || values.length == 0 ) return; 431 | scope.options.forEach((oVal,i)=>{ 432 | values.forEach((vVal,i)=>{ 433 | if(angular.equals(vVal,oVal[1])){ 434 | scope.isChecked[oVal[0]] = true; 435 | } 436 | }) 437 | }) 438 | } 439 | } 440 | //#TODO ?: WRAP INTO $timeout? 441 | $timeout(()=>{ 442 | initIsChecked(); 443 | ngModelController.$render(); 444 | }) 445 | 446 | } 447 | }; 448 | } 449 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import "./ionic-modal-select.js"; 2 | -------------------------------------------------------------------------------- /src/modal-template-multiple.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

{{::ui.modalTitle}}

5 |
6 | 7 |
8 | 12 | 15 |
16 | 17 | 18 |
19 |

{{::ui.loadListMessage}}

20 |

21 | 22 |

23 |
24 | 25 |
26 | 27 | 28 | 44 | 45 | 46 |
47 |
48 |
51 | 54 |
55 |
56 |
57 |
58 |
59 |
60 | 61 | 62 |
63 | 64 |
65 | 66 |
67 |
68 | -------------------------------------------------------------------------------- /src/modal-template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

{{::ui.modalTitle}}

5 |
6 | 7 |
8 | 12 | 15 |
16 | 17 | 18 |
19 |

{{::ui.loadListMessage}}

20 |

21 | 22 |

23 |
24 |
25 |
26 |
27 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
42 |
43 |
44 |
45 |
46 |
47 | 48 |
49 |
50 |
51 | 52 |
53 | 54 | 55 | 56 | 57 | 58 | 59 |
60 | -------------------------------------------------------------------------------- /tests/compile-directive.tests.js: -------------------------------------------------------------------------------- 1 | describe('compile directive', function(){ 2 | 3 | var elm, elm2, scope; 4 | 5 | beforeEach(module('ionic-modal-select')); 6 | 7 | beforeEach(inject(function($rootScope, $compile) { 8 | elm = angular.element('
') 9 | elm2 = angular.element('
') 10 | 11 | scope = $rootScope; 12 | scope.a = "some inner content"; 13 | scope.b = "some new inner content"; 14 | scope.inner = "{{a}}"; 15 | 16 | $compile(elm)(scope); 17 | $compile(elm2)(scope); 18 | 19 | scope.$digest(); 20 | 21 | })); 22 | 23 | it('should compile inner content', function(){ 24 | var a = elm.find('a'); 25 | 26 | expect(a.length).toBe(1); 27 | expect(a.eq(0).text()).toBe("some inner content"); 28 | }); 29 | 30 | it('should compile inner content again if something changes', function(){ 31 | var a; 32 | scope.inner = "{{b}}"; 33 | scope.$digest(); 34 | a = elm.find('a'); 35 | 36 | expect(a.length).toBe(1); 37 | expect(a.eq(0).text()).toBe("some new inner content"); 38 | }); 39 | 40 | it('should not compile inner content again if something changes but compile-once attr is set to "true"', function(){ 41 | var a, a2; 42 | scope.inner = "{{a}}"; 43 | scope.$digest(); 44 | scope.inner = "{{b}}"; 45 | scope.$digest(); 46 | a = elm.find('a'); 47 | a2 = elm2.find('a'); 48 | 49 | expect(a.eq(0).text()).toBe("some new inner content"); 50 | expect(a2.eq(0).text()).toBe("some inner content"); 51 | }); 52 | 53 | }); -------------------------------------------------------------------------------- /tests/my.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Wed Nov 18 2015 21:50:12 GMT+0100 (CET) 3 | 4 | module.exports = function(config) { 5 | config.set({ 6 | 7 | // base path that will be used to resolve all patterns (eg. files, exclude) 8 | basePath: '', 9 | 10 | 11 | // frameworks to use 12 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 13 | frameworks: ['jasmine'], 14 | 15 | 16 | // list of files / patterns to load in the browser 17 | files: [ 18 | '../bower_components/ionic/release/js/ionic.bundle.js', 19 | '../dist/ionic-modal-select.js', 20 | '../bower_components/angular-mocks/angular-mocks.js', 21 | '**/*tests.js' 22 | ], 23 | 24 | 25 | // list of files to exclude 26 | exclude: [ 27 | ], 28 | 29 | 30 | // preprocess matching files before serving them to the browser 31 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 32 | preprocessors: { 33 | }, 34 | 35 | 36 | // test results reporter to use 37 | // possible values: 'dots', 'progress' 38 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 39 | reporters: ['progress'], 40 | 41 | 42 | // web server port 43 | port: 9876, 44 | 45 | 46 | // enable / disable colors in the output (reporters and logs) 47 | colors: true, 48 | 49 | 50 | // level of logging 51 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 52 | logLevel: config.LOG_INFO, 53 | 54 | 55 | // enable / disable watching file and executing tests whenever any file changes 56 | autoWatch: true, 57 | 58 | 59 | // start these browsers 60 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 61 | browsers: ['PhantomJS'], 62 | 63 | 64 | // Continuous Integration mode 65 | // if true, Karma captures browsers, runs the tests and exits 66 | singleRun: false, 67 | 68 | // Concurrency level 69 | // how many browser should be started simultanous 70 | concurrency: Infinity 71 | }) 72 | } 73 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var webpack = require("webpack"); 2 | 3 | module.exports = { 4 | devtool: 'sourcemap', 5 | output: { 6 | filename: 'ionic-modal-select.js' 7 | }, 8 | plugins : [ 9 | 10 | ], 11 | module: { 12 | loaders: [ 13 | { test: /\.js$/, exclude: [/app\/lib/, /node_modules/], loader: 'ng-annotate!babel' }, 14 | 15 | ], 16 | 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /webpack.config.production.js: -------------------------------------------------------------------------------- 1 | var webpack = require("webpack"); 2 | 3 | module.exports = { 4 | devtool: 'sourcemap', 5 | output: { 6 | filename: 'ionic-modal-select.min.js' 7 | }, 8 | plugins : [ 9 | new webpack.optimize.UglifyJsPlugin({ minimize: true }) 10 | ], 11 | module: { 12 | loaders: [ 13 | { test: /\.js$/, exclude: [/app\/lib/, /node_modules/], loader: 'ng-annotate!babel' }, 14 | ], 15 | 16 | } 17 | }; 18 | --------------------------------------------------------------------------------