├── .editorconfig ├── .ember-cli ├── .eslintignore ├── .eslintrc.js ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .npmignore ├── .npmrc ├── .prettierignore ├── .prettierrc.js ├── .stylelintignore ├── .stylelintrc.js ├── .template-lintrc.js ├── .watchmanconfig ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── addon ├── .gitkeep ├── components │ ├── model-select-multiple.hbs │ ├── model-select-multiple.js │ ├── model-select.hbs │ ├── model-select.js │ └── model-select │ │ ├── options.hbs │ │ ├── options.js │ │ └── spinner.hbs └── utils │ └── get-config-option.js ├── app ├── .gitkeep ├── components │ ├── model-select-multiple.js │ ├── model-select.js │ └── model-select │ │ ├── options.js │ │ └── spinner.js ├── styles │ └── ember-model-select.scss └── utils │ └── get-config-option.js ├── blueprints └── ember-model-select │ └── index.js ├── compile-css.js ├── ember-cli-build.js ├── index.js ├── package.json ├── pnpm-lock.yaml ├── testem.js ├── tests ├── dummy │ ├── app │ │ ├── app.js │ │ ├── components │ │ │ └── .gitkeep │ │ ├── controllers │ │ │ ├── .gitkeep │ │ │ └── docs │ │ │ │ └── components │ │ │ │ ├── model-select-multiple.js │ │ │ │ └── model-select.js │ │ ├── helpers │ │ │ └── .gitkeep │ │ ├── index.html │ │ ├── models │ │ │ ├── .gitkeep │ │ │ └── user.js │ │ ├── router.js │ │ ├── routes │ │ │ └── .gitkeep │ │ ├── serializers │ │ │ └── application.js │ │ ├── styles │ │ │ └── app.scss │ │ └── templates │ │ │ ├── application.hbs │ │ │ ├── docs.hbs │ │ │ ├── docs │ │ │ ├── components │ │ │ │ ├── model-select-multiple.md │ │ │ │ └── model-select.md │ │ │ ├── index.md │ │ │ ├── quickstart.md │ │ │ └── usage.md │ │ │ ├── index.hbs │ │ │ └── not-found.hbs │ ├── config │ │ ├── addon-docs.js │ │ ├── deploy.js │ │ ├── ember-cli-update.json │ │ ├── ember-try.js │ │ ├── environment.js │ │ ├── optional-features.json │ │ └── targets.js │ ├── mirage │ │ ├── config.js │ │ ├── factories │ │ │ └── user.js │ │ ├── scenarios │ │ │ └── default.js │ │ └── serializers │ │ │ └── application.js │ └── public │ │ └── robots.txt ├── helpers │ └── index.js ├── index.html ├── integration │ ├── .gitkeep │ └── components │ │ ├── model-select-multiple-test.js │ │ ├── model-select-test.js │ │ └── model-select │ │ └── spinner-test.js ├── test-helper.js └── unit │ ├── .gitkeep │ └── utils │ └── get-config-option-test.js └── vendor └── .gitkeep /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | end_of_line = lf 9 | charset = utf-8 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | indent_style = space 13 | indent_size = 2 14 | 15 | [*.hbs] 16 | insert_final_newline = false 17 | 18 | [*.{diff,md}] 19 | trim_trailing_whitespace = false 20 | -------------------------------------------------------------------------------- /.ember-cli: -------------------------------------------------------------------------------- 1 | { 2 | /** 3 | Ember CLI sends analytics information by default. The data is completely 4 | anonymous, but there are times when you might want to disable this behavior. 5 | 6 | Setting `disableAnalytics` to true will prevent any data from being sent. 7 | */ 8 | "disableAnalytics": false, 9 | 10 | /** 11 | Setting `isTypeScriptProject` to true will force the blueprint generators to generate TypeScript 12 | rather than JavaScript by default, when a TypeScript version of a given blueprint is available. 13 | */ 14 | "isTypeScriptProject": false 15 | } 16 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | # unconventional js 2 | /blueprints/*/files/ 3 | /vendor/ 4 | 5 | # compiled output 6 | /dist/ 7 | /tmp/ 8 | 9 | # dependencies 10 | /bower_components/ 11 | /node_modules/ 12 | 13 | # misc 14 | /coverage/ 15 | !.* 16 | .*/ 17 | .eslintcache 18 | 19 | # ember-try 20 | /.node_modules.ember-try/ 21 | /bower.json.ember-try 22 | /npm-shrinkwrap.json.ember-try 23 | /package.json.ember-try 24 | /package-lock.json.ember-try 25 | /yarn.lock.ember-try 26 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | root: true, 5 | parser: '@babel/eslint-parser', 6 | parserOptions: { 7 | ecmaVersion: 'latest', 8 | sourceType: 'module', 9 | requireConfigFile: false, 10 | babelOptions: { 11 | plugins: [ 12 | ['@babel/plugin-proposal-decorators', { decoratorsBeforeExport: true }], 13 | ], 14 | }, 15 | }, 16 | plugins: ['ember'], 17 | extends: [ 18 | 'eslint:recommended', 19 | 'plugin:ember/recommended', 20 | 'plugin:prettier/recommended', 21 | ], 22 | env: { 23 | browser: true, 24 | }, 25 | rules: {}, 26 | overrides: [ 27 | // node files 28 | { 29 | files: [ 30 | './.eslintrc.js', 31 | './.prettierrc.js', 32 | './.stylelintrc.js', 33 | './.template-lintrc.js', 34 | './ember-cli-build.js', 35 | './index.js', 36 | './testem.js', 37 | './blueprints/*/index.js', 38 | './config/**/*.js', 39 | './tests/dummy/config/**/*.js', 40 | './compile-css.js', 41 | ], 42 | parserOptions: { 43 | sourceType: 'script', 44 | }, 45 | env: { 46 | browser: false, 47 | node: true, 48 | }, 49 | extends: ['plugin:n/recommended'], 50 | }, 51 | { 52 | // test files 53 | files: ['tests/**/*-test.{js,ts}'], 54 | extends: ['plugin:qunit/recommended'], 55 | }, 56 | ], 57 | }; 58 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - master 8 | pull_request: {} 9 | 10 | env: 11 | PNPM_VERSION: 8.13.1 12 | 13 | concurrency: 14 | group: ci-${{ github.head_ref || github.ref }} 15 | cancel-in-progress: true 16 | 17 | jobs: 18 | test: 19 | name: "Tests" 20 | runs-on: ubuntu-latest 21 | timeout-minutes: 10 22 | 23 | steps: 24 | - uses: actions/checkout@v4 25 | - uses: pnpm/action-setup@v2.4.0 26 | with: 27 | version: ${{ env.PNPM_VERSION }} 28 | - name: Install Node 29 | uses: actions/setup-node@v3 30 | with: 31 | node-version: 16.x 32 | cache: pnpm 33 | - name: Install Dependencies 34 | run: pnpm install --frozen-lockfile 35 | - name: Lint 36 | run: pnpm run lint 37 | - name: Run Tests 38 | run: pnpm run test:ember 39 | 40 | floating: 41 | name: "Floating Dependencies" 42 | runs-on: ubuntu-latest 43 | timeout-minutes: 10 44 | 45 | steps: 46 | - uses: actions/checkout@v4 47 | - uses: pnpm/action-setup@v2.4.0 48 | with: 49 | version: ${{ env.PNPM_VERSION }} 50 | - uses: actions/setup-node@v3 51 | with: 52 | node-version: 16.x 53 | cache: pnpm 54 | - name: Install Dependencies 55 | run: pnpm install 56 | - name: Run Tests 57 | run: pnpm run test:ember 58 | 59 | try-scenarios: 60 | name: ${{ matrix.try-scenario }} 61 | runs-on: ubuntu-latest 62 | needs: "test" 63 | timeout-minutes: 10 64 | 65 | strategy: 66 | fail-fast: false 67 | matrix: 68 | try-scenario: 69 | - power-select-4 70 | - power-select-5 71 | - power-select-6 72 | - power-select-7 73 | - ember-lts-3.28 74 | - ember-lts-4.4 75 | - ember-lts-4.8 76 | - ember-lts-4.12 77 | - ember-release 78 | - ember-beta 79 | - ember-canary 80 | - ember-default-with-jquery 81 | - ember-classic 82 | - embroider-safe 83 | - embroider-optimized 84 | 85 | steps: 86 | - uses: actions/checkout@v4 87 | - uses: pnpm/action-setup@v2.4.0 88 | with: 89 | version: ${{ env.PNPM_VERSION }} 90 | - name: Install Node 91 | uses: actions/setup-node@v3 92 | with: 93 | node-version: 16.x 94 | cache: pnpm 95 | - name: Install Dependencies 96 | run: pnpm install --frozen-lockfile 97 | - name: Run Tests 98 | run: ./node_modules/.bin/ember try:one ${{ matrix.try-scenario }} 99 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist/ 5 | /tmp/ 6 | 7 | # dependencies 8 | /bower_components/ 9 | /node_modules/ 10 | 11 | # misc 12 | /.env* 13 | /.pnp* 14 | /.sass-cache 15 | /.eslintcache 16 | /connect.lock 17 | /coverage/ 18 | /libpeerconnection.log 19 | /npm-debug.log* 20 | /testem.log 21 | /yarn-error.log 22 | 23 | # ember-try 24 | /.node_modules.ember-try/ 25 | /bower.json.ember-try 26 | /npm-shrinkwrap.json.ember-try 27 | /package.json.ember-try 28 | /package-lock.json.ember-try 29 | /yarn.lock.ember-try 30 | 31 | # broccoli-debug 32 | /DEBUG/ 33 | 34 | /.idea 35 | /vendor/ember-model-select.css 36 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist/ 3 | /tmp/ 4 | 5 | # dependencies 6 | /bower_components/ 7 | 8 | # misc 9 | /.bowerrc 10 | /.editorconfig 11 | /.ember-cli 12 | /.env* 13 | /.eslintcache 14 | /.eslintignore 15 | /.eslintrc.js 16 | /.git/ 17 | /.github/ 18 | /.gitignore 19 | /.prettierignore 20 | /.prettierrc.js 21 | /.stylelintignore 22 | /.stylelintrc.js 23 | /.template-lintrc.js 24 | /.travis.yml 25 | /.watchmanconfig 26 | /bower.json 27 | /CONTRIBUTING.md 28 | /ember-cli-build.js 29 | /testem.js 30 | /tests/ 31 | /yarn-error.log 32 | /yarn.lock 33 | .gitkeep 34 | 35 | # ember-try 36 | /.node_modules.ember-try/ 37 | /bower.json.ember-try 38 | /npm-shrinkwrap.json.ember-try 39 | /package.json.ember-try 40 | /package-lock.json.ember-try 41 | /yarn.lock.ember-try 42 | 43 | # other 44 | /.idea 45 | /config/addon-docs.js 46 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | tag-version-prefix="" 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # unconventional js 2 | /blueprints/*/files/ 3 | /vendor/ 4 | 5 | # compiled output 6 | /dist/ 7 | /tmp/ 8 | 9 | # dependencies 10 | /bower_components/ 11 | /node_modules/ 12 | 13 | # misc 14 | /coverage/ 15 | !.* 16 | .eslintcache 17 | .lint-todo/ 18 | 19 | # ember-try 20 | /.node_modules.ember-try/ 21 | /bower.json.ember-try 22 | /npm-shrinkwrap.json.ember-try 23 | /package.json.ember-try 24 | /package-lock.json.ember-try 25 | /yarn.lock.ember-try 26 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | overrides: [ 5 | { 6 | files: '*.{js,ts}', 7 | options: { 8 | singleQuote: true, 9 | }, 10 | }, 11 | ], 12 | }; 13 | -------------------------------------------------------------------------------- /.stylelintignore: -------------------------------------------------------------------------------- 1 | # unconventional files 2 | /blueprints/*/files/ 3 | 4 | # compiled output 5 | /dist/ 6 | 7 | # addons 8 | /.node_modules.ember-try/ 9 | 10 | /vendor/ember-model-select.css 11 | -------------------------------------------------------------------------------- /.stylelintrc.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | extends: ['stylelint-config-standard', 'stylelint-prettier/recommended'], 5 | }; 6 | -------------------------------------------------------------------------------- /.template-lintrc.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | extends: 'recommended', 5 | rules: { 6 | 'no-inline-styles': false, 7 | 'attribute-indentation': false, 8 | }, 9 | }; 10 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | { 2 | "ignore_dirs": ["tmp", "dist"] 3 | } 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | ## 1.0.0-beta.3 (2020-12-05) 3 | 4 | #### :boom: Breaking Change 5 | * [#93](https://github.com/nickschot/ember-model-select/pull/93) Upgrade to ember-cli 3.22, use co-location for components ([@nickschot](https://github.com/nickschot)) 6 | 7 | #### Committers: 1 8 | - Nick Schot ([@nickschot](https://github.com/nickschot)) 9 | 10 | 11 | ## 1.0.0-beta.2 (2020-07-16) 12 | 13 | #### :rocket: Enhancement 14 | * [#87](https://github.com/nickschot/ember-model-select/pull/87) Add argument to specify a "source" as an alternative to the ember-data store ([@joegaudet](https://github.com/joegaudet)) 15 | 16 | #### :house: Internal 17 | * [#84](https://github.com/nickschot/ember-model-select/pull/84) update addon-docs to latest version ([@nickschot](https://github.com/nickschot)) 18 | * [#83](https://github.com/nickschot/ember-model-select/pull/83) fix addon-docs generating incorrect URL's for versioned documentation… ([@nickschot](https://github.com/nickschot)) 19 | 20 | #### Committers: 2 21 | - Joe Gaudet ([@joegaudet](https://github.com/joegaudet)) 22 | - Nick Schot ([@nickschot](https://github.com/nickschot)) 23 | 24 | 25 | ## 1.0.0-beta.1 (2020-06-04) 26 | 27 | #### :boom: Breaking Change 28 | * [#78](https://github.com/nickschot/ember-model-select/pull/78) Update to ember-power-select@4 and Ember Octane/Glimmer Components ([@ttill](https://github.com/ttill)) 29 | 30 | #### Committers: 1 31 | - Till Theato ([@ttill](https://github.com/ttill)) 32 | 33 | 34 | ## 0.2.1 (2019-10-03) 35 | 36 | #### :bug: Bug Fix 37 | * [#74](https://github.com/nickschot/ember-model-select/pull/74) Bugfix to enable usage of query and search propery at the same time ([@michaelw8](https://github.com/michaelw8)) 38 | 39 | #### :house: Internal 40 | * [#75](https://github.com/nickschot/ember-model-select/pull/75) add test for query functionality ([@nickschot](https://github.com/nickschot)) 41 | 42 | #### Committers: 2 43 | - Michael ([@michaelw8](https://github.com/michaelw8)) 44 | - Nick Schot ([@nickschot](https://github.com/nickschot)) 45 | 46 | 47 | ## 0.2.0 (2019-09-27) 48 | 49 | #### :bug: Bug Fix 50 | * [#73](https://github.com/nickschot/ember-model-select/pull/73) update to ember-cli 3.12 & update all dependencies (Closes [#69](https://github.com/nickschot/ember-model-select/issues/69) ) ([@nickschot](https://github.com/nickschot)) 51 | 52 | #### Committers: 1 53 | - Nick Schot ([@nickschot](https://github.com/nickschot)) 54 | 55 | 56 | ## 0.1.2 (2019-05-10) 57 | 58 | #### :bug: Bug Fix 59 | * [#70](https://github.com/nickschot/ember-model-select/pull/70) lock ember-infinity to 1.4.2 ([@nickschot](https://github.com/nickschot)) 60 | 61 | #### Committers: 1 62 | - Nick Schot ([@nickschot](https://github.com/nickschot)) 63 | 64 | 65 | ## 0.1.1 (2019-03-27) 66 | 67 | #### :bug: Bug Fix 68 | * [#68](https://github.com/nickschot/ember-model-select/pull/68) fix ember-get-config import not always working due to missing dependency ([@nickschot](https://github.com/nickschot)) 69 | 70 | #### :memo: Documentation 71 | * [#66](https://github.com/nickschot/ember-model-select/pull/66) fix minor formatting issues in docs ([@nickschot](https://github.com/nickschot)) 72 | 73 | #### Committers: 1 74 | - Nick Schot ([@nickschot](https://github.com/nickschot)) 75 | 76 | 77 | ## 0.1.0 (2019-03-27) 78 | 79 | #### :rocket: Enhancement 80 | * [#52](https://github.com/nickschot/ember-model-select/pull/52) add assertion for empty searchProperty ([@nickschot](https://github.com/nickschot)) 81 | * [#53](https://github.com/nickschot/ember-model-select/pull/53) overlay spinner on caret and clear button when loading ([@nickschot](https://github.com/nickschot)) 82 | 83 | #### :memo: Documentation 84 | * [#65](https://github.com/nickschot/ember-model-select/pull/65) add quickstart ([@nickschot](https://github.com/nickschot)) 85 | 86 | #### Committers: 1 87 | - Nick Schot ([@nickschot](https://github.com/nickschot)) 88 | 89 | 90 | ## 0.1.0-rc.2 (2019-02-18) 91 | 92 | #### :rocket: Enhancement 93 | * [#62](https://github.com/nickschot/ember-model-select/pull/62) Add block support ([@nickschot](https://github.com/nickschot)) 94 | 95 | #### :house: Internal 96 | * [#61](https://github.com/nickschot/ember-model-select/pull/61) update dependencies within range ([@nickschot](https://github.com/nickschot)) 97 | 98 | #### Committers: 1 99 | - Nick Schot ([@nickschot](https://github.com/nickschot)) 100 | 101 | 102 | ## 0.1.0-rc.1 (2019-02-15) 103 | 104 | #### :bug: Bug Fix 105 | * [#59](https://github.com/nickschot/ember-model-select/pull/59) Fix passing id as selectedModel ([@nickschot](https://github.com/nickschot)) 106 | 107 | #### :house: Internal 108 | * [#58](https://github.com/nickschot/ember-model-select/pull/58) add fixed seed for mirage resulting in deterministic data ([@nickschot](https://github.com/nickschot)) 109 | 110 | #### Committers: 1 111 | - Nick Schot ([@nickschot](https://github.com/nickschot)) 112 | 113 | 114 | ## 0.1.0-beta.10 (2019-02-04) 115 | 116 | #### :rocket: Enhancement 117 | * [#56](https://github.com/nickschot/ember-model-select/pull/56) pass through ember-power-select's onclose hook ([@nickschot](https://github.com/nickschot)) 118 | 119 | #### :house: Internal 120 | * [#57](https://github.com/nickschot/ember-model-select/pull/57) switch from npm to yarn & ember-cli 3.7 ([@nickschot](https://github.com/nickschot)) 121 | * [#55](https://github.com/nickschot/ember-model-select/pull/55) run compile css in strict mode ([@nickschot](https://github.com/nickschot)) 122 | * [#54](https://github.com/nickschot/ember-model-select/pull/54) add changelog script ([@nickschot](https://github.com/nickschot)) 123 | 124 | #### Committers: 1 125 | - Nick Schot ([@nickschot](https://github.com/nickschot)) 126 | 127 | 128 | ## 0.1.0-beta.9 (2018-12-21) 129 | 130 | #### :memo: Documentation 131 | * [#49](https://github.com/nickschot/ember-model-select/pull/49) addon docs ([@nickschot](https://github.com/nickschot)) 132 | 133 | #### :house: Internal 134 | * [#50](https://github.com/nickschot/ember-model-select/pull/50) remove loading-mask component ([@nickschot](https://github.com/nickschot)) 135 | 136 | #### Committers: 1 137 | - Nick Schot ([@nickschot](https://github.com/nickschot)) 138 | 139 | 140 | ## 0.1.0-beta.8 (2018-12-20) 141 | 142 | #### :rocket: Enhancement 143 | * [#48](https://github.com/nickschot/ember-model-select/pull/48) reworked loading (spinner) display & immediately show create option in list ([@nickschot](https://github.com/nickschot)) 144 | 145 | #### Committers: 1 146 | - Nick Schot ([@nickschot](https://github.com/nickschot)) 147 | 148 | 149 | ## 0.1.0-beta.7 (2018-12-20) 150 | 151 | #### :bug: Bug Fix 152 | * [#47](https://github.com/nickschot/ember-model-select/pull/47) passthrough ember infinity parameters in multiple select ([@nickschot](https://github.com/nickschot)) 153 | 154 | #### Committers: 1 155 | - Nick Schot ([@nickschot](https://github.com/nickschot)) 156 | 157 | 158 | ## 0.1.0-beta.6 (2018-12-20) 159 | 160 | #### :boom: Breaking Change 161 | * [#35](https://github.com/nickschot/ember-model-select/pull/35) align all hooks with power-select ([@nickschot](https://github.com/nickschot)) 162 | * [#34](https://github.com/nickschot/ember-model-select/pull/34) set fallbacks for all arguments ([@nickschot](https://github.com/nickschot)) 163 | 164 | #### :rocket: Enhancement 165 | * [#46](https://github.com/nickschot/ember-model-select/pull/46) add create support to multiple-select ([@nickschot](https://github.com/nickschot)) 166 | * [#36](https://github.com/nickschot/ember-model-select/pull/36) add {{model-select-multiple}} component ([@nickschot](https://github.com/nickschot)) 167 | * [#34](https://github.com/nickschot/ember-model-select/pull/34) set fallbacks for all arguments ([@nickschot](https://github.com/nickschot)) 168 | 169 | #### :bug: Bug Fix 170 | * [#45](https://github.com/nickschot/ember-model-select/pull/45) pass the power-select public api as second arg to onchange hook ([@nickschot](https://github.com/nickschot)) 171 | * [#42](https://github.com/nickschot/ember-model-select/pull/42) clearing the model-select was not working ([@nickschot](https://github.com/nickschot)) 172 | * [#37](https://github.com/nickschot/ember-model-select/pull/37) show loading state when search task is running ([@nickschot](https://github.com/nickschot)) 173 | 174 | #### :memo: Documentation 175 | * [#43](https://github.com/nickschot/ember-model-select/pull/43) add dummy variants for all varieties of model-select ([@nickschot](https://github.com/nickschot)) 176 | 177 | #### Committers: 1 178 | - Nick Schot ([@nickschot](https://github.com/nickschot)) 179 | 180 | 181 | ## 0.1.0-beta.5 (2018-12-18) 182 | 183 | #### :rocket: Enhancement 184 | * [#29](https://github.com/nickschot/ember-model-select/pull/29) add with-create functionality ([@nickschot](https://github.com/nickschot)) 185 | * [#28](https://github.com/nickschot/ember-model-select/pull/28) ember cli 3.6.0 ([@nickschot](https://github.com/nickschot)) 186 | 187 | #### :bug: Bug Fix 188 | * [#32](https://github.com/nickschot/ember-model-select/pull/32) aria-current wasn't set to true resulting in broken highlight of options ([@nickschot](https://github.com/nickschot)) 189 | 190 | #### :house: Internal 191 | * [#33](https://github.com/nickschot/ember-model-select/pull/33) move prepublish hook to prepare hook ([@nickschot](https://github.com/nickschot)) 192 | 193 | #### Committers: 1 194 | - Nick Schot ([@nickschot](https://github.com/nickschot)) 195 | 196 | 197 | ## 0.1.0-beta.4 (2018-12-06) 198 | 199 | #### :rocket: Enhancement 200 | * [#27](https://github.com/nickschot/ember-model-select/pull/27) custom power select component template ([@nickschot](https://github.com/nickschot)) 201 | 202 | #### :house: Internal 203 | * [#26](https://github.com/nickschot/ember-model-select/pull/26) add github-pages support ([@nickschot](https://github.com/nickschot)) 204 | 205 | #### Committers: 1 206 | - Nick Schot ([@nickschot](https://github.com/nickschot)) 207 | 208 | 209 | ## 0.1.0-beta.3 (2018-12-02) 210 | 211 | #### :bug: Bug Fix 212 | * [#23](https://github.com/nickschot/ember-model-select/pull/23) fix blueprint generation ([@nickschot](https://github.com/nickschot)) 213 | 214 | #### Committers: 1 215 | - Nick Schot ([@nickschot](https://github.com/nickschot)) 216 | 217 | 218 | ## 0.1.0-beta.2 (2018-12-02) 219 | 220 | #### :rocket: Enhancement 221 | * [#22](https://github.com/nickschot/ember-model-select/pull/22) add scss import when ember-cli-sass is present ([@nickschot](https://github.com/nickschot)) 222 | * [#21](https://github.com/nickschot/ember-model-select/pull/21) add support for precompiled css ([@nickschot](https://github.com/nickschot)) 223 | * [#20](https://github.com/nickschot/ember-model-select/pull/20) support global config ([@nickschot](https://github.com/nickschot)) 224 | * [#18](https://github.com/nickschot/ember-model-select/pull/18) add support for full ember-power-select API ([@nickschot](https://github.com/nickschot)) 225 | 226 | #### :house: Internal 227 | * [#19](https://github.com/nickschot/ember-model-select/pull/19) update dependencies within range ([@nickschot](https://github.com/nickschot)) 228 | 229 | #### Committers: 1 230 | - Nick Schot ([@nickschot](https://github.com/nickschot)) 231 | 232 | 233 | ## v0.1.0-beta.1 (2018-11-30) 234 | 235 | #### :boom: Breaking Change 236 | * [#11](https://github.com/nickschot/ember-model-select/pull/11) remove different filter options, prefer single query ([@nickschot](https://github.com/nickschot)) 237 | * [#13](https://github.com/nickschot/ember-model-select/pull/13) BREAKING: change default search property from 's' to 'search' ([@nickschot](https://github.com/nickschot)) 238 | * [#10](https://github.com/nickschot/ember-model-select/pull/10) remove optionAmount parameter, replaced with pageSize ([@nickschot](https://github.com/nickschot)) 239 | * [#5](https://github.com/nickschot/ember-model-select/pull/5) Add support to pass a model instance ([@nickschot](https://github.com/nickschot)) 240 | 241 | #### :rocket: Enhancement 242 | * [#9](https://github.com/nickschot/ember-model-select/pull/9) ember-cli 3.4 & dependency updates ([@nickschot](https://github.com/nickschot)) 243 | * [#5](https://github.com/nickschot/ember-model-select/pull/5) Add support to pass a model instance ([@nickschot](https://github.com/nickschot)) 244 | 245 | #### :house: Internal 246 | * [#12](https://github.com/nickschot/ember-model-select/pull/12) Add README badges ([@nickschot](https://github.com/nickschot)) 247 | * [#8](https://github.com/nickschot/ember-model-select/pull/8) Initial model-select tests ([@nickschot](https://github.com/nickschot)) 248 | 249 | #### Committers: 1 250 | - Nick Schot ([@nickschot](https://github.com/nickschot)) 251 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How To Contribute 2 | 3 | ## Installation 4 | 5 | * `git clone ` 6 | * `cd ember-model-select` 7 | * `yarn install` 8 | 9 | ## Linting 10 | 11 | * `yarn lint` 12 | * `yarn lint:fix` 13 | 14 | ## Running tests 15 | 16 | * `ember test` – Runs the test suite on the current Ember version 17 | * `ember test --server` – Runs the test suite in "watch mode" 18 | * `ember try:each` – Runs the test suite against multiple Ember versions 19 | 20 | ## Running the dummy application 21 | 22 | * `ember serve` 23 | * Visit the dummy application at [http://localhost:4200](http://localhost:4200). 24 | 25 | For more information on using ember-cli, visit [https://cli.emberjs.com/release/](https://cli.emberjs.com/release/). 26 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ember-model-select 2 | ============================================================================== 3 | [![Build Status](https://travis-ci.org/nickschot/ember-model-select.svg?branch=master)](https://travis-ci.org/nickschot/ember-model-select) [![Ember Observer Score](https://emberobserver.com/badges/ember-model-select.svg)](https://emberobserver.com/addons/ember-model-select) [![npm version](https://badge.fury.io/js/ember-model-select.svg)](https://badge.fury.io/js/ember-model-select) 4 | 5 | An [ember-cli](http://www.ember-cli.com) addon to provide a searchable model select box with infinite scroll support. 6 | 7 | The addon composes ember-power-select, ember-infinity and ember-concurrency to provide an easy to use generic model select box based on ember-data models. It can be used in any place where one might want to search for models without the need for extra JavaScript code. 8 | 9 | Documentation 10 | ------------------------------------------------------------------------------ 11 | [View the docs here](https://nickschot.github.io/ember-model-select). 12 | 13 | Compatibility 14 | ------------------------------------------------------------------------------ 15 | 16 | * Ember.js v3.28 or above 17 | * Ember CLI v3.28 or above 18 | * Node.js v16 or above 19 | 20 | 21 | Installation 22 | ------------------------------------------------------------------------------ 23 | 24 | ``` 25 | ember install ember-model-select 26 | ``` 27 | 28 | Related addons 29 | ------------------------------------------------------------------------------ 30 | - [ember-bootstrap-model-select](https://github.com/nickschot/ember-bootstrap-model-select) - [ember-bootstrap](https://www.ember-bootstrap.com) form integration for ember-model-select 31 | 32 | 33 | Contributing 34 | ------------------------------------------------------------------------------ 35 | 36 | See the [Contributing](CONTRIBUTING.md) guide for details. 37 | 38 | 39 | License 40 | ------------------------------------------------------------------------------ 41 | 42 | This project is licensed under the [MIT License](LICENSE.md). 43 | -------------------------------------------------------------------------------- /addon/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickschot/ember-model-select/050177355b037fa73f98b6aa2cb1ada07744a0cc/addon/.gitkeep -------------------------------------------------------------------------------- /addon/components/model-select-multiple.hbs: -------------------------------------------------------------------------------- 1 | 83 | {{#if (has-block)}} 84 | {{yield model}} 85 | {{else}} 86 | {{get model @labelProperty}} 87 | {{/if}} 88 | 89 | -------------------------------------------------------------------------------- /addon/components/model-select-multiple.js: -------------------------------------------------------------------------------- 1 | import PowerSelectMultipleComponent from 'ember-power-select/components/power-select-multiple'; 2 | import { action } from '@ember/object'; 3 | 4 | /** 5 | * This is a wrapper around the normal model-select component. The same arguments apply. 6 | * 7 | * @yield {object} model 8 | * 9 | * @class ModelSelectMultipleComponent 10 | */ 11 | export default class ModelSelectMultipleComponent extends PowerSelectMultipleComponent { 12 | @action 13 | change(option, select) { 14 | const suggestion = option.find((item) => item.__isSuggestion__); 15 | 16 | if (suggestion) { 17 | this.args.onCreate(suggestion.__value__, select); 18 | } else { 19 | this.args.onChange(option, select); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /addon/components/model-select.hbs: -------------------------------------------------------------------------------- 1 |
2 | 64 | {{#if (has-block)}} 65 | {{yield model}} 66 | {{else}} 67 | {{get model @labelProperty}} 68 | {{/if}} 69 | 70 | 71 | {{#if this.loadModels.isRunning}} 72 |
73 | 74 |
75 | {{/if}} 76 |
77 | -------------------------------------------------------------------------------- /addon/components/model-select.js: -------------------------------------------------------------------------------- 1 | import Component from '@glimmer/component'; 2 | 3 | import { isEmpty } from '@ember/utils'; 4 | // eslint-disable-next-line ember/no-computed-properties-in-native-classes 5 | import { computed, get, set } from '@ember/object'; 6 | import { inject as service } from '@ember/service'; 7 | import { A } from '@ember/array'; 8 | import { assign } from '@ember/polyfills'; 9 | import { action } from '@ember/object'; 10 | import { tracked } from '@glimmer/tracking'; 11 | 12 | import { timeout } from 'ember-concurrency'; 13 | import { restartableTask, dropTask } from 'ember-concurrency'; 14 | import getConfigOption from '../utils/get-config-option'; 15 | 16 | /** 17 | * The main component. 18 | * 19 | * NOTE: apart from the arguments listed explicitely here, ember-model-select supports the full 20 | * ember-power-select API which can be found: https://ember-power-select.com/docs/api-reference 21 | * 22 | * 23 | * @class ModelSelectComponent 24 | * @extends {Component} 25 | * 26 | * @yield {object} model 27 | */ 28 | export default class ModelSelectComponent extends Component { 29 | @service store; 30 | 31 | /** 32 | * Source to query, either an ember data model or the store 33 | * useful when using ember-data-has-many-query. 34 | * 35 | * @argument source 36 | * @type {Model} 37 | * @default 38 | */ 39 | get source() { 40 | return this.args.source || this.store; 41 | } 42 | 43 | @service infinity; 44 | 45 | /** 46 | * Name of the ember-data model. 47 | * 48 | * @argument modelName 49 | * @type {String} 50 | * @required 51 | */ 52 | 53 | /** 54 | * Selected model or its id. 55 | * 56 | * @argument selectedModel 57 | * @type {EmberData.Model|String|Number} 58 | */ 59 | 60 | /** 61 | * Name of property on model to use as label. 62 | * 63 | * @argument labelProperty 64 | * @type {String} 65 | * @required 66 | */ 67 | 68 | /** 69 | * Name of the key in which search queries are passed. 70 | * 71 | * @argument searchProperty 72 | * @type {String} 73 | * @default 'search' 74 | */ 75 | get searchProperty() { 76 | return ( 77 | this.args.searchProperty || getConfigOption('searchProperty', 'search') 78 | ); 79 | } 80 | 81 | /** 82 | * Optional key to search on. Will default to `labelProperty` if unset. 83 | * 84 | * @argument searchKey 85 | * @type {String} 86 | */ 87 | 88 | /** 89 | * Whether to start loading models when dropdown is opened (but no search is entered, yet). 90 | * 91 | * @argument loadDefaultOptions 92 | * @type {Boolean} 93 | * @default true 94 | */ 95 | 96 | /** 97 | * Whether or not to use infinite scroll. 98 | * 99 | * @argument infiniteScroll 100 | * @type {Boolean} 101 | * @default true 102 | */ 103 | get infiniteScroll() { 104 | return this.args.infiniteScroll === undefined || this.args.infiniteScroll; 105 | } 106 | 107 | /** 108 | * The amount of records loaded at once when `infiniteScroll` is enabled. 109 | * 110 | * @argument pageSize 111 | * @type {Number} 112 | * @default 25 113 | */ 114 | get pageSize() { 115 | return this.args.pageSize || getConfigOption('pageSize', 25); 116 | } 117 | 118 | /** 119 | * Additional parameters for data query. Can be used to sort etc. 120 | * 121 | * @argument query 122 | * @type {Object} 123 | */ 124 | 125 | /** 126 | * Debounce duration in ms used when searching. 127 | * 128 | * @argument debounceDuration 129 | * @type {Number} 130 | * @default 250 131 | */ 132 | get debounceDuration() { 133 | return ( 134 | this.args.debounceDuration || getConfigOption('debounceDuration', 250) 135 | ); 136 | } 137 | 138 | /** 139 | * Whether to allow creation of entries in case search yields no results. 140 | * 141 | * @argument withCreate 142 | * @type {Boolean} 143 | * @default false 144 | */ 145 | 146 | /** 147 | * Function which outputs the label to be shown for the create option when `withCreate` is set to `true`. 148 | * 149 | * @argument buildSuggestion 150 | * @type {Function} 151 | * @default 'Add "${term}"...' 152 | */ 153 | 154 | /** 155 | * Ember-infinity argument. 156 | * 157 | * See: https://github.com/ember-infinity/ember-infinity#json-requestresponse-customization 158 | * 159 | * @argument perPageParam 160 | * @type {String} 161 | * @default 'page[size]' 162 | */ 163 | get perPageParam() { 164 | return ( 165 | this.args.perPageParam || getConfigOption('perPageParam', 'page[size]') 166 | ); 167 | } 168 | 169 | /** 170 | * Ember-infinity argument. 171 | * 172 | * See: https://github.com/ember-infinity/ember-infinity#json-requestresponse-customization 173 | * 174 | * @argument pageParam 175 | * @type {String} 176 | * @default 'page[number]' 177 | */ 178 | get pageParam() { 179 | return this.args.pageParam || getConfigOption('pageParam', 'page[number]'); 180 | } 181 | 182 | /** 183 | * Ember-infinity argument. 184 | * 185 | * See: https://github.com/ember-infinity/ember-infinity#json-requestresponse-customization 186 | * 187 | * @argument totalPagesParam 188 | * @type {String} 189 | * @default 'meta.total' 190 | */ 191 | get totalPagesParam() { 192 | return ( 193 | this.args.totalPagesParam || 194 | getConfigOption('totalPagesParam', 'meta.total') 195 | ); 196 | } 197 | 198 | /** 199 | * Ember-power-select-option. 200 | * 201 | * See: https://ember-power-select.com/docs/api-reference/ 202 | * 203 | * @argument optionsComponent 204 | * @type {Component} 205 | * @default 'model-select/options' 206 | */ 207 | get optionsComponent() { 208 | return this.args.optionsComponent || 'model-select/options'; 209 | } 210 | 211 | /** 212 | * Called upon creation of new entry. 213 | * 214 | * @argument onCreate 215 | * @type {Action} 216 | */ 217 | 218 | @tracked _options; 219 | @tracked model; 220 | 221 | // constructor() { 222 | // super(...arguments); 223 | 224 | // assert('{{model-select}} requires a valid `modelName`.', !isEmpty(this.get('modelName'))); 225 | // assert('{{model-select}} requires a valid `labelProperty`.', !isEmpty(this.get('labelProperty'))); 226 | // assert('{{model-select}} requires `debounceDuration` to be an Integer.', !isEmpty(this.get('debounceDuration')) && Number.isInteger(this.get('debounceDuration'))); 227 | // assert('{{model-select}} `searchProperty` cannot be undefined or empty', !isEmpty(this.get('searchProperty'))); 228 | // } 229 | 230 | /** 231 | * The model selected by the user 232 | * 233 | * @property _selectedModel 234 | * @private 235 | */ 236 | // eslint-disable-next-line ember/require-computed-property-dependencies, ember/no-computed-properties-in-native-classes 237 | @computed('args.{selectedModel,modelName}') 238 | get _selectedModel() { 239 | const selectedModel = this.args.selectedModel; 240 | 241 | if ( 242 | typeof selectedModel === 'number' || 243 | typeof selectedModel === 'string' 244 | ) { 245 | const id = parseInt(selectedModel, 10); 246 | return !isNaN(id) 247 | ? this.findRecord.perform(this.args.modelName, id) 248 | : null; 249 | } else { 250 | return selectedModel; 251 | } 252 | } 253 | 254 | @dropTask 255 | *findRecord(modelName, id) { 256 | // this wrapper task is requried to avoid the following error upon fast changes 257 | // of selectedModel: 258 | // Error: Assertion Failed: You attempted to remove a function listener which 259 | // did not exist on the instance, which means you may have attempted to remove 260 | // it before it was added. 261 | return yield this.store.findRecord(modelName, id); 262 | } 263 | 264 | @restartableTask 265 | *searchModels(term, options, initialLoad = false) { 266 | let createOption; 267 | 268 | if (this.args.withCreate && term) { 269 | createOption = { 270 | __value__: term, 271 | __isSuggestion__: true, 272 | }; 273 | createOption[this.args.labelProperty] = this.args.buildSuggestion 274 | ? this.args.buildSuggestion(term) 275 | : `Add "${term}"...`; 276 | this._options = A([createOption]); 277 | } 278 | 279 | if (!initialLoad) { 280 | yield timeout(this.debounceDuration); 281 | } 282 | 283 | yield this.loadModels.perform(term, createOption); 284 | } 285 | 286 | @restartableTask 287 | *loadModels(term, createOption) { 288 | // query might be an EmptyObject/{{hash}}, make it a normal Object 289 | const query = assign({}, this.args.query); 290 | 291 | if (term) { 292 | const searchProperty = this.searchProperty; 293 | const searchKey = this.args.searchKey || this.args.labelProperty; 294 | 295 | const searchObj = get(query, `${searchProperty}`) || {}; 296 | set(searchObj, searchKey, term); 297 | set(query, searchProperty, searchObj); 298 | } 299 | 300 | let _options; 301 | 302 | if (this.infiniteScroll) { 303 | // ember-infinity configuration 304 | query.perPage = this.pageSize; 305 | 306 | query.perPageParam = this.perPageParam; 307 | query.pageParam = this.pageParam; 308 | query.totalPagesParam = this.totalPagesParam; 309 | 310 | this.model = this.infinity.model(this.args.modelName, query); 311 | 312 | _options = yield this.model; 313 | } else { 314 | set(query, this.pageParam, 1); 315 | set(query, this.perPageParam, this.pageSize); 316 | 317 | _options = yield this.source.query(this.args.modelName, query); 318 | } 319 | 320 | if (createOption) { 321 | _options.unshiftObjects([createOption]); 322 | } 323 | 324 | this._options = _options; 325 | } 326 | 327 | loadDefaultOptions() { 328 | if ( 329 | this.args.loadDefaultOptions === undefined || 330 | this.args.loadDefaultOptions 331 | ) { 332 | this.searchModels.perform(null, null, true); 333 | } 334 | } 335 | 336 | @action 337 | onOpen() { 338 | this.loadDefaultOptions(); 339 | 340 | if (this.args.onOpen) { 341 | this.args.onOpen(...arguments); 342 | } 343 | } 344 | 345 | @action 346 | onInput(term) { 347 | if (isEmpty(term)) { 348 | this.loadDefaultOptions(); 349 | } 350 | 351 | if (this.args.onInput) { 352 | this.args.onInput(...arguments); 353 | } 354 | } 355 | 356 | @action 357 | onClose() { 358 | this.searchModels.cancelAll(); 359 | 360 | if (this.args.onClose) { 361 | this.args.onClose(...arguments); 362 | } 363 | } 364 | 365 | @action 366 | change(model, select) { 367 | if (!isEmpty(model) && model.__isSuggestion__) { 368 | if (this.args.onCreate) { 369 | this.args.onCreate(model.__value__, select); 370 | } 371 | } else { 372 | if (this.args.onChange) { 373 | this.args.onChange(model, select); 374 | } 375 | } 376 | } 377 | } 378 | -------------------------------------------------------------------------------- /addon/components/model-select/options.hbs: -------------------------------------------------------------------------------- 1 | 30 | -------------------------------------------------------------------------------- /addon/components/model-select/options.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line ember/no-computed-properties-in-native-classes 2 | import { computed } from '@ember/object'; 3 | import Component from '@glimmer/component'; 4 | 5 | export default class OptionsComponent extends Component { 6 | @computed('args.{infiniteScroll,infiniteModel,select.loading}') 7 | get showLoader() { 8 | return ( 9 | this.args.infiniteScroll && 10 | this.args.infiniteModel && 11 | !this.args.select.loading 12 | ); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /addon/components/model-select/spinner.hbs: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /addon/utils/get-config-option.js: -------------------------------------------------------------------------------- 1 | import config from 'ember-get-config'; 2 | import { get } from '@ember/object'; 3 | 4 | /** 5 | * Get's the passed configuration option from the `ember-model-select` 6 | * environment key or the passed default if the config option is not set. 7 | * 8 | * @function getConfigOption 9 | * @param {String} key 10 | * @param {*} defaultValue 11 | * @return {*} The config option or the default value 12 | * @private 13 | * @hide 14 | */ 15 | export default function getConfigOption(key, defaultValue) { 16 | let value = get(config, `ember-model-select.${key}`); 17 | if (value !== undefined) { 18 | return value; 19 | } 20 | return defaultValue; 21 | } 22 | -------------------------------------------------------------------------------- /app/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickschot/ember-model-select/050177355b037fa73f98b6aa2cb1ada07744a0cc/app/.gitkeep -------------------------------------------------------------------------------- /app/components/model-select-multiple.js: -------------------------------------------------------------------------------- 1 | export { default } from 'ember-model-select/components/model-select-multiple'; 2 | -------------------------------------------------------------------------------- /app/components/model-select.js: -------------------------------------------------------------------------------- 1 | export { default } from 'ember-model-select/components/model-select'; 2 | -------------------------------------------------------------------------------- /app/components/model-select/options.js: -------------------------------------------------------------------------------- 1 | export { default } from 'ember-model-select/components/model-select/options'; 2 | -------------------------------------------------------------------------------- /app/components/model-select/spinner.js: -------------------------------------------------------------------------------- 1 | export { default } from 'ember-model-select/components/model-select/spinner'; 2 | -------------------------------------------------------------------------------- /app/styles/ember-model-select.scss: -------------------------------------------------------------------------------- 1 | @import "ember-power-select/variables"; 2 | 3 | $power-select-search-input-height: calc(2.25rem + 2px) !default; 4 | $ember-model-select__spinner-color: #007bff !default; 5 | $ember-model-select__spinner-opacity: 0.1 !default; 6 | $ember-model-select__spinner-duration: 1s !default; 7 | 8 | @keyframes ember-model-select-spin { 9 | 0% { transform: rotate(0deg); } 10 | 100% { transform: rotate(360deg); } 11 | } 12 | 13 | .ember-model-select__dropdown { 14 | .infinity-loader { 15 | display: flex; 16 | justify-content: center; 17 | align-items: center; 18 | padding: 0.25rem; 19 | overflow: hidden; 20 | } 21 | } 22 | 23 | .ember-model-select__spinner { 24 | position: relative; 25 | z-index: 2001; 26 | height: 16px; 27 | width: 16px; 28 | stroke: $ember-model-select__spinner-color; 29 | 30 | animation: ember-model-select-spin $ember-model-select__spinner-duration infinite linear; 31 | 32 | circle { 33 | stroke-opacity: $ember-model-select__spinner-opacity; 34 | } 35 | } 36 | 37 | .ember-model-select { 38 | position: relative; 39 | 40 | > .ember-model-select__loading { 41 | position: absolute; 42 | right: 1px; 43 | top: 1px; 44 | height: calc(100% - 2px); 45 | padding: 0 15px; 46 | background: #FFF; 47 | border-radius: 0 ($ember-power-select-trigger-default-border-radius - 1px) ($ember-power-select-trigger-default-border-radius - 1px) 0; 48 | 49 | display: flex; 50 | align-items: center; 51 | } 52 | } 53 | 54 | .ember-power-select-options { 55 | > li > ul { 56 | list-style: none; 57 | margin: 0; 58 | padding: 0; 59 | user-select: none; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /app/utils/get-config-option.js: -------------------------------------------------------------------------------- 1 | export { default } from 'ember-model-select/utils/get-config-option'; 2 | -------------------------------------------------------------------------------- /blueprints/ember-model-select/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | 3 | const path = require('path'); 4 | const fs = require('fs'); 5 | 6 | module.exports = { 7 | description: 'Adds style imports for the ember-model-select addon.', 8 | 9 | normalizeEntityName() { 10 | // this prevents an error when the entityName is 11 | // not specified (since that doesn't actually matter 12 | // to us 13 | }, 14 | 15 | afterInstall() { 16 | let dependencies = this.project.dependencies(); 17 | let importStatement = '\n@import "ember-model-select";\n'; 18 | 19 | if ('ember-cli-sass' in dependencies) { 20 | let stylePath = path.join('app', 'styles'); 21 | let file = path.join(stylePath, `app.scss`); 22 | 23 | if (!fs.existsSync(stylePath)) { 24 | fs.mkdirSync(stylePath); 25 | } 26 | if (fs.existsSync(file)) { 27 | this.ui.writeLine(`Added import statement to ${file}`); 28 | return this.insertIntoFile(file, importStatement, {}); 29 | } else { 30 | fs.writeFileSync(file, importStatement); 31 | this.ui.writeLine(`Created ${file}`); 32 | } 33 | } 34 | }, 35 | }; 36 | -------------------------------------------------------------------------------- /compile-css.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // eslint-disable-next-line n/no-unpublished-require 4 | const sass = require('sass'); 5 | const fs = require('fs'); 6 | const path = require('path'); 7 | 8 | const inputFile = path.join( 9 | __dirname, 10 | 'app', 11 | 'styles', 12 | 'ember-model-select.scss' 13 | ); 14 | const outputFile = path.join(__dirname, 'vendor', 'ember-model-select.css'); 15 | 16 | // Compile main file 17 | var result = sass.renderSync({ 18 | data: fs.readFileSync(inputFile, 'utf8'), 19 | includePaths: ['app/styles', 'node_modules/ember-power-select/app/styles'], 20 | }); 21 | 22 | fs.writeFileSync(outputFile, result.css); 23 | -------------------------------------------------------------------------------- /ember-cli-build.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const EmberAddon = require('ember-cli/lib/broccoli/ember-addon'); 4 | 5 | module.exports = function (defaults) { 6 | const app = new EmberAddon(defaults, { 7 | // Add options here 8 | }); 9 | 10 | /* 11 | This build file specifies the options for the dummy test app of this 12 | addon, located in `/tests/dummy` 13 | This build file does *not* influence how the addon or the app using it 14 | behave. You most likely want to be modifying `./index.js` or app's build file 15 | */ 16 | 17 | const { maybeEmbroider } = require('@embroider/test-setup'); 18 | return maybeEmbroider(app, { 19 | skipBabel: [ 20 | { 21 | package: 'qunit', 22 | }, 23 | ], 24 | }); 25 | }; 26 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | name: require('./package').name, 5 | 6 | included() { 7 | let app = this._findHost(); 8 | if (!app.__emberModelSelectIncludedInvoked) { 9 | app.__emberModelSelectIncludedInvoked = true; 10 | 11 | this._super.included.apply(this, arguments); 12 | 13 | let hasSass = !!app.registry.availablePlugins['ember-cli-sass']; 14 | 15 | // Don't include the precompiled css file if the user uses a supported CSS preprocessor 16 | if (!hasSass) { 17 | app.import('vendor/ember-model-select.css'); 18 | } 19 | } 20 | }, 21 | 22 | contentFor(type, config) { 23 | let emberPowerSelect = this.addons.find( 24 | (a) => a.name === 'ember-power-select' 25 | ); 26 | return emberPowerSelect.contentFor(type, config); 27 | }, 28 | }; 29 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ember-model-select", 3 | "version": "1.0.0-beta.3", 4 | "description": "An ember-cli addon to provide a searchable model select box with infinite scroll support.", 5 | "keywords": [ 6 | "ember-addon" 7 | ], 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/nickschot/ember-model-select" 11 | }, 12 | "license": "MIT", 13 | "author": "Nick Schot ", 14 | "directories": { 15 | "doc": "doc", 16 | "test": "tests" 17 | }, 18 | "scripts": { 19 | "build": "ember build --environment=production", 20 | "changelog": "npx lerna-changelog --from=v0.1.0-alpha.7 > CHANGELOG.md", 21 | "lint": "concurrently \"npm:lint:*(!fix)\" --names \"lint:\"", 22 | "lint:css": "stylelint \"**/*.css\" --allow-empty-input", 23 | "lint:css:fix": "concurrently \"npm:lint:css -- --fix\"", 24 | "lint:fix": "concurrently \"npm:lint:*:fix\" --names \"fix:\"", 25 | "lint:hbs": "ember-template-lint .", 26 | "lint:hbs:fix": "ember-template-lint . --fix", 27 | "lint:js": "eslint . --cache", 28 | "lint:js:fix": "eslint . --fix", 29 | "start": "ember serve", 30 | "test": "concurrently \"npm:lint\" \"npm:test:*\" --names \"lint,test:\"", 31 | "test:ember": "ember test", 32 | "test:ember-compatibility": "ember try:each", 33 | "prepare": "node ./compile-css.js" 34 | }, 35 | "dependencies": { 36 | "@ember/test-waiters": "^2.4.5", 37 | "@glimmer/component": "^1.1.2", 38 | "@glimmer/tracking": "^1.1.2", 39 | "ember-cli-babel": "^7.26.11", 40 | "ember-cli-htmlbars": "^6.3.0", 41 | "ember-concurrency": "^2.3.7", 42 | "ember-get-config": "^2.1.1", 43 | "ember-infinity": "^2.1.1", 44 | "ember-power-select": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" 45 | }, 46 | "devDependencies": { 47 | "@babel/eslint-parser": "^7.21.3", 48 | "@babel/plugin-proposal-decorators": "^7.21.0", 49 | "@ember/jquery": "^1.1.0", 50 | "@ember/optional-features": "^2.0.0", 51 | "@ember/string": "^3.0.1", 52 | "@ember/test-helpers": "^2.9.4", 53 | "@embroider/test-setup": "^2.1.1", 54 | "broccoli-asset-rev": "^3.0.0", 55 | "concurrently": "^8.0.1", 56 | "ember-auto-import": "^2.7.2", 57 | "ember-cli": "~4.12.0", 58 | "ember-cli-addon-docs": "^4.2.2", 59 | "ember-cli-addon-docs-yuidoc": "^1.0.0", 60 | "ember-cli-dependency-checker": "^3.3.1", 61 | "ember-cli-deploy": "^1.0.2", 62 | "ember-cli-deploy-build": "^2.0.0", 63 | "ember-cli-deploy-git": "^1.3.4", 64 | "ember-cli-deploy-git-ci": "^1.0.1", 65 | "ember-cli-github-pages": "^0.2.1", 66 | "ember-cli-inject-live-reload": "^2.1.0", 67 | "ember-cli-mirage": "^2.4.0", 68 | "ember-cli-sass": "^11.0.1", 69 | "ember-cli-sri": "^2.1.1", 70 | "ember-cli-terser": "^4.0.2", 71 | "ember-data": "~4.12.5", 72 | "ember-load-initializers": "^2.1.2", 73 | "ember-mirage-sauce": "^1.0.0", 74 | "ember-page-title": "^7.0.0", 75 | "ember-qunit": "^5.1.5", 76 | "ember-resolver": "^10.0.0", 77 | "ember-sinon": "^4.1.1", 78 | "ember-sinon-qunit": "^4.0.1", 79 | "ember-source": "~4.12.0", 80 | "ember-source-channel-url": "^3.0.0", 81 | "ember-template-lint": "^5.7.2", 82 | "ember-try": "^3.0.0", 83 | "eslint": "^8.37.0", 84 | "eslint-config-prettier": "^8.8.0", 85 | "eslint-plugin-ember": "^11.5.0", 86 | "eslint-plugin-n": "^15.7.0", 87 | "eslint-plugin-prettier": "^4.2.1", 88 | "eslint-plugin-qunit": "^7.3.4", 89 | "faker": "^5.1.0", 90 | "loader.js": "^4.7.0", 91 | "prettier": "^2.8.7", 92 | "qunit": "^2.20.0", 93 | "qunit-dom": "^2.0.0", 94 | "sass": "^1.17.0", 95 | "stylelint": "^15.4.0", 96 | "stylelint-config-prettier": "^9.0.5", 97 | "stylelint-config-standard": "^32.0.0", 98 | "stylelint-prettier": "^3.0.0", 99 | "webpack": "^5.89.0" 100 | }, 101 | "peerDependencies": { 102 | "ember-source": "^3.28.0 || ^4.0.0" 103 | }, 104 | "resolutions": { 105 | "@embroider/macros": "1.13.4", 106 | "@embroider/util": "1.12.1" 107 | }, 108 | "engines": { 109 | "node": "16.* || >= 18" 110 | }, 111 | "ember": { 112 | "edition": "octane" 113 | }, 114 | "ember-addon": { 115 | "configPath": "tests/dummy/config" 116 | }, 117 | "homepage": "https://nickschot.github.io/ember-model-select", 118 | "volta": { 119 | "node": "16.20.2", 120 | "pnpm": "8.13.1" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /testem.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | test_page: 'tests/index.html?hidepassed', 5 | disable_watching: true, 6 | launch_in_ci: ['Chrome'], 7 | launch_in_dev: ['Chrome'], 8 | browser_start_timeout: 120, 9 | browser_args: { 10 | Chrome: { 11 | ci: [ 12 | // --no-sandbox is needed when running Chrome inside a container 13 | process.env.CI ? '--no-sandbox' : null, 14 | '--headless', 15 | '--disable-dev-shm-usage', 16 | '--disable-software-rasterizer', 17 | '--mute-audio', 18 | '--remote-debugging-port=0', 19 | '--window-size=1440,900', 20 | ].filter(Boolean), 21 | }, 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /tests/dummy/app/app.js: -------------------------------------------------------------------------------- 1 | import Application from '@ember/application'; 2 | import Resolver from 'ember-resolver'; 3 | import loadInitializers from 'ember-load-initializers'; 4 | import config from 'dummy/config/environment'; 5 | 6 | export default class App extends Application { 7 | modulePrefix = config.modulePrefix; 8 | podModulePrefix = config.podModulePrefix; 9 | Resolver = Resolver; 10 | } 11 | 12 | loadInitializers(App, config.modulePrefix); 13 | -------------------------------------------------------------------------------- /tests/dummy/app/components/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickschot/ember-model-select/050177355b037fa73f98b6aa2cb1ada07744a0cc/tests/dummy/app/components/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/app/controllers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickschot/ember-model-select/050177355b037fa73f98b6aa2cb1ada07744a0cc/tests/dummy/app/controllers/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/app/controllers/docs/components/model-select-multiple.js: -------------------------------------------------------------------------------- 1 | import Controller from '@ember/controller'; 2 | import { A } from '@ember/array'; 3 | import { action, set } from '@ember/object'; 4 | 5 | export default class ModelSelectMultipleController extends Controller { 6 | @action 7 | createMultipleUser(name) { 8 | if (!Array.isArray(this.users2)) { 9 | set(this, 'users2', A([])); 10 | } 11 | 12 | const user = this.store.createRecord('user', { name }); 13 | this.users2.push(user); 14 | user.save(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tests/dummy/app/controllers/docs/components/model-select.js: -------------------------------------------------------------------------------- 1 | import Controller from '@ember/controller'; 2 | import { action, set } from '@ember/object'; 3 | 4 | export default class ModelSelectControler extends Controller { 5 | @action 6 | createUser(name) { 7 | const user = this.store.createRecord('user', { name }); 8 | set(this, 'user2', user); 9 | user.save(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/dummy/app/helpers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickschot/ember-model-select/050177355b037fa73f98b6aa2cb1ada07744a0cc/tests/dummy/app/helpers/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Ember Model Select 6 | 7 | 8 | 9 | {{content-for "head"}} 10 | 11 | 12 | 13 | 14 | {{content-for "head-footer"}} 15 | 16 | 17 | {{content-for "body"}} 18 | 19 | 20 | 21 | 22 | {{content-for "body-footer"}} 23 | 24 | 25 | -------------------------------------------------------------------------------- /tests/dummy/app/models/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickschot/ember-model-select/050177355b037fa73f98b6aa2cb1ada07744a0cc/tests/dummy/app/models/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/app/models/user.js: -------------------------------------------------------------------------------- 1 | import Model, { attr } from '@ember-data/model'; 2 | 3 | export default class User extends Model { 4 | @attr() name; 5 | } 6 | -------------------------------------------------------------------------------- /tests/dummy/app/router.js: -------------------------------------------------------------------------------- 1 | import AddonDocsRouter, { docsRoute } from 'ember-cli-addon-docs/router'; 2 | import config from 'dummy/config/environment'; 3 | 4 | export default class Router extends AddonDocsRouter { 5 | location = config.locationType; 6 | rootURL = config.rootURL; 7 | } 8 | 9 | Router.map(function () { 10 | docsRoute(this, function () { 11 | this.route('usage'); 12 | this.route('quickstart'); 13 | 14 | this.route('components', function () { 15 | this.route('model-select'); 16 | this.route('model-select-multiple'); 17 | }); 18 | }); 19 | this.route('not-found', { path: '/*path' }); 20 | }); 21 | -------------------------------------------------------------------------------- /tests/dummy/app/routes/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickschot/ember-model-select/050177355b037fa73f98b6aa2cb1ada07744a0cc/tests/dummy/app/routes/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/app/serializers/application.js: -------------------------------------------------------------------------------- 1 | import JSONAPISerializer from '@ember-data/serializer/json-api'; 2 | 3 | export default class ApplicationSerializer extends JSONAPISerializer {} 4 | -------------------------------------------------------------------------------- /tests/dummy/app/styles/app.scss: -------------------------------------------------------------------------------- 1 | @import "ember-power-select"; 2 | @import "ember-model-select"; 3 | -------------------------------------------------------------------------------- /tests/dummy/app/templates/application.hbs: -------------------------------------------------------------------------------- 1 |
2 | 3 | {{outlet}} 4 |
-------------------------------------------------------------------------------- /tests/dummy/app/templates/docs.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{nav.section "Introduction"}} 5 | {{nav.item "Introduction" "docs.index"}} 6 | {{nav.item "Usage" "docs.usage"}} 7 | {{nav.item "Quickstart" "docs.quickstart"}} 8 | 9 | {{nav.section "Components"}} 10 | {{nav.item "Model Select" "docs.components.model-select"}} 11 | {{nav.item "Multiple Select" "docs.components.model-select-multiple"}} 12 | 13 | 14 | 15 |
16 |
17 | {{outlet}} 18 |
19 |
20 |
21 | 22 |
-------------------------------------------------------------------------------- /tests/dummy/app/templates/docs/components/model-select-multiple.md: -------------------------------------------------------------------------------- 1 | # Model Select Multiple 2 | 3 | ## Multiple Select 4 | 5 | 6 | 16 | 17 | 18 | {{demo.snippet 'multiple-select.hbs'}} 19 | 20 | 21 | ## Multiple Select with Create 22 | There is also a `withCreate` option which can be enabled by passing `withCreate={{true}}`. The `onCreate` hook is called with the search term. An optional `buildSuggestion` function can be passed to construct the text shown in the create option. This defaults to `Add "term"...`. 23 | 24 | It is up to the user to implement the actual creation and addition of the model instance to the `selectedModel` Array. 25 | 26 | 27 | 28 | 41 | 42 | 43 | {{demo.snippet 'multiple-select-with-create.hbs'}} 44 | 45 | 46 | ## Multiple Select with Block 47 | 48 | 49 | 60 | Name: {{model.name}} 61 | 62 | 63 | 64 | {{demo.snippet 'multiple-select-with-block.hbs'}} 65 | 66 | -------------------------------------------------------------------------------- /tests/dummy/app/templates/docs/components/model-select.md: -------------------------------------------------------------------------------- 1 | # Model Select 2 | 3 | ## Single Select 4 | 5 | 6 | 17 | 18 | 19 | {{demo.snippet 'single-select.hbs'}} 20 | 21 | 22 | ## Single Select with Create 23 | There is also a `withCreate` option which can be enabled by passing `withCreate={{true}}`. The `onCreate` hook is called with the search term. An optional `buildSuggestion` function can be passed to construct the text shown in the create option. This defaults to `Add "term"...`. 24 | 25 | 26 | 27 | 41 | 42 | 43 | {{demo.snippet 'single-select-with-create.hbs'}} 44 | 45 | 46 | ## Single Select with Custom Option display 47 | The model-select can also be used with a block form. Each of the models is yielded as `model`. 48 | 49 | 50 | 62 | Name: {{model.name}} 63 | 64 | 65 | 66 | {{demo.snippet 'single-select-with-block.hbs'}} 67 | 68 | -------------------------------------------------------------------------------- /tests/dummy/app/templates/docs/index.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | An [ember-cli](https://www.ember-cli.com) addon to provide a searchable model select box with infinite scroll support. 4 | 5 | The addon composes [ember-power-select](https://ember-power-select.com), [ember-infinity](https://github.com/ember-infinity/ember-infinity) and [ember-concurrency](http://ember-concurrency.com) to provide an easy to use generic model select box based on ember-data models. It can be used in any place where one might want to search for models without the need for extra JavaScript code. 6 | -------------------------------------------------------------------------------- /tests/dummy/app/templates/docs/quickstart.md: -------------------------------------------------------------------------------- 1 | # Quickstart 2 | 3 | 1. **Install Model Select** 4 | 5 | ``` 6 | ember install ember-model-select 7 | ``` 8 | 9 | 2. **Add a model select to your template** 10 | 11 | You need to pass in the name of your model, the property on the model to use as the label and the selected model. Furthermore you can set the search key (and if necessary property) so it conforms to your API. 12 | 13 | ```handlebars 14 | 24 | ``` 25 | 26 | ## Optional steps 27 | 28 | 1. **ember-bootstrap integration** 29 | 30 | A plugin to integrate ember-model-select with ember-bootstrap forms can be found [here](https://github.com/nickschot/ember-bootstrap-model-select). 31 | 32 | 2. **global configuration** 33 | 34 | It is very likely you will need to set for example the `searchProperty` and `searchKey` to conform to your API. If you do not want to pass certain options to every instantiation of model-select you can set them in `config/environment.js`: 35 | 36 | ```javascript 37 | 'use strict'; 38 | 39 | module.exports = function(environment) { 40 | let ENV = { 41 | … 42 | 43 | 'ember-model-select': { 44 | searchProperty: 'search', 45 | pageSize: 25, 46 | debounceDuration: 250, 47 | perPageParam: 'page[size]', 48 | pageParam: 'page[number]', 49 | totalPagesParam: 'meta.total', 50 | } 51 | }; 52 | 53 | return ENV; 54 | }; 55 | ``` 56 | -------------------------------------------------------------------------------- /tests/dummy/app/templates/docs/usage.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | ## Installation 3 | From your application directory run: 4 | 5 | ```sh 6 | ember install ember-model-select 7 | ``` 8 | 9 | The addon will automatically add the necessary SCSS import to your `app.scss` or include the required CSS if you are not using `ember-cli-sass`. 10 | -------------------------------------------------------------------------------- /tests/dummy/app/templates/index.hbs: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /tests/dummy/app/templates/not-found.hbs: -------------------------------------------------------------------------------- 1 |
2 |

Not found

3 |

This page doesn't exist. Head home?

4 |
5 | -------------------------------------------------------------------------------- /tests/dummy/config/addon-docs.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | 'use strict'; 3 | 4 | const AddonDocsConfig = require('ember-cli-addon-docs/lib/config'); 5 | 6 | module.exports = class extends AddonDocsConfig { 7 | // See https://ember-learn.github.io/ember-cli-addon-docs/docs/deploying 8 | // for details on configuration you can override here. 9 | }; 10 | -------------------------------------------------------------------------------- /tests/dummy/config/deploy.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | 'use strict'; 3 | 4 | module.exports = function (deployTarget) { 5 | let ENV = { 6 | build: {}, 7 | // include other plugin configuration that applies to all deploy targets here 8 | }; 9 | 10 | if (deployTarget === 'development') { 11 | ENV.build.environment = 'development'; 12 | // configure other plugins for development deploy target here 13 | } 14 | 15 | if (deployTarget === 'staging') { 16 | ENV.build.environment = 'production'; 17 | // configure other plugins for staging deploy target here 18 | } 19 | 20 | if (deployTarget === 'production') { 21 | ENV.build.environment = 'production'; 22 | // configure other plugins for production deploy target here 23 | } 24 | 25 | // Note: if you need to build some configuration asynchronously, you can return 26 | // a promise that resolves with the ENV object instead of returning the 27 | // ENV object synchronously. 28 | return ENV; 29 | }; 30 | -------------------------------------------------------------------------------- /tests/dummy/config/ember-cli-update.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": "1.0.0", 3 | "packages": [ 4 | { 5 | "name": "ember-cli", 6 | "version": "4.12.0", 7 | "blueprints": [ 8 | { 9 | "name": "addon", 10 | "outputRepo": "https://github.com/ember-cli/ember-addon-output", 11 | "codemodsSource": "ember-addon-codemods-manifest@1", 12 | "isBaseBlueprint": true, 13 | "options": [ 14 | "--yarn", 15 | "--no-welcome" 16 | ] 17 | } 18 | ] 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /tests/dummy/config/ember-try.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const getChannelURL = require('ember-source-channel-url'); 4 | const { embroiderSafe, embroiderOptimized } = require('@embroider/test-setup'); 5 | 6 | module.exports = async function () { 7 | return { 8 | usePnpm: true, 9 | scenarios: [ 10 | { 11 | name: 'power-select-4', 12 | npm: { 13 | devDependencies: { 14 | 'ember-source': '~3.28.12', 15 | 'ember-power-select': '^4.0.0', 16 | }, 17 | }, 18 | }, 19 | { 20 | name: 'power-select-5', 21 | npm: { 22 | devDependencies: { 23 | 'ember-source': '~3.28.12', 24 | 'ember-power-select': '^5.0.0', 25 | }, 26 | }, 27 | }, 28 | { 29 | name: 'power-select-6', 30 | npm: { 31 | devDependencies: { 32 | 'ember-source': '~3.28.12', 33 | 'ember-power-select': '^6.0.0', 34 | }, 35 | }, 36 | }, 37 | { 38 | name: 'power-select-7', 39 | npm: { 40 | devDependencies: { 41 | 'ember-source': '~3.28.12', 42 | 'ember-power-select': '^7.0.0', 43 | }, 44 | }, 45 | }, 46 | { 47 | name: 'ember-lts-3.28', 48 | npm: { 49 | devDependencies: { 50 | 'ember-source': '~3.28.12', 51 | }, 52 | }, 53 | }, 54 | { 55 | name: 'ember-lts-4.4', 56 | npm: { 57 | devDependencies: { 58 | 'ember-source': '~4.4.0', 59 | }, 60 | }, 61 | }, 62 | { 63 | name: 'ember-lts-4.8', 64 | npm: { 65 | devDependencies: { 66 | 'ember-source': '~4.8.0', 67 | }, 68 | }, 69 | }, 70 | { 71 | name: 'ember-lts-4.12', 72 | npm: { 73 | devDependencies: { 74 | 'ember-source': '~4.12.0', 75 | }, 76 | }, 77 | }, 78 | { 79 | name: 'ember-release', 80 | npm: { 81 | devDependencies: { 82 | 'ember-source': await getChannelURL('release'), 83 | }, 84 | }, 85 | }, 86 | { 87 | name: 'ember-beta', 88 | npm: { 89 | devDependencies: { 90 | 'ember-source': await getChannelURL('beta'), 91 | }, 92 | }, 93 | }, 94 | { 95 | name: 'ember-canary', 96 | npm: { 97 | devDependencies: { 98 | 'ember-source': await getChannelURL('canary'), 99 | }, 100 | }, 101 | }, 102 | { 103 | name: 'ember-default-with-jquery', 104 | env: { 105 | EMBER_OPTIONAL_FEATURES: JSON.stringify({ 106 | 'jquery-integration': true, 107 | }), 108 | }, 109 | npm: { 110 | devDependencies: { 111 | '@ember/jquery': '^1.1.0', 112 | }, 113 | }, 114 | }, 115 | { 116 | name: 'ember-classic', 117 | env: { 118 | EMBER_OPTIONAL_FEATURES: JSON.stringify({ 119 | 'application-template-wrapper': true, 120 | 'default-async-observers': false, 121 | 'template-only-glimmer-components': false, 122 | }), 123 | }, 124 | npm: { 125 | ember: { 126 | edition: 'classic', 127 | }, 128 | }, 129 | }, 130 | embroiderSafe(), 131 | embroiderOptimized(), 132 | ], 133 | }; 134 | }; 135 | -------------------------------------------------------------------------------- /tests/dummy/config/environment.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (environment) { 4 | const ENV = { 5 | modulePrefix: 'dummy', 6 | environment, 7 | rootURL: '/', 8 | locationType: 'history', 9 | EmberENV: { 10 | EXTEND_PROTOTYPES: false, 11 | FEATURES: { 12 | // Here you can enable experimental features on an ember canary build 13 | // e.g. EMBER_NATIVE_DECORATOR_SUPPORT: true 14 | }, 15 | }, 16 | 17 | APP: { 18 | // Here you can pass flags/options to your application instance 19 | // when it is created 20 | }, 21 | 22 | 'ember-model-select': { 23 | totalPagesParam: 'meta.pages', 24 | }, 25 | }; 26 | 27 | if (environment === 'development') { 28 | // ENV.APP.LOG_RESOLVER = true; 29 | // ENV.APP.LOG_ACTIVE_GENERATION = true; 30 | // ENV.APP.LOG_TRANSITIONS = true; 31 | // ENV.APP.LOG_TRANSITIONS_INTERNAL = true; 32 | // ENV.APP.LOG_VIEW_LOOKUPS = true; 33 | } 34 | 35 | if (environment === 'test') { 36 | // Testem prefers this... 37 | ENV.locationType = 'none'; 38 | 39 | // keep test console output quieter 40 | ENV.APP.LOG_ACTIVE_GENERATION = false; 41 | ENV.APP.LOG_VIEW_LOOKUPS = false; 42 | 43 | ENV.APP.rootElement = '#ember-testing'; 44 | ENV.APP.autoboot = false; 45 | } 46 | 47 | if (environment === 'production') { 48 | // Allow ember-cli-addon-docs to update the rootURL in compiled assets 49 | ENV.rootURL = 'ADDON_DOCS_ROOT_URL'; 50 | // here you can enable a production-specific feature 51 | ENV['ember-cli-mirage'] = { 52 | enabled: true, 53 | }; 54 | } 55 | 56 | return ENV; 57 | }; 58 | -------------------------------------------------------------------------------- /tests/dummy/config/optional-features.json: -------------------------------------------------------------------------------- 1 | { 2 | "application-template-wrapper": false, 3 | "default-async-observers": true, 4 | "jquery-integration": false, 5 | "template-only-glimmer-components": true 6 | } 7 | -------------------------------------------------------------------------------- /tests/dummy/config/targets.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const browsers = [ 4 | 'last 1 Chrome versions', 5 | 'last 1 Firefox versions', 6 | 'last 1 Safari versions', 7 | ]; 8 | 9 | module.exports = { 10 | browsers, 11 | }; 12 | -------------------------------------------------------------------------------- /tests/dummy/mirage/config.js: -------------------------------------------------------------------------------- 1 | export default function () { 2 | // These comments are here to help you get started. Feel free to delete them. 3 | 4 | /* 5 | Config (with defaults). 6 | 7 | Note: these only affect routes defined *after* them! 8 | */ 9 | 10 | // this.urlPrefix = ''; // make this `http://localhost:8080`, for example, if your API is on a different server 11 | // this.namespace = ''; // make this `/api`, for example, if your API is namespaced 12 | // this.timing = 400; // delay for each request, automatically set to 0 during testing 13 | 14 | /* 15 | Shorthand cheatsheet: 16 | 17 | this.get('/posts'); 18 | this.post('/posts'); 19 | this.get('/posts/:id'); 20 | this.put('/posts/:id'); // or this.patch 21 | this.del('/posts/:id'); 22 | 23 | http://www.ember-cli-mirage.com/docs/v0.3.x/shorthands/ 24 | */ 25 | 26 | this.get('/users'); 27 | this.get('/users/:id'); 28 | this.post('/users', 'user'); 29 | 30 | this.passthrough(); 31 | } 32 | -------------------------------------------------------------------------------- /tests/dummy/mirage/factories/user.js: -------------------------------------------------------------------------------- 1 | import { Factory } from 'ember-cli-mirage'; 2 | import faker from 'faker'; 3 | 4 | export default Factory.extend({ 5 | name() { 6 | return faker.name.findName(); 7 | }, 8 | }); 9 | -------------------------------------------------------------------------------- /tests/dummy/mirage/scenarios/default.js: -------------------------------------------------------------------------------- 1 | import faker from 'faker'; 2 | 3 | export default function (server) { 4 | faker.seed(123); 5 | server.createList('user', 100); 6 | } 7 | -------------------------------------------------------------------------------- /tests/dummy/mirage/serializers/application.js: -------------------------------------------------------------------------------- 1 | import JSONAPISerializer from 'ember-mirage-sauce/mirage-serializers/json-api-serializer'; 2 | import { A } from '@ember/array'; 3 | 4 | export default JSONAPISerializer.extend({ 5 | searchByFields: A(['name']), 6 | }); 7 | -------------------------------------------------------------------------------- /tests/dummy/public/robots.txt: -------------------------------------------------------------------------------- 1 | # http://www.robotstxt.org 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /tests/helpers/index.js: -------------------------------------------------------------------------------- 1 | import { 2 | setupApplicationTest as upstreamSetupApplicationTest, 3 | setupRenderingTest as upstreamSetupRenderingTest, 4 | setupTest as upstreamSetupTest, 5 | } from 'ember-qunit'; 6 | 7 | // This file exists to provide wrappers around ember-qunit's / ember-mocha's 8 | // test setup functions. This way, you can easily extend the setup that is 9 | // needed per test type. 10 | 11 | function setupApplicationTest(hooks, options) { 12 | upstreamSetupApplicationTest(hooks, options); 13 | 14 | // Additional setup for application tests can be done here. 15 | // 16 | // For example, if you need an authenticated session for each 17 | // application test, you could do: 18 | // 19 | // hooks.beforeEach(async function () { 20 | // await authenticateSession(); // ember-simple-auth 21 | // }); 22 | // 23 | // This is also a good place to call test setup functions coming 24 | // from other addons: 25 | // 26 | // setupIntl(hooks); // ember-intl 27 | // setupMirage(hooks); // ember-cli-mirage 28 | } 29 | 30 | function setupRenderingTest(hooks, options) { 31 | upstreamSetupRenderingTest(hooks, options); 32 | 33 | // Additional setup for rendering tests can be done here. 34 | } 35 | 36 | function setupTest(hooks, options) { 37 | upstreamSetupTest(hooks, options); 38 | 39 | // Additional setup for unit tests can be done here. 40 | } 41 | 42 | export { setupApplicationTest, setupRenderingTest, setupTest }; 43 | -------------------------------------------------------------------------------- /tests/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Dummy Tests 6 | 7 | 8 | 9 | {{content-for "head"}} 10 | {{content-for "test-head"}} 11 | 12 | 13 | 14 | 15 | 16 | {{content-for "head-footer"}} 17 | {{content-for "test-head-footer"}} 18 | 19 | 20 | {{content-for "body"}} 21 | {{content-for "test-body"}} 22 | 23 |
24 |
25 |
26 |
27 |
28 |
29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | {{content-for "body-footer"}} 37 | {{content-for "test-body-footer"}} 38 | 39 | 40 | -------------------------------------------------------------------------------- /tests/integration/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickschot/ember-model-select/050177355b037fa73f98b6aa2cb1ada07744a0cc/tests/integration/.gitkeep -------------------------------------------------------------------------------- /tests/integration/components/model-select-multiple-test.js: -------------------------------------------------------------------------------- 1 | import { module, test } from 'qunit'; 2 | import { setupRenderingTest } from 'ember-qunit'; 3 | import sinon from 'sinon'; 4 | import { render } from '@ember/test-helpers'; 5 | import hbs from 'htmlbars-inline-precompile'; 6 | import { setupMirage } from 'ember-cli-mirage/test-support'; 7 | import { selectChoose, selectSearch } from 'ember-power-select/test-support'; 8 | import { 9 | clickTrigger, 10 | removeMultipleOption, 11 | } from 'ember-power-select/test-support/helpers'; 12 | import defaultScenario from '../../../../dummy/mirage/scenarios/default'; 13 | 14 | module('Integration | Component | model-select-multiple', function (hooks) { 15 | setupRenderingTest(hooks); 16 | setupMirage(hooks); 17 | 18 | test('it renders', async function (assert) { 19 | assert.expect(1); 20 | 21 | defaultScenario(this.server); 22 | 23 | this.noop = () => {}; 24 | 25 | await render( 26 | hbs`` 27 | ); 28 | await clickTrigger(); 29 | 30 | assert.dom('.ember-power-select-option').exists({ count: 25 }); 31 | }); 32 | 33 | test('you can select multiple items', async function (assert) { 34 | assert.expect(2); 35 | 36 | defaultScenario(this.server); 37 | 38 | this.selected = null; 39 | 40 | await render( 41 | hbs`` 42 | ); 43 | 44 | await selectChoose( 45 | '.ember-model-select-multiple-trigger', 46 | '.ember-power-select-option', 47 | 1 48 | ); 49 | await selectChoose( 50 | '.ember-model-select-multiple-trigger', 51 | '.ember-power-select-option', 52 | 2 53 | ); 54 | 55 | assert.strictEqual( 56 | this.selected.length, 57 | 2, 58 | 'two options have been selected' 59 | ); 60 | assert.dom('.ember-power-select-multiple-option').exists({ count: 2 }); 61 | }); 62 | 63 | test('you can unselect items', async function (assert) { 64 | assert.expect(2); 65 | 66 | defaultScenario(this.server); 67 | 68 | this.selected = null; 69 | 70 | await render( 71 | hbs`` 72 | ); 73 | 74 | await selectChoose( 75 | '.ember-model-select-multiple-trigger', 76 | '.ember-power-select-option', 77 | 1 78 | ); 79 | await selectChoose( 80 | '.ember-model-select-multiple-trigger', 81 | '.ember-power-select-option', 82 | 2 83 | ); 84 | 85 | await removeMultipleOption( 86 | '.ember-model-select-multiple-trigger', 87 | this.selected[0].get('name') 88 | ); 89 | 90 | assert.strictEqual(this.selected.length, 1, 'one option has been selected'); 91 | assert.dom('.ember-power-select-multiple-option').exists({ count: 1 }); 92 | }); 93 | 94 | test('it shows an Add ""... option when withCreate is true', async function (assert) { 95 | assert.expect(2); 96 | 97 | await render( 98 | hbs`` 99 | ); 100 | await selectSearch('.ember-model-select-multiple-trigger', 'test'); 101 | 102 | assert.dom('.ember-power-select-option').exists({ count: 1 }); 103 | assert.dom('.ember-power-select-option').hasText(`Add "test"...`); 104 | }); 105 | 106 | test('it fires the onCreate hook when the create option is selected', async function (assert) { 107 | assert.expect(2); 108 | 109 | this.handleCreate = sinon.spy(); 110 | 111 | await render( 112 | hbs`` 113 | ); 114 | await selectSearch('.ember-model-select-multiple-trigger', 'test'); 115 | await selectChoose( 116 | '.ember-model-select-multiple-trigger', 117 | '.ember-power-select-option', 118 | 1 119 | ); 120 | 121 | assert.ok( 122 | this.handleCreate.calledOnce, 123 | 'onCreate hook has been called once' 124 | ); 125 | assert.ok( 126 | this.handleCreate.calledWith('test'), 127 | 'onCreate hook has been called with the correct argument' 128 | ); 129 | }); 130 | 131 | test('it supports block form', async function (assert) { 132 | assert.expect(2); 133 | 134 | defaultScenario(this.server); 135 | 136 | await render( 137 | hbs`Test: {{model.name}}` 138 | ); 139 | await clickTrigger('.ember-model-select'); 140 | 141 | assert.dom('.ember-power-select-option').exists({ count: 25 }); 142 | assert 143 | .dom('.ember-power-select-option:first-child') 144 | .hasText(`Test: ${this.server.schema.users.first().name}`); 145 | }); 146 | }); 147 | -------------------------------------------------------------------------------- /tests/integration/components/model-select-test.js: -------------------------------------------------------------------------------- 1 | import { module, test } from 'qunit'; 2 | import { setupRenderingTest } from 'ember-qunit'; 3 | import sinon from 'sinon'; 4 | import { render, settled, click } from '@ember/test-helpers'; 5 | import hbs from 'htmlbars-inline-precompile'; 6 | import { setupMirage } from 'ember-cli-mirage/test-support'; 7 | import { selectChoose, selectSearch } from 'ember-power-select/test-support'; 8 | import { 9 | clickTrigger, 10 | typeInSearch, 11 | } from 'ember-power-select/test-support/helpers'; 12 | import defaultScenario from '../../../../dummy/mirage/scenarios/default'; 13 | import { timeout } from 'ember-concurrency'; 14 | import { isEmpty } from '@ember/utils'; 15 | import { set } from '@ember/object'; 16 | 17 | module('Integration | Component | model-select', function (hooks) { 18 | setupRenderingTest(hooks); 19 | setupMirage(hooks); 20 | 21 | test('it renders', async function (assert) { 22 | assert.expect(1); 23 | 24 | defaultScenario(this.server); 25 | 26 | await render(hbs``); 27 | await clickTrigger('.ember-model-select'); 28 | 29 | assert.dom('.ember-power-select-option').exists({ count: 25 }); 30 | }); 31 | 32 | test('it respects the page size option', async function (assert) { 33 | assert.expect(1); 34 | 35 | defaultScenario(this.server); 36 | 37 | await render( 38 | hbs`` 39 | ); 40 | await clickTrigger('.ember-model-select'); 41 | 42 | assert.dom('.ember-power-select-option').exists({ count: 10 }); 43 | }); 44 | 45 | test('it limits shown results based on search', async function (assert) { 46 | assert.expect(1); 47 | 48 | defaultScenario(this.server); 49 | 50 | await render( 51 | hbs`` 52 | ); 53 | await clickTrigger('.ember-model-select'); 54 | await typeInSearch('asdasdasd'); 55 | 56 | assert 57 | .dom('.ember-power-select-option--no-matches-message') 58 | .exists({ count: 1 }); 59 | }); 60 | 61 | test('it respects the search* and query parameters', async function (assert) { 62 | assert.expect(2); 63 | let requestNr = 0; 64 | 65 | this.server.get('/users', function (schema) { 66 | const queryParams = this.request.queryParams; 67 | 68 | if (requestNr === 1) { 69 | const expectedQueryParams = { 70 | 'filter[id_not_in]': '1,2,3', 71 | 'filter[name]': 'asdasdasd', 72 | 'page[number]': '1', 73 | 'page[size]': '25', 74 | }; 75 | 76 | // eslint-disable-next-line qunit/no-conditional-assertions 77 | assert.deepEqual( 78 | queryParams, 79 | expectedQueryParams, 80 | "query parameters don't match the expected ones" 81 | ); 82 | } else { 83 | const expectedQueryParams = { 84 | 'filter[id_not_in]': '1,2,3', 85 | 'page[number]': '1', 86 | 'page[size]': '25', 87 | }; 88 | 89 | // eslint-disable-next-line qunit/no-conditional-assertions 90 | assert.deepEqual( 91 | queryParams, 92 | expectedQueryParams, 93 | "query parameters don't match the expected ones" 94 | ); 95 | } 96 | 97 | requestNr++; 98 | 99 | // for this test we don't need to actuallyy filter anything, so just return all 100 | return schema.users.all(); 101 | }); 102 | 103 | await render( 104 | hbs`` 105 | ); 106 | await clickTrigger('.ember-model-select'); 107 | await typeInSearch('asdasdasd'); 108 | }); 109 | 110 | test('it triggers the onChange hook when an option is selected', async function (assert) { 111 | assert.expect(1); 112 | 113 | defaultScenario(this.server); 114 | 115 | this.handleClick = sinon.spy(); 116 | 117 | await render( 118 | hbs`` 119 | ); 120 | await selectChoose('.ember-model-select', '.ember-power-select-option', 1); 121 | 122 | assert.ok(this.handleClick.calledOnce, 'onChange hook has been called'); 123 | }); 124 | 125 | test('it loads more options when scrolling down', async function (assert) { 126 | assert.expect(1); 127 | 128 | defaultScenario(this.server); 129 | 130 | await render( 131 | hbs`` 132 | ); 133 | await clickTrigger('.ember-model-select'); 134 | 135 | this.element.querySelector('.ember-power-select-options').scrollTop = 999; 136 | 137 | //TODO: see if we can do this in a neater way 138 | await timeout(500); 139 | await settled(); 140 | 141 | assert.dom('.ember-power-select-option').exists({ count: 50 }); 142 | }); 143 | 144 | test('it does not load more options when scrolling down and infiniteLoading is false', async function (assert) { 145 | assert.expect(1); 146 | 147 | defaultScenario(this.server); 148 | 149 | await render( 150 | hbs`` 151 | ); 152 | await clickTrigger('.ember-model-select'); 153 | 154 | this.element.querySelector('.ember-power-select-options').scrollTop = 999; 155 | 156 | await settled(); 157 | 158 | assert.dom('.ember-power-select-option').exists({ count: 25 }); 159 | }); 160 | 161 | test('it shows an Add ""... option when withCreate is true', async function (assert) { 162 | assert.expect(2); 163 | 164 | await render( 165 | hbs`` 166 | ); 167 | await selectSearch('.ember-model-select', 'test'); 168 | 169 | assert.dom('.ember-power-select-option').exists({ count: 1 }); 170 | assert.dom('.ember-power-select-option').hasText(`Add "test"...`); 171 | }); 172 | 173 | test('it fires the onCreate hook when the create option is selected', async function (assert) { 174 | assert.expect(2); 175 | 176 | this.handleCreate = sinon.spy(); 177 | 178 | await render( 179 | hbs`` 180 | ); 181 | await selectSearch('.ember-model-select', 'test'); 182 | await selectChoose('.ember-model-select', '.ember-power-select-option', 1); 183 | 184 | assert.ok( 185 | this.handleCreate.calledOnce, 186 | 'onCreate hook has been called once' 187 | ); 188 | assert.ok( 189 | this.handleCreate.calledWith('test'), 190 | 'onCreate hook has been called with the correct argument' 191 | ); 192 | }); 193 | 194 | test('it can clear the selected item', async function (assert) { 195 | assert.expect(2); 196 | 197 | defaultScenario(this.server); 198 | 199 | this.selected = null; 200 | 201 | await render( 202 | hbs`` 203 | ); 204 | await selectChoose('.ember-model-select', '.ember-power-select-option', 1); 205 | 206 | assert.notOk(isEmpty(this.selected), 'selected item has been set'); 207 | 208 | await click('.ember-power-select-clear-btn'); 209 | 210 | assert.strictEqual(this.selected, null, 'selected item has been cleared'); 211 | }); 212 | 213 | test('it accepts an id passed to `selectedModel`', async function (assert) { 214 | assert.expect(2); 215 | 216 | defaultScenario(this.server); 217 | 218 | this.selected = '1'; 219 | 220 | await render( 221 | hbs`` 222 | ); 223 | assert 224 | .dom('.ember-power-select-selected-item') 225 | .hasText(this.server.schema.users.find(1).name); 226 | 227 | set(this, 'selected', 2); 228 | await settled(); 229 | assert 230 | .dom('.ember-power-select-selected-item') 231 | .hasText(this.server.schema.users.find(2).name); 232 | }); 233 | 234 | test('it supports block form', async function (assert) { 235 | assert.expect(2); 236 | 237 | defaultScenario(this.server); 238 | 239 | await render( 240 | hbs`Test: {{model.name}}` 241 | ); 242 | await clickTrigger('.ember-model-select'); 243 | 244 | assert.dom('.ember-power-select-option').exists({ count: 25 }); 245 | assert 246 | .dom('.ember-power-select-option:first-child') 247 | .hasText(`Test: ${this.server.schema.users.first().name}`); 248 | }); 249 | }); 250 | -------------------------------------------------------------------------------- /tests/integration/components/model-select/spinner-test.js: -------------------------------------------------------------------------------- 1 | import { module, test } from 'qunit'; 2 | import { setupRenderingTest } from 'ember-qunit'; 3 | import { render } from '@ember/test-helpers'; 4 | import hbs from 'htmlbars-inline-precompile'; 5 | 6 | module('Integration | Component | model-select/spinner', function (hooks) { 7 | setupRenderingTest(hooks); 8 | 9 | test('it renders the spinner element', async function (assert) { 10 | await render(hbs``); 11 | 12 | assert.dom('.ember-model-select__spinner').exists(); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /tests/test-helper.js: -------------------------------------------------------------------------------- 1 | import Application from 'dummy/app'; 2 | import config from 'dummy/config/environment'; 3 | import * as QUnit from 'qunit'; 4 | import { setApplication } from '@ember/test-helpers'; 5 | import { setup } from 'qunit-dom'; 6 | import { start } from 'ember-qunit'; 7 | import setupSinon from 'ember-sinon-qunit'; 8 | 9 | setApplication(Application.create(config.APP)); 10 | 11 | setup(QUnit.assert); 12 | 13 | setupSinon(); 14 | 15 | start(); 16 | -------------------------------------------------------------------------------- /tests/unit/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickschot/ember-model-select/050177355b037fa73f98b6aa2cb1ada07744a0cc/tests/unit/.gitkeep -------------------------------------------------------------------------------- /tests/unit/utils/get-config-option-test.js: -------------------------------------------------------------------------------- 1 | import getConfigOption from 'dummy/utils/get-config-option'; 2 | import { module, test } from 'qunit'; 3 | import { setupTest } from 'ember-qunit'; 4 | 5 | module('Unit | Utility | get-config-option', function (hooks) { 6 | setupTest(hooks); 7 | 8 | test('it returns the passed default when the global option is not set', function (assert) { 9 | assert.expect(1); 10 | 11 | assert.strictEqual(getConfigOption('perPageParam', 'foo'), 'foo'); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /vendor/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickschot/ember-model-select/050177355b037fa73f98b6aa2cb1ada07744a0cc/vendor/.gitkeep --------------------------------------------------------------------------------