├── .gitignore ├── .kube-ci └── ci.yaml ├── README.md ├── index.html ├── karma.conf.ci.js ├── karma.conf.js ├── lib ├── includes.js ├── needs-offset.js ├── offset.js ├── positions.js └── size.js ├── package-lock.json ├── package.json └── test ├── lib ├── create.js ├── each.js ├── permute.js └── stringify.js ├── test-body-borders.js ├── test-body-margins.js ├── test-containers.js ├── test-position-absolute.js ├── test-position-fixed.js ├── test-relative-body.js ├── test-scroll.js └── test-wrong-order.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | coverage 4 | -------------------------------------------------------------------------------- /.kube-ci/ci.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: argoproj.io/v1alpha1 2 | kind: Workflow 3 | metadata: 4 | annotations: 5 | kube-ci.qutics.com/cacheScope: project 6 | kube-ci.qutics.com/cacheSize: 20Gi 7 | creationTimestamp: null 8 | spec: 9 | arguments: {} 10 | entrypoint: run 11 | templates: 12 | - inputs: {} 13 | metadata: {} 14 | name: main 15 | outputs: {} 16 | steps: 17 | - - arguments: {} 18 | name: run 19 | template: run 20 | when: '{{workflow.parameters.branch}} != "gh-pages"' 21 | - container: 22 | args: 23 | - sh 24 | - -c 25 | - | 26 | set -x 27 | set -e 28 | 29 | cp /.ci-secrets/npmrc $HOME/.npmrc 30 | export XDG_CACHE_HOME=/cache/.cache 31 | export CYPRESS_CACHE_FOLDER=/cache/.cache 32 | npm set cache /cache/npm 33 | PATH=$PATH:$(pwd)/node_modules/.bin 34 | 35 | npm i 36 | npm run lint 37 | npm run coverage 38 | npm run test-ci 39 | command: 40 | - docker-entrypoint.sh 41 | env: 42 | - name: SAUCE_USERNAME 43 | valueFrom: 44 | secretKeyRef: 45 | key: SAUCE_USERNAME 46 | name: ci-secrets 47 | - name: SAUCE_ACCESS_KEY 48 | valueFrom: 49 | secretKeyRef: 50 | key: SAUCE_ACCESS_KEY 51 | name: ci-secrets 52 | image: eu.gcr.io/qubit-registry/tools/node12chrome:latest 53 | name: "" 54 | resources: {} 55 | volumeMounts: 56 | - mountPath: /.ci-secrets 57 | name: secrets 58 | - mountPath: /cache 59 | name: build-cache 60 | workingDir: /src 61 | inputs: 62 | artifacts: 63 | - git: 64 | repo: '{{workflow.parameters.repo}}' 65 | revision: '{{workflow.parameters.revision}}' 66 | sshPrivateKeySecret: 67 | key: ssh-private-key 68 | name: ci-secrets 69 | name: code 70 | path: /src 71 | metadata: {} 72 | name: run 73 | outputs: {} 74 | volumes: 75 | - name: secrets 76 | secret: 77 | secretName: ci-secrets 78 | - name: build-cache 79 | persistentVolumeClaim: 80 | claimName: '{{workflow.parameters.cacheVolumeClaimName}}' 81 | status: 82 | finishedAt: null 83 | startedAt: null 84 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## positions 2 | 3 | A small dom element positioning lib inspired by jquery-ui/position 4 | 5 | ## installation 6 | ```js 7 | npm install positions 8 | ``` 9 | 10 | ## features 11 | - no dependencies 12 | - simple functional api 13 | - well tested in ie9+ 14 | - tiny (871 B) 15 | 16 | ## usage 17 | ```js 18 | var positions = require('positions') 19 | ``` 20 | 21 | ```js 22 | // positions els 'top left' at targets 'top left' 23 | var css = positions(el, 'top left', target, 'top left') 24 | ``` 25 | 26 | top-left-top-left 27 | 28 | ```js 29 | // positions els 'center center' at targets 'center center' 30 | var css = positions(el, 'center center', target, 'center center') 31 | ``` 32 | 33 | center-center-center-center 34 | 35 | ```js 36 | // positions els bottom left at targets top left 37 | var css = positions(el, 'bottom left', target, 'top left') 38 | ``` 39 | 40 | bottom-left-top-left 41 | 42 | ```js 43 | // positions els bottom center at targets bottom center 44 | var css = positions(el, 'bottom center', target, 'bottom center') 45 | ``` 46 | 47 | bottom-center-bottom-center 48 | 49 | 50 | ...etc. 51 | 52 | 53 | ## run tests 54 | ```js 55 | npm test 56 | ``` 57 | 58 | ## browser compatibility 59 | works in all good browsers! (also in ie9+) 60 | 61 | 62 | ## Want to work on this for your day job? 63 | 64 | This project was created by the Engineering team at Qubit. As we use open source libraries, we make our projects public where possible. 65 | 66 | We’re currently looking to grow our team, so if you’re a JavaScript engineer and keen on ES2016 React+Redux applications and Node micro services, why not get in touch? Work with like minded engineers in an environment that has fantastic perks, including an annual ski trip, yoga, a competitive foosball league, and copious amounts of yogurt. 67 | 68 | Find more details on our Engineering site. Don’t have an up to date CV? Just link us your Github profile! Better yet, send us a pull request that improves this project.` 69 | Contact GitHub API Training Shop Blog About 70 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | positions 5 | 6 | 44 | 89 | 90 | 91 |
92 | position my 93 | 98 | 103 | at 104 | 109 | 's 110 | 115 | 120 |
121 |
122 |
123 |
124 | 125 | 126 | -------------------------------------------------------------------------------- /karma.conf.ci.js: -------------------------------------------------------------------------------- 1 | const karmaConfig = require('./karma.conf') 2 | const customLaunchers = { 3 | sl_ios_safari_10: { 4 | base: 'SauceLabs', 5 | browserName: 'safari', 6 | platform: 'OS X 10.11', 7 | version: '10.0' 8 | }, 9 | sl_ie_11: { 10 | base: 'SauceLabs', 11 | browserName: 'internet explorer', 12 | platform: 'Windows 8.1', 13 | version: '11' 14 | }, 15 | sl_android: { 16 | base: 'SauceLabs', 17 | browserName: 'Browser', 18 | platform: 'Android', 19 | version: '6.0', 20 | deviceName: 'Android Emulator' 21 | } 22 | } 23 | 24 | module.exports = function (config) { 25 | karmaConfig({ 26 | set: function setter (baseConfig) { 27 | config.set(sauceConfig(baseConfig)) 28 | } 29 | }) 30 | } 31 | 32 | function sauceConfig (baseConfig) { 33 | return Object.assign({}, baseConfig, { 34 | sauceLabs: { testName: '@qubit/utils' }, 35 | customLaunchers: customLaunchers, 36 | browsers: Object.keys(customLaunchers), 37 | reporters: ['progress', 'saucelabs'], 38 | coverageReporter: null 39 | }) 40 | } 41 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | const cfg = { 4 | frameworks: ['mocha'], 5 | files: ['test/*'], 6 | preprocessors: { 7 | 'test/**/*.js': ['webpack', 'sourcemap'] 8 | }, 9 | webpackMiddleware: { 10 | stats: 'errors-only', 11 | logLevel: 'error' 12 | }, 13 | reporters: ['progress'], 14 | webpack: { 15 | mode: 'development', 16 | watch: true, 17 | devtool: 'inline-source-map' 18 | }, 19 | browsers: ['Chrome'] 20 | } 21 | 22 | module.exports = function (config) { 23 | const coverage = 24 | process.argv.indexOf('--coverage') > -1 || process.argv.indexOf('-c') > -1 25 | 26 | if (coverage) { 27 | enableCoverage(cfg) 28 | } 29 | 30 | config.set(cfg) 31 | } 32 | 33 | function enableCoverage (cfg) { 34 | cfg.webpack.module = { 35 | rules: [ 36 | { 37 | test: /\.js$/, 38 | include: [path.join(__dirname, 'lib'), path.join(__dirname, 'dom')], 39 | loader: 'istanbul-instrumenter-loader' 40 | } 41 | ] 42 | } 43 | cfg.reporters.push('coverage') 44 | cfg.customLaunchers = { 45 | ChromeCustom: { 46 | base: 'ChromeHeadless', 47 | flags: ['--headless', '--no-sandbox'] 48 | } 49 | } 50 | cfg.coverageReporter = { 51 | reporters: [{ type: 'html' }, { type: 'text' }], 52 | check: { 53 | global: { 54 | statements: 80, 55 | branches: 80, 56 | functions: 80, 57 | lines: 80 58 | } 59 | } 60 | } 61 | cfg.browsers = ['ChromeCustom'] 62 | return cfg 63 | } 64 | -------------------------------------------------------------------------------- /lib/includes.js: -------------------------------------------------------------------------------- 1 | module.exports = ''.includes ? function includes (hay, needle) { 2 | return hay.includes(needle) 3 | } : function includes (hay, needle) { 4 | return hay.indexOf(needle) >= 0 5 | } 6 | -------------------------------------------------------------------------------- /lib/needs-offset.js: -------------------------------------------------------------------------------- 1 | module.exports = function needsOffset (el) { 2 | if (!el.offsetParent) return false 3 | if (el.offsetParent !== document.body) return true 4 | return window.getComputedStyle(el.offsetParent).position !== 'static' 5 | } 6 | -------------------------------------------------------------------------------- /lib/offset.js: -------------------------------------------------------------------------------- 1 | // position relative to top of document 2 | module.exports = function offset (el) { 3 | // document position is always 0, 0 irrespective of whether window has scroll 4 | if (el === document || el === document.documentElement) { 5 | return { top: 0, left: 0 } 6 | } 7 | var scroll = { 8 | top: document.body.scrollTop || document.documentElement.scrollTop, 9 | left: document.body.scrollLeft || document.documentElement.scrollLeft 10 | } 11 | 12 | // window is positioned at the scroll offset coordinates 13 | if (el === window) return scroll 14 | 15 | var rect = el.getBoundingClientRect() 16 | return { 17 | top: rect.top + scroll.top, 18 | left: rect.left + scroll.left 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/positions.js: -------------------------------------------------------------------------------- 1 | var getOffset = require('./offset') 2 | var getSize = require('./size') 3 | var includes = require('./includes') 4 | var needsOffset = require('./needs-offset') 5 | 6 | module.exports = function positions (el, my, target, their) { 7 | var mySize = getSize(el) 8 | var theirSize = getSize(target) 9 | var theirOffset = getOffset(target) 10 | var left = theirOffset.left 11 | var top = theirOffset.top 12 | var parentOffset 13 | 14 | // adjust relative to the offsetParent if appropriate 15 | if (needsOffset(el)) { 16 | parentOffset = getOffset(el.offsetParent) 17 | top -= parentOffset.top 18 | left -= parentOffset.left 19 | 20 | // add scroll if not already accounted for in the target offset 21 | if (el.offsetParent !== document.body) { 22 | top += el.offsetParent.scrollTop 23 | left += el.offsetParent.scrollLeft 24 | } 25 | } else if (!el.offsetParent) { 26 | top -= document.body.scrollTop || document.documentElement.scrollTop 27 | left -= document.body.scrollLeft || document.documentElement.scrollLeft 28 | } 29 | 30 | if (includes(their, 'right')) { 31 | left += theirSize.width 32 | } else if (!includes(their, 'left')) { 33 | left += theirSize.width / 2 34 | } 35 | 36 | if (includes(their, 'bottom')) { 37 | top += theirSize.height 38 | } else if (!includes(their, 'top')) { 39 | top += theirSize.height / 2 40 | } 41 | 42 | if (includes(my, 'right')) { 43 | left -= mySize.width 44 | } else if (!includes(my, 'left')) { 45 | left -= mySize.width / 2 46 | } 47 | 48 | if (includes(my, 'bottom')) { 49 | top -= mySize.height 50 | } else if (!includes(my, 'top')) { 51 | top -= mySize.height / 2 52 | } 53 | 54 | return { 55 | top: top, 56 | left: left 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /lib/size.js: -------------------------------------------------------------------------------- 1 | module.exports = function getSize (el) { 2 | if (el === window) { 3 | if (/Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent)) { 4 | return { 5 | width: window.innerWidth, 6 | height: window.innerHeight 7 | } 8 | } 9 | return { 10 | width: document.documentElement.clientWidth, 11 | height: document.documentElement.clientHeight 12 | } 13 | } else if (el === document || el === document.documentElement) { 14 | var body = document.body 15 | var html = document.documentElement 16 | return { 17 | width: Math.max( 18 | body.scrollWidth, 19 | body.offsetWidth, 20 | html.clientWidth, 21 | html.scrollWidth, 22 | html.offsetWidth 23 | ), 24 | height: Math.max( 25 | body.scrollHeight, 26 | body.offsetHeight, 27 | html.clientHeight, 28 | html.scrollHeight, 29 | html.offsetHeight 30 | ) 31 | } 32 | } 33 | return { 34 | width: el.offsetWidth, 35 | height: el.offsetHeight 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "positions", 3 | "version": "1.6.2", 4 | "description": "A small, dependency free dom element positioning lib inspired by jquery-ui/position", 5 | "main": "lib/positions.js", 6 | "directories": { 7 | "lib": "lib", 8 | "test": "test" 9 | }, 10 | "scripts": { 11 | "test": "karma start --single-run", 12 | "coverage": "npm test -- --coverage", 13 | "test-ci": "karma start karma.conf.ci.js --single-run", 14 | "lint": "standard", 15 | "start": "serve -Lp 1234" 16 | }, 17 | "author": "Alan Clarke (qubit.com)", 18 | "repository": { 19 | "type": "git", 20 | "url": "git+https://github.com/QubitProducts/positions.git" 21 | }, 22 | "license": "UNLICENSED", 23 | "devDependencies": { 24 | "standard": "^11.0.1" 25 | }, 26 | "bugs": { 27 | "url": "https://github.com/QubitProducts/positions/issues" 28 | }, 29 | "homepage": "https://github.com/QubitProducts/positions#readme", 30 | "keywords": [ 31 | "position", 32 | "positioning", 33 | "psotions", 34 | "relative", 35 | "jquery-ui/position" 36 | ], 37 | "dependencies": { 38 | "chai": "^4.2.0", 39 | "istanbul-instrumenter-loader": "^3.0.1", 40 | "karma": "^6.3.2", 41 | "karma-chrome-launcher": "^3.1.0", 42 | "karma-coverage": "^2.0.3", 43 | "karma-mocha": "^2.0.1", 44 | "karma-sauce-launcher": "^2.0.2", 45 | "karma-sourcemap-loader": "^0.3.8", 46 | "karma-webpack": "^4.0.2", 47 | "mocha": "^8.4.0", 48 | "serve": "^11.0.0", 49 | "systemjs": "^0.21.4", 50 | "webpack": "^4.44.1" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /test/lib/create.js: -------------------------------------------------------------------------------- 1 | var each = require('./each') 2 | var stringify = require('./stringify') 3 | 4 | module.exports = function create (style) { 5 | var styleArr = [] 6 | each(style, function (val, key) { styleArr.push(key + ':' + stringify(val)) }) 7 | var el = document.createElement('div') 8 | if (style) el.setAttribute('style', styleArr.join(';')) 9 | document.body.appendChild(el) 10 | return el 11 | } 12 | -------------------------------------------------------------------------------- /test/lib/each.js: -------------------------------------------------------------------------------- 1 | module.exports = function each (arr, fn) { 2 | for (var key in arr) if (arr.hasOwnProperty(key)) fn(arr[key], key) 3 | } 4 | -------------------------------------------------------------------------------- /test/lib/permute.js: -------------------------------------------------------------------------------- 1 | var each = require('./each') 2 | 3 | module.exports = function permute (fn) { 4 | var verticals = ['top', 'center', 'bottom'] 5 | var horizontals = ['left', 'center', 'right'] 6 | each(verticals, function (myVertical) { 7 | each(verticals, function (theirVertical) { 8 | each(horizontals, function (myHorizontal) { 9 | each(horizontals, function (theirHorizontal) { 10 | fn(myVertical, myHorizontal, theirVertical, theirHorizontal) 11 | }) 12 | }) 13 | }) 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /test/lib/stringify.js: -------------------------------------------------------------------------------- 1 | module.exports = function stringify (val) { 2 | if (typeof val === 'number') return val + 'px' 3 | return val 4 | } 5 | -------------------------------------------------------------------------------- /test/test-body-borders.js: -------------------------------------------------------------------------------- 1 | /* globals describe beforeEach afterEach it */ 2 | var expect = require('chai').expect 3 | var create = require('./lib/create') 4 | var size = require('../lib/size') 5 | var permute = require('./lib/permute') 6 | var positions = require('../lib/positions') 7 | 8 | describe('borders', function () { 9 | afterEach(function () { 10 | document.body.setAttribute('style', '') 11 | document.body.innerHTML = '' 12 | }) 13 | 14 | describe('when target is body', function () { 15 | var el, target, border, margin, bodySize, myStyle, targetStyle 16 | beforeEach(function () { 17 | border = 20 18 | document.body.style.margin = '8px' 19 | document.body.style.border = border + 'px solid rgba(0,0,0,0.1)' 20 | bodySize = size(document.body) 21 | myStyle = { 22 | top: 40, 23 | left: 30, 24 | width: 200, 25 | height: 100, 26 | position: 'absolute', 27 | background: 'rgba(0,0,255,0.1)' 28 | } 29 | targetStyle = { 30 | top: 0, 31 | left: 0, 32 | width: bodySize.width, 33 | height: bodySize.height 34 | } 35 | el = create(myStyle) 36 | target = document.body 37 | border = 22 38 | margin = 8 39 | }) 40 | permute(function (myVertical, myHorizontal, theirVertical, theirHorizontal) { 41 | it([ 42 | 'should correctly position my', myVertical, myHorizontal, 43 | 'at their', theirVertical, theirHorizontal 44 | ].join(' '), function () { 45 | var left = targetStyle.left + margin 46 | var top = targetStyle.top + margin 47 | if (theirHorizontal === 'right') left += targetStyle.width 48 | if (theirHorizontal === 'center') left += (targetStyle.width / 2) 49 | if (theirVertical === 'bottom') top += targetStyle.height 50 | if (theirVertical === 'center') top += (targetStyle.height / 2) 51 | if (myHorizontal === 'right') left -= myStyle.width 52 | if (myHorizontal === 'center') left -= (myStyle.width / 2) 53 | if (myVertical === 'bottom') top -= myStyle.height 54 | if (myVertical === 'center') top -= (myStyle.height / 2) 55 | var position = positions( 56 | el, [myVertical, myHorizontal].join(' '), 57 | target, [theirVertical, theirHorizontal].join(' ') 58 | ) 59 | el.style.left = position.left + 'px' 60 | el.style.top = position.top + 'px' 61 | expect(position).to.eql({ top: top, left: left }) 62 | }) 63 | }) 64 | }) 65 | describe('when target is not body', function () { 66 | var el, target, parent, border, myStyle, targetStyle, myParentStyle 67 | beforeEach(function () { 68 | myStyle = { 69 | top: 40, 70 | left: 30, 71 | width: 200, 72 | height: 100, 73 | position: 'absolute', 74 | background: 'rgba(0,0,255,0.1)' 75 | } 76 | targetStyle = { 77 | top: 10, 78 | left: 20, 79 | width: 300, 80 | height: 400, 81 | position: 'absolute', 82 | background: 'rgba(0,255,0,0.1)' 83 | } 84 | myParentStyle = { 85 | top: 40, 86 | left: 30, 87 | width: 200, 88 | height: 100, 89 | position: 'absolute', 90 | background: 'rgba(0,0,0,0.1)' 91 | } 92 | el = create(myStyle) 93 | target = create(targetStyle) 94 | parent = create(myParentStyle) 95 | border = 22 96 | document.body.style.border = border + 'px solid rgba(0,0,0,0.1)' 97 | parent.appendChild(el) 98 | }) 99 | permute(function (myVertical, myHorizontal, theirVertical, theirHorizontal) { 100 | it([ 101 | 'should correctly position my', myVertical, myHorizontal, 102 | 'at their', theirVertical, theirHorizontal 103 | ].join(' '), function () { 104 | var left = targetStyle.left - myParentStyle.left 105 | var top = targetStyle.top - myParentStyle.top 106 | if (theirHorizontal === 'right') left += targetStyle.width 107 | if (theirHorizontal === 'center') left += targetStyle.width / 2 108 | if (theirVertical === 'bottom') top += targetStyle.height 109 | if (theirVertical === 'center') top += targetStyle.height / 2 110 | if (myHorizontal === 'right') left -= myStyle.width 111 | if (myHorizontal === 'center') left -= myStyle.width / 2 112 | if (myVertical === 'bottom') top -= myStyle.height 113 | if (myVertical === 'center') top -= myStyle.height / 2 114 | var position = positions( 115 | el, [myVertical, myHorizontal].join(' '), 116 | target, [theirVertical, theirHorizontal].join(' ') 117 | ) 118 | el.style.left = position.left + 'px' 119 | el.style.top = position.top + 'px' 120 | expect(position).to.eql({ top: top, left: left }) 121 | }) 122 | }) 123 | }) 124 | }) 125 | -------------------------------------------------------------------------------- /test/test-body-margins.js: -------------------------------------------------------------------------------- 1 | /* globals describe beforeEach afterEach it */ 2 | var expect = require('chai').expect 3 | var create = require('./lib/create') 4 | var size = require('../lib/size') 5 | var permute = require('./lib/permute') 6 | var positions = require('../lib/positions') 7 | 8 | describe('margins', function () { 9 | afterEach(function () { 10 | document.body.setAttribute('style', '') 11 | document.body.innerHTML = '' 12 | }) 13 | 14 | describe('when target is body', function () { 15 | var el, target, margin, bodySize, myStyle, targetStyle 16 | beforeEach(function () { 17 | target = document.body 18 | margin = 22 19 | document.body.style.margin = margin + 'px' 20 | document.body.style.border = '1px solid rgba(0,0,0,0.1)' 21 | bodySize = size(document.body) 22 | myStyle = { 23 | top: 40, 24 | left: 30, 25 | width: 200, 26 | height: 100, 27 | position: 'absolute', 28 | background: 'rgba(0,0,255,0.1)' 29 | } 30 | targetStyle = { 31 | top: 0, 32 | left: 0, 33 | width: bodySize.width, 34 | height: bodySize.height 35 | } 36 | el = create(myStyle) 37 | }) 38 | permute(function (myVertical, myHorizontal, theirVertical, theirHorizontal) { 39 | it([ 40 | 'should correctly position my', myVertical, myHorizontal, 41 | 'at their', theirVertical, theirHorizontal 42 | ].join(' '), function () { 43 | var left = targetStyle.left + margin 44 | var top = targetStyle.top + margin 45 | if (theirHorizontal === 'right') left += targetStyle.width 46 | if (theirHorizontal === 'center') left += (targetStyle.width / 2) 47 | if (theirVertical === 'bottom') top += targetStyle.height 48 | if (theirVertical === 'center') top += (targetStyle.height / 2) 49 | if (myHorizontal === 'right') left -= myStyle.width 50 | if (myHorizontal === 'center') left -= (myStyle.width / 2) 51 | if (myVertical === 'bottom') top -= myStyle.height 52 | if (myVertical === 'center') top -= (myStyle.height / 2) 53 | var position = positions( 54 | el, [myVertical, myHorizontal].join(' '), 55 | target, [theirVertical, theirHorizontal].join(' ') 56 | ) 57 | el.style.left = position.left + 'px' 58 | el.style.top = position.top + 'px' 59 | expect(position).to.eql({ top: top, left: left }) 60 | }) 61 | }) 62 | }) 63 | describe('when target is not body', function () { 64 | var el, target, parent, margin, myStyle, targetStyle, myParentStyle 65 | beforeEach(function () { 66 | myStyle = { 67 | top: 40, 68 | left: 30, 69 | width: 200, 70 | height: 100, 71 | position: 'absolute', 72 | background: 'rgba(0,0,255,0.1)' 73 | } 74 | targetStyle = { 75 | top: 10, 76 | left: 20, 77 | width: 300, 78 | height: 400, 79 | position: 'absolute', 80 | background: 'rgba(0,255,0,0.1)' 81 | } 82 | myParentStyle = { 83 | top: 40, 84 | left: 30, 85 | width: 200, 86 | height: 100, 87 | position: 'absolute', 88 | background: 'rgba(0,0,0,0.1)' 89 | } 90 | el = create(myStyle) 91 | target = create(targetStyle) 92 | parent = create(myParentStyle) 93 | margin = 22 94 | document.body.style.margin = margin + 'px' 95 | document.body.style.border = '1px solid rgba(0,0,0,0.1)' 96 | parent.appendChild(el) 97 | }) 98 | permute(function (myVertical, myHorizontal, theirVertical, theirHorizontal) { 99 | it([ 100 | 'should correctly position my', myVertical, myHorizontal, 101 | 'at their', theirVertical, theirHorizontal 102 | ].join(' '), function () { 103 | var left = targetStyle.left - myParentStyle.left 104 | var top = targetStyle.top - myParentStyle.top 105 | if (theirHorizontal === 'right') left += targetStyle.width 106 | if (theirHorizontal === 'center') left += targetStyle.width / 2 107 | if (theirVertical === 'bottom') top += targetStyle.height 108 | if (theirVertical === 'center') top += targetStyle.height / 2 109 | if (myHorizontal === 'right') left -= myStyle.width 110 | if (myHorizontal === 'center') left -= myStyle.width / 2 111 | if (myVertical === 'bottom') top -= myStyle.height 112 | if (myVertical === 'center') top -= myStyle.height / 2 113 | var position = positions( 114 | el, [myVertical, myHorizontal].join(' '), 115 | target, [theirVertical, theirHorizontal].join(' ') 116 | ) 117 | el.style.left = position.left + 'px' 118 | el.style.top = position.top + 'px' 119 | expect(position).to.eql({ top: top, left: left }) 120 | }) 121 | }) 122 | }) 123 | }) 124 | -------------------------------------------------------------------------------- /test/test-containers.js: -------------------------------------------------------------------------------- 1 | /* globals describe beforeEach afterEach it */ 2 | var expect = require('chai').expect 3 | var create = require('./lib/create') 4 | var size = require('../lib/size') 5 | var permute = require('./lib/permute') 6 | var positions = require('../lib/positions') 7 | 8 | describe('containers', function () { 9 | afterEach(function () { 10 | document.body.innerHTML = '' 11 | document.body.setAttribute('style', '') 12 | }) 13 | describe('window', function () { 14 | var el, target, myStyle, targetStyle, margin 15 | beforeEach(function () { 16 | myStyle = { 17 | top: 40, 18 | left: 30, 19 | width: 200, 20 | height: 100, 21 | position: 'absolute', 22 | background: 'rgba(0,0,255,0.1)' 23 | } 24 | targetStyle = { 25 | top: 0, 26 | left: 0, 27 | width: window.innerWidth, 28 | height: window.innerHeight 29 | } 30 | margin = 8 31 | document.body.style.margin = margin + 'px' 32 | document.body.style.border = '1px solid black' 33 | el = create(myStyle) 34 | target = window 35 | }) 36 | permute(function (myVertical, myHorizontal, theirVertical, theirHorizontal) { 37 | it([ 38 | 'should correctly position my', myVertical, myHorizontal, 39 | 'at their', theirVertical, theirHorizontal 40 | ].join(' '), function () { 41 | var left = targetStyle.left 42 | var top = targetStyle.top 43 | if (theirHorizontal === 'right') left += targetStyle.width 44 | if (theirHorizontal === 'center') left += (targetStyle.width) / 2 45 | if (theirVertical === 'bottom') top += targetStyle.height 46 | if (theirVertical === 'center') top += (targetStyle.height) / 2 47 | if (myHorizontal === 'right') left -= myStyle.width 48 | if (myHorizontal === 'center') left -= myStyle.width / 2 49 | if (myVertical === 'bottom') top -= myStyle.height 50 | if (myVertical === 'center') top -= myStyle.height / 2 51 | var position = positions( 52 | el, [myVertical, myHorizontal].join(' '), 53 | target, [theirVertical, theirHorizontal].join(' ') 54 | ) 55 | el.style.left = position.left + 'px' 56 | el.style.top = position.top + 'px' 57 | expect(position).to.eql({ top: top, left: left }) 58 | }) 59 | }) 60 | }) 61 | 62 | describe('document', function () { 63 | var el, target, docSize, myStyle, targetStyle, margin 64 | beforeEach(function () { 65 | docSize = size(document) 66 | myStyle = { 67 | top: 40, 68 | left: 30, 69 | width: 200, 70 | height: 100, 71 | position: 'absolute', 72 | background: 'rgba(0,0,255,0.1)' 73 | } 74 | targetStyle = { 75 | top: 0, 76 | left: 0, 77 | width: docSize.width, 78 | height: docSize.height 79 | } 80 | document.body.style.margin = margin + 'px' 81 | el = create(myStyle) 82 | target = document 83 | }) 84 | permute(function (myVertical, myHorizontal, theirVertical, theirHorizontal) { 85 | it([ 86 | 'should correctly position my', myVertical, myHorizontal, 87 | 'at their', theirVertical, theirHorizontal 88 | ].join(' '), function () { 89 | var left = targetStyle.left 90 | var top = targetStyle.top 91 | if (theirHorizontal === 'right') left += targetStyle.width 92 | if (theirHorizontal === 'center') left += targetStyle.width / 2 93 | if (theirVertical === 'bottom') top += targetStyle.height 94 | if (theirVertical === 'center') top += targetStyle.height / 2 95 | if (myHorizontal === 'right') left -= myStyle.width 96 | if (myHorizontal === 'center') left -= myStyle.width / 2 97 | if (myVertical === 'bottom') top -= myStyle.height 98 | if (myVertical === 'center') top -= myStyle.height / 2 99 | var position = positions( 100 | el, [myVertical, myHorizontal].join(' '), 101 | target, [theirVertical, theirHorizontal].join(' ') 102 | ) 103 | el.style.left = position.left + 'px' 104 | el.style.top = position.top + 'px' 105 | expect(position).to.eql({ top: top, left: left }) 106 | }) 107 | }) 108 | }) 109 | 110 | describe('body', function () { 111 | var el, target, myStyle, targetStyle, margin, bodySize 112 | beforeEach(function () { 113 | margin = 8 114 | document.body.style.margin = margin + 'px' 115 | document.body.style.border = '1px solid black' 116 | bodySize = size(document.body) 117 | myStyle = { 118 | top: 40, 119 | left: 30, 120 | width: 200, 121 | height: 100, 122 | position: 'absolute', 123 | background: 'rgba(0,0,255,0.1)' 124 | } 125 | targetStyle = { 126 | top: 0, 127 | left: 0, 128 | width: bodySize.width, 129 | height: bodySize.height 130 | } 131 | el = create(myStyle) 132 | target = document.body 133 | }) 134 | permute(function (myVertical, myHorizontal, theirVertical, theirHorizontal) { 135 | it([ 136 | 'should correctly position my', myVertical, myHorizontal, 137 | 'at their', theirVertical, theirHorizontal 138 | ].join(' '), function () { 139 | var left = targetStyle.left + margin 140 | var top = targetStyle.top + margin 141 | if (theirHorizontal === 'right') left += targetStyle.width 142 | if (theirHorizontal === 'center') left += targetStyle.width / 2 143 | if (theirVertical === 'bottom') top += targetStyle.height 144 | if (theirVertical === 'center') top += targetStyle.height / 2 145 | if (myHorizontal === 'right') left -= myStyle.width 146 | if (myHorizontal === 'center') left -= myStyle.width / 2 147 | if (myVertical === 'bottom') top -= myStyle.height 148 | if (myVertical === 'center') top -= myStyle.height / 2 149 | var position = positions( 150 | el, [myVertical, myHorizontal].join(' '), 151 | target, [theirVertical, theirHorizontal].join(' ') 152 | ) 153 | el.style.left = position.left + 'px' 154 | el.style.top = position.top + 'px' 155 | expect(position).to.eql({ top: top, left: left }) 156 | }) 157 | }) 158 | }) 159 | }) 160 | -------------------------------------------------------------------------------- /test/test-position-absolute.js: -------------------------------------------------------------------------------- 1 | /* globals describe beforeEach afterEach it */ 2 | var positions = require('../lib/positions') 3 | var expect = require('chai').expect 4 | var create = require('./lib/create') 5 | var permute = require('./lib/permute') 6 | 7 | describe('position absolute', function () { 8 | var myStyle = { 9 | top: 40, 10 | left: 30, 11 | width: 200, 12 | height: 100, 13 | position: 'absolute', 14 | background: 'rgba(0,0,255,0.1)' 15 | } 16 | var targetStyle = { 17 | top: 10, 18 | left: 20, 19 | width: 300, 20 | height: 400, 21 | position: 'absolute', 22 | background: 'rgba(0,255,0,0.1)' 23 | } 24 | var myParentStyle = { 25 | top: 40, 26 | left: 30, 27 | width: 200, 28 | height: 100, 29 | position: 'absolute', 30 | background: 'rgba(0,0,0,0.1)' 31 | } 32 | var el, target, parent 33 | beforeEach(function () { 34 | el = create(myStyle) 35 | target = create(targetStyle) 36 | parent = create(myParentStyle) 37 | parent.appendChild(el) 38 | }) 39 | afterEach(function () { 40 | document.body.innerHTML = '' 41 | }) 42 | permute(function (myVertical, myHorizontal, theirVertical, theirHorizontal) { 43 | it([ 44 | 'should correctly position my', myVertical, myHorizontal, 45 | 'at their', theirVertical, theirHorizontal 46 | ].join(' '), function () { 47 | var left = targetStyle.left - myParentStyle.left 48 | var top = targetStyle.top - myParentStyle.top 49 | if (theirHorizontal === 'right') left += targetStyle.width 50 | if (theirHorizontal === 'center') left += targetStyle.width / 2 51 | if (theirVertical === 'bottom') top += targetStyle.height 52 | if (theirVertical === 'center') top += targetStyle.height / 2 53 | if (myHorizontal === 'right') left -= myStyle.width 54 | if (myHorizontal === 'center') left -= myStyle.width / 2 55 | if (myVertical === 'bottom') top -= myStyle.height 56 | if (myVertical === 'center') top -= myStyle.height / 2 57 | var position = positions( 58 | el, [myVertical, myHorizontal].join(' '), 59 | target, [theirVertical, theirHorizontal].join(' ') 60 | ) 61 | el.style.left = position.left + 'px' 62 | el.style.top = position.top + 'px' 63 | expect(position).to.eql({ top: top, left: left }) 64 | }) 65 | }) 66 | }) 67 | -------------------------------------------------------------------------------- /test/test-position-fixed.js: -------------------------------------------------------------------------------- 1 | /* globals describe beforeEach afterEach it */ 2 | var positions = require('../lib/positions') 3 | var expect = require('chai').expect 4 | var permute = require('./lib/permute') 5 | var create = require('./lib/create') 6 | 7 | describe('position fixed', function () { 8 | var el, target, myStyle, targetStyle 9 | beforeEach(function () { 10 | myStyle = { 11 | top: 40, 12 | left: 30, 13 | width: 200, 14 | height: 100, 15 | position: 'fixed', 16 | background: 'rgba(0,0,255,0.1)' 17 | } 18 | targetStyle = { 19 | top: 10, 20 | left: 20, 21 | width: 300, 22 | height: 400, 23 | position: 'absolute', 24 | background: 'rgba(0,255,0,0.1)' 25 | } 26 | el = create(myStyle) 27 | target = create(targetStyle) 28 | }) 29 | afterEach(function () { 30 | document.body.innerHTML = '' 31 | }) 32 | permute(function (myVertical, myHorizontal, theirVertical, theirHorizontal) { 33 | it([ 34 | 'should correctly position my', myVertical, myHorizontal, 35 | 'at their', theirVertical, theirHorizontal 36 | ].join(' '), function () { 37 | var left = targetStyle.left 38 | var top = targetStyle.top 39 | if (theirHorizontal === 'right') left += targetStyle.width 40 | if (theirHorizontal === 'center') left += targetStyle.width / 2 41 | if (theirVertical === 'bottom') top += targetStyle.height 42 | if (theirVertical === 'center') top += targetStyle.height / 2 43 | if (myHorizontal === 'right') left -= myStyle.width 44 | if (myHorizontal === 'center') left -= myStyle.width / 2 45 | if (myVertical === 'bottom') top -= myStyle.height 46 | if (myVertical === 'center') top -= myStyle.height / 2 47 | var position = positions( 48 | el, [myVertical, myHorizontal].join(' '), 49 | target, [theirVertical, theirHorizontal].join(' ') 50 | ) 51 | el.style.left = position.left + 'px' 52 | el.style.top = position.top + 'px' 53 | expect(position).to.eql({ top: top, left: left }) 54 | }) 55 | }) 56 | }) 57 | -------------------------------------------------------------------------------- /test/test-relative-body.js: -------------------------------------------------------------------------------- 1 | /* globals describe beforeEach afterEach it */ 2 | var expect = require('chai').expect 3 | var create = require('./lib/create') 4 | var size = require('../lib/size') 5 | var permute = require('./lib/permute') 6 | var positions = require('../lib/positions') 7 | 8 | describe('containers', function () { 9 | afterEach(function () { 10 | document.body.innerHTML = '' 11 | document.body.setAttribute('style', '') 12 | }) 13 | describe('window', function () { 14 | var el, target, myStyle, targetStyle, margin 15 | beforeEach(function () { 16 | myStyle = { 17 | top: 40, 18 | left: 30, 19 | width: 200, 20 | height: 100, 21 | position: 'absolute', 22 | background: 'rgba(0,0,255,0.1)' 23 | } 24 | targetStyle = { 25 | top: 0, 26 | left: 0, 27 | width: window.innerWidth, 28 | height: window.innerHeight 29 | } 30 | margin = 8 31 | document.body.style.position = 'relative' 32 | document.body.style.margin = margin + 'px' 33 | document.body.style.border = '1px solid black' 34 | el = create(myStyle) 35 | target = window 36 | }) 37 | permute(function (myVertical, myHorizontal, theirVertical, theirHorizontal) { 38 | it([ 39 | 'should correctly position my', myVertical, myHorizontal, 40 | 'at their', theirVertical, theirHorizontal 41 | ].join(' '), function () { 42 | var left = targetStyle.left - margin 43 | var top = targetStyle.top - margin 44 | if (theirHorizontal === 'right') left += targetStyle.width 45 | if (theirHorizontal === 'center') left += (targetStyle.width) / 2 46 | if (theirVertical === 'bottom') top += targetStyle.height 47 | if (theirVertical === 'center') top += (targetStyle.height) / 2 48 | if (myHorizontal === 'right') left -= myStyle.width 49 | if (myHorizontal === 'center') left -= myStyle.width / 2 50 | if (myVertical === 'bottom') top -= myStyle.height 51 | if (myVertical === 'center') top -= myStyle.height / 2 52 | var position = positions( 53 | el, [myVertical, myHorizontal].join(' '), 54 | target, [theirVertical, theirHorizontal].join(' ') 55 | ) 56 | el.style.left = position.left + 'px' 57 | el.style.top = position.top + 'px' 58 | expect(position).to.eql({ top: top, left: left }) 59 | }) 60 | }) 61 | }) 62 | 63 | describe('document', function () { 64 | var el, target, docSize, myStyle, targetStyle, margin 65 | beforeEach(function () { 66 | docSize = size(document) 67 | myStyle = { 68 | top: 40, 69 | left: 30, 70 | width: 200, 71 | height: 100, 72 | position: 'absolute', 73 | background: 'rgba(0,0,255,0.1)' 74 | } 75 | targetStyle = { 76 | top: 0, 77 | left: 0, 78 | width: docSize.width, 79 | height: docSize.height 80 | } 81 | document.body.style.position = 'relative' 82 | margin = 8 83 | document.body.style.margin = margin + 'px' 84 | el = create(myStyle) 85 | target = document 86 | }) 87 | permute(function (myVertical, myHorizontal, theirVertical, theirHorizontal) { 88 | it([ 89 | 'should correctly position my', myVertical, myHorizontal, 90 | 'at their', theirVertical, theirHorizontal 91 | ].join(' '), function () { 92 | var left = targetStyle.left - margin 93 | var top = targetStyle.top - margin 94 | if (theirHorizontal === 'right') left += targetStyle.width 95 | if (theirHorizontal === 'center') left += targetStyle.width / 2 96 | if (theirVertical === 'bottom') top += targetStyle.height 97 | if (theirVertical === 'center') top += targetStyle.height / 2 98 | if (myHorizontal === 'right') left -= myStyle.width 99 | if (myHorizontal === 'center') left -= myStyle.width / 2 100 | if (myVertical === 'bottom') top -= myStyle.height 101 | if (myVertical === 'center') top -= myStyle.height / 2 102 | var position = positions( 103 | el, [myVertical, myHorizontal].join(' '), 104 | target, [theirVertical, theirHorizontal].join(' ') 105 | ) 106 | el.style.left = position.left + 'px' 107 | el.style.top = position.top + 'px' 108 | expect(position).to.eql({ top: top, left: left }) 109 | }) 110 | }) 111 | }) 112 | 113 | describe('body', function () { 114 | var el, target, myStyle, targetStyle, margin, bodySize 115 | beforeEach(function () { 116 | margin = 8 117 | document.body.style.position = 'relative' 118 | document.body.style.margin = margin + 'px' 119 | document.body.style.border = '1px solid black' 120 | bodySize = size(document.body) 121 | myStyle = { 122 | top: 40, 123 | left: 30, 124 | width: 200, 125 | height: 100, 126 | position: 'absolute', 127 | background: 'rgba(0,0,255,0.1)' 128 | } 129 | targetStyle = { 130 | top: 0, 131 | left: 0, 132 | width: bodySize.width, 133 | height: bodySize.height 134 | } 135 | el = create(myStyle) 136 | target = document.body 137 | }) 138 | permute(function (myVertical, myHorizontal, theirVertical, theirHorizontal) { 139 | it([ 140 | 'should correctly position my', myVertical, myHorizontal, 141 | 'at their', theirVertical, theirHorizontal 142 | ].join(' '), function () { 143 | var left = targetStyle.left 144 | var top = targetStyle.top 145 | if (theirHorizontal === 'right') left += targetStyle.width 146 | if (theirHorizontal === 'center') left += targetStyle.width / 2 147 | if (theirVertical === 'bottom') top += targetStyle.height 148 | if (theirVertical === 'center') top += targetStyle.height / 2 149 | if (myHorizontal === 'right') left -= myStyle.width 150 | if (myHorizontal === 'center') left -= myStyle.width / 2 151 | if (myVertical === 'bottom') top -= myStyle.height 152 | if (myVertical === 'center') top -= myStyle.height / 2 153 | var position = positions( 154 | el, [myVertical, myHorizontal].join(' '), 155 | target, [theirVertical, theirHorizontal].join(' ') 156 | ) 157 | el.style.left = position.left + 'px' 158 | el.style.top = position.top + 'px' 159 | expect(position).to.eql({ top: top, left: left }) 160 | }) 161 | }) 162 | }) 163 | }) 164 | -------------------------------------------------------------------------------- /test/test-scroll.js: -------------------------------------------------------------------------------- 1 | /* globals describe beforeEach afterEach it */ 2 | var positions = require('../lib/positions') 3 | var expect = require('chai').expect 4 | var create = require('./lib/create') 5 | var permute = require('./lib/permute') 6 | var size = require('../lib/size') 7 | 8 | describe('scroll', function () { 9 | afterEach(function () { 10 | document.body.innerHTML = '' 11 | document.body.setAttribute('style', '') 12 | }) 13 | describe('fixed with relative parent and absolute target', function () { 14 | var el, target, parent, myStyle, targetStyle, myParentStyle 15 | beforeEach(function () { 16 | myStyle = { 17 | top: 140, 18 | left: 30, 19 | width: 20, 20 | height: 20, 21 | position: 'fixed', 22 | background: 'rgba(255, 0, 0, 0.5)' 23 | } 24 | targetStyle = { 25 | top: 200, 26 | left: 20, 27 | width: 40, 28 | height: 40, 29 | position: 'absolute', 30 | background: 'rgba(0, 255, 0, 0.5)' 31 | } 32 | myParentStyle = { 33 | top: 40, 34 | left: 30, 35 | width: 200, 36 | height: 100, 37 | overflow: 'scroll', 38 | position: 'relative', 39 | background: 'rgba(0,0,0,0.1)' 40 | } 41 | el = create(myStyle) 42 | target = create(targetStyle) 43 | parent = create(myParentStyle) 44 | document.body.style.border = '1px solid black' 45 | parent.appendChild(el) 46 | parent.appendChild(target) 47 | parent.scrollTop = 140 48 | }) 49 | permute(function (myVertical, myHorizontal, theirVertical, theirHorizontal) { 50 | it([ 51 | 'should correctly position my', myVertical, myHorizontal, 52 | 'at their', theirVertical, theirHorizontal 53 | ].join(' '), function () { 54 | var left = targetStyle.left + parent.offsetLeft - parent.scrollLeft 55 | var top = targetStyle.top + parent.offsetTop - parent.scrollTop 56 | if (theirHorizontal === 'right') left += targetStyle.width 57 | if (theirHorizontal === 'center') left += targetStyle.width / 2 58 | if (theirVertical === 'bottom') top += targetStyle.height 59 | if (theirVertical === 'center') top += targetStyle.height / 2 60 | if (myHorizontal === 'right') left -= myStyle.width 61 | if (myHorizontal === 'center') left -= myStyle.width / 2 62 | if (myVertical === 'bottom') top -= myStyle.height 63 | if (myVertical === 'center') top -= myStyle.height / 2 64 | var position = positions( 65 | el, [myVertical, myHorizontal].join(' '), 66 | target, [theirVertical, theirHorizontal].join(' ') 67 | ) 68 | el.style.left = position.left + 'px' 69 | el.style.top = position.top + 'px' 70 | expect(position).to.eql({ top: top, left: left }) 71 | }) 72 | }) 73 | }) 74 | describe('fixed with absolute parent and absolute target', function () { 75 | var el, target, parent, myStyle, targetStyle, myParentStyle 76 | beforeEach(function () { 77 | myStyle = { 78 | top: 140, 79 | left: 30, 80 | width: 20, 81 | height: 20, 82 | position: 'fixed', 83 | background: 'rgba(255, 0, 0, 0.5)' 84 | } 85 | targetStyle = { 86 | top: 200, 87 | left: 20, 88 | width: 40, 89 | height: 40, 90 | position: 'absolute', 91 | background: 'rgba(0, 255, 0, 0.5)' 92 | } 93 | myParentStyle = { 94 | top: 40, 95 | left: 30, 96 | width: 200, 97 | height: 100, 98 | overflow: 'scroll', 99 | position: 'absolute', 100 | background: 'rgba(0,0,0,0.1)' 101 | } 102 | document.body.style.border = '1px solid black' 103 | el = create(myStyle) 104 | target = create(targetStyle) 105 | parent = create(myParentStyle) 106 | parent.appendChild(el) 107 | parent.appendChild(target) 108 | parent.scrollTop = 140 109 | }) 110 | permute(function (myVertical, myHorizontal, theirVertical, theirHorizontal) { 111 | it([ 112 | 'should correctly position my', myVertical, myHorizontal, 113 | 'at their', theirVertical, theirHorizontal 114 | ].join(' '), function () { 115 | var left = targetStyle.left + parent.offsetLeft - parent.scrollLeft 116 | var top = targetStyle.top + parent.offsetTop - parent.scrollTop 117 | if (theirHorizontal === 'right') left += targetStyle.width 118 | if (theirHorizontal === 'center') left += targetStyle.width / 2 119 | if (theirVertical === 'bottom') top += targetStyle.height 120 | if (theirVertical === 'center') top += targetStyle.height / 2 121 | if (myHorizontal === 'right') left -= myStyle.width 122 | if (myHorizontal === 'center') left -= myStyle.width / 2 123 | if (myVertical === 'bottom') top -= myStyle.height 124 | if (myVertical === 'center') top -= myStyle.height / 2 125 | var position = positions( 126 | el, [myVertical, myHorizontal].join(' '), 127 | target, [theirVertical, theirHorizontal].join(' ') 128 | ) 129 | el.style.left = position.left + 'px' 130 | el.style.top = position.top + 'px' 131 | expect(position).to.eql({ top: top, left: left }) 132 | }) 133 | }) 134 | }) 135 | describe('fixed with absolute parent and fixed target', function () { 136 | var el, target, parent, myStyle, targetStyle, myParentStyle 137 | beforeEach(function () { 138 | myStyle = { 139 | top: 140, 140 | left: 30, 141 | width: 20, 142 | height: 20, 143 | position: 'fixed', 144 | background: 'rgba(255, 0, 0, 0.5)' 145 | } 146 | targetStyle = { 147 | top: 200, 148 | left: 20, 149 | width: 40, 150 | height: 40, 151 | position: 'fixed', 152 | background: 'rgba(0, 255, 0, 0.5)' 153 | } 154 | myParentStyle = { 155 | top: 40, 156 | left: 30, 157 | width: 200, 158 | height: 100, 159 | overflow: 'scroll', 160 | position: 'relative', 161 | background: 'rgba(0,0,0,0.1)' 162 | } 163 | document.body.style.border = '1px solid black' 164 | el = create(myStyle) 165 | target = create(targetStyle) 166 | parent = create(myParentStyle) 167 | parent.appendChild(el) 168 | parent.appendChild(target) 169 | parent.scrollTop = 140 170 | }) 171 | permute(function (myVertical, myHorizontal, theirVertical, theirHorizontal) { 172 | it([ 173 | 'should correctly position my', myVertical, myHorizontal, 174 | 'at their', theirVertical, theirHorizontal 175 | ].join(' '), function () { 176 | var left = targetStyle.left 177 | var top = targetStyle.top 178 | if (theirHorizontal === 'right') left += targetStyle.width 179 | if (theirHorizontal === 'center') left += targetStyle.width / 2 180 | if (theirVertical === 'bottom') top += targetStyle.height 181 | if (theirVertical === 'center') top += targetStyle.height / 2 182 | if (myHorizontal === 'right') left -= myStyle.width 183 | if (myHorizontal === 'center') left -= myStyle.width / 2 184 | if (myVertical === 'bottom') top -= myStyle.height 185 | if (myVertical === 'center') top -= myStyle.height / 2 186 | var position = positions( 187 | el, [myVertical, myHorizontal].join(' '), 188 | target, [theirVertical, theirHorizontal].join(' ') 189 | ) 190 | el.style.left = position.left + 'px' 191 | el.style.top = position.top + 'px' 192 | expect(position).to.eql({ top: top, left: left }) 193 | }) 194 | }) 195 | }) 196 | describe('absolute with absolute parent and absolute target', function () { 197 | var el, target, parent, myStyle, targetStyle, myParentStyle 198 | beforeEach(function () { 199 | myStyle = { 200 | top: 140, 201 | left: 30, 202 | width: 20, 203 | height: 20, 204 | position: 'absolute', 205 | background: 'rgba(255, 0, 0, 0.5)' 206 | } 207 | targetStyle = { 208 | top: 200, 209 | left: 20, 210 | width: 40, 211 | height: 40, 212 | position: 'absolute', 213 | background: 'rgba(0, 255, 0, 0.5)' 214 | } 215 | myParentStyle = { 216 | top: 40, 217 | left: 30, 218 | width: 200, 219 | height: 100, 220 | overflow: 'scroll', 221 | position: 'relative', 222 | background: 'rgba(0,0,0,0.1)' 223 | } 224 | el = create(myStyle) 225 | target = create(targetStyle) 226 | parent = create(myParentStyle) 227 | parent.appendChild(el) 228 | parent.appendChild(target) 229 | parent.scrollTop = 140 230 | }) 231 | permute(function (myVertical, myHorizontal, theirVertical, theirHorizontal) { 232 | it([ 233 | 'should correctly position my', myVertical, myHorizontal, 234 | 'at their', theirVertical, theirHorizontal 235 | ].join(' '), function () { 236 | var left = target.offsetLeft 237 | var top = target.offsetTop 238 | if (theirHorizontal === 'right') left += targetStyle.width 239 | if (theirHorizontal === 'center') left += targetStyle.width / 2 240 | if (theirVertical === 'bottom') top += targetStyle.height 241 | if (theirVertical === 'center') top += targetStyle.height / 2 242 | if (myHorizontal === 'right') left -= myStyle.width 243 | if (myHorizontal === 'center') left -= myStyle.width / 2 244 | if (myVertical === 'bottom') top -= myStyle.height 245 | if (myVertical === 'center') top -= myStyle.height / 2 246 | var position = positions( 247 | el, [myVertical, myHorizontal].join(' '), 248 | target, [theirVertical, theirHorizontal].join(' ') 249 | ) 250 | el.style.left = position.left + 'px' 251 | el.style.top = position.top + 'px' 252 | expect(position).to.eql({ top: top, left: left }) 253 | }) 254 | }) 255 | }) 256 | describe('absolute with relative parent and relative target', function () { 257 | var el, target, parent, myStyle, targetStyle, myParentStyle 258 | beforeEach(function () { 259 | myStyle = { 260 | top: 140, 261 | left: 30, 262 | width: 20, 263 | height: 20, 264 | position: 'absolute', 265 | background: 'rgba(255, 0, 0, 0.5)' 266 | } 267 | targetStyle = { 268 | width: 40, 269 | height: 40, 270 | position: 'relative', 271 | 'margin-left': '20px', 272 | 'margin-top': '200px', 273 | background: 'rgba(0, 255, 0, 0.5)' 274 | } 275 | myParentStyle = { 276 | top: 40, 277 | left: 30, 278 | width: 200, 279 | height: 100, 280 | overflow: 'scroll', 281 | position: 'relative', 282 | background: 'rgba(0,0,0,0.1)' 283 | } 284 | el = create(myStyle) 285 | target = create(targetStyle) 286 | parent = create(myParentStyle) 287 | parent.appendChild(el) 288 | parent.appendChild(target) 289 | parent.scrollTop = 140 290 | }) 291 | permute(function (myVertical, myHorizontal, theirVertical, theirHorizontal) { 292 | it([ 293 | 'should correctly position my', myVertical, myHorizontal, 294 | 'at their', theirVertical, theirHorizontal 295 | ].join(' '), function () { 296 | var left = target.offsetLeft 297 | var top = target.offsetTop 298 | if (theirHorizontal === 'right') left += targetStyle.width 299 | if (theirHorizontal === 'center') left += targetStyle.width / 2 300 | if (theirVertical === 'bottom') top += targetStyle.height 301 | if (theirVertical === 'center') top += targetStyle.height / 2 302 | if (myHorizontal === 'right') left -= myStyle.width 303 | if (myHorizontal === 'center') left -= myStyle.width / 2 304 | if (myVertical === 'bottom') top -= myStyle.height 305 | if (myVertical === 'center') top -= myStyle.height / 2 306 | var position = positions( 307 | el, [myVertical, myHorizontal].join(' '), 308 | target, [theirVertical, theirHorizontal].join(' ') 309 | ) 310 | el.style.left = position.left + 'px' 311 | el.style.top = position.top + 'px' 312 | expect(position).to.eql({ top: top, left: left }) 313 | }) 314 | }) 315 | }) 316 | describe('parent is body and is absolute and target is relative', function () { 317 | var el, target, myStyle, targetStyle, fillerStyle 318 | beforeEach(function () { 319 | myStyle = { 320 | top: 140, 321 | left: 30, 322 | width: 20, 323 | height: 20, 324 | position: 'absolute', 325 | background: 'rgba(255, 0, 0, 0.5)' 326 | } 327 | targetStyle = { 328 | width: 40, 329 | height: 40, 330 | position: 'relative', 331 | 'margin-left': '20px', 332 | 'margin-top': '200px', 333 | background: 'rgba(0, 255, 0, 0.5)' 334 | } 335 | fillerStyle = { 336 | width: 20, 337 | height: Math.min(1000000000, window.innerHeight * 100), 338 | position: 'relative', 339 | background: 'rgba(0,0,0,0.1)' 340 | } 341 | document.body.style.margin = '8px' 342 | el = create(myStyle) 343 | target = create(targetStyle) 344 | create(fillerStyle) 345 | window.scroll(0, 100) 346 | }) 347 | permute(function (myVertical, myHorizontal, theirVertical, theirHorizontal) { 348 | it([ 349 | 'should correctly position my', myVertical, myHorizontal, 350 | 'at their', theirVertical, theirHorizontal 351 | ].join(' '), function () { 352 | var left = parseInt(target.offsetLeft, 10) 353 | var top = parseInt(target.offsetTop, 10) 354 | if (theirHorizontal === 'right') left += targetStyle.width 355 | if (theirHorizontal === 'center') left += targetStyle.width / 2 356 | if (theirVertical === 'bottom') top += targetStyle.height 357 | if (theirVertical === 'center') top += targetStyle.height / 2 358 | if (myHorizontal === 'right') left -= myStyle.width 359 | if (myHorizontal === 'center') left -= myStyle.width / 2 360 | if (myVertical === 'bottom') top -= myStyle.height 361 | if (myVertical === 'center') top -= myStyle.height / 2 362 | var position = positions( 363 | el, [myVertical, myHorizontal].join(' '), 364 | target, [theirVertical, theirHorizontal].join(' ') 365 | ) 366 | el.style.left = position.left + 'px' 367 | el.style.top = position.top + 'px' 368 | expect(position).to.eql({ top: top, left: left }) 369 | }) 370 | }) 371 | }) 372 | describe('parent is body and is absolute and target is fixed', function () { 373 | var el, target, myStyle, targetStyle, fillerStyle, scrollAmount 374 | beforeEach(function () { 375 | scrollAmount = 100 376 | myStyle = { 377 | top: 140, 378 | left: 30, 379 | width: 20, 380 | height: 20, 381 | position: 'absolute', 382 | background: 'rgba(255, 0, 0, 0.5)' 383 | } 384 | targetStyle = { 385 | width: 40, 386 | height: 40, 387 | position: 'fixed', 388 | 'margin-left': '20px', 389 | 'margin-top': '200px', 390 | background: 'rgba(0, 255, 0, 0.5)' 391 | } 392 | fillerStyle = { 393 | width: 20, 394 | height: Math.min(1000000000, window.innerHeight * 100), 395 | position: 'relative', 396 | background: 'rgba(0,0,0,0.1)' 397 | } 398 | document.body.style.margin = '8px' 399 | el = create(myStyle) 400 | target = create(targetStyle) 401 | create(fillerStyle) 402 | window.scroll(0, scrollAmount) 403 | }) 404 | permute(function (myVertical, myHorizontal, theirVertical, theirHorizontal) { 405 | it([ 406 | 'should correctly position my', myVertical, myHorizontal, 407 | 'at their', theirVertical, theirHorizontal 408 | ].join(' '), function () { 409 | var left = parseInt(target.offsetLeft, 10) 410 | var top = parseInt(target.offsetTop, 10) + scrollAmount 411 | if (theirHorizontal === 'right') left += targetStyle.width 412 | if (theirHorizontal === 'center') left += targetStyle.width / 2 413 | if (theirVertical === 'bottom') top += targetStyle.height 414 | if (theirVertical === 'center') top += targetStyle.height / 2 415 | if (myHorizontal === 'right') left -= myStyle.width 416 | if (myHorizontal === 'center') left -= myStyle.width / 2 417 | if (myVertical === 'bottom') top -= myStyle.height 418 | if (myVertical === 'center') top -= myStyle.height / 2 419 | var position = positions( 420 | el, [myVertical, myHorizontal].join(' '), 421 | target, [theirVertical, theirHorizontal].join(' ') 422 | ) 423 | el.style.left = position.left + 'px' 424 | el.style.top = position.top + 'px' 425 | expect(position).to.eql({ top: top, left: left }) 426 | }) 427 | }) 428 | }) 429 | describe('parent is body and is fixed and target is relative', function () { 430 | var el, target, myStyle, targetStyle, fillerStyle, scrollAmount 431 | beforeEach(function () { 432 | myStyle = { 433 | top: 140, 434 | left: 30, 435 | width: 20, 436 | height: 20, 437 | position: 'fixed', 438 | background: 'rgba(255, 0, 0, 0.5)' 439 | } 440 | targetStyle = { 441 | width: 40, 442 | height: 40, 443 | position: 'relative', 444 | 'margin-left': '20px', 445 | 'margin-top': '200px', 446 | background: 'rgba(0, 255, 0, 0.5)' 447 | } 448 | fillerStyle = { 449 | width: 20, 450 | height: Math.min(1000000000, window.innerHeight * 100), 451 | position: 'relative', 452 | background: 'rgba(0,0,0,0.1)' 453 | } 454 | document.body.style.margin = '8px' 455 | el = create(myStyle) 456 | target = create(targetStyle) 457 | create(fillerStyle) 458 | scrollAmount = 100 459 | window.scroll(0, scrollAmount) 460 | }) 461 | permute(function (myVertical, myHorizontal, theirVertical, theirHorizontal) { 462 | it([ 463 | 'should correctly position my', myVertical, myHorizontal, 464 | 'at their', theirVertical, theirHorizontal 465 | ].join(' '), function () { 466 | var left = parseInt(target.offsetLeft, 10) 467 | var top = parseInt(target.offsetTop, 10) - scrollAmount 468 | if (theirHorizontal === 'right') left += targetStyle.width 469 | if (theirHorizontal === 'center') left += targetStyle.width / 2 470 | if (theirVertical === 'bottom') top += targetStyle.height 471 | if (theirVertical === 'center') top += targetStyle.height / 2 472 | if (myHorizontal === 'right') left -= myStyle.width 473 | if (myHorizontal === 'center') left -= myStyle.width / 2 474 | if (myVertical === 'bottom') top -= myStyle.height 475 | if (myVertical === 'center') top -= myStyle.height / 2 476 | var position = positions( 477 | el, [myVertical, myHorizontal].join(' '), 478 | target, [theirVertical, theirHorizontal].join(' ') 479 | ) 480 | el.style.left = position.left + 'px' 481 | el.style.top = position.top + 'px' 482 | expect(position).to.eql({ top: top, left: left }) 483 | }) 484 | }) 485 | }) 486 | describe('parent is body and is fixed and target is fixed', function () { 487 | var el, target, myStyle, targetStyle, fillerStyle, scrollAmount 488 | beforeEach(function () { 489 | scrollAmount = 100 490 | myStyle = { 491 | top: 140, 492 | left: 30, 493 | width: 20, 494 | height: 20, 495 | position: 'fixed', 496 | background: 'rgba(255, 0, 0, 0.5)' 497 | } 498 | targetStyle = { 499 | width: 40, 500 | height: 40, 501 | position: 'fixed', 502 | 'margin-left': '20px', 503 | 'margin-top': '200px', 504 | background: 'rgba(0, 255, 0, 0.5)' 505 | } 506 | fillerStyle = { 507 | width: 20, 508 | height: Math.min(1000000000, window.innerHeight * 100), 509 | position: 'relative', 510 | background: 'rgba(0,0,0,0.1)' 511 | } 512 | document.body.style.margin = '8px' 513 | el = create(myStyle) 514 | target = create(targetStyle) 515 | create(fillerStyle) 516 | window.scroll(0, scrollAmount) 517 | }) 518 | permute(function (myVertical, myHorizontal, theirVertical, theirHorizontal) { 519 | it([ 520 | 'should correctly position my', myVertical, myHorizontal, 521 | 'at their', theirVertical, theirHorizontal 522 | ].join(' '), function () { 523 | var left = parseInt(target.offsetLeft, 10) 524 | var top = parseInt(target.offsetTop, 10) 525 | if (theirHorizontal === 'right') left += targetStyle.width 526 | if (theirHorizontal === 'center') left += targetStyle.width / 2 527 | if (theirVertical === 'bottom') top += targetStyle.height 528 | if (theirVertical === 'center') top += targetStyle.height / 2 529 | if (myHorizontal === 'right') left -= myStyle.width 530 | if (myHorizontal === 'center') left -= myStyle.width / 2 531 | if (myVertical === 'bottom') top -= myStyle.height 532 | if (myVertical === 'center') top -= myStyle.height / 2 533 | var position = positions( 534 | el, [myVertical, myHorizontal].join(' '), 535 | target, [theirVertical, theirHorizontal].join(' ') 536 | ) 537 | el.style.left = position.left + 'px' 538 | el.style.top = position.top + 'px' 539 | expect(position).to.eql({ top: top, left: left }) 540 | }) 541 | }) 542 | }) 543 | describe('parent is body and is absolute and target is document', function () { 544 | var el, target, myStyle, fillerStyle, margin, scrollAmount, docSize 545 | beforeEach(function () { 546 | target = document 547 | scrollAmount = 100 548 | myStyle = { 549 | top: 140, 550 | left: 30, 551 | width: 20, 552 | height: 20, 553 | position: 'absolute', 554 | background: 'rgba(255, 0, 0, 0.5)' 555 | } 556 | fillerStyle = { 557 | width: 20, 558 | height: Math.min(1000000000, window.innerHeight * 100), 559 | position: 'relative', 560 | background: 'rgba(0,0,0,0.1)' 561 | } 562 | margin = 8 563 | document.body.style.border = '10px solid rgba(0,255,0,0.1)' 564 | document.body.style.margin = margin + 'px' 565 | el = create(myStyle) 566 | create(fillerStyle) 567 | docSize = size(target) 568 | window.scroll(0, scrollAmount) 569 | }) 570 | permute(function (myVertical, myHorizontal, theirVertical, theirHorizontal) { 571 | it([ 572 | 'should correctly position my', myVertical, myHorizontal, 573 | 'at their', theirVertical, theirHorizontal 574 | ].join(' '), function () { 575 | var left = 0 576 | var top = 0 577 | if (theirHorizontal === 'right') left += docSize.width 578 | if (theirHorizontal === 'center') left += docSize.width / 2 579 | if (theirVertical === 'bottom') top += docSize.height 580 | if (theirVertical === 'center') top += docSize.height / 2 581 | if (myHorizontal === 'right') left -= myStyle.width 582 | if (myHorizontal === 'center') left -= myStyle.width / 2 583 | if (myVertical === 'bottom') top -= myStyle.height 584 | if (myVertical === 'center') top -= myStyle.height / 2 585 | var position = positions( 586 | el, [myVertical, myHorizontal].join(' '), 587 | target, [theirVertical, theirHorizontal].join(' ') 588 | ) 589 | el.style.left = position.left + 'px' 590 | el.style.top = position.top + 'px' 591 | expect(position).to.eql({ top: top, left: left }) 592 | }) 593 | }) 594 | }) 595 | describe('parent is body and is absolute and target is body', function () { 596 | var el, target, myStyle, margin, fillerStyle, scrollAmount, bodySize 597 | beforeEach(function () { 598 | target = document.body 599 | scrollAmount = 100 600 | myStyle = { 601 | top: 140, 602 | left: 30, 603 | width: 20, 604 | height: 20, 605 | position: 'absolute', 606 | background: 'rgba(255, 0, 0, 0.5)' 607 | } 608 | fillerStyle = { 609 | width: 20, 610 | height: Math.min(1000000000, window.innerHeight * 100), 611 | position: 'relative', 612 | background: 'rgba(0,0,0,0.1)' 613 | } 614 | margin = 8 615 | document.body.style.margin = margin + 'px' 616 | document.body.style.border = '10px solid rgba(0,255,0,0.1)' 617 | el = create(myStyle) 618 | create(fillerStyle) 619 | window.scroll(0, scrollAmount) 620 | bodySize = size(target) 621 | }) 622 | permute(function (myVertical, myHorizontal, theirVertical, theirHorizontal) { 623 | it([ 624 | 'should correctly position my', myVertical, myHorizontal, 625 | 'at their', theirVertical, theirHorizontal 626 | ].join(' '), function () { 627 | var left = margin 628 | var top = margin 629 | if (theirHorizontal === 'right') left += bodySize.width 630 | if (theirHorizontal === 'center') left += bodySize.width / 2 631 | if (theirVertical === 'bottom') top += bodySize.height 632 | if (theirVertical === 'center') top += bodySize.height / 2 633 | if (myHorizontal === 'right') left -= myStyle.width 634 | if (myHorizontal === 'center') left -= myStyle.width / 2 635 | if (myVertical === 'bottom') top -= myStyle.height 636 | if (myVertical === 'center') top -= myStyle.height / 2 637 | var position = positions( 638 | el, [myVertical, myHorizontal].join(' '), 639 | target, [theirVertical, theirHorizontal].join(' ') 640 | ) 641 | el.style.left = position.left + 'px' 642 | el.style.top = position.top + 'px' 643 | expect(position).to.eql({ top: top, left: left }) 644 | }) 645 | }) 646 | }) 647 | describe('parent is body and is absolute and target is document', function () { 648 | var el, target, myStyle, fillerStyle, margin, scrollAmount, docSize 649 | beforeEach(function () { 650 | target = document 651 | scrollAmount = 100 652 | myStyle = { 653 | top: 140, 654 | left: 30, 655 | width: 20, 656 | height: 20, 657 | position: 'absolute', 658 | background: 'rgba(255, 0, 0, 0.5)' 659 | } 660 | fillerStyle = { 661 | width: 20, 662 | height: Math.min(1000000000, window.innerHeight * 100), 663 | position: 'relative', 664 | background: 'rgba(0,0,0,0.1)' 665 | } 666 | margin = 8 667 | document.body.style.border = '10px solid rgba(0,255,0,0.1)' 668 | document.body.style.margin = margin + 'px' 669 | el = create(myStyle) 670 | create(fillerStyle) 671 | window.scroll(0, scrollAmount) 672 | docSize = size(target) 673 | }) 674 | permute(function (myVertical, myHorizontal, theirVertical, theirHorizontal) { 675 | it([ 676 | 'should correctly position my', myVertical, myHorizontal, 677 | 'at their', theirVertical, theirHorizontal 678 | ].join(' '), function () { 679 | var left = 0 680 | var top = 0 681 | if (theirHorizontal === 'right') left += docSize.width 682 | if (theirHorizontal === 'center') left += docSize.width / 2 683 | if (theirVertical === 'bottom') top += docSize.height 684 | if (theirVertical === 'center') top += docSize.height / 2 685 | if (myHorizontal === 'right') left -= myStyle.width 686 | if (myHorizontal === 'center') left -= myStyle.width / 2 687 | if (myVertical === 'bottom') top -= myStyle.height 688 | if (myVertical === 'center') top -= myStyle.height / 2 689 | var position = positions( 690 | el, [myVertical, myHorizontal].join(' '), 691 | target, [theirVertical, theirHorizontal].join(' ') 692 | ) 693 | el.style.left = position.left + 'px' 694 | el.style.top = position.top + 'px' 695 | expect(position).to.eql({ top: top, left: left }) 696 | }) 697 | }) 698 | }) 699 | describe('parent is body and is fixed and target is window', function () { 700 | var el, target, myStyle, margin, fillerStyle, scrollAmount, windowSize 701 | beforeEach(function () { 702 | target = window 703 | scrollAmount = 100 704 | myStyle = { 705 | top: 140, 706 | left: 30, 707 | width: 20, 708 | height: 20, 709 | position: 'fixed', 710 | background: 'rgba(255, 0, 0, 0.5)' 711 | } 712 | fillerStyle = { 713 | width: 20, 714 | height: Math.min(1000000000, window.innerHeight * 100), 715 | position: 'relative', 716 | background: 'rgba(0,0,0,0.1)' 717 | } 718 | margin = 8 719 | document.body.style.margin = margin + 'px' 720 | document.body.style.border = '10px solid rgba(0,255,0,0.1)' 721 | el = create(myStyle) 722 | create(fillerStyle) 723 | window.scroll(0, scrollAmount) 724 | windowSize = size(window) 725 | }) 726 | permute(function (myVertical, myHorizontal, theirVertical, theirHorizontal) { 727 | it([ 728 | 'should correctly position my', myVertical, myHorizontal, 729 | 'at their', theirVertical, theirHorizontal 730 | ].join(' '), function () { 731 | var left = 0 732 | var top = 0 733 | if (theirHorizontal === 'right') left += windowSize.width 734 | if (theirHorizontal === 'center') left += windowSize.width / 2 735 | if (theirVertical === 'bottom') top += windowSize.height 736 | if (theirVertical === 'center') top += windowSize.height / 2 737 | if (myHorizontal === 'right') left -= myStyle.width 738 | if (myHorizontal === 'center') left -= myStyle.width / 2 739 | if (myVertical === 'bottom') top -= myStyle.height 740 | if (myVertical === 'center') top -= myStyle.height / 2 741 | var position = positions( 742 | el, [myVertical, myHorizontal].join(' '), 743 | target, [theirVertical, theirHorizontal].join(' ') 744 | ) 745 | el.style.left = position.left + 'px' 746 | el.style.top = position.top + 'px' 747 | expect(position).to.eql({ top: top, left: left }) 748 | }) 749 | }) 750 | }) 751 | describe('parent is body and is absolute and target is window', function () { 752 | var el, target, myStyle, margin, fillerStyle, scrollAmount, windowSize 753 | beforeEach(function () { 754 | target = window 755 | scrollAmount = 100 756 | myStyle = { 757 | top: 140, 758 | left: 30, 759 | width: 20, 760 | height: 20, 761 | position: 'absolute', 762 | background: 'rgba(255, 0, 0, 0.5)' 763 | } 764 | fillerStyle = { 765 | width: 20, 766 | height: Math.min(1000000000, window.innerHeight * 100), 767 | position: 'relative', 768 | background: 'rgba(0,0,0,0.1)' 769 | } 770 | margin = 8 771 | document.body.style.margin = margin + 'px' 772 | document.body.style.border = '10px solid rgba(0,255,0,0.1)' 773 | el = create(myStyle) 774 | create(fillerStyle) 775 | window.scroll(0, scrollAmount) 776 | windowSize = size(window) 777 | }) 778 | permute(function (myVertical, myHorizontal, theirVertical, theirHorizontal) { 779 | it([ 780 | 'should correctly position my', myVertical, myHorizontal, 781 | 'at their', theirVertical, theirHorizontal 782 | ].join(' '), function () { 783 | var left = 0 784 | var top = scrollAmount 785 | if (theirHorizontal === 'right') left += windowSize.width 786 | if (theirHorizontal === 'center') left += windowSize.width / 2 787 | if (theirVertical === 'bottom') top += windowSize.height 788 | if (theirVertical === 'center') top += windowSize.height / 2 789 | if (myHorizontal === 'right') left -= myStyle.width 790 | if (myHorizontal === 'center') left -= myStyle.width / 2 791 | if (myVertical === 'bottom') top -= myStyle.height 792 | if (myVertical === 'center') top -= myStyle.height / 2 793 | var position = positions( 794 | el, [myVertical, myHorizontal].join(' '), 795 | target, [theirVertical, theirHorizontal].join(' ') 796 | ) 797 | el.style.left = position.left + 'px' 798 | el.style.top = position.top + 'px' 799 | expect(position).to.eql({ top: top, left: left }) 800 | }) 801 | }) 802 | }) 803 | }) 804 | -------------------------------------------------------------------------------- /test/test-wrong-order.js: -------------------------------------------------------------------------------- 1 | /* globals describe beforeEach afterEach it */ 2 | var positions = require('../lib/positions') 3 | var expect = require('chai').expect 4 | var create = require('./lib/create') 5 | var permute = require('./lib/permute') 6 | 7 | describe('position fixed', function () { 8 | var myStyle = { 9 | top: 40, 10 | left: 30, 11 | width: 200, 12 | height: 100, 13 | position: 'fixed', 14 | background: 'blue' 15 | } 16 | var targetStyle = { 17 | top: 10, 18 | left: 20, 19 | width: 300, 20 | height: 400, 21 | position: 'fixed', 22 | background: 'red' 23 | } 24 | var el, target 25 | beforeEach(function () { 26 | el = create(myStyle) 27 | target = create(targetStyle) 28 | }) 29 | afterEach(function () { 30 | document.body.innerHTML = '' 31 | }) 32 | permute(function (myVertical, myHorizontal, theirVertical, theirHorizontal) { 33 | it([ 34 | 'should correctly position my', myHorizontal, myVertical, 35 | 'at their', theirHorizontal, theirVertical 36 | ].join(' '), function () { 37 | var left = targetStyle.left 38 | var top = targetStyle.top 39 | if (theirHorizontal === 'right') left += targetStyle.width 40 | if (theirHorizontal === 'center') left += targetStyle.width / 2 41 | if (theirVertical === 'bottom') top += targetStyle.height 42 | if (theirVertical === 'center') top += targetStyle.height / 2 43 | if (myHorizontal === 'right') left -= myStyle.width 44 | if (myHorizontal === 'center') left -= myStyle.width / 2 45 | if (myVertical === 'bottom') top -= myStyle.height 46 | if (myVertical === 'center') top -= myStyle.height / 2 47 | var position = positions( 48 | el, [myHorizontal, myVertical].join(' '), 49 | target, [theirHorizontal, theirVertical].join(' ') 50 | ) 51 | el.style.left = position.left + 'px' 52 | el.style.top = position.top + 'px' 53 | expect(position).to.eql({ top: top, left: left }) 54 | }) 55 | }) 56 | }) 57 | --------------------------------------------------------------------------------