├── .editorconfig ├── .ember-cli ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .npmignore ├── .template-lintrc.js ├── .travis.yml ├── .watchmanconfig ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── addon ├── components │ ├── ember-popper-base.js │ ├── ember-popper-targeting-parent.js │ └── ember-popper.js └── templates │ └── components │ ├── ember-popper-targeting-parent.hbs │ └── ember-popper.hbs ├── app ├── .gitkeep ├── components │ ├── ember-popper-targeting-parent.js │ └── ember-popper.js └── templates │ └── components │ ├── ember-popper-targeting-parent.js │ └── ember-popper.js ├── config ├── ember-try.js └── environment.js ├── ember-cli-build.js ├── index.js ├── jsconfig.json ├── package.json ├── testem.js ├── tests ├── dummy │ ├── app │ │ ├── app.js │ │ ├── components │ │ │ └── .gitkeep │ │ ├── controllers │ │ │ ├── .gitkeep │ │ │ └── application.js │ │ ├── helpers │ │ │ └── .gitkeep │ │ ├── index.html │ │ ├── models │ │ │ └── .gitkeep │ │ ├── router.js │ │ ├── routes │ │ │ └── .gitkeep │ │ ├── styles │ │ │ └── app.css │ │ └── templates │ │ │ └── application.hbs │ ├── config │ │ ├── environment.js │ │ ├── optional-features.json │ │ └── targets.js │ └── public │ │ └── robots.txt ├── helpers │ ├── .gitkeep │ └── resolver.js ├── index.html ├── integration │ ├── .gitkeep │ └── components │ │ ├── ember-popper-targeting-parent-test.js │ │ └── ember-popper │ │ ├── action-test.js │ │ ├── attributes-test.js │ │ ├── events-enabled-test.js │ │ ├── modifiers-test.js │ │ ├── placement-test.js │ │ ├── register-api-test.js │ │ ├── render-in-place-test.js │ │ └── target-test.js ├── test-helper.js └── unit │ └── .gitkeep ├── vendor ├── .gitkeep └── shims.js └── yarn.lock /.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 | [*] 9 | end_of_line = lf 10 | charset = utf-8 11 | trim_trailing_whitespace = true 12 | insert_final_newline = true 13 | indent_style = space 14 | indent_size = 2 15 | 16 | [*.hbs] 17 | insert_final_newline = false 18 | 19 | [*.{diff,md}] 20 | trim_trailing_whitespace = false 21 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | # ember-try 18 | /.node_modules.ember-try/ 19 | /bower.json.ember-try 20 | /package.json.ember-try 21 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: 'babel-eslint', 4 | parserOptions: { 5 | ecmaVersion: 2018, 6 | sourceType: 'module', 7 | ecmaFeatures: { 8 | legacyDecorators: true 9 | } 10 | }, 11 | plugins: [ 12 | 'ember' 13 | ], 14 | extends: [ 15 | 'eslint:recommended', 16 | 'plugin:ember/recommended' 17 | ], 18 | env: { 19 | browser: true 20 | }, 21 | globals: { 22 | Popper: false 23 | }, 24 | rules: { 25 | 'ember/no-jquery': 'error' 26 | }, 27 | overrides: [ 28 | // node files 29 | { 30 | files: [ 31 | '.eslintrc.js', 32 | '.template-lintrc.js', 33 | 'ember-cli-build.js', 34 | 'index.js', 35 | 'testem.js', 36 | 'blueprints/*/index.js', 37 | 'config/**/*.js', 38 | 'tests/dummy/config/**/*.js' 39 | ], 40 | excludedFiles: [ 41 | 'addon/**', 42 | 'addon-test-support/**', 43 | 'app/**', 44 | 'tests/dummy/app/**' 45 | ], 46 | parserOptions: { 47 | sourceType: 'script' 48 | }, 49 | env: { 50 | browser: false, 51 | node: true 52 | }, 53 | plugins: ['node'], 54 | rules: Object.assign({}, require('eslint-plugin-node').configs.recommended.rules, { 55 | // add your custom rules and overrides for node files here 56 | }) 57 | } 58 | ] 59 | }; 60 | -------------------------------------------------------------------------------- /.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 | /connect.lock 16 | /coverage/ 17 | /libpeerconnection.log 18 | /npm-debug.log* 19 | /testem.log 20 | /yarn-error.log 21 | .tern-project 22 | .DS_Store 23 | 24 | # ember-try 25 | /.node_modules.ember-try/ 26 | /bower.json.ember-try 27 | /package.json.ember-try 28 | -------------------------------------------------------------------------------- /.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 | /.eslintignore 14 | /.eslintrc.js 15 | /.git/ 16 | /.gitignore 17 | /.template-lintrc.js 18 | /.travis.yml 19 | /.watchmanconfig 20 | /bower.json 21 | /config/ember-try.js 22 | /CONTRIBUTING.md 23 | /ember-cli-build.js 24 | /testem.js 25 | /tests/ 26 | /yarn.lock 27 | .gitkeep 28 | 29 | # ember-try 30 | /.node_modules.ember-try/ 31 | /bower.json.ember-try 32 | /package.json.ember-try 33 | -------------------------------------------------------------------------------- /.template-lintrc.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | extends: 'octane' 5 | }; 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | language: node_js 3 | node_js: 4 | # we recommend testing addons with the same minimum supported node version as Ember CLI 5 | # so that your addon works for all apps 6 | - "10" 7 | 8 | sudo: false 9 | dist: trusty 10 | 11 | addons: 12 | chrome: stable 13 | 14 | cache: 15 | yarn: true 16 | 17 | env: 18 | global: 19 | # See https://git.io/vdao3 for details. 20 | - JOBS=1 21 | 22 | branches: 23 | only: 24 | - master 25 | # npm version tags 26 | - /^v\d+\.\d+\.\d+/ 27 | 28 | jobs: 29 | fast_finish: true 30 | allow_failures: 31 | - env: EMBER_TRY_SCENARIO=ember-canary 32 | 33 | include: 34 | # runs linting and tests with current locked deps 35 | - stage: "Tests" 36 | name: "Tests" 37 | script: 38 | # Disabled for now, remove when refactored to Octane idioms! 39 | # - yarn lint:hbs 40 | - yarn lint:js 41 | - yarn test 42 | 43 | - name: "Floating Dependencies" 44 | install: 45 | - yarn install --no-lockfile --non-interactive 46 | script: 47 | - yarn test 48 | 49 | # we recommend new addons test the current and previous LTS 50 | # as well as latest stable release (bonus points to beta/canary) 51 | - stage: "Additional Tests" 52 | env: EMBER_TRY_SCENARIO=ember-lts-3.12 53 | - env: EMBER_TRY_SCENARIO=ember-release 54 | - env: EMBER_TRY_SCENARIO=ember-beta 55 | - env: EMBER_TRY_SCENARIO=ember-canary 56 | - env: EMBER_TRY_SCENARIO=ember-default-with-jquery 57 | - env: EMBER_TRY_SCENARIO=ember-classic 58 | 59 | before_install: 60 | - curl -o- -L https://yarnpkg.com/install.sh | bash 61 | - export PATH=$HOME/.yarn/bin:$PATH 62 | 63 | install: 64 | - yarn install --non-interactive 65 | 66 | script: 67 | - node_modules/.bin/ember try:one $EMBER_TRY_SCENARIO 68 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | { 2 | "ignore_dirs": ["tmp", "dist"] 3 | } 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## [v0.10.1](https://github.com/kybishop/ember-popper/tree/v0.10.1) (2019-06-24) 4 | 5 | [Full Changelog](https://github.com/kybishop/ember-popper/compare/v0.10.0...v0.10.1) 6 | 7 | **Fixed bugs:** 8 | 9 | - api.\_popperElement is undefined [\#105](https://github.com/kybishop/ember-popper/issues/105) 10 | - Pass correct popper element in the registerAPI \#105 [\#106](https://github.com/kybishop/ember-popper/pull/106) ([urbany](https://github.com/urbany)) 11 | 12 | ## [v0.10.0](https://github.com/kybishop/ember-popper/tree/v0.10.0) (2019-06-08) 13 | 14 | [Full Changelog](https://github.com/kybishop/ember-popper/compare/v0.9.2...v0.10.0) 15 | 16 | **Implemented enhancements:** 17 | 18 | - Support angle bracket invocation [\#101](https://github.com/kybishop/ember-popper/pull/101) ([simonihmig](https://github.com/simonihmig)) 19 | 20 | **Closed issues:** 21 | 22 | - Support Angle Bracket Invocation [\#98](https://github.com/kybishop/ember-popper/issues/98) 23 | 24 | **Merged pull requests:** 25 | 26 | - Remove ember-native-dom-helpers [\#104](https://github.com/kybishop/ember-popper/pull/104) ([simonihmig](https://github.com/simonihmig)) 27 | - Drop ember-in-element-polyfill [\#103](https://github.com/kybishop/ember-popper/pull/103) ([simonihmig](https://github.com/simonihmig)) 28 | - Drop node 6 support [\#102](https://github.com/kybishop/ember-popper/pull/102) ([simonihmig](https://github.com/simonihmig)) 29 | - Drop support for Ember \<2.18 [\#100](https://github.com/kybishop/ember-popper/pull/100) ([simonihmig](https://github.com/simonihmig)) 30 | - TravisCI: Remove deprecated `sudo: false` option [\#97](https://github.com/kybishop/ember-popper/pull/97) ([Turbo87](https://github.com/Turbo87)) 31 | - ember 3.4 [\#96](https://github.com/kybishop/ember-popper/pull/96) ([kybishop](https://github.com/kybishop)) 32 | 33 | ## [v0.9.2](https://github.com/kybishop/ember-popper/tree/v0.9.2) (2018-10-12) 34 | 35 | [Full Changelog](https://github.com/kybishop/ember-popper/compare/v0.9.1...v0.9.2) 36 | 37 | **Closed issues:** 38 | 39 | - Deprecation warning on Ember 3.4 from use of sendAction [\#91](https://github.com/kybishop/ember-popper/issues/91) 40 | - no popper container in test mode with application-template-wrapper disabled [\#90](https://github.com/kybishop/ember-popper/issues/90) 41 | - Node 4 support [\#84](https://github.com/kybishop/ember-popper/issues/84) 42 | 43 | **Merged pull requests:** 44 | 45 | - Remove decorators [\#94](https://github.com/kybishop/ember-popper/pull/94) ([mhluska](https://github.com/mhluska)) 46 | 47 | ## [v0.9.1](https://github.com/kybishop/ember-popper/tree/v0.9.1) (2018-07-05) 48 | 49 | [Full Changelog](https://github.com/kybishop/ember-popper/compare/v0.9.0...v0.9.1) 50 | 51 | **Closed issues:** 52 | 53 | - "Attempting to change value of a readonly property" on Safari 9 [\#87](https://github.com/kybishop/ember-popper/issues/87) 54 | - misaligned if parent initially hidden [\#86](https://github.com/kybishop/ember-popper/issues/86) 55 | - Cleanup/Refactoring [\#71](https://github.com/kybishop/ember-popper/issues/71) 56 | 57 | **Merged pull requests:** 58 | 59 | - Move `babel-eslint` to dev dependencies [\#89](https://github.com/kybishop/ember-popper/pull/89) ([Turbo87](https://github.com/Turbo87)) 60 | - feat\(api\): support hidden attribute [\#85](https://github.com/kybishop/ember-popper/pull/85) ([jamesarosen](https://github.com/jamesarosen)) 61 | - refactor\(legacy support\): use unified component [\#83](https://github.com/kybishop/ember-popper/pull/83) ([simonihmig](https://github.com/simonihmig)) 62 | 63 | ## [v0.9.0](https://github.com/kybishop/ember-popper/tree/v0.9.0) (2018-03-20) 64 | 65 | [Full Changelog](https://github.com/kybishop/ember-popper/compare/v0.8.3...v0.9.0) 66 | 67 | **Closed issues:** 68 | 69 | - Decorators import scoped to `@ember` [\#81](https://github.com/kybishop/ember-popper/issues/81) 70 | - Cannot read property 'browsers' of undefined [\#79](https://github.com/kybishop/ember-popper/issues/79) 71 | 72 | **Merged pull requests:** 73 | 74 | - ember 3.1 [\#80](https://github.com/kybishop/ember-popper/pull/80) ([kybishop](https://github.com/kybishop)) 75 | - \[BREAKING\] ember-popper component now requires a target. new component, ember-popper-targeting-parent for those that need it [\#70](https://github.com/kybishop/ember-popper/pull/70) ([kybishop](https://github.com/kybishop)) 76 | 77 | ## [v0.8.3](https://github.com/kybishop/ember-popper/tree/v0.8.3) (2018-02-05) 78 | 79 | [Full Changelog](https://github.com/kybishop/ember-popper/compare/v0.8.2...v0.8.3) 80 | 81 | **Closed issues:** 82 | 83 | - WARNING [\#75](https://github.com/kybishop/ember-popper/issues/75) 84 | - '-start' & '-end' shift ? [\#74](https://github.com/kybishop/ember-popper/issues/74) 85 | 86 | **Merged pull requests:** 87 | 88 | - chore\(deps\): Update legacy shims and @argument [\#77](https://github.com/kybishop/ember-popper/pull/77) ([pzuraq](https://github.com/pzuraq)) 89 | - chore\(deps\) add @ember-decorators/babel-transforms [\#76](https://github.com/kybishop/ember-popper/pull/76) ([kybishop](https://github.com/kybishop)) 90 | - chore\(alphabetize unordered properties\) [\#68](https://github.com/kybishop/ember-popper/pull/68) ([kybishop](https://github.com/kybishop)) 91 | 92 | ## [v0.8.2](https://github.com/kybishop/ember-popper/tree/v0.8.2) (2017-12-03) 93 | 94 | [Full Changelog](https://github.com/kybishop/ember-popper/compare/v0.8.1...v0.8.2) 95 | 96 | **Closed issues:** 97 | 98 | - Include a test which ensures production builds complete without error [\#65](https://github.com/kybishop/ember-popper/issues/65) 99 | - Production builds for addon and consuming apps are broken [\#64](https://github.com/kybishop/ember-popper/issues/64) 100 | 101 | **Merged pull requests:** 102 | 103 | - fix\(production builds\) bump @ember-decorators/argument [\#67](https://github.com/kybishop/ember-popper/pull/67) ([kybishop](https://github.com/kybishop)) 104 | - chore\(tests\): Adds a production test scenario [\#66](https://github.com/kybishop/ember-popper/pull/66) ([pzuraq](https://github.com/pzuraq)) 105 | 106 | ## [v0.8.1](https://github.com/kybishop/ember-popper/tree/v0.8.1) (2017-12-03) 107 | 108 | [Full Changelog](https://github.com/kybishop/ember-popper/compare/v0.8.0...v0.8.1) 109 | 110 | **Merged pull requests:** 111 | 112 | - chore\(bump deps\) ember 2.17, etc. [\#63](https://github.com/kybishop/ember-popper/pull/63) ([kybishop](https://github.com/kybishop)) 113 | 114 | ## [v0.8.0](https://github.com/kybishop/ember-popper/tree/v0.8.0) (2017-12-01) 115 | 116 | [Full Changelog](https://github.com/kybishop/ember-popper/compare/v0.7.3...v0.8.0) 117 | 118 | **Merged pull requests:** 119 | 120 | - bugfix\(target\): Changes the target property to avoid collisions - BREAKING [\#62](https://github.com/kybishop/ember-popper/pull/62) ([pzuraq](https://github.com/pzuraq)) 121 | - update\(argument\): Updates @argument and types [\#61](https://github.com/kybishop/ember-popper/pull/61) ([pzuraq](https://github.com/pzuraq)) 122 | 123 | ## [v0.7.3](https://github.com/kybishop/ember-popper/tree/v0.7.3) (2017-11-04) 124 | 125 | [Full Changelog](https://github.com/kybishop/ember-popper/compare/v0.7.2...v0.7.3) 126 | 127 | **Closed issues:** 128 | 129 | - Type assertion fails in IE11 [\#56](https://github.com/kybishop/ember-popper/issues/56) 130 | 131 | **Merged pull requests:** 132 | 133 | - chore\(bump deps\) @ember-decorators/argument bugfix [\#59](https://github.com/kybishop/ember-popper/pull/59) ([kybishop](https://github.com/kybishop)) 134 | 135 | ## [v0.7.2](https://github.com/kybishop/ember-popper/tree/v0.7.2) (2017-11-03) 136 | 137 | [Full Changelog](https://github.com/kybishop/ember-popper/compare/v0.7.1...v0.7.2) 138 | 139 | **Closed issues:** 140 | 141 | - Allow toggling of renderInPlace [\#57](https://github.com/kybishop/ember-popper/issues/57) 142 | 143 | **Merged pull requests:** 144 | 145 | - fix\(toggling renderInPlace\) [\#58](https://github.com/kybishop/ember-popper/pull/58) ([kybishop](https://github.com/kybishop)) 146 | 147 | ## [v0.7.1](https://github.com/kybishop/ember-popper/tree/v0.7.1) (2017-11-01) 148 | 149 | [Full Changelog](https://github.com/kybishop/ember-popper/compare/v0.7.0...v0.7.1) 150 | 151 | **Merged pull requests:** 152 | 153 | - bugfix\(legacy\): Bumps ember-legacy-class-transform [\#55](https://github.com/kybishop/ember-popper/pull/55) ([pzuraq](https://github.com/pzuraq)) 154 | 155 | ## [v0.7.0](https://github.com/kybishop/ember-popper/tree/v0.7.0) (2017-11-01) 156 | 157 | [Full Changelog](https://github.com/kybishop/ember-popper/compare/v0.6.6...v0.7.0) 158 | 159 | **Merged pull requests:** 160 | 161 | - refactor\(raf\): Remove requestAnimationFrame [\#54](https://github.com/kybishop/ember-popper/pull/54) ([pzuraq](https://github.com/pzuraq)) 162 | - \[BREAKING\] feat\(api\): Normalizes registerAPI [\#53](https://github.com/kybishop/ember-popper/pull/53) ([pzuraq](https://github.com/pzuraq)) 163 | - bugfix\(fastboot\): Adds element polyfill [\#52](https://github.com/kybishop/ember-popper/pull/52) ([pzuraq](https://github.com/pzuraq)) 164 | - refactor\(decorators\): Refactor to use ember-argument-decorators [\#51](https://github.com/kybishop/ember-popper/pull/51) ([pzuraq](https://github.com/pzuraq)) 165 | 166 | ## [v0.6.6](https://github.com/kybishop/ember-popper/tree/v0.6.6) (2017-10-20) 167 | 168 | [Full Changelog](https://github.com/kybishop/ember-popper/compare/v0.6.5...v0.6.6) 169 | 170 | **Merged pull requests:** 171 | 172 | - Remove unused debug helpers [\#50](https://github.com/kybishop/ember-popper/pull/50) ([simonihmig](https://github.com/simonihmig)) 173 | 174 | ## [v0.6.5](https://github.com/kybishop/ember-popper/tree/v0.6.5) (2017-10-19) 175 | 176 | [Full Changelog](https://github.com/kybishop/ember-popper/compare/v0.6.4...v0.6.5) 177 | 178 | **Closed issues:** 179 | 180 | - Production build fails if sourcemaps are enabled [\#46](https://github.com/kybishop/ember-popper/issues/46) 181 | - How to add preventOverflow [\#44](https://github.com/kybishop/ember-popper/issues/44) 182 | - Fails for IE9/10 [\#42](https://github.com/kybishop/ember-popper/issues/42) 183 | 184 | **Merged pull requests:** 185 | 186 | - fix\(sourcemaps\) include sourcemaps in assets [\#48](https://github.com/kybishop/ember-popper/pull/48) ([kybishop](https://github.com/kybishop)) 187 | - chore\(upgrade deps\) ember 2.16 and more [\#47](https://github.com/kybishop/ember-popper/pull/47) ([kybishop](https://github.com/kybishop)) 188 | - Fix node 4 support [\#45](https://github.com/kybishop/ember-popper/pull/45) ([simonihmig](https://github.com/simonihmig)) 189 | 190 | ## [v0.6.4](https://github.com/kybishop/ember-popper/tree/v0.6.4) (2017-09-16) 191 | 192 | [Full Changelog](https://github.com/kybishop/ember-popper/compare/v0.6.3...v0.6.4) 193 | 194 | **Merged pull requests:** 195 | 196 | - fix\(renderInPlace\) added missing update action to yield [\#43](https://github.com/kybishop/ember-popper/pull/43) ([kybishop](https://github.com/kybishop)) 197 | - Fix version detection for Ember beta and alpha \(canary\) [\#41](https://github.com/kybishop/ember-popper/pull/41) ([simonihmig](https://github.com/simonihmig)) 198 | 199 | ## [v0.6.3](https://github.com/kybishop/ember-popper/tree/v0.6.3) (2017-09-09) 200 | 201 | [Full Changelog](https://github.com/kybishop/ember-popper/compare/v0.6.2...v0.6.3) 202 | 203 | **Merged pull requests:** 204 | 205 | - Check for destroyed component [\#40](https://github.com/kybishop/ember-popper/pull/40) ([simonihmig](https://github.com/simonihmig)) 206 | 207 | ## [v0.6.2](https://github.com/kybishop/ember-popper/tree/v0.6.2) (2017-09-08) 208 | 209 | [Full Changelog](https://github.com/kybishop/ember-popper/compare/v0.6.1...v0.6.2) 210 | 211 | **Merged pull requests:** 212 | 213 | - Support ARIA role [\#39](https://github.com/kybishop/ember-popper/pull/39) ([simonihmig](https://github.com/simonihmig)) 214 | - Add onCreate and onUpdate actions [\#38](https://github.com/kybishop/ember-popper/pull/38) ([simonihmig](https://github.com/simonihmig)) 215 | - fix\(flakey eventsEnabled test\) [\#37](https://github.com/kybishop/ember-popper/pull/37) ([kybishop](https://github.com/kybishop)) 216 | 217 | ## [v0.6.1](https://github.com/kybishop/ember-popper/tree/v0.6.1) (2017-09-02) 218 | 219 | [Full Changelog](https://github.com/kybishop/ember-popper/compare/v0.6.0...v0.6.1) 220 | 221 | **Merged pull requests:** 222 | 223 | - chore\(bump deps\) [\#36](https://github.com/kybishop/ember-popper/pull/36) ([kybishop](https://github.com/kybishop)) 224 | - chore\(remove jquery\) [\#35](https://github.com/kybishop/ember-popper/pull/35) ([kybishop](https://github.com/kybishop)) 225 | 226 | ## [v0.6.0](https://github.com/kybishop/ember-popper/tree/v0.6.0) (2017-08-26) 227 | 228 | [Full Changelog](https://github.com/kybishop/ember-popper/compare/v0.5.1...v0.6.0) 229 | 230 | **Merged pull requests:** 231 | 232 | - feat\(onFoundTarget\) hook executed if a new target is found [\#32](https://github.com/kybishop/ember-popper/pull/32) ([kybishop](https://github.com/kybishop)) 233 | 234 | ## [v0.5.1](https://github.com/kybishop/ember-popper/tree/v0.5.1) (2017-07-27) 235 | 236 | [Full Changelog](https://github.com/kybishop/ember-popper/compare/v0.5.0...v0.5.1) 237 | 238 | **Merged pull requests:** 239 | 240 | - feature\(update\): Adds sync update action [\#30](https://github.com/kybishop/ember-popper/pull/30) ([pzuraq](https://github.com/pzuraq)) 241 | 242 | ## [v0.5.0](https://github.com/kybishop/ember-popper/tree/v0.5.0) (2017-07-21) 243 | 244 | [Full Changelog](https://github.com/kybishop/ember-popper/compare/v0.4.0...v0.5.0) 245 | 246 | **Closed issues:** 247 | 248 | - Use `class` instead of `popperClass` [\#12](https://github.com/kybishop/ember-popper/issues/12) 249 | 250 | **Merged pull requests:** 251 | 252 | - bugfix\(update/id\): Makes id work and less aggressively updates [\#29](https://github.com/kybishop/ember-popper/pull/29) ([pzuraq](https://github.com/pzuraq)) 253 | 254 | ## [v0.4.0](https://github.com/kybishop/ember-popper/tree/v0.4.0) (2017-07-20) 255 | 256 | [Full Changelog](https://github.com/kybishop/ember-popper/compare/v0.3.2...v0.4.0) 257 | 258 | **Closed issues:** 259 | 260 | - Legacy support \(Ember \<= 2.9\) [\#20](https://github.com/kybishop/ember-popper/issues/20) 261 | - Testing [\#2](https://github.com/kybishop/ember-popper/issues/2) 262 | 263 | **Merged pull requests:** 264 | 265 | - refactor\(major\): ES6 classes, legacy build support, linting, only yield actions [\#28](https://github.com/kybishop/ember-popper/pull/28) ([kybishop](https://github.com/kybishop)) 266 | - fix\(renderInPlace\) allow renderInplace to be false in fastboot [\#27](https://github.com/kybishop/ember-popper/pull/27) ([kybishop](https://github.com/kybishop)) 267 | - chore\(tests\) eventsEnabled [\#26](https://github.com/kybishop/ember-popper/pull/26) ([kybishop](https://github.com/kybishop)) 268 | - chore\(tests\) modifiers tests [\#25](https://github.com/kybishop/ember-popper/pull/25) ([kybishop](https://github.com/kybishop)) 269 | - chore\(tests\) test target param [\#24](https://github.com/kybishop/ember-popper/pull/24) ([kybishop](https://github.com/kybishop)) 270 | - feat\(better fastboot compat\) render in place in Fastboot [\#23](https://github.com/kybishop/ember-popper/pull/23) ([kybishop](https://github.com/kybishop)) 271 | - chore\(tests\) placement tests [\#22](https://github.com/kybishop/ember-popper/pull/22) ([kybishop](https://github.com/kybishop)) 272 | - feat\(popperContainer\) allow popperContainer to be set via selector + chore\(tests\) renderInPlace [\#21](https://github.com/kybishop/ember-popper/pull/21) ([kybishop](https://github.com/kybishop)) 273 | 274 | ## [v0.3.2](https://github.com/kybishop/ember-popper/tree/v0.3.2) (2017-07-08) 275 | 276 | [Full Changelog](https://github.com/kybishop/ember-popper/compare/v0.3.1...v0.3.2) 277 | 278 | **Merged pull requests:** 279 | 280 | - fix\[babel options\] don't overwrite existing options [\#19](https://github.com/kybishop/ember-popper/pull/19) ([kybishop](https://github.com/kybishop)) 281 | 282 | ## [v0.3.1](https://github.com/kybishop/ember-popper/tree/v0.3.1) (2017-07-08) 283 | 284 | [Full Changelog](https://github.com/kybishop/ember-popper/compare/v0.3.0...v0.3.1) 285 | 286 | **Merged pull requests:** 287 | 288 | - Fix broken build for consuming apps on ember-cli 2.10-2.13 when in test or prod mode [\#18](https://github.com/kybishop/ember-popper/pull/18) ([kybishop](https://github.com/kybishop)) 289 | - popper.js to v1.10.8 and upgrade ember-cli [\#17](https://github.com/kybishop/ember-popper/pull/17) ([kybishop](https://github.com/kybishop)) 290 | 291 | ## [v0.3.0](https://github.com/kybishop/ember-popper/tree/v0.3.0) (2017-06-22) 292 | 293 | [Full Changelog](https://github.com/kybishop/ember-popper/compare/v0.2.0...v0.3.0) 294 | 295 | **Closed issues:** 296 | 297 | - FastBoot support: ReferenceError: navigator is not defined [\#14](https://github.com/kybishop/ember-popper/issues/14) 298 | 299 | **Merged pull requests:** 300 | 301 | - feat\(fastboot\) fastboot compat and popper bump to 1.10.2 [\#16](https://github.com/kybishop/ember-popper/pull/16) ([kybishop](https://github.com/kybishop)) 302 | 303 | ## [v0.2.0](https://github.com/kybishop/ember-popper/tree/v0.2.0) (2017-05-23) 304 | 305 | [Full Changelog](https://github.com/kybishop/ember-popper/compare/v0.1.1...v0.2.0) 306 | 307 | **Closed issues:** 308 | 309 | - META: API Discussion [\#6](https://github.com/kybishop/ember-popper/issues/6) 310 | 311 | **Merged pull requests:** 312 | 313 | - chore\(upgrade deps\) [\#13](https://github.com/kybishop/ember-popper/pull/13) ([kybishop](https://github.com/kybishop)) 314 | - feat\(flatten top-level options\) placement, modifiers, eventsEnabled [\#11](https://github.com/kybishop/ember-popper/pull/11) ([kybishop](https://github.com/kybishop)) 315 | 316 | ## [v0.1.1](https://github.com/kybishop/ember-popper/tree/v0.1.1) (2017-05-17) 317 | 318 | [Full Changelog](https://github.com/kybishop/ember-popper/compare/v0.1.0...v0.1.1) 319 | 320 | **Merged pull requests:** 321 | 322 | - fix\(popper recreation\) wait until the element has rerendered [\#9](https://github.com/kybishop/ember-popper/pull/9) ([kybishop](https://github.com/kybishop)) 323 | - recalculate popper class when dependent props change [\#8](https://github.com/kybishop/ember-popper/pull/8) ([kybishop](https://github.com/kybishop)) 324 | 325 | ## [v0.1.0](https://github.com/kybishop/ember-popper/tree/v0.1.0) (2017-05-17) 326 | 327 | [Full Changelog](https://github.com/kybishop/ember-popper/compare/v0.0.3...v0.1.0) 328 | 329 | **Closed issues:** 330 | 331 | - Support for tagless components? [\#3](https://github.com/kybishop/ember-popper/issues/3) 332 | 333 | **Merged pull requests:** 334 | 335 | - fix\(missing import warning\) for popper.js sourcemap [\#7](https://github.com/kybishop/ember-popper/pull/7) ([kybishop](https://github.com/kybishop)) 336 | 337 | ## [v0.0.3](https://github.com/kybishop/ember-popper/tree/v0.0.3) (2017-05-02) 338 | 339 | [Full Changelog](https://github.com/kybishop/ember-popper/compare/v0.0.2...v0.0.3) 340 | 341 | **Merged pull requests:** 342 | 343 | - fixups\(lots of comments and a few minor changes\) [\#5](https://github.com/kybishop/ember-popper/pull/5) ([kybishop](https://github.com/kybishop)) 344 | - fix\(z-index issues\) render poppers in the body by default [\#4](https://github.com/kybishop/ember-popper/pull/4) ([kybishop](https://github.com/kybishop)) 345 | 346 | ## [v0.0.2](https://github.com/kybishop/ember-popper/tree/v0.0.2) (2017-04-20) 347 | 348 | [Full Changelog](https://github.com/kybishop/ember-popper/compare/358058191632eaf18ee0e4d2605ba48bf4ebcbd8...v0.0.2) 349 | 350 | **Merged pull requests:** 351 | 352 | - feature\(asserts\): Adds asserts and other strippable debug helpers [\#1](https://github.com/kybishop/ember-popper/pull/1) ([pzuraq](https://github.com/pzuraq)) 353 | 354 | 355 | 356 | \* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How To Contribute 2 | 3 | ## Installation 4 | 5 | * `git clone ` 6 | * `cd my-addon` 7 | * `npm install` 8 | 9 | ## Linting 10 | 11 | * `npm run lint:hbs` 12 | * `npm run lint:js` 13 | * `npm run lint:js -- --fix` 14 | 15 | ## Running tests 16 | 17 | * `ember test` – Runs the test suite on the current Ember version 18 | * `ember test --server` – Runs the test suite in "watch mode" 19 | * `ember try:each` – Runs the test suite against multiple Ember versions 20 | 21 | ## Running the dummy application 22 | 23 | * `ember serve` 24 | * Visit the dummy application at [http://localhost:4200](http://localhost:4200). 25 | 26 | For more information on using ember-cli, visit [https://ember-cli.com/](https://ember-cli.com/). -------------------------------------------------------------------------------- /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 | DEPRECATED: use [ember-popper-modifier](https://github.com/adopted-ember-addons/ember-popper-modifier) or [ember-popperjs](https://github.com/NullVoxPopuli/ember-popperjs) 2 | -------------------------------------------------------------------------------- /addon/components/ember-popper-base.js: -------------------------------------------------------------------------------- 1 | import Component from '@ember/component'; 2 | import { computed } from '@ember/object'; 3 | import { assert } from '@ember/debug'; 4 | import layout from '../templates/components/ember-popper'; 5 | import { scheduler as raf } from 'ember-raf-scheduler'; 6 | 7 | export default Component.extend({ 8 | layout, 9 | 10 | tagName: '', 11 | 12 | // ================== PUBLIC CONFIG OPTIONS ================== 13 | 14 | /** 15 | * Whether event listeners, resize and scroll, for repositioning the popper are initially enabled. 16 | * @argument({ defaultIfUndefined: true }) 17 | * @type('boolean') 18 | */ 19 | eventsEnabled: true, 20 | 21 | /** 22 | * Whether the Popper element should be hidden. Use this and CSS for `[hidden]` instead of 23 | * an `{{if}}` if you want to animate the Popper's entry and/or exit. 24 | * @argument({ defaultIfUndefined: false }) 25 | * @type('boolean') 26 | */ 27 | hidden: false, 28 | 29 | /** 30 | * Modifiers that will be merged into the Popper instance's options hash. 31 | * https://popper.js.org/popper-documentation.html#Popper.DEFAULTS 32 | * @argument 33 | * @type(optional('object')) 34 | */ 35 | modifiers: null, 36 | 37 | /** 38 | * onCreate callback merged (if present) into the Popper instance's options hash. 39 | * https://popper.js.org/popper-documentation.html#Popper.Defaults.onCreate 40 | * @argument 41 | * @type(optional(Function)) 42 | */ 43 | onCreate: null, 44 | 45 | /** 46 | * onUpdate callback merged (if present) into the Popper instance's options hash. 47 | * https://popper.js.org/popper-documentation.html#Popper.Defaults.onUpdate 48 | * @argument 49 | * @type(optional(Function)) 50 | */ 51 | onUpdate: null, 52 | 53 | /** 54 | * Placement of the popper. One of ['top', 'right', 'bottom', 'left']. 55 | * @argument({ defaultIfUndefined: true }) 56 | * @type('string') 57 | */ 58 | placement: 'bottom', 59 | 60 | /** 61 | * The popper element needs to be moved higher in the DOM tree to avoid z-index issues. 62 | * See the block-comment in the template for more details. `.ember-application` is applied 63 | * to the root element of the ember app by default, so we move it up to there. 64 | * @argument({ defaultIfUndefined: true }) 65 | * @type(Selector) 66 | */ 67 | popperContainer: '.ember-application', 68 | 69 | /** 70 | * An optional function to be called when a new target is located. 71 | * The target is passed in as an argument to the function. 72 | * @argument 73 | * @type(optional(Action)) 74 | */ 75 | registerAPI: null, 76 | 77 | /** 78 | * If `true`, the popper element will not be moved to popperContainer. WARNING: This can cause 79 | * z-index issues where your popper will be overlapped by DOM elements that aren't nested as 80 | * deeply in the DOM tree. 81 | * @argument({ defaultIfUndefined: true }) 82 | * @type('boolean') 83 | */ 84 | renderInPlace: false, 85 | 86 | // ================== PRIVATE PROPERTIES ================== 87 | 88 | /** 89 | * Tracks current/previous state of `_renderInPlace`. 90 | */ 91 | _didRenderInPlace: false, 92 | 93 | /** 94 | * Tracks current/previous value of `eventsEnabled` option 95 | */ 96 | _eventsEnabled: null, 97 | 98 | /** 99 | * Parent of the element on didInsertElement, before it may have been moved 100 | */ 101 | _initialParentNode: null, 102 | 103 | /** 104 | * Tracks current/previous value of `modifiers` option 105 | */ 106 | _modifiers: null, 107 | 108 | /** 109 | * Tracks current/previous value of `onCreate` callback 110 | */ 111 | _onCreate: null, 112 | 113 | /** 114 | * Tracks current/previous value of `onUpdate` callback 115 | */ 116 | _onUpdate: null, 117 | 118 | /** 119 | * Tracks current/previous value of `placement` option 120 | */ 121 | _placement: null, 122 | 123 | /** 124 | * Set in didInsertElement() once the Popper is initialized. 125 | * Passed to consumers via a named yield. 126 | */ 127 | _popper: null, 128 | 129 | /** 130 | * Tracks popper element 131 | */ 132 | _popperElement: null, 133 | 134 | /** 135 | * Tracks current/previous value of popper target 136 | */ 137 | _popperTarget: null, 138 | 139 | /** 140 | * Public API of the popper sent to external components in `registerAPI` 141 | */ 142 | _publicAPI: null, 143 | 144 | /** 145 | * ID for the requestAnimationFrame used for updates, used to cancel 146 | * the RAF on component destruction 147 | */ 148 | _updateRAF: null, 149 | 150 | // ================== LIFECYCLE HOOKS ================== 151 | 152 | willDestroyElement() { 153 | this._super(...arguments); 154 | if (this._popper !== null) { 155 | this._popper.destroy(); 156 | } 157 | raf.forget(this._updateRAF); 158 | }, 159 | 160 | update() { 161 | this._popper.update(); 162 | }, 163 | 164 | scheduleUpdate() { 165 | if (this._updateRAF !== null) { 166 | return; 167 | } 168 | 169 | this._updateRAF = raf.schedule('affect', () => { 170 | this._updateRAF = null; 171 | this._popper.update(); 172 | }); 173 | }, 174 | 175 | enableEventListeners() { 176 | this._popper.enableEventListeners(); 177 | }, 178 | 179 | disableEventListeners() { 180 | this._popper.disableEventListeners(); 181 | }, 182 | 183 | /** 184 | * ================== ACTIONS ================== 185 | */ 186 | 187 | actions: { 188 | update() { 189 | this.update(); 190 | }, 191 | 192 | scheduleUpdate() { 193 | this.scheduleUpdate(); 194 | }, 195 | 196 | enableEventListeners() { 197 | this.enableEventListeners(); 198 | }, 199 | 200 | disableEventListeners() { 201 | this.disableEventListeners(); 202 | }, 203 | 204 | didInsertPopperElement(element) { 205 | this._popperElement = element 206 | this._updatePopper(); 207 | }, 208 | 209 | willDestroyPopperElement() { 210 | this._popperElement = null 211 | }, 212 | 213 | didUpdatePopperSettings() { 214 | this._updatePopper() 215 | } 216 | }, 217 | 218 | // ================== PRIVATE IMPLEMENTATION DETAILS ================== 219 | 220 | _updatePopper() { 221 | if (this.isDestroying || this.isDestroyed || !this._popperElement) { 222 | return; 223 | } 224 | 225 | const eventsEnabled = this.get('eventsEnabled'); 226 | const modifiers = this.get('modifiers'); 227 | const onCreate = this.get('onCreate'); 228 | const onUpdate = this.get('onUpdate'); 229 | const placement = this.get('placement'); 230 | const popperTarget = this._getPopperTarget(); 231 | const renderInPlace = this.get('_renderInPlace'); 232 | 233 | // Compare against previous values to see if anything has changed 234 | const didChange = renderInPlace !== this._didRenderInPlace 235 | || popperTarget !== this._popperTarget 236 | || eventsEnabled !== this._eventsEnabled 237 | || modifiers !== this._modifiers 238 | || placement !== this._placement 239 | || onCreate !== this._onCreate 240 | || onUpdate !== this._onUpdate; 241 | 242 | if (didChange === true) { 243 | if (this._popper !== null) { 244 | this._popper.destroy(); 245 | } 246 | 247 | // Store current values to check against on updates 248 | this._didRenderInPlace = renderInPlace; 249 | this._eventsEnabled = eventsEnabled; 250 | this._modifiers = modifiers; 251 | this._onCreate = onCreate; 252 | this._onUpdate = onUpdate; 253 | this._placement = placement; 254 | this._popperTarget = popperTarget; 255 | 256 | const options = { 257 | eventsEnabled, 258 | modifiers, 259 | placement 260 | }; 261 | 262 | if (onCreate) { 263 | assert('onCreate of ember-popper must be a function', typeof onCreate === 'function'); 264 | options.onCreate = onCreate; 265 | } 266 | 267 | if (onUpdate) { 268 | assert('onUpdate of ember-popper must be a function', typeof onUpdate === 'function'); 269 | options.onUpdate = onUpdate; 270 | } 271 | 272 | this._popper = new Popper(popperTarget, this._popperElement, options); 273 | 274 | // Execute the registerAPI hook last to ensure the Popper is initialized on the target 275 | if (this.get('registerAPI') !== null) { 276 | /* eslint-disable ember/closure-actions */ 277 | this.get('registerAPI')(this._getPublicAPI()); 278 | } 279 | } 280 | }, 281 | 282 | _getPopperTarget() { 283 | return this.get('popperTarget'); 284 | }, 285 | 286 | _getPublicAPI() { 287 | if (this._publicAPI === null) { 288 | // bootstrap the public API with fields that are guaranteed to be static, 289 | // such as imperative actions 290 | this._publicAPI = { 291 | disableEventListeners: this.disableEventListeners.bind(this), 292 | enableEventListeners: this.enableEventListeners.bind(this), 293 | scheduleUpdate: this.scheduleUpdate.bind(this), 294 | update: this.update.bind(this) 295 | }; 296 | } 297 | 298 | this._publicAPI.popperElement = this._popperElement; 299 | this._publicAPI.popperTarget = this._popperTarget; 300 | 301 | return this._publicAPI; 302 | }, 303 | 304 | _popperContainer: computed('_renderInPlace', 'popperContainer', function() { 305 | const renderInPlace = this.get('_renderInPlace'); 306 | const maybeContainer = this.get('popperContainer'); 307 | 308 | let popperContainer; 309 | 310 | if (renderInPlace) { 311 | popperContainer = this._initialParentNode; 312 | } else if (maybeContainer instanceof Element) { 313 | popperContainer = maybeContainer; 314 | } else if (typeof maybeContainer === 'string') { 315 | const selector = maybeContainer; 316 | const possibleContainers = self.document.querySelectorAll(selector); 317 | 318 | assert(`ember-popper with popperContainer selector "${selector}" found ` 319 | + `${possibleContainers.length} possible containers when there should be exactly 1`, 320 | possibleContainers.length === 1); 321 | 322 | popperContainer = possibleContainers[0]; 323 | } 324 | 325 | return popperContainer; 326 | }), 327 | 328 | _renderInPlace: computed('renderInPlace', function() { 329 | // self.document is undefined in Fastboot, so we have to render in 330 | // place for the popper to show up at all. 331 | return self.document ? !!this.get('renderInPlace') : true; 332 | }) 333 | }); 334 | -------------------------------------------------------------------------------- /addon/components/ember-popper-targeting-parent.js: -------------------------------------------------------------------------------- 1 | import EmberPopperBase from './ember-popper-base'; 2 | import layout from '../templates/components/ember-popper-targeting-parent'; 3 | import { guidFor } from '@ember/object/internals'; 4 | 5 | export default EmberPopperBase.extend({ 6 | layout, 7 | 8 | // ================== LIFECYCLE HOOKS ================== 9 | 10 | init() { 11 | this.id = this.id || `${guidFor(this)}-popper`; 12 | this._parentFinder = self.document ? self.document.createTextNode('') : ''; 13 | this._super(...arguments); 14 | }, 15 | 16 | didInsertElement() { 17 | this._super(...arguments); 18 | this._initialParentNode = this._parentFinder.parentNode; 19 | }, 20 | 21 | /** 22 | * Used to get the popper target whenever updating the Popper 23 | */ 24 | _getPopperTarget() { 25 | return this._initialParentNode; 26 | } 27 | }); 28 | -------------------------------------------------------------------------------- /addon/components/ember-popper.js: -------------------------------------------------------------------------------- 1 | import EmberPopperBase from './ember-popper-base'; 2 | import { guidFor } from '@ember/object/internals'; 3 | 4 | export default EmberPopperBase.extend({ 5 | /** 6 | * The element the popper will target. 7 | * @argument 8 | * @type(Element) 9 | */ 10 | popperTarget: null, 11 | 12 | // ================== LIFECYCLE HOOKS ================== 13 | 14 | init() { 15 | this.id = this.id || `${guidFor(this)}-popper`; 16 | this._super(...arguments); 17 | } 18 | }); 19 | -------------------------------------------------------------------------------- /addon/templates/components/ember-popper-targeting-parent.hbs: -------------------------------------------------------------------------------- 1 | {{unbound this._parentFinder}} 2 | 3 | {{!-- Elements that exist deep within the document tree are given an implicitly lower z-index 4 | value than elements that aren't as deep in the tree; this has the effect of hiding our 5 | ember-popper behind less-nested elements. Due to the way z-indexing works, we cannot simply 6 | add a higher z-index value to our ember-popper. To avoid this issue, we render the element 7 | on the document body, giving it the highest default z-index value. --}} 8 | {{#if this.renderInPlace}} 9 | {{!-- Add a wrapper around the yielded block so we have something for the Popper to target --}} 10 | 22 | {{else}} 23 | {{#in-element this._popperContainer insertBefore=null}} 24 | 36 | {{/in-element}} 37 | {{/if}} 38 | -------------------------------------------------------------------------------- /addon/templates/components/ember-popper.hbs: -------------------------------------------------------------------------------- 1 | {{!-- Elements that exist deep within the document tree are given an implicitly lower z-index 2 | value than elements that aren't as deep in the tree; this has the effect of hiding our 3 | ember-popper behind less-nested elements. Due to the way z-indexing works, we cannot simply 4 | add a higher z-index value to our ember-popper. To avoid this issue, we render the element 5 | on the document body, giving it the highest default z-index value. --}} 6 | {{#if this.renderInPlace}} 7 | {{!-- Add a wrapper around the yielded block so we have something for the Popper to target --}} 8 | 20 | {{else}} 21 | {{#in-element this._popperContainer insertBefore=null}} 22 | 34 | {{/in-element}} 35 | {{/if}} 36 | -------------------------------------------------------------------------------- /app/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kybishop/ember-popper/db1e44545814fb9522f335aa6fc2c364cf669af4/app/.gitkeep -------------------------------------------------------------------------------- /app/components/ember-popper-targeting-parent.js: -------------------------------------------------------------------------------- 1 | export { default } from 'ember-popper/components/ember-popper-targeting-parent'; 2 | -------------------------------------------------------------------------------- /app/components/ember-popper.js: -------------------------------------------------------------------------------- 1 | export { default } from 'ember-popper/components/ember-popper'; -------------------------------------------------------------------------------- /app/templates/components/ember-popper-targeting-parent.js: -------------------------------------------------------------------------------- 1 | export { default } from 'ember-popper/templates/components/ember-popper-targeting-parent'; 2 | -------------------------------------------------------------------------------- /app/templates/components/ember-popper.js: -------------------------------------------------------------------------------- 1 | export { default } from 'ember-popper/templates/components/ember-popper'; 2 | -------------------------------------------------------------------------------- /config/ember-try.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const getChannelURL = require('ember-source-channel-url'); 4 | 5 | module.exports = async function() { 6 | return { 7 | useYarn: true, 8 | scenarios: [ 9 | { 10 | name: 'ember-lts-3.12', 11 | npm: { 12 | devDependencies: { 13 | 'ember-source': '~3.12.0' 14 | } 15 | } 16 | }, 17 | { 18 | name: 'ember-release', 19 | npm: { 20 | devDependencies: { 21 | 'ember-source': await getChannelURL('release') 22 | } 23 | } 24 | }, 25 | { 26 | name: 'ember-beta', 27 | npm: { 28 | devDependencies: { 29 | 'ember-source': await getChannelURL('beta') 30 | } 31 | } 32 | }, 33 | { 34 | name: 'ember-canary', 35 | npm: { 36 | devDependencies: { 37 | 'ember-source': await getChannelURL('canary') 38 | } 39 | } 40 | }, 41 | // The default `.travis.yml` runs this scenario via `npm test`, 42 | // not via `ember try`. It's still included here so that running 43 | // `ember try:each` manually or from a customized CI config will run it 44 | // along with all the other scenarios. 45 | { 46 | name: 'ember-default', 47 | npm: { 48 | devDependencies: {} 49 | } 50 | }, 51 | { 52 | name: 'ember-default-with-jquery', 53 | env: { 54 | EMBER_OPTIONAL_FEATURES: JSON.stringify({ 55 | 'jquery-integration': true 56 | }) 57 | }, 58 | npm: { 59 | devDependencies: { 60 | '@ember/jquery': '^0.5.1' 61 | } 62 | } 63 | }, 64 | { 65 | name: 'ember-classic', 66 | env: { 67 | EMBER_OPTIONAL_FEATURES: JSON.stringify({ 68 | 'application-template-wrapper': true, 69 | 'default-async-observers': false, 70 | 'template-only-glimmer-components': false 71 | }) 72 | }, 73 | npm: { 74 | ember: { 75 | edition: 'classic' 76 | } 77 | } 78 | } 79 | ] 80 | }; 81 | }; 82 | -------------------------------------------------------------------------------- /config/environment.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(/* environment, appConfig */) { 4 | return { }; 5 | }; 6 | -------------------------------------------------------------------------------- /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 options = {}; 7 | 8 | if (defaults.project.findAddonByName('ember-native-dom-event-dispatcher')) { 9 | options.vendorFiles = { 'jquery.js': null }; 10 | } 11 | 12 | const app = new EmberAddon(defaults, options); 13 | 14 | /* 15 | This build file specifies the options for the dummy test app of this 16 | addon, located in `/tests/dummy` 17 | This build file does *not* influence how the addon or the app using it 18 | behave. You most likely want to be modifying `./index.js` or app's build file 19 | */ 20 | 21 | return app.toTree(); 22 | }; 23 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable ember-suave/prefer-destructuring */ 2 | 'use strict'; 3 | 4 | const fastbootTransform = require('fastboot-transform'); 5 | 6 | module.exports = { 7 | name: require('./package').name, 8 | 9 | options: { 10 | nodeAssets: { 11 | 'popper.js': { 12 | srcDir: 'dist/umd', 13 | import: { 14 | include: ['popper.js'], 15 | processTree(input) { 16 | return fastbootTransform(input); 17 | } 18 | }, 19 | public: ['popper.js.map'] 20 | } 21 | } 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES6", 4 | "experimentalDecorators": true 5 | }, 6 | "include": [ 7 | "addon/**/*" 8 | ], 9 | "exclude": [ 10 | "node_modules", 11 | "tmp" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ember-popper", 3 | "version": "0.11.3", 4 | "description": "An Ember-centric wrapper around Popper.js", 5 | "keywords": [ 6 | "ember-addon", 7 | "tooltips", 8 | "popovers" 9 | ], 10 | "repository": "https://github.com/kybishop/ember-popper", 11 | "license": "MIT", 12 | "author": { 13 | "name": "Kyle Bishop", 14 | "email": "kybishop@gmail.com", 15 | "url": "http://kybishop.com" 16 | }, 17 | "directories": { 18 | "doc": "doc", 19 | "test": "tests" 20 | }, 21 | "scripts": { 22 | "build": "ember build", 23 | "lint:hbs": "ember-template-lint .", 24 | "lint:js": "eslint .", 25 | "start": "ember serve", 26 | "test": "ember test", 27 | "test:all": "ember try:each" 28 | }, 29 | "dependencies": { 30 | "@ember/render-modifiers": "^1.0.2", 31 | "ember-cli-babel": "^7.13.0", 32 | "ember-cli-htmlbars": "^4.2.0", 33 | "ember-cli-node-assets": "^0.2.2", 34 | "ember-in-element-polyfill": "^1.0.0", 35 | "ember-raf-scheduler": "^0.1.0", 36 | "fastboot-transform": "^0.1.0", 37 | "popper.js": "^1.14.1" 38 | }, 39 | "devDependencies": { 40 | "@ember/optional-features": "^1.1.0", 41 | "@glimmer/component": "^1.0.0", 42 | "babel-eslint": "^10.0.3", 43 | "broccoli-asset-rev": "^3.0.0", 44 | "ember-auto-import": "^1.5.3", 45 | "ember-cli": "~3.15.2", 46 | "ember-cli-dependency-checker": "^3.2.0", 47 | "ember-cli-eslint": "^5.1.0", 48 | "ember-cli-fastboot": "^1.1.0", 49 | "ember-cli-inject-live-reload": "^2.0.1", 50 | "ember-cli-sri": "^2.1.1", 51 | "ember-cli-uglify": "^3.0.0", 52 | "ember-disable-prototype-extensions": "^1.1.3", 53 | "ember-export-application-global": "^2.0.1", 54 | "ember-load-initializers": "^2.1.1", 55 | "ember-maybe-import-regenerator": "^0.1.6", 56 | "ember-qunit": "^4.6.0", 57 | "ember-resolver": "^7.0.0", 58 | "ember-source": "~3.15.0", 59 | "ember-source-channel-url": "^2.0.1", 60 | "ember-try": "^1.4.0", 61 | "eslint-plugin-ember": "^7.7.1", 62 | "eslint-plugin-ember-suave": "^1.0.0", 63 | "eslint-plugin-node": "^10.0.0", 64 | "loader.js": "^4.7.0", 65 | "qunit-dom": "^0.9.2" 66 | }, 67 | "engines": { 68 | "node": "10.* || >= 12.*" 69 | }, 70 | "ember": { 71 | "edition": "octane" 72 | }, 73 | "ember-addon": { 74 | "configPath": "tests/dummy/config" 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /testem.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | module.exports = { 3 | test_page: 'tests/index.html?hidepassed&dockcontainer', 4 | disable_watching: true, 5 | launch_in_ci: [ 6 | 'Chrome' 7 | ], 8 | launch_in_dev: [ 9 | 'Chrome' 10 | ], 11 | browser_args: { 12 | Chrome: { 13 | ci: [ 14 | // --no-sandbox is needed when running Chrome inside a container 15 | process.env.CI ? '--no-sandbox' : null, 16 | '--headless', 17 | '--disable-dev-shm-usage', 18 | '--disable-software-rasterizer', 19 | '--mute-audio', 20 | '--remote-debugging-port=0', 21 | '--window-size=1440,900' 22 | ].filter(Boolean) 23 | } 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /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 './config/environment'; 5 | 6 | const App = Application.extend({ 7 | modulePrefix: config.modulePrefix, 8 | podModulePrefix: config.podModulePrefix, 9 | Resolver 10 | }); 11 | 12 | loadInitializers(App, config.modulePrefix); 13 | 14 | export default App; 15 | -------------------------------------------------------------------------------- /tests/dummy/app/components/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kybishop/ember-popper/db1e44545814fb9522f335aa6fc2c364cf669af4/tests/dummy/app/components/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/app/controllers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kybishop/ember-popper/db1e44545814fb9522f335aa6fc2c364cf669af4/tests/dummy/app/controllers/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/app/controllers/application.js: -------------------------------------------------------------------------------- 1 | import Controller from '@ember/controller'; 2 | import { inject as service } from '@ember/service'; 3 | import { computed } from '@ember/object'; 4 | 5 | export default Controller.extend({ 6 | fastboot: service(), 7 | 8 | eventsEnabled: true, 9 | showTargetedPopper: true, 10 | 11 | _popperTarget: computed(function() { 12 | if (this.get('fastboot.isFastBoot')) { 13 | return; 14 | } 15 | return document.querySelector('.right'); 16 | }), 17 | 18 | actions: { 19 | toggleShowTargetedPopper() { 20 | this.toggleProperty('showTargetedPopper'); 21 | }, 22 | 23 | toggleEventsEnabled() { 24 | this.toggleProperty('eventsEnabled'); 25 | } 26 | } 27 | }); 28 | -------------------------------------------------------------------------------- /tests/dummy/app/helpers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kybishop/ember-popper/db1e44545814fb9522f335aa6fc2c364cf669af4/tests/dummy/app/helpers/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Dummy 7 | 8 | 9 | 10 | {{content-for "head"}} 11 | 12 | 13 | 14 | 15 | {{content-for "head-footer"}} 16 | 17 | 18 | {{content-for "body"}} 19 | 20 | 21 | 22 | 23 | {{content-for "body-footer"}} 24 | 25 | 26 | -------------------------------------------------------------------------------- /tests/dummy/app/models/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kybishop/ember-popper/db1e44545814fb9522f335aa6fc2c364cf669af4/tests/dummy/app/models/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/app/router.js: -------------------------------------------------------------------------------- 1 | import EmberRouter from '@ember/routing/router'; 2 | import config from './config/environment'; 3 | 4 | export default class Router extends EmberRouter { 5 | location = config.locationType; 6 | rootURL = config.rootURL; 7 | } 8 | 9 | Router.map(function() { 10 | }); 11 | -------------------------------------------------------------------------------- /tests/dummy/app/routes/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kybishop/ember-popper/db1e44545814fb9522f335aa6fc2c364cf669af4/tests/dummy/app/routes/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/app/styles/app.css: -------------------------------------------------------------------------------- 1 | .row { 2 | display: flex; 3 | } 4 | 5 | .box { 6 | display: flex; 7 | flex-grow: 1; 8 | } 9 | 10 | .left { 11 | background-color: red; 12 | width: 80%; 13 | } 14 | 15 | .right { 16 | background-color: blue; 17 | width: 20%; 18 | } 19 | 20 | .left, .right, .box { 21 | height: 100px; 22 | } 23 | 24 | .popper { 25 | background: #FFC107; 26 | color: black; 27 | border-radius: 3px; 28 | box-shadow: 0 0 2px rgba(0,0,0,0.5); 29 | padding: 10px; 30 | text-align: center; 31 | } 32 | 33 | .popper .popper-arrow { 34 | width: 0; 35 | height: 0; 36 | border-style: solid; 37 | position: absolute; 38 | margin: 5px; 39 | } 40 | 41 | .popper .popper-arrow { 42 | border-color: #FFC107; 43 | } 44 | 45 | .popper[x-placement^="top"] { 46 | margin-bottom: 5px; 47 | } 48 | 49 | .popper[x-placement^="top"] .popper-arrow { 50 | border-width: 5px 5px 0 5px; 51 | border-left-color: transparent; 52 | border-right-color: transparent; 53 | border-bottom-color: transparent; 54 | bottom: -5px; 55 | left: calc(50% - 5px); 56 | margin-top: 0; 57 | margin-bottom: 0; 58 | } 59 | 60 | .popper[x-placement^="bottom"] { 61 | margin-top: 5px; 62 | } 63 | 64 | .popper[x-placement^="bottom"] .popper-arrow { 65 | border-width: 0 5px 5px 5px; 66 | border-left-color: transparent; 67 | border-right-color: transparent; 68 | border-top-color: transparent; 69 | top: -5px; 70 | left: calc(50% - 5px); 71 | margin-top: 0; 72 | margin-bottom: 0; 73 | } 74 | 75 | .popper[x-placement^="right"] { 76 | margin-left: 5px; 77 | } 78 | 79 | .popper[x-placement^="right"] .popper-arrow { 80 | border-width: 5px 5px 5px 0; 81 | border-left-color: transparent; 82 | border-top-color: transparent; 83 | border-bottom-color: transparent; 84 | left: -5px; 85 | top: calc(50% - 5px); 86 | margin-left: 0; 87 | margin-right: 0; 88 | } 89 | 90 | .popper[x-placement^="left"] { 91 | margin-right: 5px; 92 | } 93 | 94 | .popper[x-placement^="left"] .popper-arrow { 95 | border-width: 5px 0 5px 5px; 96 | border-top-color: transparent; 97 | border-right-color: transparent; 98 | border-bottom-color: transparent; 99 | right: -5px; 100 | top: calc(50% - 5px); 101 | margin-left: 0; 102 | margin-right: 0; 103 | } 104 | -------------------------------------------------------------------------------- /tests/dummy/app/templates/application.hbs: -------------------------------------------------------------------------------- 1 |
2 |
3 | {{#ember-popper-targeting-parent id='parent' class='popper' eventsEnabled=eventsEnabled}} 4 | Hello from the left! I have no explicit target. 5 |
6 | 7 | {{#ember-popper-targeting-parent class="popper" renderInPlace=true}} 8 | P O P P E R C E P T I O N 9 |
10 | I also have no explicit target, 11 |
12 | but am a child of the popper above 13 |
14 | {{/ember-popper-targeting-parent}} 15 | {{/ember-popper-targeting-parent}} 16 |
17 |
18 |
19 | 20 | {{#if showTargetedPopper}} 21 | {{#ember-popper class="popper" popperTarget=_popperTarget}} 22 | Hello from the right! 23 |
24 | I explicitly target the right div 25 |
26 | {{/ember-popper}} 27 | {{/if}} 28 | 29 |
30 | 31 |
32 |
33 | 34 |
35 | -------------------------------------------------------------------------------- /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: 'auto', 9 | EmberENV: { 10 | FEATURES: { 11 | // Here you can enable experimental features on an ember canary build 12 | // e.g. EMBER_NATIVE_DECORATOR_SUPPORT: true 13 | }, 14 | EXTEND_PROTOTYPES: { 15 | // Prevent Ember Data from overriding Date.parse. 16 | Date: false 17 | } 18 | }, 19 | 20 | APP: { 21 | // Here you can pass flags/options to your application instance 22 | // when it is created 23 | } 24 | }; 25 | 26 | if (environment === 'development') { 27 | // ENV.APP.LOG_RESOLVER = true; 28 | // ENV.APP.LOG_ACTIVE_GENERATION = true; 29 | // ENV.APP.LOG_TRANSITIONS = true; 30 | // ENV.APP.LOG_TRANSITIONS_INTERNAL = true; 31 | // ENV.APP.LOG_VIEW_LOOKUPS = true; 32 | } 33 | 34 | if (environment === 'test') { 35 | // Testem prefers this... 36 | ENV.locationType = 'none'; 37 | 38 | // keep test console output quieter 39 | ENV.APP.LOG_ACTIVE_GENERATION = false; 40 | ENV.APP.LOG_VIEW_LOOKUPS = false; 41 | 42 | ENV.APP.rootElement = '#ember-testing'; 43 | ENV.APP.autoboot = false; 44 | } 45 | 46 | if (environment === 'production') { 47 | // here you can enable a production-specific feature 48 | } 49 | 50 | return ENV; 51 | }; 52 | -------------------------------------------------------------------------------- /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 | const isCI = !!process.env.CI; 10 | const isProduction = process.env.EMBER_ENV === 'production'; 11 | 12 | if (isCI || isProduction) { 13 | browsers.push('ie 11'); 14 | } 15 | 16 | module.exports = { 17 | browsers 18 | }; 19 | -------------------------------------------------------------------------------- /tests/dummy/public/robots.txt: -------------------------------------------------------------------------------- 1 | # http://www.robotstxt.org 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /tests/helpers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kybishop/ember-popper/db1e44545814fb9522f335aa6fc2c364cf669af4/tests/helpers/.gitkeep -------------------------------------------------------------------------------- /tests/helpers/resolver.js: -------------------------------------------------------------------------------- 1 | import Resolver from '../../resolver'; 2 | import config from '../../config/environment'; 3 | 4 | const resolver = Resolver.create(); 5 | 6 | resolver.namespace = { 7 | modulePrefix: config.modulePrefix, 8 | podModulePrefix: config.podModulePrefix 9 | }; 10 | 11 | export default resolver; 12 | -------------------------------------------------------------------------------- /tests/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Dummy Tests 7 | 8 | 9 | 10 | {{content-for "head"}} 11 | {{content-for "test-head"}} 12 | 13 | 14 | 15 | 16 | 17 | 29 | 30 | {{content-for "head-footer"}} 31 | {{content-for "test-head-footer"}} 32 | 33 | 34 | {{content-for "body"}} 35 | {{content-for "test-body"}} 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | {{content-for "body-footer"}} 44 | {{content-for "test-body-footer"}} 45 | 46 | 47 | -------------------------------------------------------------------------------- /tests/integration/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kybishop/ember-popper/db1e44545814fb9522f335aa6fc2c364cf669af4/tests/integration/.gitkeep -------------------------------------------------------------------------------- /tests/integration/components/ember-popper-targeting-parent-test.js: -------------------------------------------------------------------------------- 1 | import hbs from 'htmlbars-inline-precompile'; 2 | import { module, test } from 'qunit'; 3 | import { setupRenderingTest } from 'ember-qunit'; 4 | 5 | import { render, settled } from '@ember/test-helpers'; 6 | 7 | module('Integration | Component | sanity check', function(hooks) { 8 | setupRenderingTest(hooks); 9 | 10 | hooks.beforeEach(function() { 11 | this.actions = {}; 12 | this.send = (actionName, ...args) => this.actions[actionName].apply(this, args); 13 | }); 14 | 15 | test('it targets the parent', async function(assert) { 16 | await render(hbs` 17 |
18 | {{#ember-popper-targeting-parent class='popper-element' placement='bottom'}} 19 | template block text 20 | {{/ember-popper-targeting-parent}} 21 |
22 | `); 23 | 24 | const parent = document.getElementById('parent'); 25 | const popper = document.querySelector('.popper-element'); 26 | 27 | return settled().then(() => { 28 | assert.equal(parent.getBoundingClientRect().bottom, 29 | popper.getBoundingClientRect().top); 30 | 31 | }); 32 | }); 33 | 34 | test('it passes ariaRole as role', async function(assert) { 35 | await this.render(hbs` 36 |
37 | {{#ember-popper-targeting-parent ariaRole='tooltip' id='popper-element'}} 38 | The tooltip 39 | {{/ember-popper-targeting-parent}} 40 |
41 | `); 42 | 43 | const tooltip = document.querySelector('#popper-element'); 44 | assert.equal(tooltip.getAttribute('role'), 'tooltip'); 45 | }); 46 | 47 | test('it passes hidden', async function(assert) { 48 | this.set('hidden', false); 49 | 50 | await this.render(hbs` 51 |
52 | {{#ember-popper-targeting-parent id='popper-element' hidden=hidden}} 53 | A possibly hidden popper 54 | {{/ember-popper-targeting-parent}} 55 |
56 | `); 57 | 58 | const tooltip = document.querySelector('#popper-element'); 59 | assert.equal(tooltip.hidden, false); 60 | this.set('hidden', true); 61 | assert.equal(tooltip.hidden, true); 62 | }); 63 | 64 | test('registerAPI returns the parent', async function(assert) { 65 | this.actions.registerAPI = ({ popperTarget }) => { 66 | const parent = document.querySelector('.parent'); 67 | assert.equal(popperTarget, parent); 68 | }; 69 | 70 | await render(hbs` 71 |
72 | {{#ember-popper-targeting-parent class='popper-element' registerAPI=(action 'registerAPI')}} 73 | template block text 74 | {{/ember-popper-targeting-parent}} 75 |
76 | `); 77 | }); 78 | }); 79 | -------------------------------------------------------------------------------- /tests/integration/components/ember-popper/action-test.js: -------------------------------------------------------------------------------- 1 | import { module, test } from 'qunit'; 2 | import { setupRenderingTest } from 'ember-qunit'; 3 | import { render, settled, triggerEvent } from '@ember/test-helpers'; 4 | import hbs from 'htmlbars-inline-precompile'; 5 | 6 | module('ember-popper-targeting-parent', 'Integration | Component | actions', function(hooks) { 7 | setupRenderingTest(hooks); 8 | 9 | hooks.beforeEach(function() { 10 | this.actions = {}; 11 | this.send = (actionName, ...args) => this.actions[actionName].apply(this, args); 12 | }); 13 | 14 | test('it calls onCreate', async function(assert) { 15 | assert.expect(2); 16 | 17 | let called = 0; 18 | 19 | this.actions.create = (data) => { 20 | called++; 21 | assert.ok(data && data.instance, 'onCreate action is called with dataObject'); 22 | }; 23 | 24 | await render(hbs` 25 | {{#ember-popper-targeting-parent onCreate=(action "create")}} 26 | template block text 27 | {{/ember-popper-targeting-parent}} 28 | `); 29 | 30 | assert.equal(called, 1, 'onCreate action has been called'); 31 | }); 32 | 33 | test('it calls onUpdate', async function(assert) { 34 | assert.expect(2); 35 | 36 | let called = 0; 37 | 38 | this.actions.update = (data) => { 39 | called++; 40 | assert.ok(data && data.instance, 'onUpdate action is called with dataObject'); 41 | }; 42 | 43 | await render(hbs` 44 | {{#ember-popper-targeting-parent onUpdate=(action "update")}} 45 | template block text 46 | {{/ember-popper-targeting-parent}} 47 | `); 48 | 49 | await triggerEvent(document.querySelector('body'), 'scroll'); 50 | 51 | await settled(); 52 | // this seems to fix the previous flakiness in this test, not sure why though... 53 | await new Promise((resolve) => setTimeout(resolve, 50)); 54 | 55 | assert.equal(called, 1, 'onUpdate action has been called after event'); 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /tests/integration/components/ember-popper/attributes-test.js: -------------------------------------------------------------------------------- 1 | import { module, test } from 'qunit'; 2 | import { setupRenderingTest } from 'ember-qunit'; 3 | import { render, find } from '@ember/test-helpers'; 4 | import hbs from 'htmlbars-inline-precompile'; 5 | 6 | module('Integration | Component | attributes', function(hooks) { 7 | setupRenderingTest(hooks); 8 | 9 | test('id is bound correctly', async function(assert) { 10 | await render(hbs` 11 |
12 | {{#ember-popper-targeting-parent placement='top' id='foo'}} 13 | test 14 | {{/ember-popper-targeting-parent}} 15 |
16 | `); 17 | 18 | assert.dom('#foo').exists('id attribute bound correctly'); 19 | }); 20 | 21 | test('class is bound correctly', async function(assert) { 22 | await render(hbs` 23 |
24 | {{#ember-popper-targeting-parent placement='top' class='foo'}} 25 | test 26 | {{/ember-popper-targeting-parent}} 27 |
28 | `); 29 | 30 | assert.dom('.foo').exists('class attribute bound correctly'); 31 | }); 32 | 33 | test('hidden is bound correctly', async function(assert) { 34 | await this.render(hbs` 35 |
36 | {{#ember-popper-targeting-parent id='foo' hidden=true}} 37 | test 38 | {{/ember-popper-targeting-parent}} 39 |
40 | `); 41 | 42 | assert.equal(find('#foo').hidden, true, 'hidden attribute bound correctly'); 43 | }); 44 | 45 | test('role is bound correctly', async function(assert) { 46 | await render(hbs` 47 |
48 | {{#ember-popper-targeting-parent id='foo' placement='top' ariaRole='tooltip'}} 49 | test 50 | {{/ember-popper-targeting-parent}} 51 |
52 | `); 53 | 54 | assert.dom('#foo').hasAttribute('role', 'tooltip', 'role attribute bound correctly'); 55 | }); 56 | 57 | test('any attributes are supported with angle bracket invocation', async function(assert) { 58 | await render(hbs` 59 |
60 | 61 | test 62 | 63 |
64 | `); 65 | 66 | assert.dom('#foo').hasAttribute('role', 'tooltip', 'role attribute bound correctly'); 67 | assert.dom('#foo').hasAttribute('title', 'bar', 'title attribute bound correctly'); 68 | assert.dom('#foo').hasAttribute('data-test-foo'); 69 | }); 70 | }); 71 | -------------------------------------------------------------------------------- /tests/integration/components/ember-popper/events-enabled-test.js: -------------------------------------------------------------------------------- 1 | import { module, test } from 'qunit'; 2 | import { setupRenderingTest } from 'ember-qunit'; 3 | import { render, settled, triggerEvent } from '@ember/test-helpers'; 4 | import hbs from 'htmlbars-inline-precompile'; 5 | 6 | module('Integration | Component | eventsEnabled', function(hooks) { 7 | setupRenderingTest(hooks); 8 | 9 | test('sets eventsEnabled in the Popper instance', async function(assert) { 10 | await render(hbs` 11 |
12 | {{#ember-popper-targeting-parent placement='bottom' class='events-enabled'}} 13 | eventsEnabled test 14 | {{/ember-popper-targeting-parent}} 15 | 16 | {{#ember-popper-targeting-parent eventsEnabled=false placement='bottom' class='events-disabled'}} 17 | eventsEnabled test 18 | {{/ember-popper-targeting-parent}} 19 |
20 | `); 21 | 22 | const parent = document.querySelector('.parent'); 23 | const eventsEnabledPopper = document.querySelector('.events-enabled'); 24 | const eventsDisabledPopper = document.querySelector('.events-disabled'); 25 | 26 | await settled(); 27 | 28 | const initialBottomOfParent = parent.getBoundingClientRect().bottom; 29 | const eventsEnabledInitialPosition = eventsEnabledPopper.getBoundingClientRect().top; 30 | const eventsDisabledInitialPosition = eventsDisabledPopper.getBoundingClientRect().top; 31 | 32 | // Sanity check 33 | assert.equal(initialBottomOfParent, 34 | eventsEnabledInitialPosition, 35 | 'initial eventsEnabled position is correct'); 36 | assert.equal(initialBottomOfParent, 37 | eventsDisabledInitialPosition, 38 | 'initial eventsDisabled position is correct'); 39 | 40 | parent.style.height = '200px'; 41 | 42 | // Wait for repaint from style change, then trigger scroll 43 | await settled(); 44 | await triggerEvent(document.querySelector('body'), 'scroll'); 45 | await settled(); 46 | await settled(); 47 | await triggerEvent(document.querySelector('body'), 'scroll'); 48 | await settled(); 49 | 50 | // Sanity check 51 | assert.notEqual(initialBottomOfParent, 52 | parent.getBoundingClientRect().bottom, 53 | 'the parent moved'); 54 | 55 | assert.equal(eventsEnabledPopper.getBoundingClientRect().top, 56 | parent.getBoundingClientRect().bottom, 57 | 'events enabled poppers move on scroll'); 58 | 59 | assert.equal(eventsDisabledPopper.getBoundingClientRect().top, 60 | eventsDisabledInitialPosition, 61 | "events not enabled poppers don't move on scroll"); 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /tests/integration/components/ember-popper/modifiers-test.js: -------------------------------------------------------------------------------- 1 | import { module, test } from 'qunit'; 2 | import { setupRenderingTest } from 'ember-qunit'; 3 | import { render, settled } from '@ember/test-helpers'; 4 | import hbs from 'htmlbars-inline-precompile'; 5 | 6 | module('Integration | Component | modifiers', function(hooks) { 7 | setupRenderingTest(hooks); 8 | 9 | test('it passes the modifiers to the Popper.js instance', async function(assert) { 10 | this.set('arrowsEnabledModifier', { arrow: { enabled: true } }); 11 | this.set('arrowsDisabledModifier', { arrow: { enabled: false } }); 12 | 13 | await render(hbs` 14 |
15 | {{#ember-popper-targeting-parent class='arrow-enabled' modifiers=arrowsEnabledModifier}} 16 | modifiers test 17 |
18 | {{/ember-popper-targeting-parent}} 19 | 20 | {{#ember-popper-targeting-parent class='arrow-disabled' modifiers=arrowsDisabledModifier}} 21 | modifiers test 22 |
23 | {{/ember-popper-targeting-parent}} 24 |
25 | `); 26 | 27 | const arrowEnabledPopper = document.querySelector('.arrow-enabled'); 28 | const arrowDisabledPopper = document.querySelector('.arrow-disabled'); 29 | 30 | return settled().then(() => { 31 | assert.ok(arrowEnabledPopper.querySelector('.popper-arrow').hasAttribute('style')); 32 | 33 | // Note the '!': this popper's arrow div should not receive any styles 34 | assert.ok(!arrowDisabledPopper.querySelector('.popper-arrow').hasAttribute('style')); 35 | }); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /tests/integration/components/ember-popper/placement-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 | placement', function(hooks) { 7 | setupRenderingTest(hooks); 8 | 9 | test('it places the popper appropriately', async function(assert) { 10 | await render(hbs` 11 |
20 | {{#ember-popper-targeting-parent id='left-plz' placement="left"}} 21 | template block text 22 | {{/ember-popper-targeting-parent}} 23 | {{#ember-popper-targeting-parent id='right-plz' placement="right"}} 24 | template block text 25 | {{/ember-popper-targeting-parent}} 26 | {{#ember-popper-targeting-parent id='top-plz' placement="top"}} 27 | template block text 28 | {{/ember-popper-targeting-parent}} 29 | {{#ember-popper-targeting-parent id='bottom-plz' placement="bottom"}} 30 | template block text 31 | {{/ember-popper-targeting-parent}} 32 |
33 | `); 34 | 35 | const leftPopper = document.getElementById('left-plz'); 36 | const rightPopper = document.getElementById('right-plz'); 37 | const topPopper = document.getElementById('top-plz'); 38 | const bottomPopper = document.getElementById('bottom-plz'); 39 | 40 | assert.equal(leftPopper.getAttribute('x-placement'), 'left'); 41 | assert.equal(rightPopper.getAttribute('x-placement'), 'right'); 42 | assert.equal(topPopper.getAttribute('x-placement'), 'top'); 43 | assert.equal(bottomPopper.getAttribute('x-placement'), 'bottom'); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /tests/integration/components/ember-popper/register-api-test.js: -------------------------------------------------------------------------------- 1 | import hbs from 'htmlbars-inline-precompile'; 2 | import { module, test } from 'qunit'; 3 | import { setupRenderingTest } from 'ember-qunit'; 4 | 5 | import { render, settled } from '@ember/test-helpers'; 6 | 7 | module('Integration | Component | registerAPI', function(hooks) { 8 | setupRenderingTest(hooks); 9 | 10 | hooks.beforeEach(function() { 11 | this.actions = {}; 12 | this.send = (actionName, ...args) => this.actions[actionName].apply(this, args); 13 | }); 14 | 15 | hooks.beforeEach(function() { 16 | this.set('foundTarget', null); 17 | this.set('show', false); 18 | }); 19 | 20 | test('registerAPI returns the explicit target', async function(assert) { 21 | assert.expect(1); 22 | 23 | this.actions.registerAPI = ({ popperTarget }) => { 24 | const expectedTarget = document.getElementById('parent'); 25 | assert.equal(popperTarget, expectedTarget); 26 | }; 27 | 28 | await render(hbs` 29 |
30 |
31 | 32 | {{#if show}} 33 | {{#ember-popper class='popper-element' 34 | registerAPI=(action 'registerAPI') 35 | popperTarget=popperTarget}} 36 | template block text 37 | {{/ember-popper}} 38 | {{/if}} 39 | `); 40 | 41 | const popperTarget = document.getElementById('parent'); 42 | this.set('popperTarget', popperTarget); 43 | this.set('show', true); 44 | 45 | return settled(); 46 | }); 47 | 48 | test('registerAPI returns the explicit popper element', async function(assert) { 49 | let registeredPopperElement; 50 | 51 | this.actions.registerAPI = ({ popperElement }) => { 52 | registeredPopperElement = popperElement; 53 | }; 54 | 55 | await render(hbs` 56 |
57 | {{#ember-popper-targeting-parent class='popper-element' 58 | registerAPI=(action 'registerAPI')}} 59 | template block text 60 | {{/ember-popper-targeting-parent}} 61 |
62 | `); 63 | 64 | await settled(); 65 | 66 | const expectedPopperElement = document.querySelector('.popper-element'); 67 | assert.ok(registeredPopperElement, 'registerAPI has provided popperElement'); 68 | assert.equal(registeredPopperElement, expectedPopperElement, `popperElement matches expected element`); 69 | }); 70 | 71 | test('when the popper changes the API is reregistered', async function(assert) { 72 | assert.expect(2); 73 | 74 | this.actions.registerAPI = () => assert.ok('register API called'); 75 | 76 | this.set('eventsEnabled', true); 77 | 78 | await render(hbs` 79 |
80 | {{#ember-popper-targeting-parent class='popper-element' 81 | eventsEnabled=eventsEnabled 82 | registerAPI=(action 'registerAPI')}} 83 | template block text 84 | {{/ember-popper-targeting-parent}} 85 |
86 | `); 87 | 88 | this.set('eventsEnabled', false); 89 | }); 90 | 91 | test('when the popper target changes the API reregisters with the new target', async function(assert) { 92 | let foundTarget; 93 | 94 | this.actions.registerAPI = ({ popperTarget }) => foundTarget = popperTarget; 95 | 96 | await render(hbs` 97 |
98 |
99 | 100 |
101 |
102 | 103 | {{#if show}} 104 | {{#ember-popper class='popper-element' 105 | registerAPI=(action 'registerAPI') 106 | popperTarget=popperTarget}} 107 | template block text 108 | {{/ember-popper}} 109 | {{/if}} 110 | `); 111 | 112 | const initialTarget = document.getElementById('initialTarget'); 113 | const newTarget = document.getElementById('newTarget'); 114 | 115 | this.set('popperTarget', initialTarget); 116 | 117 | this.set('show', true); 118 | await settled(); 119 | 120 | return settled().then(() => { 121 | assert.equal(foundTarget, initialTarget); 122 | 123 | this.set('popperTarget', newTarget); 124 | 125 | return settled().then(() => { 126 | assert.equal(foundTarget, newTarget, 'the target changed'); 127 | }); 128 | }); 129 | }); 130 | }); 131 | -------------------------------------------------------------------------------- /tests/integration/components/ember-popper/render-in-place-test.js: -------------------------------------------------------------------------------- 1 | import { module, test } from 'qunit'; 2 | import { setupRenderingTest } from 'ember-qunit'; 3 | import { render, settled } from '@ember/test-helpers'; 4 | import hbs from 'htmlbars-inline-precompile'; 5 | 6 | module('Integration | Component | renderInPlace', function(hooks) { 7 | setupRenderingTest(hooks); 8 | 9 | test('false: renders in the body', async function(assert) { 10 | await render(hbs` 11 |
12 | {{#ember-popper-targeting-parent class='hello' renderInPlace=false}} 13 | template block text 14 | {{/ember-popper-targeting-parent}} 15 |
16 | `); 17 | 18 | const popper = document.querySelector('.hello'); 19 | 20 | // Sanity check 21 | assert.equal(popper.innerHTML.trim(), 'template block text'); 22 | assert.ok(popper.hasAttribute('x-placement')); 23 | 24 | assert.equal(popper.parentElement, document.querySelector('.ember-application')); 25 | }); 26 | 27 | test('false with an explicit popperContainer: renders in the popperContainer', async function(assert) { 28 | this.set('show', false); 29 | await render(hbs` 30 |
31 |
32 | {{#if show}} 33 |
34 | {{#ember-popper-targeting-parent class='hello' popperContainer='.poppers-plz' renderInPlace=false}} 35 | template block text 36 | {{/ember-popper-targeting-parent}} 37 |
38 | {{/if}} 39 | `); 40 | // ensure the container is in DOM before rendering the popper element 41 | this.set('show', true); 42 | await settled(); 43 | 44 | const popper = document.querySelector('.hello'); 45 | 46 | // Sanity check 47 | assert.equal(popper.innerHTML.trim(), 'template block text'); 48 | assert.ok(popper.hasAttribute('x-placement')); 49 | 50 | assert.equal(popper.parentElement, document.querySelector('.poppers-plz')); 51 | }); 52 | 53 | test('true: renders in place', async function(assert) { 54 | await render(hbs` 55 |
56 | {{#ember-popper-targeting-parent class='hello' renderInPlace=true}} 57 | template block text 58 | {{/ember-popper-targeting-parent}} 59 |
60 | `); 61 | 62 | const popper = document.querySelector('.hello'); 63 | 64 | // Sanity check 65 | assert.equal(popper.innerHTML.trim(), 'template block text'); 66 | assert.ok(popper.hasAttribute('x-placement')); 67 | 68 | assert.equal(popper.parentElement, document.querySelector('.parent')); 69 | }); 70 | }); 71 | -------------------------------------------------------------------------------- /tests/integration/components/ember-popper/target-test.js: -------------------------------------------------------------------------------- 1 | import { module, test } from 'qunit'; 2 | import { setupRenderingTest } from 'ember-qunit'; 3 | import { render, settled } from '@ember/test-helpers'; 4 | import hbs from 'htmlbars-inline-precompile'; 5 | 6 | module('Integration | Component | target', function(hooks) { 7 | setupRenderingTest(hooks); 8 | 9 | test('it targets the explicit target', async function(assert) { 10 | // wait to show the ember-popper until we have set the popperTarget property. 11 | this.set('show', false); 12 | 13 | await render(hbs` 14 |
15 | the target 16 |
17 | 18 | {{#if show}} 19 | {{#ember-popper id='attachment' popperTarget=popperTarget}} 20 | template block text 21 | {{/ember-popper}} 22 | {{/if}} 23 | `); 24 | 25 | const popperTarget = document.getElementById('target'); 26 | 27 | this.set('popperTarget', popperTarget); 28 | 29 | // Show the ember-popper-targeted now that we have a target to pass it 30 | this.set('show', true); 31 | await settled(); 32 | 33 | const popper = document.getElementById('attachment'); 34 | 35 | assert.equal(popper.innerHTML.trim(), 'template block text'); 36 | assert.ok(popper.hasAttribute('x-placement')); 37 | 38 | assert.equal(popper.parentElement, document.querySelector('.ember-application')); 39 | 40 | return settled().then(() => { 41 | assert.equal(popperTarget.getBoundingClientRect().bottom, 42 | popper.getBoundingClientRect().top); 43 | }); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /tests/test-helper.js: -------------------------------------------------------------------------------- 1 | import Application from '../app'; 2 | import config from '../config/environment'; 3 | import { setApplication } from '@ember/test-helpers'; 4 | import { start } from 'ember-qunit'; 5 | import registerRAFWaiter from 'ember-raf-scheduler/test-support/register-waiter'; 6 | 7 | registerRAFWaiter(); 8 | setApplication(Application.create(config.APP)); 9 | 10 | start(); 11 | -------------------------------------------------------------------------------- /tests/unit/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kybishop/ember-popper/db1e44545814fb9522f335aa6fc2c364cf669af4/tests/unit/.gitkeep -------------------------------------------------------------------------------- /vendor/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kybishop/ember-popper/db1e44545814fb9522f335aa6fc2c364cf669af4/vendor/.gitkeep -------------------------------------------------------------------------------- /vendor/shims.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var lastTime = 0; 3 | var vendors = ['ms', 'moz', 'webkit', 'o']; 4 | for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { 5 | window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame']; 6 | window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] 7 | || window[vendors[x]+'CancelRequestAnimationFrame']; 8 | } 9 | 10 | if (!window.requestAnimationFrame) 11 | window.requestAnimationFrame = function(callback, element) { 12 | var currTime = new Date().getTime(); 13 | var timeToCall = Math.max(0, 16 - (currTime - lastTime)); 14 | var id = window.setTimeout(function() { callback(currTime + timeToCall); }, 15 | timeToCall); 16 | lastTime = currTime + timeToCall; 17 | return id; 18 | }; 19 | 20 | if (!window.cancelAnimationFrame) 21 | window.cancelAnimationFrame = function(id) { 22 | clearTimeout(id); 23 | }; 24 | }()); 25 | 26 | (function() { 27 | function makeShim(name, globalName) { 28 | define(name, ['exports'], function(exports) { 29 | 'use strict'; 30 | 31 | exports.__esModule = true; 32 | var globalParts = globalName.split('.'); 33 | var globalValue = window[globalParts[0]]; 34 | 35 | for (var i = 1; i < globalParts.length; i++) { 36 | globalValue = globalValue[globalParts[i]]; 37 | } 38 | 39 | exports.default = globalValue; 40 | }); 41 | } 42 | 43 | makeShim('ember-computed', 'Ember.computed'); 44 | makeShim('ember-metal/get', 'Ember.get'); 45 | })(); 46 | --------------------------------------------------------------------------------