diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..12760983 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,6 @@ +## v1.0.0 +- Coffeescript -> ES6 +- Proper UMD Wrapper +- Update build steps +- Add changelog +- Provide minified CSS diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..8e4b9c54 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,59 @@ +# Contributing Guide + +You will need: + +- Node.js/io.js & npm +- Bower +- Gulp + + +## Getting started + +1. Fork the project +2. Clone your forked project by running `git clone git@github.com:{ + YOUR_USERNAME }/tether.git` +3. Run `npm install` to install both node modules and bower components +4. Test that you can build the source by moving/renaming the existing `dist` + directory and running `npm run build` +5. Assuming everything went well, you should now have a `dist` directory that + matches the one you moved in step 4 + + +## Writing code! + +We use `gulp` to facilitate things like transpilation, minification, etc. so +can you focus on writing relevant code. If there is a fix or feature you would like +to contribute, we ask that you take the following steps: + +1. Most of the _editable_ code lives in the `src` directory while built code + will end up in the `dist` directory upon running `npm run build`. + +2. Depending on how big your changes are, bump the version numbers appropriately + in `bower.json` and `package.json`. We try to follow semver, so a good rule + of thumb for how to bump the version is: + - A fix to existing code, perform a patch bump e.g. x.x.0 -> x.x.1 + - New feature, perform a minor bump e.g. x.0.x -> x.1.x + - Breaking changes such a rewrite, perform a major bump e.g. + 1.x.x -> 2.x.x + + Versioning is hard, so just use good judgement and we'll be more than happy + to help out. + + __NOTE__: There is a `gulp` task that will automate some of the versioning. + You can run `gulp version:{type}` where type is `patch|minor|major` to + update both `bower.json` and `package.json` as well as add the appropriate + git tag. + +3. Provide a thoughtful commit message and push your changes to your fork using + `git push origin master` (assuming your forked project is using `origin` for + the remote name and you are on the `master` branch). + +4. Open a Pull Request on GitHub with a description of your changes. + + +## Testing + +Work in progress. We are hoping to add some tests, so if you would like to help +us get started, feel free to contact us through the Issues or open a Pull +Request. + diff --git a/README.md b/README.md index 3a92b877..2c51f3e1 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,29 @@ It aims to be the canonical implementation of this type of positioning, such tha Take a look at the documentation for a more detailed explanation of why you should star it now to remember it for your next project. +## Install + +__npm__ +```sh +$ npm install tether +``` + +__bower__ +```sh +$ bower install tether +``` + +## Usage + [![Tether Docs](http://i.imgur.com/YCx8cLr.png)](http://github.hubspot.com/tether/#usage) -### [Demo & Documentation](http://github.hubspot.com/tether/) +[Demo & API Documentation](http://github.hubspot.com/tether/) + + +## Contributing + +We encourage contributions of all kinds. If you would like to contribute in some way, please review our [guidelines for contributing](CONTRIBUTING.md). + + +## License +Copyright © 2015 HubSpot - [MIT License](LICENSE) diff --git a/bower.json b/bower.json index e4a36e68..2fbcdfb6 100644 --- a/bower.json +++ b/bower.json @@ -1,17 +1,20 @@ { "name": "tether", - "version": "0.7.2", - "main": "tether.js", + "version": "1.0.0", "homepage": "https://github.hubspot.com/tether", "authors": [ "Zack Bloom ", "Adam Schwartz " ], + "maintainers": [ + "Nicholas Hwang " + ], "description": "A client-side library to make absolutely positioned elements attach to elements in the page efficiently.", "keywords": [ "javascript" ], "license": "MIT", + "main": "dist/js/tether.js", "ignore": [ "**/.*", "node_modules", diff --git a/coffee/abutment.coffee b/coffee/abutment.coffee deleted file mode 100644 index 59c785fa..00000000 --- a/coffee/abutment.coffee +++ /dev/null @@ -1,41 +0,0 @@ -{getBounds, updateClasses, defer} = @Tether.Utils - -@Tether.modules.push - position: ({top, left}) -> - {height, width} = @cache 'element-bounds', => getBounds @element - - targetPos = @getTargetBounds() - - bottom = top + height - right = left + width - - abutted = [] - if top <= targetPos.bottom and bottom >= targetPos.top - for side in ['left', 'right'] - if targetPos[side] in [left, right] - abutted.push side - - if left <= targetPos.right and right >= targetPos.left - for side in ['top', 'bottom'] - if targetPos[side] in [top, bottom] - abutted.push side - - allClasses = [] - addClasses = [] - - sides = ['left', 'top', 'right', 'bottom'] - allClasses.push @getClass('abutted') - for side in sides - allClasses.push "#{ @getClass('abutted') }-#{ side }" - - if abutted.length - addClasses.push @getClass('abutted') - for side in abutted - addClasses.push "#{ @getClass('abutted') }-#{ side }" - - defer => - unless @options.addTargetClasses is false - updateClasses @target, addClasses, allClasses - updateClasses @element, addClasses, allClasses - - true diff --git a/coffee/constraint.coffee b/coffee/constraint.coffee deleted file mode 100644 index 496b187a..00000000 --- a/coffee/constraint.coffee +++ /dev/null @@ -1,261 +0,0 @@ -{getOuterSize, getBounds, getSize, extend, updateClasses, defer} = @Tether.Utils - -MIRROR_ATTACH = - left: 'right' - right: 'left' - top: 'bottom' - bottom: 'top' - middle: 'middle' - -BOUNDS_FORMAT = ['left', 'top', 'right', 'bottom'] - -getBoundingRect = (tether, to) -> - if to is 'scrollParent' - to = tether.scrollParent - else if to is 'window' - to = [pageXOffset, pageYOffset, innerWidth + pageXOffset, innerHeight + pageYOffset] - - if to is document - to = to.documentElement - - if to.nodeType? - pos = size = getBounds to - style = getComputedStyle to - - to = [pos.left, pos.top, size.width + pos.left, size.height + pos.top] - - for side, i in BOUNDS_FORMAT - side = side[0].toUpperCase() + side.substr(1) - if side in ['Top', 'Left'] - to[i] += parseFloat style["border#{ side }Width"] - else - to[i] -= parseFloat style["border#{ side }Width"] - - to - -@Tether.modules.push - position: ({top, left, targetAttachment}) -> - return true unless @options.constraints - - removeClass = (prefix) => - @removeClass prefix - for side in BOUNDS_FORMAT - @removeClass "#{ prefix }-#{ side }" - - {height, width} = @cache 'element-bounds', => getBounds @element - - if width is 0 and height is 0 and @lastSize? - # Handle the item getting hidden as a result of our positioning without glitching - # the classes in and out - {width, height} = @lastSize - - targetSize = @cache 'target-bounds', => @getTargetBounds() - targetHeight = targetSize.height - targetWidth = targetSize.width - - tAttachment = {} - eAttachment = {} - - allClasses = [@getClass('pinned'), @getClass('out-of-bounds')] - for constraint in @options.constraints - allClasses.push(constraint.outOfBoundsClass) if constraint.outOfBoundsClass - allClasses.push(constraint.pinnedClass) if constraint.pinnedClass - - for cls in allClasses - for side in ['left', 'top', 'right', 'bottom'] - allClasses.push "#{ cls }-#{ side }" - - addClasses = [] - - tAttachment = extend {}, targetAttachment - eAttachment = extend {}, @attachment - - for constraint in @options.constraints - {to, attachment, pin} = constraint - - attachment ?= '' - - if ' ' in attachment - [changeAttachY, changeAttachX] = attachment.split(' ') - else - changeAttachX = changeAttachY = attachment - - bounds = getBoundingRect @, to - - if changeAttachY in ['target', 'both'] - if (top < bounds[1] and tAttachment.top is 'top') - top += targetHeight - tAttachment.top = 'bottom' - - if (top + height > bounds[3] and tAttachment.top is 'bottom') - top -= targetHeight - tAttachment.top = 'top' - - if changeAttachY is 'together' - if top < bounds[1] and tAttachment.top is 'top' - if eAttachment.top is 'bottom' - top += targetHeight - tAttachment.top = 'bottom' - - top += height - eAttachment.top = 'top' - else if eAttachment.top is 'top' - top += targetHeight - tAttachment.top = 'bottom' - - top -= height - eAttachment.top = 'bottom' - - if top + height > bounds[3] and tAttachment.top is 'bottom' - if eAttachment.top is 'top' - top -= targetHeight - tAttachment.top = 'top' - - top -= height - eAttachment.top = 'bottom' - else if eAttachment.top is 'bottom' - top -= targetHeight - tAttachment.top = 'top' - - top += height - eAttachment.top = 'top' - - if tAttachment.top is 'middle' - if top + height > bounds[3] and eAttachment.top is 'top' - top -= height - eAttachment.top = 'bottom' - - else if top < bounds[1] and eAttachment.top is 'bottom' - top += height - eAttachment.top = 'top' - - if changeAttachX in ['target', 'both'] - if (left < bounds[0] and tAttachment.left is 'left') - left += targetWidth - tAttachment.left = 'right' - - if (left + width > bounds[2] and tAttachment.left is 'right') - left -= targetWidth - tAttachment.left = 'left' - - if changeAttachX is 'together' - if left < bounds[0] and tAttachment.left is 'left' - if eAttachment.left is 'right' - left += targetWidth - tAttachment.left = 'right' - - left += width - eAttachment.left = 'left' - - else if eAttachment.left is 'left' - left += targetWidth - tAttachment.left = 'right' - - left -= width - eAttachment.left = 'right' - - else if left + width > bounds[2] and tAttachment.left is 'right' - if eAttachment.left is 'left' - left -= targetWidth - tAttachment.left = 'left' - - left -= width - eAttachment.left = 'right' - - else if eAttachment.left is 'right' - left -= targetWidth - tAttachment.left = 'left' - - left += width - eAttachment.left = 'left' - - else if tAttachment.left is 'center' - if left + width > bounds[2] and eAttachment.left is 'left' - left -= width - eAttachment.left = 'right' - - else if left < bounds[0] and eAttachment.left is 'right' - left += width - eAttachment.left = 'left' - - if changeAttachY in ['element', 'both'] - if (top < bounds[1] and eAttachment.top is 'bottom') - top += height - eAttachment.top = 'top' - - if (top + height > bounds[3] and eAttachment.top is 'top') - top -= height - eAttachment.top = 'bottom' - - if changeAttachX in ['element', 'both'] - if (left < bounds[0] and eAttachment.left is 'right') - left += width - eAttachment.left = 'left' - - if (left + width > bounds[2] and eAttachment.left is 'left') - left -= width - eAttachment.left = 'right' - - if typeof pin is 'string' - pin = (p.trim() for p in pin.split ',') - else if pin is true - pin = ['top', 'left', 'right', 'bottom'] - - pin or= [] - - pinned = [] - oob = [] - if top < bounds[1] - if 'top' in pin - top = bounds[1] - pinned.push 'top' - else - oob.push 'top' - - if top + height > bounds[3] - if 'bottom' in pin - top = bounds[3] - height - pinned.push 'bottom' - else - oob.push 'bottom' - - if left < bounds[0] - if 'left' in pin - left = bounds[0] - pinned.push 'left' - else - oob.push 'left' - - if left + width > bounds[2] - if 'right' in pin - left = bounds[2] - width - pinned.push 'right' - else - oob.push 'right' - - if pinned.length - pinnedClass = @options.pinnedClass ? @getClass('pinned') - addClasses.push pinnedClass - for side in pinned - addClasses.push "#{ pinnedClass }-#{ side }" - - if oob.length - oobClass = @options.outOfBoundsClass ? @getClass('out-of-bounds') - addClasses.push oobClass - for side in oob - addClasses.push "#{ oobClass }-#{ side }" - - if 'left' in pinned or 'right' in pinned - eAttachment.left = tAttachment.left = false - if 'top' in pinned or 'bottom' in pinned - eAttachment.top = tAttachment.top = false - - if tAttachment.top isnt targetAttachment.top or tAttachment.left isnt targetAttachment.left or eAttachment.top isnt @attachment.top or eAttachment.left isnt @attachment.left - @updateAttachClasses eAttachment, tAttachment - - defer => - unless @options.addTargetClasses is false - updateClasses @target, addClasses, allClasses - updateClasses @element, addClasses, allClasses - - {top, left} diff --git a/coffee/markAttachment.coffee b/coffee/markAttachment.coffee deleted file mode 100644 index b29c9efa..00000000 --- a/coffee/markAttachment.coffee +++ /dev/null @@ -1,30 +0,0 @@ -@Tether.modules.push - initialize: -> - @markers = {} - - for type in ['target', 'element'] - el = document.createElement 'div' - el.className = @getClass("#{ type }-marker") - - dot = document.createElement 'div' - dot.className = @getClass('marker-dot') - el.appendChild dot - - @[type].appendChild el - - @markers[type] = {dot, el} - - position: ({manualOffset, manualTargetOffset}) -> - offsets = - element: manualOffset - target: manualTargetOffset - - for type, offset of offsets - for side, val of offset - if typeof val isnt 'string' or (val.indexOf('%') is -1 and val.indexOf('px') is -1) - val += 'px' - - if @markers[type].dot.style[side] isnt val - @markers[type].dot.style[side] = val - - true diff --git a/coffee/shift.coffee b/coffee/shift.coffee deleted file mode 100644 index 4dede411..00000000 --- a/coffee/shift.coffee +++ /dev/null @@ -1,27 +0,0 @@ -@Tether.modules.push - position: ({top, left}) -> - return unless @options.shift - - result = (val) -> - if typeof val is 'function' - val.call @, {top, left} - else - val - - shift = result @options.shift - - if typeof shift is 'string' - shift = shift.split(' ') - shift[1] or= shift[0] - - [shiftTop, shiftLeft] = shift - - shiftTop = parseFloat shiftTop, 10 - shiftLeft = parseFloat shiftLeft, 10 - else - [shiftTop, shiftLeft] = [shift.top, shift.left] - - top += shiftTop - left += shiftLeft - - {top, left} diff --git a/coffee/tether.coffee b/coffee/tether.coffee deleted file mode 100644 index 33ffd0da..00000000 --- a/coffee/tether.coffee +++ /dev/null @@ -1,576 +0,0 @@ -if not @Tether? - throw new Error "You must include the utils.js file before tether.js" - -Tether = @Tether - -{getScrollParent, getSize, getOuterSize, getBounds, getOffsetParent, extend, addClass, removeClass, updateClasses, defer, flush, getScrollBarSize} = Tether.Utils - -within = (a, b, diff=1) -> - a + diff >= b >= a - diff - -transformKey = do -> - el = document.createElement 'div' - - for key in ['transform', 'webkitTransform', 'OTransform', 'MozTransform', 'msTransform'] - if el.style[key] isnt undefined - return key - -tethers = [] - -position = -> - for tether in tethers - tether.position(false) - - flush() - -now = -> - performance?.now?() ? +new Date - -do -> - lastCall = null - lastDuration = null - pendingTimeout = null - - tick = -> - if lastDuration? and lastDuration > 16 - # We voluntarily throttle ourselves if we can't manage 60fps - lastDuration = Math.min(lastDuration - 16, 250) - - # Just in case this is the last event, remember to position just once more - pendingTimeout = setTimeout tick, 250 - return - - if lastCall? and (now() - lastCall) < 10 - # Some browsers call events a little too frequently, refuse to run more than is reasonable - return - - if pendingTimeout? - clearTimeout pendingTimeout - pendingTimeout = null - - lastCall = now() - - position() - - lastDuration = now() - lastCall - - for event in ['resize', 'scroll', 'touchmove'] - window.addEventListener event, tick - -MIRROR_LR = - center: 'center' - left: 'right' - right: 'left' - -MIRROR_TB = - middle: 'middle' - top: 'bottom' - bottom: 'top' - -OFFSET_MAP = - top: 0 - left: 0 - middle: '50%' - center: '50%' - bottom: '100%' - right: '100%' - -autoToFixedAttachment = (attachment, relativeToAttachment) -> - {left, top} = attachment - - if left is 'auto' - left = MIRROR_LR[relativeToAttachment.left] - - if top is 'auto' - top = MIRROR_TB[relativeToAttachment.top] - - {left, top} - -attachmentToOffset = (attachment) -> - return { - left: OFFSET_MAP[attachment.left] ? attachment.left - top: OFFSET_MAP[attachment.top] ? attachment.top - } - -addOffset = (offsets...) -> - out = {top: 0, left: 0} - - for {top, left} in offsets - if typeof top is 'string' - top = parseFloat(top, 10) - if typeof left is 'string' - left = parseFloat(left, 10) - - out.top += top - out.left += left - - out - -offsetToPx = (offset, size) -> - if typeof offset.left is 'string' and offset.left.indexOf('%') isnt -1 - offset.left = parseFloat(offset.left, 10) / 100 * size.width - if typeof offset.top is 'string' and offset.top.indexOf('%') isnt -1 - offset.top = parseFloat(offset.top, 10) / 100 * size.height - - offset - -parseAttachment = parseOffset = (value) -> - [top, left] = value.split(' ') - - {top, left} - -class _Tether - @modules: [] - - constructor: (options) -> - tethers.push @ - - @history = [] - - @setOptions options, false - - for module in Tether.modules - module.initialize?.call(@) - - @position() - - getClass: (key) -> - if @options.classes?[key] - @options.classes[key] - else if @options.classes?[key] isnt false - if @options.classPrefix - "#{ @options.classPrefix }-#{ key }" - else - key - else - '' - - setOptions: (@options, position=true) -> - defaults = - offset: '0 0' - targetOffset: '0 0' - targetAttachment: 'auto auto' - classPrefix: 'tether' - - @options = extend defaults, @options - - {@element, @target, @targetModifier} = @options - - if @target is 'viewport' - @target = document.body - @targetModifier = 'visible' - else if @target is 'scroll-handle' - @target = document.body - @targetModifier = 'scroll-handle' - - for key in ['element', 'target'] - if not @[key]? - throw new Error "Tether Error: Both element and target must be defined" - - if @[key].jquery? - @[key] = @[key][0] - else if typeof @[key] is 'string' - @[key] = document.querySelector @[key] - - addClass @element, @getClass 'element' - unless @options.addTargetClasses is false - addClass @target, @getClass 'target' - - if not @options.attachment - throw new Error "Tether Error: You must provide an attachment" - - @targetAttachment = parseAttachment @options.targetAttachment - @attachment = parseAttachment @options.attachment - @offset = parseOffset @options.offset - @targetOffset = parseOffset @options.targetOffset - - if @scrollParent? - @disable() - - if @targetModifier is 'scroll-handle' - @scrollParent = @target - else - @scrollParent = getScrollParent @target - - unless @options.enabled is false - @enable(position) - - getTargetBounds: -> - if @targetModifier? - switch @targetModifier - when 'visible' - if @target is document.body - {top: pageYOffset, left: pageXOffset, height: innerHeight, width: innerWidth} - else - bounds = getBounds @target - - out = - height: bounds.height - width: bounds.width - top: bounds.top - left: bounds.left - - out.height = Math.min(out.height, bounds.height - (pageYOffset - bounds.top)) - out.height = Math.min(out.height, bounds.height - ((bounds.top + bounds.height) - (pageYOffset + innerHeight))) - out.height = Math.min(innerHeight, out.height) - out.height -= 2 - - out.width = Math.min(out.width, bounds.width - (pageXOffset - bounds.left)) - out.width = Math.min(out.width, bounds.width - ((bounds.left + bounds.width) - (pageXOffset + innerWidth))) - out.width = Math.min(innerWidth, out.width) - out.width -= 2 - - if out.top < pageYOffset - out.top = pageYOffset - if out.left < pageXOffset - out.left = pageXOffset - - out - - when 'scroll-handle' - target = @target - if target is document.body - target = document.documentElement - - bounds = - left: pageXOffset - top: pageYOffset - height: innerHeight - width: innerWidth - else - bounds = getBounds target - - style = getComputedStyle target - - hasBottomScroll = target.scrollWidth > target.clientWidth or 'scroll' is [style.overflow, style.overflowX] or @target isnt document.body - - scrollBottom = 0 - if hasBottomScroll - scrollBottom = 15 - - height = bounds.height - parseFloat(style.borderTopWidth) - parseFloat(style.borderBottomWidth) - scrollBottom - - out = - width: 15 - height: height * 0.975 * (height / target.scrollHeight) - left: bounds.left + bounds.width - parseFloat(style.borderLeftWidth) - 15 - - fitAdj = 0 - if height < 408 and @target is document.body - fitAdj = -0.00011 * Math.pow(height, 2) - 0.00727 * height + 22.58 - - if @target isnt document.body - out.height = Math.max out.height, 24 - - scrollPercentage = @target.scrollTop / (target.scrollHeight - height) - out.top = scrollPercentage * (height - out.height - fitAdj) + bounds.top + parseFloat(style.borderTopWidth) - - if @target is document.body - out.height = Math.max out.height, 24 - - out - else - getBounds @target - - clearCache: -> - @_cache = {} - - cache: (k, getter) -> - # More than one module will often need the same DOM info, so - # we keep a cache which is cleared on each position call - @_cache ?= {} - - if not @_cache[k]? - @_cache[k] = getter.call(@) - - @_cache[k] - - enable: (position=true) -> - unless @options.addTargetClasses is false - addClass @target, @getClass 'enabled' - addClass @element, @getClass 'enabled' - @enabled = true - - if @scrollParent isnt document - @scrollParent.addEventListener 'scroll', @position - - if position - @position() - - disable: -> - removeClass @target, @getClass 'enabled' - removeClass @element, @getClass 'enabled' - @enabled = false - - if @scrollParent? - @scrollParent.removeEventListener 'scroll', @position - - destroy: -> - @disable() - - for tether, i in tethers - if tether is @ - tethers.splice i, 1 - break - - updateAttachClasses: (elementAttach=@attachment, targetAttach=@targetAttachment) -> - sides = ['left', 'top', 'bottom', 'right', 'middle', 'center'] - - if @_addAttachClasses?.length - # updateAttachClasses can be called more than once in a position call, so - # we need to clean up after ourselves such that when the last defer gets - # ran it doesn't add any extra classes from previous calls. - @_addAttachClasses.splice 0, @_addAttachClasses.length - - add = @_addAttachClasses ?= [] - add.push "#{ @getClass('element-attached') }-#{ elementAttach.top }" if elementAttach.top - add.push "#{ @getClass('element-attached') }-#{ elementAttach.left }" if elementAttach.left - add.push "#{ @getClass('target-attached') }-#{ targetAttach.top }" if targetAttach.top - add.push "#{ @getClass('target-attached') }-#{ targetAttach.left }" if targetAttach.left - - all = [] - all.push "#{ @getClass('element-attached') }-#{ side }" for side in sides - all.push "#{ @getClass('target-attached') }-#{ side }" for side in sides - - defer => - return unless @_addAttachClasses? - - updateClasses @element, @_addAttachClasses, all - unless @options.addTargetClasses is false - updateClasses @target, @_addAttachClasses, all - - @_addAttachClasses = undefined - - position: (flushChanges=true) => - # flushChanges commits the changes immediately, leave true unless you are positioning multiple - # tethers (in which case call Tether.Utils.flush yourself when you're done) - - return unless @enabled - - @clearCache() - - # Turn 'auto' attachments into the appropriate corner or edge - targetAttachment = autoToFixedAttachment(@targetAttachment, @attachment) - - @updateAttachClasses @attachment, targetAttachment - - elementPos = @cache 'element-bounds', => getBounds @element - {width, height} = elementPos - - if width is 0 and height is 0 and @lastSize? - # We cache the height and width to make it possible to position elements that are - # getting hidden. - {width, height} = @lastSize - else - @lastSize = {width, height} - - targetSize = targetPos = @cache 'target-bounds', => @getTargetBounds() - - # Get an actual px offset from the attachment - offset = offsetToPx attachmentToOffset(@attachment), {width, height} - targetOffset = offsetToPx attachmentToOffset(targetAttachment), targetSize - - manualOffset = offsetToPx(@offset, {width, height}) - manualTargetOffset = offsetToPx(@targetOffset, targetSize) - - # Add the manually provided offset - offset = addOffset offset, manualOffset - targetOffset = addOffset targetOffset, manualTargetOffset - - # It's now our goal to make (element position + offset) == (target position + target offset) - left = targetPos.left + targetOffset.left - offset.left - top = targetPos.top + targetOffset.top - offset.top - - for module in Tether.modules - ret = module.position.call(@, {left, top, targetAttachment, targetPos, @attachment, elementPos, offset, targetOffset, manualOffset, manualTargetOffset, scrollbarSize}) - - if ret is false - return false - else if not ret? or typeof ret isnt 'object' - continue - else - {top, left} = ret - - # We describe the position three different ways to give the optimizer - # a chance to decide the best possible way to position the element - # with the fewest repaints. - next = { - # It's position relative to the page (absolute positioning when - # the element is a child of the body) - page: - top: top - left: left - - # It's position relative to the viewport (fixed positioning) - viewport: - top: top - pageYOffset - bottom: pageYOffset - top - height + innerHeight - left: left - pageXOffset - right: pageXOffset - left - width + innerWidth - } - - if document.body.scrollWidth > window.innerWidth - scrollbarSize = @cache 'scrollbar-size', getScrollBarSize - next.viewport.bottom -= scrollbarSize.height - - if document.body.scrollHeight > window.innerHeight - scrollbarSize = @cache 'scrollbar-size', getScrollBarSize - next.viewport.right -= scrollbarSize.width - - if document.body.style.position not in ['', 'static'] or document.body.parentElement.style.position not in ['', 'static'] - # Absolute positioning in the body will be relative to the page, not the 'initial containing block' - next.page.bottom = document.body.scrollHeight - top - height - next.page.right = document.body.scrollWidth - left - width - - if @options.optimizations?.moveElement isnt false and not @targetModifier? - offsetParent = @cache 'target-offsetparent', => getOffsetParent @target - offsetPosition = @cache 'target-offsetparent-bounds', -> getBounds offsetParent - offsetParentStyle = getComputedStyle offsetParent - elementStyle = getComputedStyle @element - offsetParentSize = offsetPosition - - offsetBorder = {} - for side in ['Top', 'Left', 'Bottom', 'Right'] - offsetBorder[side.toLowerCase()] = parseFloat offsetParentStyle["border#{ side }Width"] - - offsetPosition.right = document.body.scrollWidth - offsetPosition.left - offsetParentSize.width + offsetBorder.right - offsetPosition.bottom = document.body.scrollHeight - offsetPosition.top - offsetParentSize.height + offsetBorder.bottom - - if next.page.top >= (offsetPosition.top + offsetBorder.top) and next.page.bottom >= offsetPosition.bottom - if next.page.left >= (offsetPosition.left + offsetBorder.left) and next.page.right >= offsetPosition.right - # We're within the visible part of the target's scroll parent - - scrollTop = offsetParent.scrollTop - scrollLeft = offsetParent.scrollLeft - - # It's position relative to the target's offset parent (absolute positioning when - # the element is moved to be a child of the target's offset parent). - next.offset = - top: next.page.top - offsetPosition.top + scrollTop - offsetBorder.top - left: next.page.left - offsetPosition.left + scrollLeft - offsetBorder.left - - - # We could also travel up the DOM and try each containing context, rather than only - # looking at the body, but we're gonna get diminishing returns. - - @move next - - @history.unshift next - - if @history.length > 3 - @history.pop() - - if flushChanges - flush() - - true - - move: (position) -> - return if not @element.parentNode? - - same = {} - - for type of position - same[type] = {} - - for key of position[type] - found = false - - for point in @history - unless within(point[type]?[key], position[type][key]) - found = true - break - - if not found - same[type][key] = true - - css = {top: '', left: '', right: '', bottom: ''} - - transcribe = (same, pos) => - if @options.optimizations?.gpu isnt false - if same.top - css.top = 0 - yPos = pos.top - else - css.bottom = 0 - yPos = -pos.bottom - - if same.left - css.left = 0 - xPos = pos.left - else - css.right = 0 - xPos = -pos.right - - - css[transformKey] = "translateX(#{ Math.round xPos }px) translateY(#{ Math.round yPos }px)" - - if transformKey isnt 'msTransform' - # The Z transform will keep this in the GPU (faster, and prevents artifacts), - # but IE9 doesn't support 3d transforms and will choke. - css[transformKey] += " translateZ(0)" - - else - if same.top - css.top = "#{ pos.top }px" - else - css.bottom = "#{ pos.bottom }px" - - if same.left - css.left = "#{ pos.left }px" - else - css.right = "#{ pos.right }px" - - moved = false - if (same.page.top or same.page.bottom) and (same.page.left or same.page.right) - css.position = 'absolute' - transcribe same.page, position.page - - else if (same.viewport.top or same.viewport.bottom) and (same.viewport.left or same.viewport.right) - css.position = 'fixed' - - transcribe same.viewport, position.viewport - - else if same.offset? and same.offset.top and same.offset.left - css.position = 'absolute' - - offsetParent = @cache 'target-offsetparent', => getOffsetParent @target - - if getOffsetParent(@element) isnt offsetParent - defer => - @element.parentNode.removeChild @element - offsetParent.appendChild @element - - transcribe same.offset, position.offset - - moved = true - - else - css.position = 'absolute' - transcribe {top: true, left: true}, position.page - - if not moved and @element.parentNode.tagName isnt 'BODY' - @element.parentNode.removeChild @element - document.body.appendChild @element - - # Any css change will trigger a repaint, so let's avoid one if nothing changed - writeCSS = {} - write = false - for key, val of css - elVal = @element.style[key] - - if elVal isnt '' and val isnt '' and key in ['top', 'left', 'bottom', 'right'] - elVal = parseFloat elVal - val = parseFloat val - - if elVal isnt val - write = true - writeCSS[key] = css[key] - - if write - defer => - extend @element.style, writeCSS - -Tether.position = position - -@Tether = extend _Tether, Tether diff --git a/coffee/utils.coffee b/coffee/utils.coffee deleted file mode 100644 index 9d391759..00000000 --- a/coffee/utils.coffee +++ /dev/null @@ -1,223 +0,0 @@ -@Tether ?= {modules: []} - -getScrollParent = (el) -> - position = getComputedStyle(el).position - - if position is 'fixed' - return el - - scrollParent = undefined - - parent = el - while parent = parent.parentNode - try - style = getComputedStyle parent - - return parent if not style? - - if /(auto|scroll)/.test(style['overflow'] + style['overflowY'] + style['overflowX']) - if position isnt 'absolute' or style['position'] in ['relative', 'absolute', 'fixed'] - return parent - - return document.body - -uniqueId = do -> - id = 0 - -> - id++ - -zeroPosCache = {} -getOrigin = (doc) -> - # getBoundingClientRect is unfortunately too accurate. It introduces a pixel or two of - # jitter as the user scrolls that messes with our ability to detect if two positions - # are equivilant or not. We place an element at the top left of the page that will - # get the same jitter, so we can cancel the two out. - node = doc._tetherZeroElement - if not node? - node = doc.createElement 'div' - node.setAttribute 'data-tether-id', uniqueId() - extend node.style, - top: 0 - left: 0 - position: 'absolute' - - doc.body.appendChild node - - doc._tetherZeroElement = node - - id = node.getAttribute 'data-tether-id' - if not zeroPosCache[id]? - zeroPosCache[id] = {} - for k, v of node.getBoundingClientRect() - # Can't use extend, as on IE9, elements don't resolve to be hasOwnProperty - zeroPosCache[id][k] = v - - # Clear the cache when this position call is done - defer -> - zeroPosCache[id] = undefined - - return zeroPosCache[id] - -node = null -getBounds = (el) -> - if el is document - doc = document - el = document.documentElement - else - doc = el.ownerDocument - - docEl = doc.documentElement - - box = {} - # The original object returned by getBoundingClientRect is immutable, so we clone it - # We can't use extend because the properties are not considered part of the object by hasOwnProperty in IE9 - for k, v of el.getBoundingClientRect() - box[k] = v - - origin = getOrigin doc - - box.top -= origin.top - box.left -= origin.left - - box.width ?= document.body.scrollWidth - box.left - box.right - box.height ?= document.body.scrollHeight - box.top - box.bottom - - box.top = box.top - docEl.clientTop - box.left = box.left - docEl.clientLeft - box.right = doc.body.clientWidth - box.width - box.left - box.bottom = doc.body.clientHeight - box.height - box.top - - box - -getOffsetParent = (el) -> - el.offsetParent or document.documentElement - -getScrollBarSize = -> - inner = document.createElement 'div' - inner.style.width = '100%' - inner.style.height = '200px' - - outer = document.createElement 'div' - extend outer.style, - position: 'absolute' - top: 0 - left: 0 - pointerEvents: 'none' - visibility: 'hidden' - width: '200px' - height: '150px' - overflow: 'hidden' - - outer.appendChild inner - - document.body.appendChild outer - - widthContained = inner.offsetWidth - outer.style.overflow = 'scroll' - widthScroll = inner.offsetWidth - - if widthContained is widthScroll - widthScroll = outer.clientWidth - - document.body.removeChild outer - - width = widthContained - widthScroll - - {width, height: width} - -extend = (out={}) -> - args = [] - Array::push.apply(args, arguments) - - for obj in args[1..] when obj - for own key, val of obj - out[key] = val - - out - -removeClass = (el, name) -> - if el.classList? - el.classList.remove(cls) for cls in name.split(' ') when cls.trim() - else - className = getClassName(el).replace(new RegExp("(^| )#{ name.split(' ').join('|') }( |$)", 'gi'), ' ') - setClassName el, className - -addClass = (el, name) -> - if el.classList? - el.classList.add(cls) for cls in name.split(' ') when cls.trim() - else - removeClass el, name - cls = getClassName(el) + " #{name}" - setClassName el, cls - -hasClass = (el, name) -> - if el.classList? - el.classList.contains(name) - else - new RegExp("(^| )#{ name }( |$)", 'gi').test(getClassName(el)) - -getClassName = (el) -> - if el.className instanceof SVGAnimatedString - el.className.baseVal - else - el.className - -setClassName = (el, className) -> - el.setAttribute 'class', className - - -updateClasses = (el, add, all) -> - # Of the set of 'all' classes, we need the 'add' classes, and only the - # 'add' classes to be set. - for cls in all when cls not in add - if hasClass(el, cls) - removeClass el, cls - - for cls in add - if not hasClass(el, cls) - addClass el, cls - -deferred = [] - -defer = (fn) -> - deferred.push fn - -flush = -> - fn() while fn = deferred.pop() - -class Evented - on: (event, handler, ctx, once=false) -> - @bindings ?= {} - @bindings[event] ?= [] - @bindings[event].push {handler, ctx, once} - - once: (event, handler, ctx) -> - @on(event, handler, ctx, true) - - off: (event, handler) -> - return unless @bindings?[event]? - - if not handler? - delete @bindings[event] - else - i = 0 - while i < @bindings[event].length - if @bindings[event][i].handler is handler - @bindings[event].splice i, 1 - else - i++ - - trigger: (event, args...) -> - if @bindings?[event] - i = 0 - while i < @bindings[event].length - {handler, ctx, once} = @bindings[event][i] - - handler.apply(ctx ? @, args) - - if once - @bindings[event].splice i, 1 - else - i++ - -@Tether.Utils = {getScrollParent, getBounds, getOffsetParent, extend, addClass, removeClass, hasClass, updateClasses, defer, flush, uniqueId, Evented, getScrollBarSize} diff --git a/component.json b/component.json index e5939011..67b6bfdc 100644 --- a/component.json +++ b/component.json @@ -1,19 +1,22 @@ { "name": "tether", "repo": "HubSpot/tether", - "version": "0.6.5", + "version": "1.0.0", "description": "A client-side library to make absolutely positioned elements attach to elements in the page efficiently.", "authors": [ "Zack Bloom ", "Adam Schwartz " ], + "maintainers": [ + "Nicholas Hwang " + ], "license": "MIT", "demo": "http://github.hubspot.com/tether/docs/welcome/", - "main": "tether.js", + "main": "dist/js/tether.js", "styles": [ - "css/tether.css" + "dist/css/tether.css" ], "scripts": [ - "tether.js" + "dist/js/tether.js" ] } diff --git a/css/tether-theme-arrows-dark.css b/dist/css/tether-theme-arrows-dark.css similarity index 100% rename from css/tether-theme-arrows-dark.css rename to dist/css/tether-theme-arrows-dark.css diff --git a/dist/css/tether-theme-arrows-dark.min.css b/dist/css/tether-theme-arrows-dark.min.css new file mode 100644 index 00000000..07f9d8c7 --- /dev/null +++ b/dist/css/tether-theme-arrows-dark.min.css @@ -0,0 +1 @@ +.tether-element.tether-theme-arrows-dark.tether-element-attached-bottom.tether-element-attached-center .tether-content,.tether-element.tether-theme-arrows-dark.tether-element-attached-bottom.tether-element-attached-left.tether-target-attached-top .tether-content,.tether-element.tether-theme-arrows-dark.tether-element-attached-bottom.tether-element-attached-right.tether-target-attached-top .tether-content{margin-bottom:16px}.tether-element.tether-theme-arrows-dark.tether-element-attached-bottom.tether-element-attached-right.tether-target-attached-left .tether-content,.tether-element.tether-theme-arrows-dark.tether-element-attached-right.tether-element-attached-middle .tether-content,.tether-element.tether-theme-arrows-dark.tether-element-attached-top.tether-element-attached-right.tether-target-attached-left .tether-content{margin-right:16px}.tether-element,.tether-element *,.tether-element :after,.tether-element :before,.tether-element:after,.tether-element:before{box-sizing:border-box}.tether-element{position:absolute;display:none}.tether-element.tether-open{display:block}.tether-element.tether-theme-arrows-dark{max-width:100%;max-height:100%}.tether-element.tether-theme-arrows-dark .tether-content{border-radius:5px;position:relative;font-family:inherit;background:#000;color:#fff;padding:1em;font-size:1.1em;line-height:1.5em}.tether-element.tether-theme-arrows-dark .tether-content:before{content:"";display:block;position:absolute;width:0;height:0;border-color:transparent;border-width:16px;border-style:solid}.tether-element.tether-theme-arrows-dark.tether-element-attached-bottom.tether-element-attached-center .tether-content:before{top:100%;left:50%;margin-left:-16px;border-top-color:#000}.tether-element.tether-theme-arrows-dark.tether-element-attached-top.tether-element-attached-center .tether-content{margin-top:16px}.tether-element.tether-theme-arrows-dark.tether-element-attached-top.tether-element-attached-center .tether-content:before{bottom:100%;left:50%;margin-left:-16px;border-bottom-color:#000}.tether-element.tether-theme-arrows-dark.tether-element-attached-bottom.tether-element-attached-left.tether-target-attached-right .tether-content,.tether-element.tether-theme-arrows-dark.tether-element-attached-left.tether-element-attached-middle .tether-content,.tether-element.tether-theme-arrows-dark.tether-element-attached-top.tether-element-attached-left.tether-target-attached-right .tether-content{margin-left:16px}.tether-element.tether-theme-arrows-dark.tether-element-attached-right.tether-element-attached-middle .tether-content:before{left:100%;top:50%;margin-top:-16px;border-left-color:#000}.tether-element.tether-theme-arrows-dark.tether-element-attached-left.tether-element-attached-middle .tether-content:before{right:100%;top:50%;margin-top:-16px;border-right-color:#000}.tether-element.tether-theme-arrows-dark.tether-element-attached-top.tether-element-attached-left.tether-target-attached-bottom .tether-content,.tether-element.tether-theme-arrows-dark.tether-element-attached-top.tether-element-attached-right.tether-target-attached-bottom .tether-content{margin-top:16px}.tether-element.tether-theme-arrows-dark.tether-element-attached-top.tether-element-attached-left.tether-target-attached-bottom .tether-content:before{bottom:100%;left:16px;border-bottom-color:#000}.tether-element.tether-theme-arrows-dark.tether-element-attached-top.tether-element-attached-right.tether-target-attached-bottom .tether-content:before{bottom:100%;right:16px;border-bottom-color:#000}.tether-element.tether-theme-arrows-dark.tether-element-attached-bottom.tether-element-attached-left.tether-target-attached-top .tether-content:before{top:100%;left:16px;border-top-color:#000}.tether-element.tether-theme-arrows-dark.tether-element-attached-bottom.tether-element-attached-right.tether-target-attached-top .tether-content:before{top:100%;right:16px;border-top-color:#000}.tether-element.tether-theme-arrows-dark.tether-element-attached-top.tether-element-attached-right.tether-target-attached-left .tether-content:before{top:16px;left:100%;border-left-color:#000}.tether-element.tether-theme-arrows-dark.tether-element-attached-top.tether-element-attached-left.tether-target-attached-right .tether-content:before{top:16px;right:100%;border-right-color:#000}.tether-element.tether-theme-arrows-dark.tether-element-attached-bottom.tether-element-attached-right.tether-target-attached-left .tether-content:before{bottom:16px;left:100%;border-left-color:#000}.tether-element.tether-theme-arrows-dark.tether-element-attached-bottom.tether-element-attached-left.tether-target-attached-right .tether-content:before{bottom:16px;right:100%;border-right-color:#000} \ No newline at end of file diff --git a/css/tether-theme-arrows.css b/dist/css/tether-theme-arrows.css similarity index 100% rename from css/tether-theme-arrows.css rename to dist/css/tether-theme-arrows.css diff --git a/dist/css/tether-theme-arrows.min.css b/dist/css/tether-theme-arrows.min.css new file mode 100644 index 00000000..1f2c9e28 --- /dev/null +++ b/dist/css/tether-theme-arrows.min.css @@ -0,0 +1 @@ +.tether-element.tether-theme-arrows.tether-element-attached-bottom.tether-element-attached-center .tether-content,.tether-element.tether-theme-arrows.tether-element-attached-bottom.tether-element-attached-left.tether-target-attached-top .tether-content,.tether-element.tether-theme-arrows.tether-element-attached-bottom.tether-element-attached-right.tether-target-attached-top .tether-content{margin-bottom:16px}.tether-element.tether-theme-arrows.tether-element-attached-bottom.tether-element-attached-right.tether-target-attached-left .tether-content,.tether-element.tether-theme-arrows.tether-element-attached-right.tether-element-attached-middle .tether-content,.tether-element.tether-theme-arrows.tether-element-attached-top.tether-element-attached-right.tether-target-attached-left .tether-content{margin-right:16px}.tether-element,.tether-element *,.tether-element :after,.tether-element :before,.tether-element:after,.tether-element:before{box-sizing:border-box}.tether-element{position:absolute;display:none}.tether-element.tether-open{display:block}.tether-element.tether-theme-arrows{max-width:100%;max-height:100%}.tether-element.tether-theme-arrows .tether-content{border-radius:5px;position:relative;font-family:inherit;background:#fff;color:inherit;padding:1em;font-size:1.1em;line-height:1.5em;-webkit-transform:translateZ(0);transform:translateZ(0);-webkit-filter:drop-shadow(0 1px 4px rgba(0, 0, 0, .2));filter:drop-shadow(0 1px 4px rgba(0, 0, 0, .2))}.tether-element.tether-theme-arrows .tether-content:before{content:"";display:block;position:absolute;width:0;height:0;border-color:transparent;border-width:16px;border-style:solid}.tether-element.tether-theme-arrows.tether-element-attached-bottom.tether-element-attached-center .tether-content:before{top:100%;left:50%;margin-left:-16px;border-top-color:#fff}.tether-element.tether-theme-arrows.tether-element-attached-top.tether-element-attached-center .tether-content{margin-top:16px}.tether-element.tether-theme-arrows.tether-element-attached-top.tether-element-attached-center .tether-content:before{bottom:100%;left:50%;margin-left:-16px;border-bottom-color:#fff}.tether-element.tether-theme-arrows.tether-element-attached-bottom.tether-element-attached-left.tether-target-attached-right .tether-content,.tether-element.tether-theme-arrows.tether-element-attached-left.tether-element-attached-middle .tether-content,.tether-element.tether-theme-arrows.tether-element-attached-top.tether-element-attached-left.tether-target-attached-right .tether-content{margin-left:16px}.tether-element.tether-theme-arrows.tether-element-attached-right.tether-element-attached-middle .tether-content:before{left:100%;top:50%;margin-top:-16px;border-left-color:#fff}.tether-element.tether-theme-arrows.tether-element-attached-left.tether-element-attached-middle .tether-content:before{right:100%;top:50%;margin-top:-16px;border-right-color:#fff}.tether-element.tether-theme-arrows.tether-element-attached-top.tether-element-attached-left.tether-target-attached-bottom .tether-content,.tether-element.tether-theme-arrows.tether-element-attached-top.tether-element-attached-right.tether-target-attached-bottom .tether-content{margin-top:16px}.tether-element.tether-theme-arrows.tether-element-attached-top.tether-element-attached-left.tether-target-attached-bottom .tether-content:before{bottom:100%;left:16px;border-bottom-color:#fff}.tether-element.tether-theme-arrows.tether-element-attached-top.tether-element-attached-right.tether-target-attached-bottom .tether-content:before{bottom:100%;right:16px;border-bottom-color:#fff}.tether-element.tether-theme-arrows.tether-element-attached-bottom.tether-element-attached-left.tether-target-attached-top .tether-content:before{top:100%;left:16px;border-top-color:#fff}.tether-element.tether-theme-arrows.tether-element-attached-bottom.tether-element-attached-right.tether-target-attached-top .tether-content:before{top:100%;right:16px;border-top-color:#fff}.tether-element.tether-theme-arrows.tether-element-attached-top.tether-element-attached-right.tether-target-attached-left .tether-content:before{top:16px;left:100%;border-left-color:#fff}.tether-element.tether-theme-arrows.tether-element-attached-top.tether-element-attached-left.tether-target-attached-right .tether-content:before{top:16px;right:100%;border-right-color:#fff}.tether-element.tether-theme-arrows.tether-element-attached-bottom.tether-element-attached-right.tether-target-attached-left .tether-content:before{bottom:16px;left:100%;border-left-color:#fff}.tether-element.tether-theme-arrows.tether-element-attached-bottom.tether-element-attached-left.tether-target-attached-right .tether-content:before{bottom:16px;right:100%;border-right-color:#fff} \ No newline at end of file diff --git a/css/tether-theme-basic.css b/dist/css/tether-theme-basic.css similarity index 100% rename from css/tether-theme-basic.css rename to dist/css/tether-theme-basic.css diff --git a/dist/css/tether-theme-basic.min.css b/dist/css/tether-theme-basic.min.css new file mode 100644 index 00000000..f117c479 --- /dev/null +++ b/dist/css/tether-theme-basic.min.css @@ -0,0 +1 @@ +.tether-element,.tether-element *,.tether-element :after,.tether-element :before,.tether-element:after,.tether-element:before{box-sizing:border-box}.tether-element{position:absolute;display:none}.tether-element.tether-open{display:block}.tether-element.tether-theme-basic{max-width:100%;max-height:100%}.tether-element.tether-theme-basic .tether-content{border-radius:5px;box-shadow:0 2px 8px rgba(0,0,0,.2);font-family:inherit;background:#fff;color:inherit;padding:1em;font-size:1.1em;line-height:1.5em} \ No newline at end of file diff --git a/css/tether.css b/dist/css/tether.css similarity index 100% rename from css/tether.css rename to dist/css/tether.css diff --git a/dist/css/tether.min.css b/dist/css/tether.min.css new file mode 100644 index 00000000..328251c9 --- /dev/null +++ b/dist/css/tether.min.css @@ -0,0 +1 @@ +.tether-element,.tether-element *,.tether-element :after,.tether-element :before,.tether-element:after,.tether-element:before{box-sizing:border-box}.tether-element{position:absolute;display:none}.tether-element.tether-open{display:block} \ No newline at end of file diff --git a/dist/js/tether.js b/dist/js/tether.js new file mode 100644 index 00000000..1b58fff6 --- /dev/null +++ b/dist/js/tether.js @@ -0,0 +1,1693 @@ +/*! tether 1.0.0 */ + +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(factory); + } else if (typeof exports === 'object') { + module.exports = factory(require, exports, module); + } else { + root.Tether = factory(); + } +}(this, function(require, exports, module) { + +'use strict'; + +var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + +var TetherBase = undefined; +if (typeof TetherBase === 'undefined') { + TetherBase = { modules: [] }; +} + +function getScrollParent(el) { + var _getComputedStyle = getComputedStyle(el); + + var position = _getComputedStyle.position; + + if (position === 'fixed') { + return el; + } + + var parent = el; + while (parent = parent.parentNode) { + var style = undefined; + try { + style = getComputedStyle(parent); + } catch (err) {} + + if (typeof style === 'undefined') { + return parent; + } + + var overflow = style.overflow; + var overflowX = style.overflowX; + var overflowY = style.overflowY; + + if (/(auto|scroll)/.test(overflow + overflowY + overflowX)) { + if (position !== 'absolute' || ['relative', 'absolute', 'fixed'].indexOf(style.position) >= 0) { + return parent; + } + } + } + + return document.body; +} + +var uniqueId = (function () { + var id = 0; + return function () { + return ++id; + }; +})(); + +var zeroPosCache = {}; +var getOrigin = function getOrigin(doc) { + // getBoundingClientRect is unfortunately too accurate. It introduces a pixel or two of + // jitter as the user scrolls that messes with our ability to detect if two positions + // are equivilant or not. We place an element at the top left of the page that will + // get the same jitter, so we can cancel the two out. + var node = doc._tetherZeroElement; + if (typeof node === 'undefined') { + node = doc.createElement('div'); + node.setAttribute('data-tether-id', uniqueId()); + extend(node.style, { + top: 0, + left: 0, + position: 'absolute' + }); + + doc.body.appendChild(node); + + doc._tetherZeroElement = node; + } + + var id = node.getAttribute('data-tether-id'); + if (typeof zeroPosCache[id] === 'undefined') { + zeroPosCache[id] = {}; + + var rect = node.getBoundingClientRect(); + for (var k in rect) { + // Can't use extend, as on IE9, elements don't resolve to be hasOwnProperty + zeroPosCache[id][k] = rect[k]; + } + + // Clear the cache when this position call is done + defer(function () { + delete zeroPosCache[id]; + }); + } + + return zeroPosCache[id]; +}; + +function getBounds(el) { + var doc = undefined; + if (el === document) { + doc = document; + el = document.documentElement; + } else { + doc = el.ownerDocument; + } + + var docEl = doc.documentElement; + + var box = {}; + // The original object returned by getBoundingClientRect is immutable, so we clone it + // We can't use extend because the properties are not considered part of the object by hasOwnProperty in IE9 + var rect = el.getBoundingClientRect(); + for (var k in rect) { + box[k] = rect[k]; + } + + var origin = getOrigin(doc); + + box.top -= origin.top; + box.left -= origin.left; + + if (typeof box.width === 'undefined') { + box.width = document.body.scrollWidth - box.left - box.right; + } + if (typeof box.height === 'undefined') { + box.height = document.body.scrollHeight - box.top - box.bottom; + } + + box.top = box.top - docEl.clientTop; + box.left = box.left - docEl.clientLeft; + box.right = doc.body.clientWidth - box.width - box.left; + box.bottom = doc.body.clientHeight - box.height - box.top; + + return box; +} + +function getOffsetParent(el) { + return el.offsetParent || document.documentElement; +} + +function getScrollBarSize() { + var inner = document.createElement('div'); + inner.style.width = '100%'; + inner.style.height = '200px'; + + var outer = document.createElement('div'); + extend(outer.style, { + position: 'absolute', + top: 0, + left: 0, + pointerEvents: 'none', + visibility: 'hidden', + width: '200px', + height: '150px', + overflow: 'hidden' + }); + + outer.appendChild(inner); + + document.body.appendChild(outer); + + var widthContained = inner.offsetWidth; + outer.style.overflow = 'scroll'; + var widthScroll = inner.offsetWidth; + + if (widthContained === widthScroll) { + widthScroll = outer.clientWidth; + } + + document.body.removeChild(outer); + + var width = widthContained - widthScroll; + + return { width: width, height: width }; +} + +function extend() { + var out = arguments[0] === undefined ? {} : arguments[0]; + + var args = []; + + Array.prototype.push.apply(args, arguments); + + args.slice(1).forEach(function (obj) { + if (obj) { + for (var key in obj) { + if (({}).hasOwnProperty.call(obj, key)) { + out[key] = obj[key]; + } + } + } + }); + + return out; +} + +function removeClass(el, name) { + if (typeof el.classList !== 'undefined') { + name.split(' ').forEach(function (cls) { + if (cls.trim()) { + el.classList.remove(cls); + } + }); + } else { + var regex = new RegExp('(^| )' + name.split(' ').join('|') + '( |$)', 'gi'); + var className = getClassName(el).replace(regex, ' '); + setClassName(el, className); + } +} + +function addClass(el, name) { + if (typeof el.classList !== 'undefined') { + name.split(' ').forEach(function (cls) { + if (cls.trim()) { + el.classList.add(cls); + } + }); + } else { + removeClass(el, name); + var cls = getClassName(el) + ' #{name}'; + setClassName(el, cls); + } +} + +function hasClass(el, name) { + if (typeof el.classList !== 'undefined') { + return el.classList.contains(name); + } + var className = getClassName(el); + return new RegExp('(^| )' + name + '( |$)', 'gi').test(className); +} + +function getClassName(el) { + if (el.className instanceof SVGAnimatedString) { + return el.className.baseVal; + } + return el.className; +} + +function setClassName(el, className) { + el.setAttribute('class', className); +} + +function updateClasses(el, add, all) { + // Of the set of 'all' classes, we need the 'add' classes, and only the + // 'add' classes to be set. + all.forEach(function (cls) { + if (add.indexOf(cls) === -1 && hasClass(el, cls)) { + removeClass(el, cls); + } + }); + + add.forEach(function (cls) { + if (!hasClass(el, cls)) { + addClass(el, cls); + } + }); +} + +var deferred = []; + +var defer = function defer(fn) { + deferred.push(fn); +}; + +var flush = function flush() { + var fn = undefined; + while (fn = deferred.pop()) { + fn(); + } +}; + +var Evented = (function () { + function Evented() { + _classCallCheck(this, Evented); + } + + _createClass(Evented, [{ + key: 'on', + value: function on(event, handler, ctx) { + var once = arguments[3] === undefined ? false : arguments[3]; + + if (typeof this.bindings === 'undefined') { + this.bindings = {}; + } + if (typeof this.bindings[event] === 'undefined') { + this.bindings[event] = []; + } + this.bindings[event].push({ handler: handler, ctx: ctx, once: once }); + } + }, { + key: 'once', + value: function once(event, handler, ctx) { + this.on(event, handler, ctx, true); + } + }, { + key: 'off', + value: function off(event, handler) { + if (typeof this.bindings !== 'undefined' && typeof this.bindings[event] !== 'undefined') { + return; + } + + if (typeof handler === 'undefined') { + delete this.bindings[event]; + } else { + var i = 0; + while (i < this.bindings[event].length) { + if (this.bindings[event][i].handler === handler) { + this.bindings[event].splice(i, 1); + } else { + ++i; + } + } + } + } + }, { + key: 'trigger', + value: function trigger(event) { + for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + + if (typeof this.bindings !== 'undefined' && this.bindings[event]) { + var i = 0; + while (i < this.bindings[event].length) { + var _bindings$event$i = this.bindings[event][i]; + var handler = _bindings$event$i.handler; + var ctx = _bindings$event$i.ctx; + var once = _bindings$event$i.once; + + var context = ctx; + if (typeof context === 'undefined') { + context = this; + } + + handler.apply(context, args); + + if (once) { + this.bindings[event].splice(i, 1); + } else { + ++i; + } + } + } + } + }]); + + return Evented; +})(); + +TetherBase.Utils = { + getScrollParent: getScrollParent, + getBounds: getBounds, + getOffsetParent: getOffsetParent, + extend: extend, + addClass: addClass, + removeClass: removeClass, + hasClass: hasClass, + updateClasses: updateClasses, + defer: defer, + flush: flush, + uniqueId: uniqueId, + Evented: Evented, + getScrollBarSize: getScrollBarSize +}; +/* globals TetherBase, performance */ + +'use strict'; + +var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + +function _slicedToArray(arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + +if (typeof TetherBase === 'undefined') { + throw new Error('You must include the utils.js file before tether.js'); +} + +var _TetherBase$Utils = TetherBase.Utils; +var getScrollParent = _TetherBase$Utils.getScrollParent; +var getBounds = _TetherBase$Utils.getBounds; +var getOffsetParent = _TetherBase$Utils.getOffsetParent; +var extend = _TetherBase$Utils.extend; +var addClass = _TetherBase$Utils.addClass; +var removeClass = _TetherBase$Utils.removeClass; +var updateClasses = _TetherBase$Utils.updateClasses; +var defer = _TetherBase$Utils.defer; +var flush = _TetherBase$Utils.flush; +var getScrollBarSize = _TetherBase$Utils.getScrollBarSize; + +function within(a, b) { + var diff = arguments[2] === undefined ? 1 : arguments[2]; + + return a + diff >= b && b >= a - diff; +} + +var transformKey = (function () { + var el = document.createElement('div'); + + var transforms = ['transform', 'webkitTransform', 'OTransform', 'MozTransform', 'msTransform']; + for (var i = 0; i < transforms.length; ++i) { + var key = transforms[i]; + if (el.style[key] !== undefined) { + return key; + } + } +})(); + +var tethers = []; + +var position = function position() { + tethers.forEach(function (tether) { + tether.position(false); + }); + flush(); +}; + +function now() { + if (typeof performance !== 'undefined' && typeof performance.now !== 'undefined') { + return performance.now(); + } + return +new Date(); +} + +(function () { + var lastCall = null; + var lastDuration = null; + var pendingTimeout = null; + + var tick = function tick() { + if (typeof lastDuration !== 'undefined' && lastDuration > 16) { + // We voluntarily throttle ourselves if we can't manage 60fps + lastDuration = Math.min(lastDuration - 16, 250); + + // Just in case this is the last event, remember to position just once more + pendingTimeout = setTimeout(tick, 250); + return; + } + + if (typeof lastCall !== 'undefined' && now() - lastCall < 10) { + // Some browsers call events a little too frequently, refuse to run more than is reasonable + return; + } + + if (typeof pendingTimeout !== 'undefined') { + clearTimeout(pendingTimeout); + pendingTimeout = null; + } + + lastCall = now(); + position(); + lastDuration = now() - lastCall; + }; + + ['resize', 'scroll', 'touchmove'].forEach(function (event) { + window.addEventListener(event, tick); + }); +})(); + +var MIRROR_LR = { + center: 'center', + left: 'right', + right: 'left' +}; + +var MIRROR_TB = { + middle: 'middle', + top: 'bottom', + bottom: 'top' +}; + +var OFFSET_MAP = { + top: 0, + left: 0, + middle: '50%', + center: '50%', + bottom: '100%', + right: '100%' +}; + +var autoToFixedAttachment = function autoToFixedAttachment(attachment, relativeToAttachment) { + var left = attachment.left; + var top = attachment.top; + + if (left === 'auto') { + left = MIRROR_LR[relativeToAttachment.left]; + } + + if (top === 'auto') { + top = MIRROR_TB[relativeToAttachment.top]; + } + + return { left: left, top: top }; +}; + +var attachmentToOffset = function attachmentToOffset(attachment) { + var left = attachment.left; + var top = attachment.top; + + if (typeof OFFSET_MAP[attachment.left] !== 'undefined') { + left = OFFSET_MAP[attachment.left]; + } + + if (typeof OFFSET_MAP[attachment.top] !== 'undefined') { + top = OFFSET_MAP[attachment.top]; + } + + return { left: left, top: top }; +}; + +function addOffset() { + for (var _len = arguments.length, offsets = Array(_len), _key = 0; _key < _len; _key++) { + offsets[_key] = arguments[_key]; + } + + var out = { top: 0, left: 0 }; + + offsets.forEach(function (_ref) { + var top = _ref.top; + var left = _ref.left; + + if (typeof top === 'string') { + top = parseFloat(top, 10); + } + if (typeof left === 'string') { + left = parseFloat(left, 10); + } + + out.top += top; + out.left += left; + }); + + return out; +} + +function offsetToPx(offset, size) { + if (typeof offset.left === 'string' && offset.left.indexOf('%') !== -1) { + offset.left = parseFloat(offset.left, 10) / 100 * size.width; + } + if (typeof offset.top === 'string' && offset.top.indexOf('%') !== -1) { + offset.top = parseFloat(offset.top, 10) / 100 * size.height; + } + + return offset; +} + +var parseOffset = function parseOffset(value) { + var _value$split = value.split(' '); + + var _value$split2 = _slicedToArray(_value$split, 2); + + var top = _value$split2[0]; + var left = _value$split2[1]; + + return { top: top, left: left }; +}; +var parseAttachment = parseOffset; + +var TetherClass = (function () { + function TetherClass(options) { + var _this = this; + + _classCallCheck(this, TetherClass); + + this.position = this.position.bind(this); + + tethers.push(this); + + this.history = []; + + this.setOptions(options, false); + + TetherBase.modules.forEach(function (module) { + if (typeof module.initialize !== 'undefined') { + module.initialize.call(_this); + } + }); + + this.position(); + } + + _createClass(TetherClass, [{ + key: 'getClass', + value: function getClass() { + var key = arguments[0] === undefined ? '' : arguments[0]; + var classes = this.options.classes; + + if (typeof classes !== 'undefined' && classes[key]) { + return this.options.classes[key]; + } else if (this.options.classPrefix) { + return '' + this.options.classPrefix + '-' + key; + } else { + return key; + } + } + }, { + key: 'setOptions', + value: function setOptions(options) { + var _this2 = this; + + var pos = arguments[1] === undefined ? true : arguments[1]; + + var defaults = { + offset: '0 0', + targetOffset: '0 0', + targetAttachment: 'auto auto', + classPrefix: 'tether' + }; + + this.options = extend(defaults, options); + + var _options = this.options; + var element = _options.element; + var target = _options.target; + var targetModifier = _options.targetModifier; + + this.element = element; + this.target = target; + this.targetModifier = targetModifier; + + if (this.target === 'viewport') { + this.target = document.body; + this.targetModifier = 'visible'; + } else if (this.target === 'scroll-handle') { + this.target = document.body; + this.targetModifier = 'scroll-handle'; + } + + ['element', 'target'].forEach(function (key) { + if (typeof _this2[key] === 'undefined') { + throw new Error('Tether Error: Both element and target must be defined'); + } + + if (typeof _this2[key].jquery !== 'undefined') { + _this2[key] = _this2[key][0]; + } else if (typeof _this2[key] === 'string') { + _this2[key] = document.querySelector(_this2[key]); + } + }); + + addClass(this.element, this.getClass('element')); + if (!(this.options.addTargetClasses === false)) { + addClass(this.target, this.getClass('target')); + } + + if (!this.options.attachment) { + throw new Error('Tether Error: You must provide an attachment'); + } + + this.targetAttachment = parseAttachment(this.options.targetAttachment); + this.attachment = parseAttachment(this.options.attachment); + this.offset = parseOffset(this.options.offset); + this.targetOffset = parseOffset(this.options.targetOffset); + + if (typeof this.scrollParent !== 'undefined') { + this.disable(); + } + + if (this.targetModifier === 'scroll-handle') { + this.scrollParent = this.target; + } else { + this.scrollParent = getScrollParent(this.target); + } + + if (!(this.options.enabled === false)) { + this.enable(pos); + } + } + }, { + key: 'getTargetBounds', + value: function getTargetBounds() { + if (typeof this.targetModifier !== 'undefined') { + if (this.targetModifier === 'visible') { + if (this.target === document.body) { + return { top: pageYOffset, left: pageXOffset, height: innerHeight, width: innerWidth }; + } else { + var bounds = getBounds(this.target); + + var out = { + height: bounds.height, + width: bounds.width, + top: bounds.top, + left: bounds.left + }; + + out.height = Math.min(out.height, bounds.height - (pageYOffset - bounds.top)); + out.height = Math.min(out.height, bounds.height - (bounds.top + bounds.height - (pageYOffset + innerHeight))); + out.height = Math.min(innerHeight, out.height); + out.height -= 2; + + out.width = Math.min(out.width, bounds.width - (pageXOffset - bounds.left)); + out.width = Math.min(out.width, bounds.width - (bounds.left + bounds.width - (pageXOffset + innerWidth))); + out.width = Math.min(innerWidth, out.width); + out.width -= 2; + + if (out.top < pageYOffset) { + out.top = pageYOffset; + } + if (out.left < pageXOffset) { + out.left = pageXOffset; + } + + return out; + } + } else if (this.targetModifier === 'scroll-handle') { + var bounds = undefined; + var target = this.target; + if (target === document.body) { + target = document.documentElement; + + bounds = { + left: pageXOffset, + top: pageYOffset, + height: innerHeight, + width: innerWidth + }; + } else { + bounds = getBounds(target); + } + + var style = getComputedStyle(target); + + var hasBottomScroll = target.scrollWidth > target.clientWidth || [style.overflow, style.overflowX].indexOf('scroll') >= 0 || this.target !== document.body; + + var scrollBottom = 0; + if (hasBottomScroll) { + scrollBottom = 15; + } + + var height = bounds.height - parseFloat(style.borderTopWidth) - parseFloat(style.borderBottomWidth) - scrollBottom; + + var out = { + width: 15, + height: height * 0.975 * (height / target.scrollHeight), + left: bounds.left + bounds.width - parseFloat(style.borderLeftWidth) - 15 + }; + + var fitAdj = 0; + if (height < 408 && this.target === document.body) { + fitAdj = -0.00011 * Math.pow(height, 2) - 0.00727 * height + 22.58; + } + + if (this.target !== document.body) { + out.height = Math.max(out.height, 24); + } + + var scrollPercentage = this.target.scrollTop / (target.scrollHeight - height); + out.top = scrollPercentage * (height - out.height - fitAdj) + bounds.top + parseFloat(style.borderTopWidth); + + if (this.target === document.body) { + out.height = Math.max(out.height, 24); + } + + return out; + } + } else { + return getBounds(this.target); + } + } + }, { + key: 'clearCache', + value: function clearCache() { + this._cache = {}; + } + }, { + key: 'cache', + value: function cache(k, getter) { + // More than one module will often need the same DOM info, so + // we keep a cache which is cleared on each position call + if (typeof this._cache === 'undefined') { + this._cache = {}; + } + + if (typeof this._cache[k] === 'undefined') { + this._cache[k] = getter.call(this); + } + + return this._cache[k]; + } + }, { + key: 'enable', + value: function enable() { + var pos = arguments[0] === undefined ? true : arguments[0]; + + if (!(this.options.addTargetClasses === false)) { + addClass(this.target, this.getClass('enabled')); + } + addClass(this.element, this.getClass('enabled')); + this.enabled = true; + + if (this.scrollParent !== document) { + this.scrollParent.addEventListener('scroll', this.position); + } + + if (pos) { + this.position(); + } + } + }, { + key: 'disable', + value: function disable() { + removeClass(this.target, this.getClass('enabled')); + removeClass(this.element, this.getClass('enabled')); + this.enabled = false; + + if (typeof this.scrollParent !== 'undefined') { + this.scrollParent.removeEventListener('scroll', this.position); + } + } + }, { + key: 'destroy', + value: function destroy() { + var _this3 = this; + + this.disable(); + + tethers.forEach(function (tether, i) { + if (tether === _this3) { + tethers.splice(i, 1); + return; + } + }); + } + }, { + key: 'updateAttachClasses', + value: function updateAttachClasses(elementAttach, targetAttach) { + var _this4 = this; + + elementAttach = elementAttach || this.attachment; + targetAttach = targetAttach || this.targetAttachment; + var sides = ['left', 'top', 'bottom', 'right', 'middle', 'center']; + + if (typeof this._addAttachClasses !== 'undefined' && this._addAttachClasses.length) { + // updateAttachClasses can be called more than once in a position call, so + // we need to clean up after ourselves such that when the last defer gets + // ran it doesn't add any extra classes from previous calls. + this._addAttachClasses.splice(0, this._addAttachClasses.length); + } + + if (typeof this._addAttachClasses === 'undefined') { + this._addAttachClasses = []; + } + var add = this._addAttachClasses; + + if (elementAttach.top) { + add.push('' + this.getClass('element-attached') + '-' + elementAttach.top); + } + if (elementAttach.left) { + add.push('' + this.getClass('element-attached') + '-' + elementAttach.left); + } + if (targetAttach.top) { + add.push('' + this.getClass('target-attached') + '-' + targetAttach.top); + } + if (targetAttach.left) { + add.push('' + this.getClass('target-attached') + '-' + targetAttach.left); + } + + var all = []; + sides.forEach(function (side) { + all.push('' + _this4.getClass('element-attached') + '-' + side); + all.push('' + _this4.getClass('target-attached') + '-' + side); + }); + + defer(function () { + if (!(typeof _this4._addAttachClasses !== 'undefined')) { + return; + } + + updateClasses(_this4.element, _this4._addAttachClasses, all); + if (!(_this4.options.addTargetClasses === false)) { + updateClasses(_this4.target, _this4._addAttachClasses, all); + } + + delete _this4._addAttachClasses; + }); + } + }, { + key: 'position', + value: function position() { + var _this5 = this; + + var flushChanges = arguments[0] === undefined ? true : arguments[0]; + + // flushChanges commits the changes immediately, leave true unless you are positioning multiple + // tethers (in which case call Tether.Utils.flush yourself when you're done) + + if (!this.enabled) { + return; + } + + this.clearCache(); + + // Turn 'auto' attachments into the appropriate corner or edge + var targetAttachment = autoToFixedAttachment(this.targetAttachment, this.attachment); + + this.updateAttachClasses(this.attachment, targetAttachment); + + var elementPos = this.cache('element-bounds', function () { + return getBounds(_this5.element); + }); + + var width = elementPos.width; + var height = elementPos.height; + + if (width === 0 && height === 0 && typeof this.lastSize !== 'undefined') { + var _lastSize = this.lastSize; + + // We cache the height and width to make it possible to position elements that are + // getting hidden. + width = _lastSize.width; + height = _lastSize.height; + } else { + this.lastSize = { width: width, height: height }; + } + + var targetPos = this.cache('target-bounds', function () { + return _this5.getTargetBounds(); + }); + var targetSize = targetPos; + + // Get an actual px offset from the attachment + var offset = offsetToPx(attachmentToOffset(this.attachment), { width: width, height: height }); + var targetOffset = offsetToPx(attachmentToOffset(targetAttachment), targetSize); + + var manualOffset = offsetToPx(this.offset, { width: width, height: height }); + var manualTargetOffset = offsetToPx(this.targetOffset, targetSize); + + // Add the manually provided offset + offset = addOffset(offset, manualOffset); + targetOffset = addOffset(targetOffset, manualTargetOffset); + + // It's now our goal to make (element position + offset) == (target position + target offset) + var left = targetPos.left + targetOffset.left - offset.left; + var top = targetPos.top + targetOffset.top - offset.top; + + for (var i = 0; i < TetherBase.modules.length; ++i) { + var _module2 = TetherBase.modules[i]; + var ret = _module2.position.call(this, { + left: left, + top: top, + targetAttachment: targetAttachment, + targetPos: targetPos, + elementPos: elementPos, + offset: offset, + targetOffset: targetOffset, + manualOffset: manualOffset, + manualTargetOffset: manualTargetOffset, + scrollbarSize: scrollbarSize, + attachment: this.attachment + }); + + if (ret === false) { + return false; + } else if (typeof ret === 'undefined' || typeof ret !== 'object') { + continue; + } else { + top = ret.top; + left = ret.left; + } + } + + // We describe the position three different ways to give the optimizer + // a chance to decide the best possible way to position the element + // with the fewest repaints. + var next = { + // It's position relative to the page (absolute positioning when + // the element is a child of the body) + page: { + top: top, + left: left + }, + + // It's position relative to the viewport (fixed positioning) + viewport: { + top: top - pageYOffset, + bottom: pageYOffset - top - height + innerHeight, + left: left - pageXOffset, + right: pageXOffset - left - width + innerWidth + } + }; + + var scrollbarSize = undefined; + if (document.body.scrollWidth > window.innerWidth) { + scrollbarSize = this.cache('scrollbar-size', getScrollBarSize); + next.viewport.bottom -= scrollbarSize.height; + } + + if (document.body.scrollHeight > window.innerHeight) { + scrollbarSize = this.cache('scrollbar-size', getScrollBarSize); + next.viewport.right -= scrollbarSize.width; + } + + if (['', 'static'].indexOf(document.body.style.position) === -1 || ['', 'static'].indexOf(document.body.parentElement.style.position) === -1) { + // Absolute positioning in the body will be relative to the page, not the 'initial containing block' + next.page.bottom = document.body.scrollHeight - top - height; + next.page.right = document.body.scrollWidth - left - width; + } + + if (typeof this.options.optimizations !== 'undefined' && this.options.optimizations.moveElement !== false && !(typeof this.targetModifier !== 'undefined')) { + (function () { + var offsetParent = _this5.cache('target-offsetparent', function () { + return getOffsetParent(_this5.target); + }); + var offsetPosition = _this5.cache('target-offsetparent-bounds', function () { + return getBounds(offsetParent); + }); + var offsetParentStyle = getComputedStyle(offsetParent); + var offsetParentSize = offsetPosition; + + var offsetBorder = {}; + ['Top', 'Left', 'Bottom', 'Right'].forEach(function (side) { + offsetBorder[side.toLowerCase()] = parseFloat(offsetParentStyle['border' + side + 'Width']); + }); + + offsetPosition.right = document.body.scrollWidth - offsetPosition.left - offsetParentSize.width + offsetBorder.right; + offsetPosition.bottom = document.body.scrollHeight - offsetPosition.top - offsetParentSize.height + offsetBorder.bottom; + + if (next.page.top >= offsetPosition.top + offsetBorder.top && next.page.bottom >= offsetPosition.bottom) { + if (next.page.left >= offsetPosition.left + offsetBorder.left && next.page.right >= offsetPosition.right) { + // We're within the visible part of the target's scroll parent + var scrollTop = offsetParent.scrollTop; + var scrollLeft = offsetParent.scrollLeft; + + // It's position relative to the target's offset parent (absolute positioning when + // the element is moved to be a child of the target's offset parent). + next.offset = { + top: next.page.top - offsetPosition.top + scrollTop - offsetBorder.top, + left: next.page.left - offsetPosition.left + scrollLeft - offsetBorder.left + }; + } + } + })(); + } + + // We could also travel up the DOM and try each containing context, rather than only + // looking at the body, but we're gonna get diminishing returns. + + this.move(next); + + this.history.unshift(next); + + if (this.history.length > 3) { + this.history.pop(); + } + + if (flushChanges) { + flush(); + } + + return true; + } + }, { + key: 'move', + + // THE ISSUE + value: function move(pos) { + var _this6 = this; + + if (!(typeof this.element.parentNode !== 'undefined')) { + return; + } + + var same = {}; + + for (var type in pos) { + same[type] = {}; + + for (var key in pos[type]) { + var found = false; + + for (var i = 0; i < this.history.length; ++i) { + var point = this.history[i]; + if (typeof point[type] !== 'undefined' && !within(point[type][key], pos[type][key])) { + found = true; + break; + } + } + + if (!found) { + same[type][key] = true; + } + } + } + + var css = { top: '', left: '', right: '', bottom: '' }; + + var transcribe = function transcribe(_same, _pos) { + var hasOptimizations = typeof _this6.options.optimizations !== 'undefined'; + var gpu = hasOptimizations ? _this6.options.optimizations.gpu : null; + if (gpu !== false) { + var yPos = undefined, + xPos = undefined; + if (_same.top) { + css.top = 0; + yPos = _pos.top; + } else { + css.bottom = 0; + yPos = -_pos.bottom; + } + + if (_same.left) { + css.left = 0; + xPos = _pos.left; + } else { + css.right = 0; + xPos = -_pos.right; + } + + css[transformKey] = 'translateX(' + Math.round(xPos) + 'px) translateY(' + Math.round(yPos) + 'px)'; + + if (transformKey !== 'msTransform') { + // The Z transform will keep this in the GPU (faster, and prevents artifacts), + // but IE9 doesn't support 3d transforms and will choke. + css[transformKey] += ' translateZ(0)'; + } + } else { + if (_same.top) { + css.top = '' + _pos.top + 'px'; + } else { + css.bottom = '' + _pos.bottom + 'px'; + } + + if (_same.left) { + css.left = '' + _pos.left + 'px'; + } else { + css.right = '' + _pos.right + 'px'; + } + } + }; + + var moved = false; + if ((same.page.top || same.page.bottom) && (same.page.left || same.page.right)) { + css.position = 'absolute'; + transcribe(same.page, pos.page); + } else if ((same.viewport.top || same.viewport.bottom) && (same.viewport.left || same.viewport.right)) { + css.position = 'fixed'; + transcribe(same.viewport, pos.viewport); + } else if (typeof same.offset !== 'undefined' && same.offset.top && same.offset.left) { + (function () { + css.position = 'absolute'; + var offsetParent = _this6.cache('target-offsetparent', function () { + return getOffsetParent(_this6.target); + }); + + if (getOffsetParent(_this6.element) !== offsetParent) { + defer(function () { + _this6.element.parentNode.removeChild(_this6.element); + offsetParent.appendChild(_this6.element); + }); + } + + transcribe(same.offset, pos.offset); + moved = true; + })(); + } else { + css.position = 'absolute'; + transcribe({ top: true, left: true }, pos.page); + } + + if (!moved && this.element.parentNode.tagName !== 'BODY') { + this.element.parentNode.removeChild(this.element); + document.body.appendChild(this.element); + } + + // Any css change will trigger a repaint, so let's avoid one if nothing changed + var writeCSS = {}; + var write = false; + for (var key in css) { + var val = css[key]; + var elVal = this.element.style[key]; + + if (elVal !== '' && val !== '' && ['top', 'left', 'bottom', 'right'].indexOf(key) >= 0) { + elVal = parseFloat(elVal); + val = parseFloat(val); + } + + if (elVal !== val) { + write = true; + writeCSS[key] = val; + } + } + + if (write) { + defer(function () { + extend(_this6.element.style, writeCSS); + }); + } + } + }]); + + return TetherClass; +})(); + +TetherClass.modules = []; + +TetherBase.position = position; + +var Tether = extend(TetherClass, TetherBase); +/* globals TetherBase */ + +'use strict'; + +function _slicedToArray(arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } } + +var _TetherBase$Utils = TetherBase.Utils; +var getBounds = _TetherBase$Utils.getBounds; +var extend = _TetherBase$Utils.extend; +var updateClasses = _TetherBase$Utils.updateClasses; +var defer = _TetherBase$Utils.defer; + +var BOUNDS_FORMAT = ['left', 'top', 'right', 'bottom']; + +function getBoundingRect(tether, to) { + if (to === 'scrollParent') { + to = tether.scrollParent; + } else if (to === 'window') { + to = [pageXOffset, pageYOffset, innerWidth + pageXOffset, innerHeight + pageYOffset]; + } + + if (to === document) { + to = to.documentElement; + } + + if (typeof to.nodeType !== 'undefined') { + (function () { + var size = getBounds(to); + var pos = size; + var style = getComputedStyle(to); + + to = [pos.left, pos.top, size.width + pos.left, size.height + pos.top]; + + BOUNDS_FORMAT.forEach(function (side, i) { + side = side[0].toUpperCase() + side.substr(1); + if (side === 'Top' || side === 'Left') { + to[i] += parseFloat(style['border' + side + 'Width']); + } else { + to[i] -= parseFloat(style['border' + side + 'Width']); + } + }); + })(); + } + + return to; +} + +TetherBase.modules.push({ + position: function position(_ref) { + var _this = this; + + var top = _ref.top; + var left = _ref.left; + var targetAttachment = _ref.targetAttachment; + + if (!this.options.constraints) { + return true; + } + + var _cache = this.cache('element-bounds', function () { + return getBounds(_this.element); + }); + + var height = _cache.height; + var width = _cache.width; + + if (width === 0 && height === 0 && typeof this.lastSize !== 'undefined') { + var _lastSize = this.lastSize; + + // Handle the item getting hidden as a result of our positioning without glitching + // the classes in and out + width = _lastSize.width; + height = _lastSize.height; + } + + var targetSize = this.cache('target-bounds', function () { + return _this.getTargetBounds(); + }); + + var targetHeight = targetSize.height; + var targetWidth = targetSize.width; + + var allClasses = [this.getClass('pinned'), this.getClass('out-of-bounds')]; + + this.options.constraints.forEach(function (constraint) { + var outOfBoundsClass = constraint.outOfBoundsClass; + var pinnedClass = constraint.pinnedClass; + + if (outOfBoundsClass) { + allClasses.push(outOfBoundsClass); + } + if (pinnedClass) { + allClasses.push(pinnedClass); + } + }); + + allClasses.forEach(function (cls) { + ['left', 'top', 'right', 'bottom'].forEach(function (side) { + allClasses.push('' + cls + '-' + side); + }); + }); + + var addClasses = []; + + var tAttachment = extend({}, targetAttachment); + var eAttachment = extend({}, this.attachment); + + this.options.constraints.forEach(function (constraint) { + var to = constraint.to; + var attachment = constraint.attachment; + var pin = constraint.pin; + + if (typeof attachment === 'undefined') { + attachment = ''; + } + + var changeAttachX = undefined, + changeAttachY = undefined; + if (attachment.indexOf(' ') >= 0) { + var _attachment$split = attachment.split(' '); + + var _attachment$split2 = _slicedToArray(_attachment$split, 2); + + changeAttachY = _attachment$split2[0]; + changeAttachX = _attachment$split2[1]; + } else { + changeAttachX = changeAttachY = attachment; + } + + var bounds = getBoundingRect(_this, to); + + if (changeAttachY === 'target' || changeAttachY === 'both') { + if (top < bounds[1] && tAttachment.top === 'top') { + top += targetHeight; + tAttachment.top = 'bottom'; + } + + if (top + height > bounds[3] && tAttachment.top === 'bottom') { + top -= targetHeight; + tAttachment.top = 'top'; + } + } + + if (changeAttachY === 'together') { + if (top < bounds[1] && tAttachment.top === 'top') { + if (eAttachment.top === 'bottom') { + top += targetHeight; + tAttachment.top = 'bottom'; + + top += height; + eAttachment.top = 'top'; + } else if (eAttachment.top === 'top') { + top += targetHeight; + tAttachment.top = 'bottom'; + + top -= height; + eAttachment.top = 'bottom'; + } + } + + if (top + height > bounds[3] && tAttachment.top === 'bottom') { + if (eAttachment.top === 'top') { + top -= targetHeight; + tAttachment.top = 'top'; + + top -= height; + eAttachment.top = 'bottom'; + } else if (eAttachment.top === 'bottom') { + top -= targetHeight; + tAttachment.top = 'top'; + + top += height; + eAttachment.top = 'top'; + } + } + + if (tAttachment.top === 'middle') { + if (top + height > bounds[3] && eAttachment.top === 'top') { + top -= height; + eAttachment.top = 'bottom'; + } else if (top < bounds[1] && eAttachment.top === 'bottom') { + top += height; + eAttachment.top = 'top'; + } + } + } + + if (changeAttachX === 'target' || changeAttachX === 'both') { + if (left < bounds[0] && tAttachment.left === 'left') { + left += targetWidth; + tAttachment.left = 'right'; + } + + if (left + width > bounds[2] && tAttachment.left === 'right') { + left -= targetWidth; + tAttachment.left = 'left'; + } + } + + if (changeAttachX === 'together') { + if (left < bounds[0] && tAttachment.left === 'left') { + if (eAttachment.left === 'right') { + left += targetWidth; + tAttachment.left = 'right'; + + left += width; + eAttachment.left = 'left'; + } else if (eAttachment.left === 'left') { + left += targetWidth; + tAttachment.left = 'right'; + + left -= width; + eAttachment.left = 'right'; + } + } else if (left + width > bounds[2] && tAttachment.left === 'right') { + if (eAttachment.left === 'left') { + left -= targetWidth; + tAttachment.left = 'left'; + + left -= width; + eAttachment.left = 'right'; + } else if (eAttachment.left === 'right') { + left -= targetWidth; + tAttachment.left = 'left'; + + left += width; + eAttachment.left = 'left'; + } + } else if (tAttachment.left === 'center') { + if (left + width > bounds[2] && eAttachment.left === 'left') { + left -= width; + eAttachment.left = 'right'; + } else if (left < bounds[0] && eAttachment.left === 'right') { + left += width; + eAttachment.left = 'left'; + } + } + } + + if (changeAttachY === 'element' || changeAttachY === 'both') { + if (top < bounds[1] && eAttachment.top === 'bottom') { + top += height; + eAttachment.top = 'top'; + } + + if (top + height > bounds[3] && eAttachment.top === 'top') { + top -= height; + eAttachment.top = 'bottom'; + } + } + + if (changeAttachX === 'element' || changeAttachX === 'both') { + if (left < bounds[0] && eAttachment.left === 'right') { + left += width; + eAttachment.left = 'left'; + } + + if (left + width > bounds[2] && eAttachment.left === 'left') { + left -= width; + eAttachment.left = 'right'; + } + } + + if (typeof pin === 'string') { + pin = pin.split(',').map(function (p) { + return p.trim(); + }); + } else if (pin === true) { + pin = ['top', 'left', 'right', 'bottom']; + } + + pin = pin || []; + + var pinned = []; + var oob = []; + + if (top < bounds[1]) { + if (pin.indexOf('top') >= 0) { + top = bounds[1]; + pinned.push('top'); + } else { + oob.push('top'); + } + } + + if (top + height > bounds[3]) { + if (pin.indexOf('bottom') >= 0) { + top = bounds[3] - height; + pinned.push('bottom'); + } else { + oob.push('bottom'); + } + } + + if (left < bounds[0]) { + if (pin.indexOf('left') >= 0) { + left = bounds[0]; + pinned.push('left'); + } else { + oob.push('left'); + } + } + + if (left + width > bounds[2]) { + if (pin.indexOf('right') >= 0) { + left = bounds[2] - width; + pinned.push('right'); + } else { + oob.push('right'); + } + } + + if (pinned.length) { + (function () { + var pinnedClass = undefined; + if (typeof _this.options.pinnedClass !== 'undefined') { + pinnedClass = _this.options.pinnedClass; + } else { + pinnedClass = _this.getClass('pinned'); + } + + addClasses.push(pinnedClass); + pinned.forEach(function (side) { + addClasses.push('' + pinnedClass + '-' + side); + }); + })(); + } + + if (oob.length) { + (function () { + var oobClass = undefined; + if (typeof _this.options.outOfBoundsClass !== 'undefined') { + oobClass = _this.options.outOfBoundsClass; + } else { + oobClass = _this.getClass('out-of-bounds'); + } + + addClasses.push(oobClass); + oob.forEach(function (side) { + addClasses.push('' + oobClass + '-' + side); + }); + })(); + } + + if (pinned.indexOf('left') >= 0 || pinned.indexOf('right') >= 0) { + eAttachment.left = tAttachment.left = false; + } + if (pinned.indexOf('top') >= 0 || pinned.indexOf('bottom') >= 0) { + eAttachment.top = tAttachment.top = false; + } + + if (tAttachment.top !== targetAttachment.top || tAttachment.left !== targetAttachment.left || eAttachment.top !== _this.attachment.top || eAttachment.left !== _this.attachment.left) { + _this.updateAttachClasses(eAttachment, tAttachment); + } + }); + + defer(function () { + if (!(_this.options.addTargetClasses === false)) { + updateClasses(_this.target, addClasses, allClasses); + } + updateClasses(_this.element, addClasses, allClasses); + }); + + return { top: top, left: left }; + } +}); +/* globals TetherBase */ + +'use strict'; + +var _TetherBase$Utils = TetherBase.Utils; +var getBounds = _TetherBase$Utils.getBounds; +var updateClasses = _TetherBase$Utils.updateClasses; +var defer = _TetherBase$Utils.defer; + +TetherBase.modules.push({ + position: function position(_ref) { + var _this = this; + + var top = _ref.top; + var left = _ref.left; + + var _cache = this.cache('element-bounds', function () { + return getBounds(_this.element); + }); + + var height = _cache.height; + var width = _cache.width; + + var targetPos = this.getTargetBounds(); + + var bottom = top + height; + var right = left + width; + + var abutted = []; + if (top <= targetPos.bottom && bottom >= targetPos.top) { + ['left', 'right'].forEach(function (side) { + var targetPosSide = targetPos[side]; + if (targetPosSide === left || targetPosSide === right) { + abutted.push(side); + } + }); + } + + if (left <= targetPos.right && right >= targetPos.left) { + ['top', 'bottom'].forEach(function (side) { + var targetPosSide = targetPos[side]; + if (targetPosSide === top || targetPosSide === bottom) { + abutted.push(side); + } + }); + } + + var allClasses = []; + var addClasses = []; + + var sides = ['left', 'top', 'right', 'bottom']; + allClasses.push(this.getClass('abutted')); + sides.forEach(function (side) { + allClasses.push('' + _this.getClass('abutted') + '-' + side); + }); + + if (abutted.length) { + addClasses.push(this.getClass('abutted')); + } + + abutted.forEach(function (side) { + addClasses.push('' + _this.getClass('abutted') + '-' + side); + }); + + defer(function () { + if (!(_this.options.addTargetClasses === false)) { + updateClasses(_this.target, addClasses, allClasses); + } + updateClasses(_this.element, addClasses, allClasses); + }); + + return true; + } +}); +/* globals TetherBase */ + +'use strict'; + +function _slicedToArray(arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } } + +TetherBase.modules.push({ + position: function position(_ref) { + var top = _ref.top; + var left = _ref.left; + + if (!this.options.shift) { + return; + } + + var shift = this.options.shift; + if (typeof this.options.shift === 'function') { + shift = this.options.shift.call(this, { top: top, left: left }); + } + + var shiftTop = undefined, + shiftLeft = undefined; + if (typeof shift === 'string') { + shift = shift.split(' '); + shift[1] = shift[1] || shift[0]; + + var _shift = _slicedToArray(shift, 2); + + shiftTop = _shift[0]; + shiftLeft = _shift[1]; + + shiftTop = parseFloat(shiftTop, 10); + shiftLeft = parseFloat(shiftLeft, 10); + } else { + shiftTop = shift.top; + shiftLeft = shift.left; + } + + top += shiftTop; + left += shiftLeft; + + return { top: top, left: left }; + } +}); +return Tether; + +})); diff --git a/dist/js/tether.min.js b/dist/js/tether.min.js new file mode 100644 index 00000000..f7a1f934 --- /dev/null +++ b/dist/js/tether.min.js @@ -0,0 +1 @@ +!function(t,e){"function"==typeof define&&define.amd?define(e):"object"==typeof exports?module.exports=e(require,exports,module):t.Tether=e()}(this,function(t,e,o){"use strict";function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function n(t){var e=getComputedStyle(t),o=e.position;if("fixed"===o)return t;for(var i=t;i=i.parentNode;){var n=void 0;try{n=getComputedStyle(i)}catch(r){}if("undefined"==typeof n)return i;var s=n.overflow,a=n.overflowX,f=n.overflowY;if(/(auto|scroll)/.test(s+f+a)&&("absolute"!==o||["relative","absolute","fixed"].indexOf(n.position)>=0))return i}return document.body}function r(t){var e=void 0;t===document?(e=document,t=document.documentElement):e=t.ownerDocument;var o=e.documentElement,i={},n=t.getBoundingClientRect();for(var r in n)i[r]=n[r];var s=A(e);return i.top-=s.top,i.left-=s.left,"undefined"==typeof i.width&&(i.width=document.body.scrollWidth-i.left-i.right),"undefined"==typeof i.height&&(i.height=document.body.scrollHeight-i.top-i.bottom),i.top=i.top-o.clientTop,i.left=i.left-o.clientLeft,i.right=e.body.clientWidth-i.width-i.left,i.bottom=e.body.clientHeight-i.height-i.top,i}function s(t){return t.offsetParent||document.documentElement}function a(){var t=document.createElement("div");t.style.width="100%",t.style.height="200px";var e=document.createElement("div");f(e.style,{position:"absolute",top:0,left:0,pointerEvents:"none",visibility:"hidden",width:"200px",height:"150px",overflow:"hidden"}),e.appendChild(t),document.body.appendChild(e);var o=t.offsetWidth;e.style.overflow="scroll";var i=t.offsetWidth;o===i&&(i=e.clientWidth),document.body.removeChild(e);var n=o-i;return{width:n,height:n}}function f(){var t=void 0===arguments[0]?{}:arguments[0],e=[];return Array.prototype.push.apply(e,arguments),e.slice(1).forEach(function(e){if(e)for(var o in e)({}).hasOwnProperty.call(e,o)&&(t[o]=e[o])}),t}function h(t,e){if("undefined"!=typeof t.classList)e.split(" ").forEach(function(e){e.trim()&&t.classList.remove(e)});else{var o=new RegExp("(^| )"+e.split(" ").join("|")+"( |$)","gi"),i=p(t).replace(o," ");u(t,i)}}function l(t,e){if("undefined"!=typeof t.classList)e.split(" ").forEach(function(e){e.trim()&&t.classList.add(e)});else{h(t,e);var o=p(t)+" #{name}";u(t,o)}}function d(t,e){if("undefined"!=typeof t.classList)return t.classList.contains(e);var o=p(t);return new RegExp("(^| )"+e+"( |$)","gi").test(o)}function p(t){return t.className instanceof SVGAnimatedString?t.className.baseVal:t.className}function u(t,e){t.setAttribute("class",e)}function c(t,e,o){o.forEach(function(o){-1===e.indexOf(o)&&d(t,o)&&h(t,o)}),e.forEach(function(e){d(t,e)||l(t,e)})}function g(t,e){if(Array.isArray(t))return t;if(Symbol.iterator in Object(t)){var o=[],i=!0,n=!1,r=void 0;try{for(var s,a=t[Symbol.iterator]();!(i=(s=a.next()).done)&&(o.push(s.value),!e||o.length!==e);i=!0);}catch(f){n=!0,r=f}finally{try{!i&&a["return"]&&a["return"]()}finally{if(n)throw r}}return o}throw new TypeError("Invalid attempt to destructure non-iterable instance")}function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function m(t,e){var o=void 0===arguments[2]?1:arguments[2];return t+o>=e&&e>=t-o}function v(){return"undefined"!=typeof performance&&"undefined"!=typeof performance.now?performance.now():+new Date}function y(){for(var t=arguments.length,e=Array(t),o=0;t>o;o++)e[o]=arguments[o];var i={top:0,left:0};return e.forEach(function(t){var e=t.top,o=t.left;"string"==typeof e&&(e=parseFloat(e,10)),"string"==typeof o&&(o=parseFloat(o,10)),i.top+=e,i.left+=o}),i}function b(t,e){return"string"==typeof t.left&&-1!==t.left.indexOf("%")&&(t.left=parseFloat(t.left,10)/100*e.width),"string"==typeof t.top&&-1!==t.top.indexOf("%")&&(t.top=parseFloat(t.top,10)/100*e.height),t}function g(t,e){if(Array.isArray(t))return t;if(Symbol.iterator in Object(t)){var o=[],i=!0,n=!1,r=void 0;try{for(var s,a=t[Symbol.iterator]();!(i=(s=a.next()).done)&&(o.push(s.value),!e||o.length!==e);i=!0);}catch(f){n=!0,r=f}finally{try{!i&&a["return"]&&a["return"]()}finally{if(n)throw r}}return o}throw new TypeError("Invalid attempt to destructure non-iterable instance")}function w(t,e){return"scrollParent"===e?e=t.scrollParent:"window"===e&&(e=[pageXOffset,pageYOffset,innerWidth+pageXOffset,innerHeight+pageYOffset]),e===document&&(e=e.documentElement),"undefined"!=typeof e.nodeType&&!function(){var t=r(e),o=t,i=getComputedStyle(e);e=[o.left,o.top,t.width+o.left,t.height+o.top],U.forEach(function(t,o){t=t[0].toUpperCase()+t.substr(1),"Top"===t||"Left"===t?e[o]+=parseFloat(i["border"+t+"Width"]):e[o]-=parseFloat(i["border"+t+"Width"])})}(),e}function g(t,e){if(Array.isArray(t))return t;if(Symbol.iterator in Object(t)){var o=[],i=!0,n=!1,r=void 0;try{for(var s,a=t[Symbol.iterator]();!(i=(s=a.next()).done)&&(o.push(s.value),!e||o.length!==e);i=!0);}catch(f){n=!0,r=f}finally{try{!i&&a["return"]&&a["return"]()}finally{if(n)throw r}}return o}throw new TypeError("Invalid attempt to destructure non-iterable instance")}var C=function(){function t(t,e){for(var o=0;o1?e-1:0),i=1;e>i;i++)o[i-1]=arguments[i];if("undefined"!=typeof this.bindings&&this.bindings[t])for(var n=0;n16?(e=Math.min(e-16,250),void(o=setTimeout(n,250))):void("undefined"!=typeof t&&v()-t<10||("undefined"!=typeof o&&(clearTimeout(o),o=null),t=v(),_(),e=v()-t))};["resize","scroll","touchmove"].forEach(function(t){window.addEventListener(t,i)})}();var z={center:"center",left:"right",right:"left"},F={middle:"middle",top:"bottom",bottom:"top"},L={top:0,left:0,middle:"50%",center:"50%",bottom:"100%",right:"100%"},Y=function(t,e){var o=t.left,i=t.top;return"auto"===o&&(o=z[e.left]),"auto"===i&&(i=F[e.top]),{left:o,top:i}},H=function(t){var e=t.left,o=t.top;return"undefined"!=typeof L[t.left]&&(e=L[t.left]),"undefined"!=typeof L[t.top]&&(o=L[t.top]),{left:e,top:o}},X=function(t){var e=t.split(" "),o=g(e,2),i=o[0],n=o[1];return{top:i,left:n}},j=X,N=function(){function t(e){var o=this;i(this,t),this.position=this.position.bind(this),B.push(this),this.history=[],this.setOptions(e,!1),O.modules.forEach(function(t){"undefined"!=typeof t.initialize&&t.initialize.call(o)}),this.position()}return C(t,[{key:"getClass",value:function(){var t=void 0===arguments[0]?"":arguments[0],e=this.options.classes;return"undefined"!=typeof e&&e[t]?this.options.classes[t]:this.options.classPrefix?""+this.options.classPrefix+"-"+t:t}},{key:"setOptions",value:function(t){var e=this,o=void 0===arguments[1]?!0:arguments[1],i={offset:"0 0",targetOffset:"0 0",targetAttachment:"auto auto",classPrefix:"tether"};this.options=f(i,t);var r=this.options,s=r.element,a=r.target,h=r.targetModifier;if(this.element=s,this.target=a,this.targetModifier=h,"viewport"===this.target?(this.target=document.body,this.targetModifier="visible"):"scroll-handle"===this.target&&(this.target=document.body,this.targetModifier="scroll-handle"),["element","target"].forEach(function(t){if("undefined"==typeof e[t])throw new Error("Tether Error: Both element and target must be defined");"undefined"!=typeof e[t].jquery?e[t]=e[t][0]:"string"==typeof e[t]&&(e[t]=document.querySelector(e[t]))}),l(this.element,this.getClass("element")),this.options.addTargetClasses!==!1&&l(this.target,this.getClass("target")),!this.options.attachment)throw new Error("Tether Error: You must provide an attachment");this.targetAttachment=j(this.options.targetAttachment),this.attachment=j(this.options.attachment),this.offset=X(this.options.offset),this.targetOffset=X(this.options.targetOffset),"undefined"!=typeof this.scrollParent&&this.disable(),this.scrollParent="scroll-handle"===this.targetModifier?this.target:n(this.target),this.options.enabled!==!1&&this.enable(o)}},{key:"getTargetBounds",value:function(){if("undefined"==typeof this.targetModifier)return r(this.target);if("visible"===this.targetModifier){if(this.target===document.body)return{top:pageYOffset,left:pageXOffset,height:innerHeight,width:innerWidth};var t=r(this.target),e={height:t.height,width:t.width,top:t.top,left:t.left};return e.height=Math.min(e.height,t.height-(pageYOffset-t.top)),e.height=Math.min(e.height,t.height-(t.top+t.height-(pageYOffset+innerHeight))),e.height=Math.min(innerHeight,e.height),e.height-=2,e.width=Math.min(e.width,t.width-(pageXOffset-t.left)),e.width=Math.min(e.width,t.width-(t.left+t.width-(pageXOffset+innerWidth))),e.width=Math.min(innerWidth,e.width),e.width-=2,e.topo.clientWidth||[i.overflow,i.overflowX].indexOf("scroll")>=0||this.target!==document.body,s=0;n&&(s=15);var a=t.height-parseFloat(i.borderTopWidth)-parseFloat(i.borderBottomWidth)-s,e={width:15,height:.975*a*(a/o.scrollHeight),left:t.left+t.width-parseFloat(i.borderLeftWidth)-15},f=0;408>a&&this.target===document.body&&(f=-11e-5*Math.pow(a,2)-.00727*a+22.58),this.target!==document.body&&(e.height=Math.max(e.height,24));var h=this.target.scrollTop/(o.scrollHeight-a);return e.top=h*(a-e.height-f)+t.top+parseFloat(i.borderTopWidth),this.target===document.body&&(e.height=Math.max(e.height,24)),e}}},{key:"clearCache",value:function(){this._cache={}}},{key:"cache",value:function(t,e){return"undefined"==typeof this._cache&&(this._cache={}),"undefined"==typeof this._cache[t]&&(this._cache[t]=e.call(this)),this._cache[t]}},{key:"enable",value:function(){var t=void 0===arguments[0]?!0:arguments[0];this.options.addTargetClasses!==!1&&l(this.target,this.getClass("enabled")),l(this.element,this.getClass("enabled")),this.enabled=!0,this.scrollParent!==document&&this.scrollParent.addEventListener("scroll",this.position),t&&this.position()}},{key:"disable",value:function(){h(this.target,this.getClass("enabled")),h(this.element,this.getClass("enabled")),this.enabled=!1,"undefined"!=typeof this.scrollParent&&this.scrollParent.removeEventListener("scroll",this.position)}},{key:"destroy",value:function(){var t=this;this.disable(),B.forEach(function(e,o){return e===t?void B.splice(o,1):void 0})}},{key:"updateAttachClasses",value:function(t,e){var o=this;t=t||this.attachment,e=e||this.targetAttachment;var i=["left","top","bottom","right","middle","center"];"undefined"!=typeof this._addAttachClasses&&this._addAttachClasses.length&&this._addAttachClasses.splice(0,this._addAttachClasses.length),"undefined"==typeof this._addAttachClasses&&(this._addAttachClasses=[]);var n=this._addAttachClasses;t.top&&n.push(""+this.getClass("element-attached")+"-"+t.top),t.left&&n.push(""+this.getClass("element-attached")+"-"+t.left),e.top&&n.push(""+this.getClass("target-attached")+"-"+e.top),e.left&&n.push(""+this.getClass("target-attached")+"-"+e.left);var r=[];i.forEach(function(t){r.push(""+o.getClass("element-attached")+"-"+t),r.push(""+o.getClass("target-attached")+"-"+t)}),S(function(){"undefined"!=typeof o._addAttachClasses&&(c(o.element,o._addAttachClasses,r),o.options.addTargetClasses!==!1&&c(o.target,o._addAttachClasses,r),delete o._addAttachClasses)})}},{key:"position",value:function(){var t=this,e=void 0===arguments[0]?!0:arguments[0];if(this.enabled){this.clearCache();var o=Y(this.targetAttachment,this.attachment);this.updateAttachClasses(this.attachment,o);var i=this.cache("element-bounds",function(){return r(t.element)}),n=i.width,f=i.height;if(0===n&&0===f&&"undefined"!=typeof this.lastSize){var h=this.lastSize;n=h.width,f=h.height}else this.lastSize={width:n,height:f};var l=this.cache("target-bounds",function(){return t.getTargetBounds()}),d=l,p=b(H(this.attachment),{width:n,height:f}),u=b(H(o),d),c=b(this.offset,{width:n,height:f}),g=b(this.targetOffset,d);p=y(p,c),u=y(u,g);for(var m=l.left+u.left-p.left,v=l.top+u.top-p.top,w=0;wwindow.innerWidth&&(A=this.cache("scrollbar-size",a),x.viewport.bottom-=A.height),document.body.scrollHeight>window.innerHeight&&(A=this.cache("scrollbar-size",a),x.viewport.right-=A.width),(-1===["","static"].indexOf(document.body.style.position)||-1===["","static"].indexOf(document.body.parentElement.style.position))&&(x.page.bottom=document.body.scrollHeight-v-f,x.page.right=document.body.scrollWidth-m-n),"undefined"!=typeof this.options.optimizations&&this.options.optimizations.moveElement!==!1&&"undefined"==typeof this.targetModifier&&!function(){var e=t.cache("target-offsetparent",function(){return s(t.target)}),o=t.cache("target-offsetparent-bounds",function(){return r(e)}),i=getComputedStyle(e),n=o,a={};if(["Top","Left","Bottom","Right"].forEach(function(t){a[t.toLowerCase()]=parseFloat(i["border"+t+"Width"])}),o.right=document.body.scrollWidth-o.left-n.width+a.right,o.bottom=document.body.scrollHeight-o.top-n.height+a.bottom,x.page.top>=o.top+a.top&&x.page.bottom>=o.bottom&&x.page.left>=o.left+a.left&&x.page.right>=o.right){var f=e.scrollTop,h=e.scrollLeft;x.offset={top:x.page.top-o.top+f-a.top,left:x.page.left-o.left+h-a.left}}}(),this.move(x),this.history.unshift(x),this.history.length>3&&this.history.pop(),e&&W(),!0}}},{key:"move",value:function(t){var e=this;if("undefined"!=typeof this.element.parentNode){var o={};for(var i in t){o[i]={};for(var n in t[i]){for(var r=!1,a=0;a=0&&(v=parseFloat(v),g=parseFloat(g)),v!==g&&(c=!0,u[n]=g)}c&&S(function(){f(e.element.style,u)})}}}]),t}();N.modules=[],O.position=_;var R=f(N,O),P=O.Utils,r=P.getBounds,f=P.extend,c=P.updateClasses,S=P.defer,U=["left","top","right","bottom"];O.modules.push({position:function(t){var e=this,o=t.top,i=t.left,n=t.targetAttachment;if(!this.options.constraints)return!0;var s=this.cache("element-bounds",function(){return r(e.element)}),a=s.height,h=s.width;if(0===h&&0===a&&"undefined"!=typeof this.lastSize){var l=this.lastSize;h=l.width,a=l.height}var d=this.cache("target-bounds",function(){return e.getTargetBounds()}),p=d.height,u=d.width,m=[this.getClass("pinned"),this.getClass("out-of-bounds")];this.options.constraints.forEach(function(t){var e=t.outOfBoundsClass,o=t.pinnedClass;e&&m.push(e),o&&m.push(o)}),m.forEach(function(t){["left","top","right","bottom"].forEach(function(e){m.push(""+t+"-"+e)})});var v=[],y=f({},n),b=f({},this.attachment);return this.options.constraints.forEach(function(t){var r=t.to,s=t.attachment,f=t.pin;"undefined"==typeof s&&(s="");var l=void 0,d=void 0;if(s.indexOf(" ")>=0){var c=s.split(" "),m=g(c,2);d=m[0],l=m[1]}else l=d=s;var C=w(e,r);("target"===d||"both"===d)&&(oC[3]&&"bottom"===y.top&&(o-=p,y.top="top")),"together"===d&&(oC[3]&&"bottom"===y.top&&("top"===b.top?(o-=p,y.top="top",o-=a,b.top="bottom"):"bottom"===b.top&&(o-=p,y.top="top",o+=a,b.top="top")),"middle"===y.top&&(o+a>C[3]&&"top"===b.top?(o-=a,b.top="bottom"):oC[2]&&"right"===y.left&&(i-=u,y.left="left")),"together"===l&&(iC[2]&&"right"===y.left?"left"===b.left?(i-=u,y.left="left",i-=h,b.left="right"):"right"===b.left&&(i-=u,y.left="left",i+=h,b.left="left"):"center"===y.left&&(i+h>C[2]&&"left"===b.left?(i-=h,b.left="right"):iC[3]&&"top"===b.top&&(o-=a,b.top="bottom")),("element"===l||"both"===l)&&(iC[2]&&"left"===b.left&&(i-=h,b.left="right")),"string"==typeof f?f=f.split(",").map(function(t){return t.trim()}):f===!0&&(f=["top","left","right","bottom"]),f=f||[];var O=[],E=[];o=0?(o=C[1],O.push("top")):E.push("top")),o+a>C[3]&&(f.indexOf("bottom")>=0?(o=C[3]-a,O.push("bottom")):E.push("bottom")),i=0?(i=C[0],O.push("left")):E.push("left")),i+h>C[2]&&(f.indexOf("right")>=0?(i=C[2]-h,O.push("right")):E.push("right")),O.length&&!function(){var t=void 0;t="undefined"!=typeof e.options.pinnedClass?e.options.pinnedClass:e.getClass("pinned"),v.push(t),O.forEach(function(e){v.push(""+t+"-"+e)})}(),E.length&&!function(){var t=void 0;t="undefined"!=typeof e.options.outOfBoundsClass?e.options.outOfBoundsClass:e.getClass("out-of-bounds"),v.push(t),E.forEach(function(e){v.push(""+t+"-"+e)})}(),(O.indexOf("left")>=0||O.indexOf("right")>=0)&&(b.left=y.left=!1),(O.indexOf("top")>=0||O.indexOf("bottom")>=0)&&(b.top=y.top=!1),(y.top!==n.top||y.left!==n.left||b.top!==e.attachment.top||b.left!==e.attachment.left)&&e.updateAttachClasses(b,y)}),S(function(){e.options.addTargetClasses!==!1&&c(e.target,v,m),c(e.element,v,m)}),{top:o,left:i}}});var P=O.Utils,r=P.getBounds,c=P.updateClasses,S=P.defer;return O.modules.push({position:function(t){var e=this,o=t.top,i=t.left,n=this.cache("element-bounds",function(){return r(e.element)}),s=n.height,a=n.width,f=this.getTargetBounds(),h=o+s,l=i+a,d=[];o<=f.bottom&&h>=f.top&&["left","right"].forEach(function(t){var e=f[t];(e===i||e===l)&&d.push(t)}),i<=f.right&&l>=f.left&&["top","bottom"].forEach(function(t){var e=f[t];(e===o||e===h)&&d.push(t)});var p=[],u=[],g=["left","top","right","bottom"];return p.push(this.getClass("abutted")),g.forEach(function(t){p.push(""+e.getClass("abutted")+"-"+t)}),d.length&&u.push(this.getClass("abutted")),d.forEach(function(t){u.push(""+e.getClass("abutted")+"-"+t)}),S(function(){e.options.addTargetClasses!==!1&&c(e.target,u,p),c(e.element,u,p)}),!0}}),O.modules.push({position:function(t){var e=t.top,o=t.left;if(this.options.shift){var i=this.options.shift;"function"==typeof this.options.shift&&(i=this.options.shift.call(this,{top:e,left:o}));var n=void 0,r=void 0;if("string"==typeof i){i=i.split(" "),i[1]=i[1]||i[0];var s=g(i,2);n=s[0],r=s[1],n=parseFloat(n,10),r=parseFloat(r,10)}else n=i.top,r=i.left;return e+=n,o+=r,{top:e,left:o}}}}),R}); \ No newline at end of file diff --git a/gulpfile.coffee b/gulpfile.coffee deleted file mode 100644 index 972f22f6..00000000 --- a/gulpfile.coffee +++ /dev/null @@ -1,63 +0,0 @@ -gulp = require('gulp') -coffee = require('gulp-coffee') -concat = require('gulp-concat') -header = require('gulp-header') -prefixer = require('gulp-autoprefixer') -rename = require('gulp-rename') -sass = require('gulp-sass') -uglify = require('gulp-uglify') -wrap = require('gulp-wrap-umd') - -pkg = require('./package.json') -banner = "/*! #{ pkg.name } #{ pkg.version } */\n" - -gulp.task 'coffee', -> - gulp.src('./coffee/*') - .pipe(coffee()) - .pipe(gulp.dest('./js/')) - - gulp.src('./docs/coffee/*') - .pipe(coffee()) - .pipe(gulp.dest('./docs/js/')) - - gulp.src('./docs/welcome/coffee/*') - .pipe(coffee()) - .pipe(gulp.dest('./docs/welcome/js/')) - -gulp.task 'concat', -> - gulp.src(['./js/utils.js', './js/tether.js', './js/constraint.js', './js/abutment.js', './js/shift.js']) - .pipe(concat('tether.js')) - .pipe(wrap( - namespace: 'Tether' - exports: 'this.Tether' - )) - .pipe(header(banner)) - .pipe(gulp.dest('./')) - -gulp.task 'uglify', -> - gulp.src('./tether.js') - .pipe(uglify()) - .pipe(header(banner)) - .pipe(rename('tether.min.js')) - .pipe(gulp.dest('./')) - -gulp.task 'js', -> - gulp.run 'coffee', -> - gulp.run 'concat', -> - gulp.run 'uglify', -> - -gulp.task 'sass', -> - for path in ['', 'docs/', 'docs/welcome/'] - gulp.src("./#{ path }sass/*") - .pipe(sass()) - .pipe(prefixer()) - .pipe(gulp.dest("./#{ path }css")) - -gulp.task 'default', -> - gulp.run 'js', 'sass' - - gulp.watch './**/*.coffee', -> - gulp.run 'js' - - gulp.watch './**/*.sass', -> - gulp.run 'sass' diff --git a/gulpfile.js b/gulpfile.js index cfbdf871..54932904 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,2 +1,102 @@ -require('coffee-script') -require('./gulpfile.coffee') +var del = require('del'); +var gulp = require('gulp'); +var babel = require('gulp-babel'); +var bump = require('gulp-bump'); +var concat = require('gulp-concat'); +var filter = require('gulp-filter'); +var header = require('gulp-header'); +var minify = require('gulp-minify-css'); +var plumber = require('gulp-plumber'); +var prefixer = require('gulp-autoprefixer'); +var rename = require('gulp-rename'); +var uglify = require('gulp-uglify'); +var sass = require('gulp-sass'); +var tagVersion = require('gulp-tag-version'); +var umd = require('gulp-wrap-umd'); + +// Variables +var distDir = './dist'; +var pkg = require('./package.json'); +var banner = ['/*!', pkg.name, pkg.version, '*/\n'].join(' '); +var umdOptions = { + exports: 'Tether', + namespace: 'Tether' +}; + + +// Clean +gulp.task('clean', function() { + del.sync([distDir]); +}); + + +// Javascript +gulp.task('js', function() { + gulp.src([ + './src/js/utils.js', + './src/js/tether.js', + './src/js/constraint.js', + './src/js/abutment.js', + './src/js/shift.js' + ]) + .pipe(plumber()) + .pipe(babel()) + .pipe(concat('tether.js')) + .pipe(umd(umdOptions)) + .pipe(header(banner)) + + // Original + .pipe(gulp.dest(distDir + '/js')) + + // Minified + .pipe(uglify()) + .pipe(rename({suffix: '.min'})) + .pipe(gulp.dest(distDir + '/js')); +}); + + +// CSS +gulp.task('css', function() { + gulp.src('./src/css/**/*.sass') + .pipe(plumber()) + .pipe(sass()) + .pipe(prefixer()) + + // Original + .pipe(gulp.dest(distDir + '/css')) + + // Minified + .pipe(minify()) + .pipe(rename({suffix: '.min'})) + .pipe(gulp.dest(distDir + '/css')); +}); + + +// Version bump +var VERSIONS = ['patch', 'minor', 'major']; +for (var i = 0; i < VERSIONS.length; ++i){ + (function(version) { + var pkgFilter = filter('package.json'); + gulp.task('version:' + version, function() { + gulp.src(['package.json', 'bower.json', 'component.json']) + .pipe(bump({type: version})) + .pipe(pkgFilter) + .pipe(tagVersion()) + .pipe(pkgFilter.restore()) + .pipe(gulp.dest('.')); + }); + })(VERSIONS[i]); +} + + +// Watch +gulp.task('watch', ['js', 'css'], function() { + gulp.watch('./src/js/**/*', ['js']); + gulp.watch('./src/css/**/*', ['css']); +}); + + +// Defaults +gulp.task('build', ['js', 'css']); +gulp.task('default', ['build']); + diff --git a/js/abutment.js b/js/abutment.js deleted file mode 100644 index f3a213f4..00000000 --- a/js/abutment.js +++ /dev/null @@ -1,61 +0,0 @@ -(function() { - var defer, getBounds, updateClasses, _ref; - - _ref = this.Tether.Utils, getBounds = _ref.getBounds, updateClasses = _ref.updateClasses, defer = _ref.defer; - - this.Tether.modules.push({ - position: function(_arg) { - var abutted, addClasses, allClasses, bottom, height, left, right, side, sides, targetPos, top, width, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref1, _ref2, _ref3, _ref4, _ref5, - _this = this; - top = _arg.top, left = _arg.left; - _ref1 = this.cache('element-bounds', function() { - return getBounds(_this.element); - }), height = _ref1.height, width = _ref1.width; - targetPos = this.getTargetBounds(); - bottom = top + height; - right = left + width; - abutted = []; - if (top <= targetPos.bottom && bottom >= targetPos.top) { - _ref2 = ['left', 'right']; - for (_i = 0, _len = _ref2.length; _i < _len; _i++) { - side = _ref2[_i]; - if ((_ref3 = targetPos[side]) === left || _ref3 === right) { - abutted.push(side); - } - } - } - if (left <= targetPos.right && right >= targetPos.left) { - _ref4 = ['top', 'bottom']; - for (_j = 0, _len1 = _ref4.length; _j < _len1; _j++) { - side = _ref4[_j]; - if ((_ref5 = targetPos[side]) === top || _ref5 === bottom) { - abutted.push(side); - } - } - } - allClasses = []; - addClasses = []; - sides = ['left', 'top', 'right', 'bottom']; - allClasses.push(this.getClass('abutted')); - for (_k = 0, _len2 = sides.length; _k < _len2; _k++) { - side = sides[_k]; - allClasses.push("" + (this.getClass('abutted')) + "-" + side); - } - if (abutted.length) { - addClasses.push(this.getClass('abutted')); - } - for (_l = 0, _len3 = abutted.length; _l < _len3; _l++) { - side = abutted[_l]; - addClasses.push("" + (this.getClass('abutted')) + "-" + side); - } - defer(function() { - if (_this.options.addTargetClasses !== false) { - updateClasses(_this.target, addClasses, allClasses); - } - return updateClasses(_this.element, addClasses, allClasses); - }); - return true; - } - }); - -}).call(this); diff --git a/js/constraint.js b/js/constraint.js deleted file mode 100644 index 08d2919d..00000000 --- a/js/constraint.js +++ /dev/null @@ -1,310 +0,0 @@ -(function() { - var BOUNDS_FORMAT, MIRROR_ATTACH, defer, extend, getBoundingRect, getBounds, getOuterSize, getSize, updateClasses, _ref, - __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; - - _ref = this.Tether.Utils, getOuterSize = _ref.getOuterSize, getBounds = _ref.getBounds, getSize = _ref.getSize, extend = _ref.extend, updateClasses = _ref.updateClasses, defer = _ref.defer; - - MIRROR_ATTACH = { - left: 'right', - right: 'left', - top: 'bottom', - bottom: 'top', - middle: 'middle' - }; - - BOUNDS_FORMAT = ['left', 'top', 'right', 'bottom']; - - getBoundingRect = function(tether, to) { - var i, pos, side, size, style, _i, _len; - if (to === 'scrollParent') { - to = tether.scrollParent; - } else if (to === 'window') { - to = [pageXOffset, pageYOffset, innerWidth + pageXOffset, innerHeight + pageYOffset]; - } - if (to === document) { - to = to.documentElement; - } - if (to.nodeType != null) { - pos = size = getBounds(to); - style = getComputedStyle(to); - to = [pos.left, pos.top, size.width + pos.left, size.height + pos.top]; - for (i = _i = 0, _len = BOUNDS_FORMAT.length; _i < _len; i = ++_i) { - side = BOUNDS_FORMAT[i]; - side = side[0].toUpperCase() + side.substr(1); - if (side === 'Top' || side === 'Left') { - to[i] += parseFloat(style["border" + side + "Width"]); - } else { - to[i] -= parseFloat(style["border" + side + "Width"]); - } - } - } - return to; - }; - - this.Tether.modules.push({ - position: function(_arg) { - var addClasses, allClasses, attachment, bounds, changeAttachX, changeAttachY, cls, constraint, eAttachment, height, left, oob, oobClass, p, pin, pinned, pinnedClass, removeClass, side, tAttachment, targetAttachment, targetHeight, targetSize, targetWidth, to, top, width, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _m, _n, _ref1, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7, _ref8, - _this = this; - top = _arg.top, left = _arg.left, targetAttachment = _arg.targetAttachment; - if (!this.options.constraints) { - return true; - } - removeClass = function(prefix) { - var side, _i, _len, _results; - _this.removeClass(prefix); - _results = []; - for (_i = 0, _len = BOUNDS_FORMAT.length; _i < _len; _i++) { - side = BOUNDS_FORMAT[_i]; - _results.push(_this.removeClass("" + prefix + "-" + side)); - } - return _results; - }; - _ref1 = this.cache('element-bounds', function() { - return getBounds(_this.element); - }), height = _ref1.height, width = _ref1.width; - if (width === 0 && height === 0 && (this.lastSize != null)) { - _ref2 = this.lastSize, width = _ref2.width, height = _ref2.height; - } - targetSize = this.cache('target-bounds', function() { - return _this.getTargetBounds(); - }); - targetHeight = targetSize.height; - targetWidth = targetSize.width; - tAttachment = {}; - eAttachment = {}; - allClasses = [this.getClass('pinned'), this.getClass('out-of-bounds')]; - _ref3 = this.options.constraints; - for (_i = 0, _len = _ref3.length; _i < _len; _i++) { - constraint = _ref3[_i]; - if (constraint.outOfBoundsClass) { - allClasses.push(constraint.outOfBoundsClass); - } - if (constraint.pinnedClass) { - allClasses.push(constraint.pinnedClass); - } - } - for (_j = 0, _len1 = allClasses.length; _j < _len1; _j++) { - cls = allClasses[_j]; - _ref4 = ['left', 'top', 'right', 'bottom']; - for (_k = 0, _len2 = _ref4.length; _k < _len2; _k++) { - side = _ref4[_k]; - allClasses.push("" + cls + "-" + side); - } - } - addClasses = []; - tAttachment = extend({}, targetAttachment); - eAttachment = extend({}, this.attachment); - _ref5 = this.options.constraints; - for (_l = 0, _len3 = _ref5.length; _l < _len3; _l++) { - constraint = _ref5[_l]; - to = constraint.to, attachment = constraint.attachment, pin = constraint.pin; - if (attachment == null) { - attachment = ''; - } - if (__indexOf.call(attachment, ' ') >= 0) { - _ref6 = attachment.split(' '), changeAttachY = _ref6[0], changeAttachX = _ref6[1]; - } else { - changeAttachX = changeAttachY = attachment; - } - bounds = getBoundingRect(this, to); - if (changeAttachY === 'target' || changeAttachY === 'both') { - if (top < bounds[1] && tAttachment.top === 'top') { - top += targetHeight; - tAttachment.top = 'bottom'; - } - if (top + height > bounds[3] && tAttachment.top === 'bottom') { - top -= targetHeight; - tAttachment.top = 'top'; - } - } - if (changeAttachY === 'together') { - if (top < bounds[1] && tAttachment.top === 'top') { - if (eAttachment.top === 'bottom') { - top += targetHeight; - tAttachment.top = 'bottom'; - top += height; - eAttachment.top = 'top'; - } else if (eAttachment.top === 'top') { - top += targetHeight; - tAttachment.top = 'bottom'; - top -= height; - eAttachment.top = 'bottom'; - } - } - if (top + height > bounds[3] && tAttachment.top === 'bottom') { - if (eAttachment.top === 'top') { - top -= targetHeight; - tAttachment.top = 'top'; - top -= height; - eAttachment.top = 'bottom'; - } else if (eAttachment.top === 'bottom') { - top -= targetHeight; - tAttachment.top = 'top'; - top += height; - eAttachment.top = 'top'; - } - } - if (tAttachment.top === 'middle') { - if (top + height > bounds[3] && eAttachment.top === 'top') { - top -= height; - eAttachment.top = 'bottom'; - } else if (top < bounds[1] && eAttachment.top === 'bottom') { - top += height; - eAttachment.top = 'top'; - } - } - } - if (changeAttachX === 'target' || changeAttachX === 'both') { - if (left < bounds[0] && tAttachment.left === 'left') { - left += targetWidth; - tAttachment.left = 'right'; - } - if (left + width > bounds[2] && tAttachment.left === 'right') { - left -= targetWidth; - tAttachment.left = 'left'; - } - } - if (changeAttachX === 'together') { - if (left < bounds[0] && tAttachment.left === 'left') { - if (eAttachment.left === 'right') { - left += targetWidth; - tAttachment.left = 'right'; - left += width; - eAttachment.left = 'left'; - } else if (eAttachment.left === 'left') { - left += targetWidth; - tAttachment.left = 'right'; - left -= width; - eAttachment.left = 'right'; - } - } else if (left + width > bounds[2] && tAttachment.left === 'right') { - if (eAttachment.left === 'left') { - left -= targetWidth; - tAttachment.left = 'left'; - left -= width; - eAttachment.left = 'right'; - } else if (eAttachment.left === 'right') { - left -= targetWidth; - tAttachment.left = 'left'; - left += width; - eAttachment.left = 'left'; - } - } else if (tAttachment.left === 'center') { - if (left + width > bounds[2] && eAttachment.left === 'left') { - left -= width; - eAttachment.left = 'right'; - } else if (left < bounds[0] && eAttachment.left === 'right') { - left += width; - eAttachment.left = 'left'; - } - } - } - if (changeAttachY === 'element' || changeAttachY === 'both') { - if (top < bounds[1] && eAttachment.top === 'bottom') { - top += height; - eAttachment.top = 'top'; - } - if (top + height > bounds[3] && eAttachment.top === 'top') { - top -= height; - eAttachment.top = 'bottom'; - } - } - if (changeAttachX === 'element' || changeAttachX === 'both') { - if (left < bounds[0] && eAttachment.left === 'right') { - left += width; - eAttachment.left = 'left'; - } - if (left + width > bounds[2] && eAttachment.left === 'left') { - left -= width; - eAttachment.left = 'right'; - } - } - if (typeof pin === 'string') { - pin = (function() { - var _len4, _m, _ref7, _results; - _ref7 = pin.split(','); - _results = []; - for (_m = 0, _len4 = _ref7.length; _m < _len4; _m++) { - p = _ref7[_m]; - _results.push(p.trim()); - } - return _results; - })(); - } else if (pin === true) { - pin = ['top', 'left', 'right', 'bottom']; - } - pin || (pin = []); - pinned = []; - oob = []; - if (top < bounds[1]) { - if (__indexOf.call(pin, 'top') >= 0) { - top = bounds[1]; - pinned.push('top'); - } else { - oob.push('top'); - } - } - if (top + height > bounds[3]) { - if (__indexOf.call(pin, 'bottom') >= 0) { - top = bounds[3] - height; - pinned.push('bottom'); - } else { - oob.push('bottom'); - } - } - if (left < bounds[0]) { - if (__indexOf.call(pin, 'left') >= 0) { - left = bounds[0]; - pinned.push('left'); - } else { - oob.push('left'); - } - } - if (left + width > bounds[2]) { - if (__indexOf.call(pin, 'right') >= 0) { - left = bounds[2] - width; - pinned.push('right'); - } else { - oob.push('right'); - } - } - if (pinned.length) { - pinnedClass = (_ref7 = this.options.pinnedClass) != null ? _ref7 : this.getClass('pinned'); - addClasses.push(pinnedClass); - for (_m = 0, _len4 = pinned.length; _m < _len4; _m++) { - side = pinned[_m]; - addClasses.push("" + pinnedClass + "-" + side); - } - } - if (oob.length) { - oobClass = (_ref8 = this.options.outOfBoundsClass) != null ? _ref8 : this.getClass('out-of-bounds'); - addClasses.push(oobClass); - for (_n = 0, _len5 = oob.length; _n < _len5; _n++) { - side = oob[_n]; - addClasses.push("" + oobClass + "-" + side); - } - } - if (__indexOf.call(pinned, 'left') >= 0 || __indexOf.call(pinned, 'right') >= 0) { - eAttachment.left = tAttachment.left = false; - } - if (__indexOf.call(pinned, 'top') >= 0 || __indexOf.call(pinned, 'bottom') >= 0) { - eAttachment.top = tAttachment.top = false; - } - if (tAttachment.top !== targetAttachment.top || tAttachment.left !== targetAttachment.left || eAttachment.top !== this.attachment.top || eAttachment.left !== this.attachment.left) { - this.updateAttachClasses(eAttachment, tAttachment); - } - } - defer(function() { - if (_this.options.addTargetClasses !== false) { - updateClasses(_this.target, addClasses, allClasses); - } - return updateClasses(_this.element, addClasses, allClasses); - }); - return { - top: top, - left: left - }; - } - }); - -}).call(this); diff --git a/js/markAttachment.js b/js/markAttachment.js deleted file mode 100644 index a6d8f80b..00000000 --- a/js/markAttachment.js +++ /dev/null @@ -1,46 +0,0 @@ -(function() { - this.Tether.modules.push({ - initialize: function() { - var dot, el, type, _i, _len, _ref, _results; - this.markers = {}; - _ref = ['target', 'element']; - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - type = _ref[_i]; - el = document.createElement('div'); - el.className = this.getClass("" + type + "-marker"); - dot = document.createElement('div'); - dot.className = this.getClass('marker-dot'); - el.appendChild(dot); - this[type].appendChild(el); - _results.push(this.markers[type] = { - dot: dot, - el: el - }); - } - return _results; - }, - position: function(_arg) { - var manualOffset, manualTargetOffset, offset, offsets, side, type, val; - manualOffset = _arg.manualOffset, manualTargetOffset = _arg.manualTargetOffset; - offsets = { - element: manualOffset, - target: manualTargetOffset - }; - for (type in offsets) { - offset = offsets[type]; - for (side in offset) { - val = offset[side]; - if (typeof val !== 'string' || (val.indexOf('%') === -1 && val.indexOf('px') === -1)) { - val += 'px'; - } - if (this.markers[type].dot.style[side] !== val) { - this.markers[type].dot.style[side] = val; - } - } - } - return true; - } - }); - -}).call(this); diff --git a/js/shift.js b/js/shift.js deleted file mode 100644 index 58b935f6..00000000 --- a/js/shift.js +++ /dev/null @@ -1,38 +0,0 @@ -(function() { - this.Tether.modules.push({ - position: function(_arg) { - var left, result, shift, shiftLeft, shiftTop, top, _ref; - top = _arg.top, left = _arg.left; - if (!this.options.shift) { - return; - } - result = function(val) { - if (typeof val === 'function') { - return val.call(this, { - top: top, - left: left - }); - } else { - return val; - } - }; - shift = result(this.options.shift); - if (typeof shift === 'string') { - shift = shift.split(' '); - shift[1] || (shift[1] = shift[0]); - shiftTop = shift[0], shiftLeft = shift[1]; - shiftTop = parseFloat(shiftTop, 10); - shiftLeft = parseFloat(shiftLeft, 10); - } else { - _ref = [shift.top, shift.left], shiftTop = _ref[0], shiftLeft = _ref[1]; - } - top += shiftTop; - left += shiftLeft; - return { - top: top, - left: left - }; - } - }); - -}).call(this); diff --git a/js/tether.js b/js/tether.js deleted file mode 100644 index b053126e..00000000 --- a/js/tether.js +++ /dev/null @@ -1,692 +0,0 @@ -(function() { - var MIRROR_LR, MIRROR_TB, OFFSET_MAP, Tether, addClass, addOffset, attachmentToOffset, autoToFixedAttachment, defer, extend, flush, getBounds, getOffsetParent, getOuterSize, getScrollBarSize, getScrollParent, getSize, now, offsetToPx, parseAttachment, parseOffset, position, removeClass, tethers, transformKey, updateClasses, within, _Tether, _ref, - __slice = [].slice, - __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; - - if (this.Tether == null) { - throw new Error("You must include the utils.js file before tether.js"); - } - - Tether = this.Tether; - - _ref = Tether.Utils, getScrollParent = _ref.getScrollParent, getSize = _ref.getSize, getOuterSize = _ref.getOuterSize, getBounds = _ref.getBounds, getOffsetParent = _ref.getOffsetParent, extend = _ref.extend, addClass = _ref.addClass, removeClass = _ref.removeClass, updateClasses = _ref.updateClasses, defer = _ref.defer, flush = _ref.flush, getScrollBarSize = _ref.getScrollBarSize; - - within = function(a, b, diff) { - if (diff == null) { - diff = 1; - } - return (a + diff >= b && b >= a - diff); - }; - - transformKey = (function() { - var el, key, _i, _len, _ref1; - el = document.createElement('div'); - _ref1 = ['transform', 'webkitTransform', 'OTransform', 'MozTransform', 'msTransform']; - for (_i = 0, _len = _ref1.length; _i < _len; _i++) { - key = _ref1[_i]; - if (el.style[key] !== void 0) { - return key; - } - } - })(); - - tethers = []; - - position = function() { - var tether, _i, _len; - for (_i = 0, _len = tethers.length; _i < _len; _i++) { - tether = tethers[_i]; - tether.position(false); - } - return flush(); - }; - - now = function() { - var _ref1; - return (_ref1 = typeof performance !== "undefined" && performance !== null ? typeof performance.now === "function" ? performance.now() : void 0 : void 0) != null ? _ref1 : +(new Date); - }; - - (function() { - var event, lastCall, lastDuration, pendingTimeout, tick, _i, _len, _ref1, _results; - lastCall = null; - lastDuration = null; - pendingTimeout = null; - tick = function() { - if ((lastDuration != null) && lastDuration > 16) { - lastDuration = Math.min(lastDuration - 16, 250); - pendingTimeout = setTimeout(tick, 250); - return; - } - if ((lastCall != null) && (now() - lastCall) < 10) { - return; - } - if (pendingTimeout != null) { - clearTimeout(pendingTimeout); - pendingTimeout = null; - } - lastCall = now(); - position(); - return lastDuration = now() - lastCall; - }; - _ref1 = ['resize', 'scroll', 'touchmove']; - _results = []; - for (_i = 0, _len = _ref1.length; _i < _len; _i++) { - event = _ref1[_i]; - _results.push(window.addEventListener(event, tick)); - } - return _results; - })(); - - MIRROR_LR = { - center: 'center', - left: 'right', - right: 'left' - }; - - MIRROR_TB = { - middle: 'middle', - top: 'bottom', - bottom: 'top' - }; - - OFFSET_MAP = { - top: 0, - left: 0, - middle: '50%', - center: '50%', - bottom: '100%', - right: '100%' - }; - - autoToFixedAttachment = function(attachment, relativeToAttachment) { - var left, top; - left = attachment.left, top = attachment.top; - if (left === 'auto') { - left = MIRROR_LR[relativeToAttachment.left]; - } - if (top === 'auto') { - top = MIRROR_TB[relativeToAttachment.top]; - } - return { - left: left, - top: top - }; - }; - - attachmentToOffset = function(attachment) { - var _ref1, _ref2; - return { - left: (_ref1 = OFFSET_MAP[attachment.left]) != null ? _ref1 : attachment.left, - top: (_ref2 = OFFSET_MAP[attachment.top]) != null ? _ref2 : attachment.top - }; - }; - - addOffset = function() { - var left, offsets, out, top, _i, _len, _ref1; - offsets = 1 <= arguments.length ? __slice.call(arguments, 0) : []; - out = { - top: 0, - left: 0 - }; - for (_i = 0, _len = offsets.length; _i < _len; _i++) { - _ref1 = offsets[_i], top = _ref1.top, left = _ref1.left; - if (typeof top === 'string') { - top = parseFloat(top, 10); - } - if (typeof left === 'string') { - left = parseFloat(left, 10); - } - out.top += top; - out.left += left; - } - return out; - }; - - offsetToPx = function(offset, size) { - if (typeof offset.left === 'string' && offset.left.indexOf('%') !== -1) { - offset.left = parseFloat(offset.left, 10) / 100 * size.width; - } - if (typeof offset.top === 'string' && offset.top.indexOf('%') !== -1) { - offset.top = parseFloat(offset.top, 10) / 100 * size.height; - } - return offset; - }; - - parseAttachment = parseOffset = function(value) { - var left, top, _ref1; - _ref1 = value.split(' '), top = _ref1[0], left = _ref1[1]; - return { - top: top, - left: left - }; - }; - - _Tether = (function() { - _Tether.modules = []; - - function _Tether(options) { - this.position = __bind(this.position, this); - var module, _i, _len, _ref1, _ref2; - tethers.push(this); - this.history = []; - this.setOptions(options, false); - _ref1 = Tether.modules; - for (_i = 0, _len = _ref1.length; _i < _len; _i++) { - module = _ref1[_i]; - if ((_ref2 = module.initialize) != null) { - _ref2.call(this); - } - } - this.position(); - } - - _Tether.prototype.getClass = function(key) { - var _ref1, _ref2; - if ((_ref1 = this.options.classes) != null ? _ref1[key] : void 0) { - return this.options.classes[key]; - } else if (((_ref2 = this.options.classes) != null ? _ref2[key] : void 0) !== false) { - if (this.options.classPrefix) { - return "" + this.options.classPrefix + "-" + key; - } else { - return key; - } - } else { - return ''; - } - }; - - _Tether.prototype.setOptions = function(options, position) { - var defaults, key, _i, _len, _ref1, _ref2; - this.options = options; - if (position == null) { - position = true; - } - defaults = { - offset: '0 0', - targetOffset: '0 0', - targetAttachment: 'auto auto', - classPrefix: 'tether' - }; - this.options = extend(defaults, this.options); - _ref1 = this.options, this.element = _ref1.element, this.target = _ref1.target, this.targetModifier = _ref1.targetModifier; - if (this.target === 'viewport') { - this.target = document.body; - this.targetModifier = 'visible'; - } else if (this.target === 'scroll-handle') { - this.target = document.body; - this.targetModifier = 'scroll-handle'; - } - _ref2 = ['element', 'target']; - for (_i = 0, _len = _ref2.length; _i < _len; _i++) { - key = _ref2[_i]; - if (this[key] == null) { - throw new Error("Tether Error: Both element and target must be defined"); - } - if (this[key].jquery != null) { - this[key] = this[key][0]; - } else if (typeof this[key] === 'string') { - this[key] = document.querySelector(this[key]); - } - } - addClass(this.element, this.getClass('element')); - if (this.options.addTargetClasses !== false) { - addClass(this.target, this.getClass('target')); - } - if (!this.options.attachment) { - throw new Error("Tether Error: You must provide an attachment"); - } - this.targetAttachment = parseAttachment(this.options.targetAttachment); - this.attachment = parseAttachment(this.options.attachment); - this.offset = parseOffset(this.options.offset); - this.targetOffset = parseOffset(this.options.targetOffset); - if (this.scrollParent != null) { - this.disable(); - } - if (this.targetModifier === 'scroll-handle') { - this.scrollParent = this.target; - } else { - this.scrollParent = getScrollParent(this.target); - } - if (this.options.enabled !== false) { - return this.enable(position); - } - }; - - _Tether.prototype.getTargetBounds = function() { - var bounds, fitAdj, hasBottomScroll, height, out, scrollBottom, scrollPercentage, style, target; - if (this.targetModifier != null) { - switch (this.targetModifier) { - case 'visible': - if (this.target === document.body) { - return { - top: pageYOffset, - left: pageXOffset, - height: innerHeight, - width: innerWidth - }; - } else { - bounds = getBounds(this.target); - out = { - height: bounds.height, - width: bounds.width, - top: bounds.top, - left: bounds.left - }; - out.height = Math.min(out.height, bounds.height - (pageYOffset - bounds.top)); - out.height = Math.min(out.height, bounds.height - ((bounds.top + bounds.height) - (pageYOffset + innerHeight))); - out.height = Math.min(innerHeight, out.height); - out.height -= 2; - out.width = Math.min(out.width, bounds.width - (pageXOffset - bounds.left)); - out.width = Math.min(out.width, bounds.width - ((bounds.left + bounds.width) - (pageXOffset + innerWidth))); - out.width = Math.min(innerWidth, out.width); - out.width -= 2; - if (out.top < pageYOffset) { - out.top = pageYOffset; - } - if (out.left < pageXOffset) { - out.left = pageXOffset; - } - return out; - } - break; - case 'scroll-handle': - target = this.target; - if (target === document.body) { - target = document.documentElement; - bounds = { - left: pageXOffset, - top: pageYOffset, - height: innerHeight, - width: innerWidth - }; - } else { - bounds = getBounds(target); - } - style = getComputedStyle(target); - hasBottomScroll = target.scrollWidth > target.clientWidth || 'scroll' === [style.overflow, style.overflowX] || this.target !== document.body; - scrollBottom = 0; - if (hasBottomScroll) { - scrollBottom = 15; - } - height = bounds.height - parseFloat(style.borderTopWidth) - parseFloat(style.borderBottomWidth) - scrollBottom; - out = { - width: 15, - height: height * 0.975 * (height / target.scrollHeight), - left: bounds.left + bounds.width - parseFloat(style.borderLeftWidth) - 15 - }; - fitAdj = 0; - if (height < 408 && this.target === document.body) { - fitAdj = -0.00011 * Math.pow(height, 2) - 0.00727 * height + 22.58; - } - if (this.target !== document.body) { - out.height = Math.max(out.height, 24); - } - scrollPercentage = this.target.scrollTop / (target.scrollHeight - height); - out.top = scrollPercentage * (height - out.height - fitAdj) + bounds.top + parseFloat(style.borderTopWidth); - if (this.target === document.body) { - out.height = Math.max(out.height, 24); - } - return out; - } - } else { - return getBounds(this.target); - } - }; - - _Tether.prototype.clearCache = function() { - return this._cache = {}; - }; - - _Tether.prototype.cache = function(k, getter) { - if (this._cache == null) { - this._cache = {}; - } - if (this._cache[k] == null) { - this._cache[k] = getter.call(this); - } - return this._cache[k]; - }; - - _Tether.prototype.enable = function(position) { - if (position == null) { - position = true; - } - if (this.options.addTargetClasses !== false) { - addClass(this.target, this.getClass('enabled')); - } - addClass(this.element, this.getClass('enabled')); - this.enabled = true; - if (this.scrollParent !== document) { - this.scrollParent.addEventListener('scroll', this.position); - } - if (position) { - return this.position(); - } - }; - - _Tether.prototype.disable = function() { - removeClass(this.target, this.getClass('enabled')); - removeClass(this.element, this.getClass('enabled')); - this.enabled = false; - if (this.scrollParent != null) { - return this.scrollParent.removeEventListener('scroll', this.position); - } - }; - - _Tether.prototype.destroy = function() { - var i, tether, _i, _len, _results; - this.disable(); - _results = []; - for (i = _i = 0, _len = tethers.length; _i < _len; i = ++_i) { - tether = tethers[i]; - if (tether === this) { - tethers.splice(i, 1); - break; - } else { - _results.push(void 0); - } - } - return _results; - }; - - _Tether.prototype.updateAttachClasses = function(elementAttach, targetAttach) { - var add, all, side, sides, _i, _j, _len, _len1, _ref1, - _this = this; - if (elementAttach == null) { - elementAttach = this.attachment; - } - if (targetAttach == null) { - targetAttach = this.targetAttachment; - } - sides = ['left', 'top', 'bottom', 'right', 'middle', 'center']; - if ((_ref1 = this._addAttachClasses) != null ? _ref1.length : void 0) { - this._addAttachClasses.splice(0, this._addAttachClasses.length); - } - add = this._addAttachClasses != null ? this._addAttachClasses : this._addAttachClasses = []; - if (elementAttach.top) { - add.push("" + (this.getClass('element-attached')) + "-" + elementAttach.top); - } - if (elementAttach.left) { - add.push("" + (this.getClass('element-attached')) + "-" + elementAttach.left); - } - if (targetAttach.top) { - add.push("" + (this.getClass('target-attached')) + "-" + targetAttach.top); - } - if (targetAttach.left) { - add.push("" + (this.getClass('target-attached')) + "-" + targetAttach.left); - } - all = []; - for (_i = 0, _len = sides.length; _i < _len; _i++) { - side = sides[_i]; - all.push("" + (this.getClass('element-attached')) + "-" + side); - } - for (_j = 0, _len1 = sides.length; _j < _len1; _j++) { - side = sides[_j]; - all.push("" + (this.getClass('target-attached')) + "-" + side); - } - return defer(function() { - if (_this._addAttachClasses == null) { - return; - } - updateClasses(_this.element, _this._addAttachClasses, all); - if (_this.options.addTargetClasses !== false) { - updateClasses(_this.target, _this._addAttachClasses, all); - } - return _this._addAttachClasses = void 0; - }); - }; - - _Tether.prototype.position = function(flushChanges) { - var elementPos, elementStyle, height, left, manualOffset, manualTargetOffset, module, next, offset, offsetBorder, offsetParent, offsetParentSize, offsetParentStyle, offsetPosition, ret, scrollLeft, scrollTop, scrollbarSize, side, targetAttachment, targetOffset, targetPos, targetSize, top, width, _i, _j, _len, _len1, _ref1, _ref2, _ref3, _ref4, _ref5, _ref6, - _this = this; - if (flushChanges == null) { - flushChanges = true; - } - if (!this.enabled) { - return; - } - this.clearCache(); - targetAttachment = autoToFixedAttachment(this.targetAttachment, this.attachment); - this.updateAttachClasses(this.attachment, targetAttachment); - elementPos = this.cache('element-bounds', function() { - return getBounds(_this.element); - }); - width = elementPos.width, height = elementPos.height; - if (width === 0 && height === 0 && (this.lastSize != null)) { - _ref1 = this.lastSize, width = _ref1.width, height = _ref1.height; - } else { - this.lastSize = { - width: width, - height: height - }; - } - targetSize = targetPos = this.cache('target-bounds', function() { - return _this.getTargetBounds(); - }); - offset = offsetToPx(attachmentToOffset(this.attachment), { - width: width, - height: height - }); - targetOffset = offsetToPx(attachmentToOffset(targetAttachment), targetSize); - manualOffset = offsetToPx(this.offset, { - width: width, - height: height - }); - manualTargetOffset = offsetToPx(this.targetOffset, targetSize); - offset = addOffset(offset, manualOffset); - targetOffset = addOffset(targetOffset, manualTargetOffset); - left = targetPos.left + targetOffset.left - offset.left; - top = targetPos.top + targetOffset.top - offset.top; - _ref2 = Tether.modules; - for (_i = 0, _len = _ref2.length; _i < _len; _i++) { - module = _ref2[_i]; - ret = module.position.call(this, { - left: left, - top: top, - targetAttachment: targetAttachment, - targetPos: targetPos, - attachment: this.attachment, - elementPos: elementPos, - offset: offset, - targetOffset: targetOffset, - manualOffset: manualOffset, - manualTargetOffset: manualTargetOffset, - scrollbarSize: scrollbarSize - }); - if (ret === false) { - return false; - } else if ((ret == null) || typeof ret !== 'object') { - continue; - } else { - top = ret.top, left = ret.left; - } - } - next = { - page: { - top: top, - left: left - }, - viewport: { - top: top - pageYOffset, - bottom: pageYOffset - top - height + innerHeight, - left: left - pageXOffset, - right: pageXOffset - left - width + innerWidth - } - }; - if (document.body.scrollWidth > window.innerWidth) { - scrollbarSize = this.cache('scrollbar-size', getScrollBarSize); - next.viewport.bottom -= scrollbarSize.height; - } - if (document.body.scrollHeight > window.innerHeight) { - scrollbarSize = this.cache('scrollbar-size', getScrollBarSize); - next.viewport.right -= scrollbarSize.width; - } - if (((_ref3 = document.body.style.position) !== '' && _ref3 !== 'static') || ((_ref4 = document.body.parentElement.style.position) !== '' && _ref4 !== 'static')) { - next.page.bottom = document.body.scrollHeight - top - height; - next.page.right = document.body.scrollWidth - left - width; - } - if (((_ref5 = this.options.optimizations) != null ? _ref5.moveElement : void 0) !== false && (this.targetModifier == null)) { - offsetParent = this.cache('target-offsetparent', function() { - return getOffsetParent(_this.target); - }); - offsetPosition = this.cache('target-offsetparent-bounds', function() { - return getBounds(offsetParent); - }); - offsetParentStyle = getComputedStyle(offsetParent); - elementStyle = getComputedStyle(this.element); - offsetParentSize = offsetPosition; - offsetBorder = {}; - _ref6 = ['Top', 'Left', 'Bottom', 'Right']; - for (_j = 0, _len1 = _ref6.length; _j < _len1; _j++) { - side = _ref6[_j]; - offsetBorder[side.toLowerCase()] = parseFloat(offsetParentStyle["border" + side + "Width"]); - } - offsetPosition.right = document.body.scrollWidth - offsetPosition.left - offsetParentSize.width + offsetBorder.right; - offsetPosition.bottom = document.body.scrollHeight - offsetPosition.top - offsetParentSize.height + offsetBorder.bottom; - if (next.page.top >= (offsetPosition.top + offsetBorder.top) && next.page.bottom >= offsetPosition.bottom) { - if (next.page.left >= (offsetPosition.left + offsetBorder.left) && next.page.right >= offsetPosition.right) { - scrollTop = offsetParent.scrollTop; - scrollLeft = offsetParent.scrollLeft; - next.offset = { - top: next.page.top - offsetPosition.top + scrollTop - offsetBorder.top, - left: next.page.left - offsetPosition.left + scrollLeft - offsetBorder.left - }; - } - } - } - this.move(next); - this.history.unshift(next); - if (this.history.length > 3) { - this.history.pop(); - } - if (flushChanges) { - flush(); - } - return true; - }; - - _Tether.prototype.move = function(position) { - var css, elVal, found, key, moved, offsetParent, point, same, transcribe, type, val, write, writeCSS, _i, _len, _ref1, _ref2, - _this = this; - if (this.element.parentNode == null) { - return; - } - same = {}; - for (type in position) { - same[type] = {}; - for (key in position[type]) { - found = false; - _ref1 = this.history; - for (_i = 0, _len = _ref1.length; _i < _len; _i++) { - point = _ref1[_i]; - if (!within((_ref2 = point[type]) != null ? _ref2[key] : void 0, position[type][key])) { - found = true; - break; - } - } - if (!found) { - same[type][key] = true; - } - } - } - css = { - top: '', - left: '', - right: '', - bottom: '' - }; - transcribe = function(same, pos) { - var xPos, yPos, _ref3; - if (((_ref3 = _this.options.optimizations) != null ? _ref3.gpu : void 0) !== false) { - if (same.top) { - css.top = 0; - yPos = pos.top; - } else { - css.bottom = 0; - yPos = -pos.bottom; - } - if (same.left) { - css.left = 0; - xPos = pos.left; - } else { - css.right = 0; - xPos = -pos.right; - } - css[transformKey] = "translateX(" + (Math.round(xPos)) + "px) translateY(" + (Math.round(yPos)) + "px)"; - if (transformKey !== 'msTransform') { - return css[transformKey] += " translateZ(0)"; - } - } else { - if (same.top) { - css.top = "" + pos.top + "px"; - } else { - css.bottom = "" + pos.bottom + "px"; - } - if (same.left) { - return css.left = "" + pos.left + "px"; - } else { - return css.right = "" + pos.right + "px"; - } - } - }; - moved = false; - if ((same.page.top || same.page.bottom) && (same.page.left || same.page.right)) { - css.position = 'absolute'; - transcribe(same.page, position.page); - } else if ((same.viewport.top || same.viewport.bottom) && (same.viewport.left || same.viewport.right)) { - css.position = 'fixed'; - transcribe(same.viewport, position.viewport); - } else if ((same.offset != null) && same.offset.top && same.offset.left) { - css.position = 'absolute'; - offsetParent = this.cache('target-offsetparent', function() { - return getOffsetParent(_this.target); - }); - if (getOffsetParent(this.element) !== offsetParent) { - defer(function() { - _this.element.parentNode.removeChild(_this.element); - return offsetParent.appendChild(_this.element); - }); - } - transcribe(same.offset, position.offset); - moved = true; - } else { - css.position = 'absolute'; - transcribe({ - top: true, - left: true - }, position.page); - } - if (!moved && this.element.parentNode.tagName !== 'BODY') { - this.element.parentNode.removeChild(this.element); - document.body.appendChild(this.element); - } - writeCSS = {}; - write = false; - for (key in css) { - val = css[key]; - elVal = this.element.style[key]; - if (elVal !== '' && val !== '' && (key === 'top' || key === 'left' || key === 'bottom' || key === 'right')) { - elVal = parseFloat(elVal); - val = parseFloat(val); - } - if (elVal !== val) { - write = true; - writeCSS[key] = css[key]; - } - } - if (write) { - return defer(function() { - return extend(_this.element.style, writeCSS); - }); - } - }; - - return _Tether; - - })(); - - Tether.position = position; - - this.Tether = extend(_Tether, Tether); - -}).call(this); diff --git a/js/tether.min.js b/js/tether.min.js deleted file mode 100644 index e8993a1a..00000000 --- a/js/tether.min.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! tether.js 0.2.9 */ -(function(){var a,b,c,d,e,f,g,h,i={}.hasOwnProperty,j=[].slice;null==window.Tether&&(window.Tether={}),f=function(a){var b,c,d,e,f;if(c=getComputedStyle(a).position,"fixed"===c)return a;for(d=void 0,b=a;b=b.parentNode;){if(!(e=getComputedStyle(b)))return b;if(/(auto|scroll)/.test(e.overflow+e["overflow-y"]+e["overflow-x"])&&("absolute"!==c||"relative"===(f=e.position)||"absolute"===f||"fixed"===f))return b}return document.body},d=function(a){var b,d,e,f;return d=a.ownerDocument,e=d.documentElement,b=c({},a.getBoundingClientRect()),b.top=b.top+window.pageYOffset-e.clientTop,b.left=b.left+window.pageXOffset-e.clientLeft,b.right=d.body.clientWidth-b.width-b.left,b.bottom=d.body.clientHeight-b.height-b.top,b.height&&b.width||(f=getComputedStyle(a),b.height||(b.height=parseFloat(f.height)),b.width||(b.width=parseFloat(f.width))),b},e=function(a){return a.offsetParent||document.documentElement},c=function(a){var b,c,d,e,f,g,h;for(null==a&&(a={}),b=[],Array.prototype.push.apply(b,arguments),h=b.slice(1),f=0,g=h.length;g>f;f++)if(d=h[f])for(c in d)i.call(d,c)&&(e=d[c],a[c]=e);return a},h=function(a,b){var c,d,e,f,g;if(null!=a.classList){for(f=b.split(" "),g=[],d=0,e=f.length;e>d;d++)c=f[d],g.push(a.classList.remove(c));return g}return a.className=a.className.replace(new RegExp("(^| )"+b.split(" ").join("|")+"( |$)","gi")," ")},b=function(a,b){var c,d,e,f,g;if(null!=a.classList){for(f=b.split(" "),g=[],d=0,e=f.length;e>d;d++)c=f[d],g.push(a.classList.add(c));return g}return h(a,b),a.className+=" "+b},g=function(a,b){return null!=a.classList?a.classList.contains(b):new RegExp("(^| )"+b+"( |$)","gi").test(a.className)},a=function(){function a(){}return a.prototype.on=function(a,b,c,d){var e;return null==d&&(d=!1),null==this.bindings&&(this.bindings={}),null==(e=this.bindings)[a]&&(e[a]=[]),this.bindings[a].push({handler:b,ctx:c,once:d})},a.prototype.once=function(a,b,c){return this.on(a,b,c,!0)},a.prototype.off=function(a,b){var c,d,e;if(null!=(null!=(d=this.bindings)?d[a]:void 0)){if(null==b)return delete this.bindings[a];for(c=0,e=[];cb;b++)a=v[b],d.push(a.position());return d},p=null,A=["resize","scroll"],x=0,y=A.length;y>x;x++)i=A[x],window.addEventListener(i,function(){return null==p||new Date-p>16?(p=+new Date,t()):void 0});a={center:"center",left:"right",right:"left"},b={middle:"middle",top:"bottom",bottom:"top"},c={top:0,left:0,middle:"50%",center:"50%",bottom:"100%",right:"100%"},g=function(c,d){var e,f;return e=c.left,f=c.top,"auto"===e&&(e=a[d.left]),"auto"===f&&(f=b[d.top]),{left:e,top:f}},f=function(a){var b,d;return{left:null!=(b=c[a.left])?b:a.left,top:null!=(d=c[a.top])?d:a.top}},e=function(){var a,b,c,d,e,f,g;for(b=1<=arguments.length?B.call(arguments,0):[],c={top:0,left:0},e=0,f=b.length;f>e;e++)g=b[e],d=g.top,a=g.left,"string"==typeof d&&(d=parseFloat(d,10)),"string"==typeof a&&(a=parseFloat(a,10)),c.top+=d,c.left+=a;return c},q=function(a,b){return"string"==typeof a.left&&-1!==a.left.indexOf("%")&&(a.left=parseFloat(a.left,10)/100*b.width),"string"==typeof a.top&&-1!==a.top.indexOf("%")&&(a.top=parseFloat(a.top,10)/100*b.height),a},r=s=function(a){var b,c,d;return d=a.split(" "),c=d[0],b=d[1],{top:c,left:b}},w=function(){function a(a){this.position=C(this.position,this);var b,c,d,e,f;for(v.push(this),this.history=[],this.setOptions(a,!1),e=Tether.modules,c=0,d=e.length;d>c;c++)b=e[c],null!=(f=b.initialize)&&f.call(this);this.position()}return a.modules=[],a.prototype.getClass=function(a){var b,c;return(null!=(b=this.options.classes)?b[a]:void 0)?this.options.classes[a]:(null!=(c=this.options.classes)?c[a]:void 0)!==!1?this.options.classPrefix?""+this.options.classPrefix+"-"+a:a:""},a.prototype.setOptions=function(a,b){var c,e,f,g,h,i;for(this.options=a,null==b&&(b=!0),c={offset:"0 0",targetOffset:"0 0",targetAttachment:"auto auto",classPrefix:"tether"},this.options=j(c,this.options),h=this.options,this.element=h.element,this.target=h.target,this.targetModifier=h.targetModifier,"viewport"===this.target?(this.target=document.body,this.targetModifier="visible"):"scroll-handle"===this.target&&(this.target=document.body,this.targetModifier="scroll-handle"),i=["element","target"],f=0,g=i.length;g>f;f++)if(e=i[f],null!=this[e].jquery?this[e]=this[e][0]:"string"==typeof this[e]&&(this[e]=document.querySelector(this[e])),null==this[e])throw new Error("Tether Error: Both element and target must be defined");if(d(this.element,this.getClass("element")),d(this.target,this.getClass("target")),!this.options.attachment)throw new Error("Tether Error: You must provide an attachment");return this.targetAttachment=r(this.options.targetAttachment),this.attachment=r(this.options.attachment),this.offset=s(this.options.offset),this.targetOffset=s(this.options.targetOffset),null!=this.scrollParent&&this.disable(),this.scrollParent=n(this.target),this.options.enabled!==!1?this.enable(b):void 0},a.prototype.getTargetBounds=function(){if(null==this.targetModifier)return k(this.target);switch(this.targetModifier){case"visible":return{top:pageYOffset,left:pageXOffset,height:innerHeight,width:innerWidth};case"scroll-handle":return{top:pageYOffset+innerHeight*(pageYOffset/document.body.scrollHeight),left:innerWidth-15,height:.98*innerHeight*(innerHeight/document.body.scrollHeight),width:15}}},a.prototype.clearCache=function(){return this._cache={}},a.prototype.cache=function(a,b){return null==this._cache&&(this._cache={}),null==this._cache[a]&&(this._cache[a]=b.call(this)),this._cache[a]},a.prototype.enable=function(a){var b=this;return null==a&&(a=!0),this.addClass(this.getClass("enabled")),this.enabled=!0,this.scrollParent.addEventListener("scroll",this.position),a?setTimeout(function(){return b.position()}):void 0},a.prototype.disable=function(){return this.removeClass(this.getClass("enabled")),this.enabled=!1,null!=this.scrollParent?this.scrollParent.removeEventListener("scroll",this.position):void 0},a.prototype.destroy=function(){var a,b,c,d,e;for(this.disable(),e=[],a=c=0,d=v.length;d>c;a=++c){if(b=v[a],b===this){v.splice(a,1);break}e.push(void 0)}return e},a.prototype.updateAttachClasses=function(a,b){var c,d,e,f,g,h;for(null==a&&(a=this.attachment),null==b&&(b=this.targetAttachment),d=["left","top","bottom","right","middle","center"],e=0,g=d.length;g>e;e++)c=d[e],this.removeClass(""+this.getClass("element-attached")+"-"+c);for(a.top&&this.addClass(""+this.getClass("element-attached")+"-"+a.top),a.left&&this.addClass(""+this.getClass("element-attached")+"-"+a.left),f=0,h=d.length;h>f;f++)c=d[f],this.removeClass(""+this.getClass("target-attached")+"-"+c);return b.top&&this.addClass(""+this.getClass("target-attached")+"-"+b.top),b.left?this.addClass(""+this.getClass("target-attached")+"-"+b.left):void 0},a.prototype.addClass=function(a){return d(this.element,a),d(this.target,a)},a.prototype.removeClass=function(a){return u(this.element,a),u(this.target,a)},a.prototype.position=function(){var a,b,c,d,h,i,j,m,n,o,p,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K=this;if(this.enabled){for(this.clearCache(),x=g(this.targetAttachment,this.attachment),this.updateAttachClasses(this.attachment,x),a=this.cache("element-bounds",function(){return k(K.element)}),C=a.width,b=a.height,A=z=this.cache("target-bounds",function(){return K.getTargetBounds()}),m=q(f(this.attachment),{width:C,height:b}),y=q(f(x),A),d=q(this.offset,{width:C,height:b}),h=q(this.targetOffset,A),m=e(m,d),c=z.left+y.left-m.left,B=z.top+y.top-m.top,H=Tether.modules,D=0,F=H.length;F>D;D++)if(i=H[D],t=i.position.call(this,{left:c,top:B,targetAttachment:x,targetPos:z,elementPos:a,offset:m,targetOffset:y,manualOffset:d,manualTargetOffset:h}),null!=t&&"object"==typeof t){if(t===!1)return!1;B=t.top,c=t.left}if(j={page:{top:B,bottom:document.body.scrollHeight-B-b,left:c,right:document.body.scrollWidth-c-C},viewport:{top:B-pageYOffset,bottom:pageYOffset-B-b+innerHeight,left:c-pageXOffset,right:pageXOffset-c-C+innerWidth}},(null!=(I=this.options.optimizations)?I.moveElement:void 0)!==!1&&null==this.targetModifier){for(o=this.cache("target-offsetparent",function(){return l(K.target)}),s=this.cache("target-offsetparent-bounds",function(){return k(o)}),r=getComputedStyle(o),p=s,n={},J=["top","left","bottom","right"],E=0,G=J.length;G>E;E++)w=J[E],n[w]=parseFloat(r["border-"+w+"-width"]);s.left+=n.left,s.top+=n.top,s.right=document.body.scrollWidth-s.left-p.width,s.bottom=document.body.scrollHeight-s.top-p.height,j.page.top>=s.top&&j.page.bottom>=s.bottom&&j.page.left>=s.left&&j.page.right>=s.right&&(v=o.scrollTop,u=o.scrollLeft,j.offset={top:j.page.top-s.top+v+n.top,left:j.page.left-s.left+u+n.left,right:j.page.right-s.right+o.scrollWidth-u+n.right,bottom:j.page.bottom-s.bottom+o.scrollHeight-v+n.bottom})}return this.move(j),this.history.unshift(j),this.history.length>3&&this.history.pop(),!0}},a.prototype.move=function(a){var b,c,d,e,f,g,h,i,k,m,n,o,p,q,r,s,t,u,v,w,x,y=this;if(null!=this.element.parentNode){k={};for(o in a){k[o]={};for(d in a[o]){for(c=!1,v=this.history,r=0,t=v.length;t>r;r++)if(i=v[r],(null!=(w=i[o])?w[d]:void 0)!==a[o][d]){c=!0;break}c||(k[o][d]=!0)}}if(b={top:"",left:"",right:"",bottom:""},n=function(a,c){return a.top?b.top=""+c.top+"px":b.bottom=""+c.bottom+"px",a.left?b.left=""+c.left+"px":b.right=""+c.right+"px"},e=!1,(k.page.top||k.page.bottom)&&(k.page.left||k.page.right))b.position="absolute",n(k.page,a.page);else if((k.viewport.top||k.viewport.bottom)&&(k.viewport.left||k.viewport.right))b.position="fixed",n(k.viewport,a.viewport);else if(null!=k.offset&&(k.offset.top||k.offset.bottom)&&(k.offset.left||k.offset.right)){for(b.position="absolute",g=this.cache("target-offsetparent",function(){return l(y.target)}),l(this.element)!==g&&(this.element.parentNode.removeChild(this.element),g.appendChild(this.element)),h=getComputedStyle(g),f=j({},a.offset),x=["top","left","bottom","right"],s=0,u=x.length;u>s;s++)m=x[s],f[m]-=parseFloat(h["border-"+m+"-width"]);n(k.offset,f),e=!0}else b.position="absolute",b.top=""+a.page.top+"px",b.left=""+a.page.left+"px";e||"BODY"===this.element.parentNode.tagName||(this.element.parentNode.removeChild(this.element),document.body.appendChild(this.element)),q=!1;for(d in b)if(p=b[d],this.element.style[d]!==p){q=!0;break}return q?j(this.element.style,b):void 0}},a}(),window.Tether=j(w,Tether)}.call(this),function(){var a,b,c,d,e,f,g,h,i=[].indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(b in this&&this[b]===a)return b;return-1};h=Tether.Utils,f=h.getOuterSize,e=h.getBounds,g=h.getSize,c=h.extend,b={left:"right",right:"left",top:"bottom",bottom:"top",middle:"middle"},a=["left","top","right","bottom"],d=function(b,c){var d,f,g,h,i,j,k;if("scrollParent"===c?c=b.scrollParent:"window"===c&&(c=[pageXOffset,pageYOffset,innerWidth+pageXOffset,innerHeight+pageYOffset]),null!=c.nodeType)for(f=h=e(c),i=getComputedStyle(c),c=[f.left,f.top,h.width+f.left,h.height+f.top],d=j=0,k=a.length;k>j;d=++j)g=a[d],"top"===g||"left"===g?c[d]+=parseFloat(i["border-"+g+"-width"]):c[d]-=parseFloat(i["border-"+g+"-width"]);return c},Tether.modules.push({position:function(b){var f,g,h,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W=this;if(E=b.top,o=b.left,z=b.targetAttachment,!this.options.constraints)return!0;for(v=function(b){var c,d,e,f;for(W.removeClass(b),f=[],d=0,e=a.length;e>d;d++)c=a[d],f.push(W.removeClass(""+b+"-"+c));return f},Q=this.cache("element-bounds",function(){return e(W.element)}),n=Q.height,F=Q.width,B=this.cache("target-bounds",function(){return W.getTargetBounds()}),A=B.height,C=B.width,y={},m={},w=[this.getClass("pinned"),this.getClass("out-of-bounds")],R=this.options.constraints,G=0,K=R.length;K>G;G++)l=R[G],l.outOfBoundsClass&&w.push(l.outOfBoundsClass),l.pinnedClass&&w.push(l.pinnedClass);for(H=0,L=w.length;L>H;H++)k=w[H],v(k);for(y=c({},z),m=c({},this.attachment),S=this.options.constraints,I=0,M=S.length;M>I;I++){if(l=S[I],D=l.to,f=l.attachment,s=l.pin,null==f&&(f=""),i.call(f," ")>=0?(T=f.split(" "),j=T[0],h=T[1]):h=j=f,g=d(this,D),("target"===j||"both"===j)&&(Eg[3]&&"bottom"===y.top&&(E-=A,y.top="top")),"together"===j&&(Eg[3]&&"bottom"===y.top&&("top"===m.top?(E-=A,y.top="top",E-=n,m.top="bottom"):"bottom"===m.top&&(E-=A,y.top="top",E+=n,m.top="top"))),("target"===h||"both"===h)&&(og[2]&&"right"===y.left&&(o-=C,y.left="left")),"together"===h&&(og[2]&&"right"===y.left&&("left"===m.left?(o-=C,y.left="left",o-=F,m.left="right"):"right"===m.left&&(o-=C,y.left="left",o+=F,m.left="left"))),("element"===j||"both"===j)&&(Eg[3]&&"top"===m.top&&(E-=n,m.top="bottom")),("element"===h||"both"===h)&&(og[2]&&"left"===m.left&&(o-=F,m.left="right")),"string"==typeof s?s=function(){var a,b,c,d;for(c=s.split(","),d=[],a=0,b=c.length;b>a;a++)r=c[a],d.push(r.trim());return d}():s===!0&&(s=["top","left","right","bottom"]),s||(s=[]),t=[],p=[],E=0?(E=g[1],t.push("top")):p.push("top")),E+n>g[3]&&(i.call(s,"bottom")>=0?(E=g[3]-n,t.push("bottom")):p.push("bottom")),o=0?(o=g[0],t.push("left")):p.push("left")),o+F>g[2]&&(i.call(s,"right")>=0?(o=g[2]-F,t.push("right")):p.push("right")),t.length)for(u=null!=(U=this.options.pinnedClass)?U:this.getClass("pinned"),this.addClass(u),J=0,N=t.length;N>J;J++)x=t[J],this.addClass(""+u+"-"+x);if(p.length)for(q=null!=(V=this.options.outOfBoundsClass)?V:this.getClass("out-of-bounds"),this.addClass(q),P=0,O=p.length;O>P;P++)x=p[P],this.addClass(""+q+"-"+x);(i.call(t,"left")>=0||i.call(t,"right")>=0)&&(m.left=y.left=!1),(i.call(t,"top")>=0||i.call(t,"bottom")>=0)&&(m.top=y.top=!1),(y.top!==z.top||y.left!==z.left||m.top!==this.attachment.top||m.left!==this.attachment.left)&&this.updateAttachClasses(m,y)}return{top:E,left:o}}})}.call(this),function(){var a;a=Tether.Utils.getBounds,Tether.modules.push({position:function(b){var c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z=this;if(k=b.top,f=b.left,u=this.cache("element-bounds",function(){return a(z.element)}),e=u.height,l=u.width,j=this.getTargetBounds(),d=k+e,g=f+l,c=[],k<=j.bottom&&d>=j.top)for(v=["left","right"],m=0,q=v.length;q>m;m++)h=v[m],((w=j[h])===f||w===g)&&c.push(h);if(f<=j.right&&g>=j.left)for(x=["top","bottom"],n=0,r=x.length;r>n;n++)h=x[n],((y=j[h])===k||y===d)&&c.push(h);for(i=["left","top","right","bottom"],this.removeClass(this.getClass("abutted")),o=0,s=i.length;s>o;o++)h=i[o],this.removeClass(""+this.getClass("abutted")+"-"+h);for(c.length&&this.addClass(this.getClass("abutted")),p=0,t=c.length;t>p;p++)h=c[p],this.addClass(""+this.getClass("abutted")+"-"+h);return!0}})}.call(this),function(){Tether.modules.push({position:function(a){var b,c,d,e,f,g,h;return g=a.top,b=a.left,this.options.shift?(c=function(a){return"function"==typeof a?a.call(this,{top:g,left:b}):a},d=c(this.options.shift),"string"==typeof d?(d=d.split(" "),d[1]||(d[1]=d[0]),f=d[0],e=d[1],f=parseFloat(f,10),e=parseFloat(e,10)):(h=[d.top,d.left],f=h[0],e=h[1]),g+=f,b+=e,{top:g,left:b}):void 0}})}.call(this); \ No newline at end of file diff --git a/js/utils.js b/js/utils.js deleted file mode 100644 index c1ddb6b5..00000000 --- a/js/utils.js +++ /dev/null @@ -1,345 +0,0 @@ -(function() { - var Evented, addClass, defer, deferred, extend, flush, getBounds, getClassName, getOffsetParent, getOrigin, getScrollBarSize, getScrollParent, hasClass, node, removeClass, setClassName, uniqueId, updateClasses, zeroPosCache, - __hasProp = {}.hasOwnProperty, - __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }, - __slice = [].slice; - - if (this.Tether == null) { - this.Tether = { - modules: [] - }; - } - - getScrollParent = function(el) { - var parent, position, scrollParent, style, _ref; - position = getComputedStyle(el).position; - if (position === 'fixed') { - return el; - } - scrollParent = void 0; - parent = el; - while (parent = parent.parentNode) { - try { - style = getComputedStyle(parent); - } catch (_error) {} - if (style == null) { - return parent; - } - if (/(auto|scroll)/.test(style['overflow'] + style['overflowY'] + style['overflowX'])) { - if (position !== 'absolute' || ((_ref = style['position']) === 'relative' || _ref === 'absolute' || _ref === 'fixed')) { - return parent; - } - } - } - return document.body; - }; - - uniqueId = (function() { - var id; - id = 0; - return function() { - return id++; - }; - })(); - - zeroPosCache = {}; - - getOrigin = function(doc) { - var id, k, node, v, _ref; - node = doc._tetherZeroElement; - if (node == null) { - node = doc.createElement('div'); - node.setAttribute('data-tether-id', uniqueId()); - extend(node.style, { - top: 0, - left: 0, - position: 'absolute' - }); - doc.body.appendChild(node); - doc._tetherZeroElement = node; - } - id = node.getAttribute('data-tether-id'); - if (zeroPosCache[id] == null) { - zeroPosCache[id] = {}; - _ref = node.getBoundingClientRect(); - for (k in _ref) { - v = _ref[k]; - zeroPosCache[id][k] = v; - } - defer(function() { - return zeroPosCache[id] = void 0; - }); - } - return zeroPosCache[id]; - }; - - node = null; - - getBounds = function(el) { - var box, doc, docEl, k, origin, v, _ref; - if (el === document) { - doc = document; - el = document.documentElement; - } else { - doc = el.ownerDocument; - } - docEl = doc.documentElement; - box = {}; - _ref = el.getBoundingClientRect(); - for (k in _ref) { - v = _ref[k]; - box[k] = v; - } - origin = getOrigin(doc); - box.top -= origin.top; - box.left -= origin.left; - if (box.width == null) { - box.width = document.body.scrollWidth - box.left - box.right; - } - if (box.height == null) { - box.height = document.body.scrollHeight - box.top - box.bottom; - } - box.top = box.top - docEl.clientTop; - box.left = box.left - docEl.clientLeft; - box.right = doc.body.clientWidth - box.width - box.left; - box.bottom = doc.body.clientHeight - box.height - box.top; - return box; - }; - - getOffsetParent = function(el) { - return el.offsetParent || document.documentElement; - }; - - getScrollBarSize = function() { - var inner, outer, width, widthContained, widthScroll; - inner = document.createElement('div'); - inner.style.width = '100%'; - inner.style.height = '200px'; - outer = document.createElement('div'); - extend(outer.style, { - position: 'absolute', - top: 0, - left: 0, - pointerEvents: 'none', - visibility: 'hidden', - width: '200px', - height: '150px', - overflow: 'hidden' - }); - outer.appendChild(inner); - document.body.appendChild(outer); - widthContained = inner.offsetWidth; - outer.style.overflow = 'scroll'; - widthScroll = inner.offsetWidth; - if (widthContained === widthScroll) { - widthScroll = outer.clientWidth; - } - document.body.removeChild(outer); - width = widthContained - widthScroll; - return { - width: width, - height: width - }; - }; - - extend = function(out) { - var args, key, obj, val, _i, _len, _ref; - if (out == null) { - out = {}; - } - args = []; - Array.prototype.push.apply(args, arguments); - _ref = args.slice(1); - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - obj = _ref[_i]; - if (obj) { - for (key in obj) { - if (!__hasProp.call(obj, key)) continue; - val = obj[key]; - out[key] = val; - } - } - } - return out; - }; - - removeClass = function(el, name) { - var className, cls, _i, _len, _ref, _results; - if (el.classList != null) { - _ref = name.split(' '); - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - cls = _ref[_i]; - if (cls.trim()) { - _results.push(el.classList.remove(cls)); - } - } - return _results; - } else { - className = getClassName(el).replace(new RegExp("(^| )" + (name.split(' ').join('|')) + "( |$)", 'gi'), ' '); - return setClassName(el, className); - } - }; - - addClass = function(el, name) { - var cls, _i, _len, _ref, _results; - if (el.classList != null) { - _ref = name.split(' '); - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - cls = _ref[_i]; - if (cls.trim()) { - _results.push(el.classList.add(cls)); - } - } - return _results; - } else { - removeClass(el, name); - cls = getClassName(el) + (" " + name); - return setClassName(el, cls); - } - }; - - hasClass = function(el, name) { - if (el.classList != null) { - return el.classList.contains(name); - } else { - return new RegExp("(^| )" + name + "( |$)", 'gi').test(getClassName(el)); - } - }; - - getClassName = function(el) { - if (el.className instanceof SVGAnimatedString) { - return el.className.baseVal; - } else { - return el.className; - } - }; - - setClassName = function(el, className) { - return el.setAttribute('class', className); - }; - - updateClasses = function(el, add, all) { - var cls, _i, _j, _len, _len1, _results; - for (_i = 0, _len = all.length; _i < _len; _i++) { - cls = all[_i]; - if (__indexOf.call(add, cls) < 0) { - if (hasClass(el, cls)) { - removeClass(el, cls); - } - } - } - _results = []; - for (_j = 0, _len1 = add.length; _j < _len1; _j++) { - cls = add[_j]; - if (!hasClass(el, cls)) { - _results.push(addClass(el, cls)); - } else { - _results.push(void 0); - } - } - return _results; - }; - - deferred = []; - - defer = function(fn) { - return deferred.push(fn); - }; - - flush = function() { - var fn, _results; - _results = []; - while (fn = deferred.pop()) { - _results.push(fn()); - } - return _results; - }; - - Evented = (function() { - function Evented() {} - - Evented.prototype.on = function(event, handler, ctx, once) { - var _base; - if (once == null) { - once = false; - } - if (this.bindings == null) { - this.bindings = {}; - } - if ((_base = this.bindings)[event] == null) { - _base[event] = []; - } - return this.bindings[event].push({ - handler: handler, - ctx: ctx, - once: once - }); - }; - - Evented.prototype.once = function(event, handler, ctx) { - return this.on(event, handler, ctx, true); - }; - - Evented.prototype.off = function(event, handler) { - var i, _ref, _results; - if (((_ref = this.bindings) != null ? _ref[event] : void 0) == null) { - return; - } - if (handler == null) { - return delete this.bindings[event]; - } else { - i = 0; - _results = []; - while (i < this.bindings[event].length) { - if (this.bindings[event][i].handler === handler) { - _results.push(this.bindings[event].splice(i, 1)); - } else { - _results.push(i++); - } - } - return _results; - } - }; - - Evented.prototype.trigger = function() { - var args, ctx, event, handler, i, once, _ref, _ref1, _results; - event = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; - if ((_ref = this.bindings) != null ? _ref[event] : void 0) { - i = 0; - _results = []; - while (i < this.bindings[event].length) { - _ref1 = this.bindings[event][i], handler = _ref1.handler, ctx = _ref1.ctx, once = _ref1.once; - handler.apply(ctx != null ? ctx : this, args); - if (once) { - _results.push(this.bindings[event].splice(i, 1)); - } else { - _results.push(i++); - } - } - return _results; - } - }; - - return Evented; - - })(); - - this.Tether.Utils = { - getScrollParent: getScrollParent, - getBounds: getBounds, - getOffsetParent: getOffsetParent, - extend: extend, - addClass: addClass, - removeClass: removeClass, - hasClass: hasClass, - updateClasses: updateClasses, - defer: defer, - flush: flush, - uniqueId: uniqueId, - Evented: Evented, - getScrollBarSize: getScrollBarSize - }; - -}).call(this); diff --git a/package.json b/package.json index 368ce729..18b89fcb 100644 --- a/package.json +++ b/package.json @@ -1,23 +1,34 @@ { "name": "tether", - "version": "0.7.2", + "version": "1.0.0", "description": "A client-side library to make absolutely positioned elements attach to elements in the page efficiently.", - "main": "tether.js", "authors": [ "Zack Bloom ", "Adam Schwartz " ], + "maintainers": [ + "Nicholas Hwang " + ], + "scripts": { + "build": "gulp build" + }, "license": "MIT", + "main": "dist/js/tether.js", "devDependencies": { - "coffee-script": "~1.6.3", - "gulp": "~3.3.0", - "gulp-autoprefixer": "^2.2.0", - "gulp-coffee": "~1.2.5", - "gulp-concat": "~2.1.7", - "gulp-header": "~1.0.2", - "gulp-rename": "~0.2.1", - "gulp-sass": "^2.0.0", - "gulp-uglify": "~0.1.0", - "gulp-wrap-umd": "~0.1.0" + "del": "^1.1.1", + "gulp": "^3.9.0", + "gulp-autoprefixer": "^2.3.1", + "gulp-babel": "^5.1.0", + "gulp-bump": "^0.3.0", + "gulp-concat": "^2.5.2", + "gulp-filter": "^2.0.2", + "gulp-header": "^1.2.2", + "gulp-minify-css": "^1.1.6", + "gulp-plumber": "^1.0.1", + "gulp-rename": "^1.2.2", + "gulp-sass": "^2.0.1", + "gulp-tag-version": "^1.2.1", + "gulp-uglify": "^1.2.0", + "gulp-wrap-umd": "^0.2.1" } } diff --git a/sass/helpers/_tether-theme-arrows.sass b/src/css/helpers/_tether-theme-arrows.sass similarity index 100% rename from sass/helpers/_tether-theme-arrows.sass rename to src/css/helpers/_tether-theme-arrows.sass diff --git a/sass/helpers/_tether-theme-basic.sass b/src/css/helpers/_tether-theme-basic.sass similarity index 100% rename from sass/helpers/_tether-theme-basic.sass rename to src/css/helpers/_tether-theme-basic.sass diff --git a/sass/helpers/_tether.sass b/src/css/helpers/_tether.sass similarity index 100% rename from sass/helpers/_tether.sass rename to src/css/helpers/_tether.sass diff --git a/sass/mixins/_inline-block.sass b/src/css/mixins/_inline-block.sass similarity index 100% rename from sass/mixins/_inline-block.sass rename to src/css/mixins/_inline-block.sass diff --git a/sass/mixins/_pie-clearfix.sass b/src/css/mixins/_pie-clearfix.sass similarity index 100% rename from sass/mixins/_pie-clearfix.sass rename to src/css/mixins/_pie-clearfix.sass diff --git a/sass/tether-theme-arrows-dark.sass b/src/css/tether-theme-arrows-dark.sass similarity index 100% rename from sass/tether-theme-arrows-dark.sass rename to src/css/tether-theme-arrows-dark.sass diff --git a/sass/tether-theme-arrows.sass b/src/css/tether-theme-arrows.sass similarity index 100% rename from sass/tether-theme-arrows.sass rename to src/css/tether-theme-arrows.sass diff --git a/sass/tether-theme-basic.sass b/src/css/tether-theme-basic.sass similarity index 100% rename from sass/tether-theme-basic.sass rename to src/css/tether-theme-basic.sass diff --git a/sass/tether.sass b/src/css/tether.sass similarity index 100% rename from sass/tether.sass rename to src/css/tether.sass diff --git a/src/js/abutment.js b/src/js/abutment.js new file mode 100644 index 00000000..96056353 --- /dev/null +++ b/src/js/abutment.js @@ -0,0 +1,61 @@ +/* globals TetherBase */ + +const {getBounds, updateClasses, defer} = TetherBase.Utils; + +TetherBase.modules.push({ + position({top, left}) { + const {height, width} = this.cache('element-bounds', () => { + return getBounds(this.element); + }); + + const targetPos = this.getTargetBounds(); + + const bottom = top + height; + const right = left + width; + + const abutted = []; + if (top <= targetPos.bottom && bottom >= targetPos.top) { + ['left', 'right'].forEach(side => { + const targetPosSide = targetPos[side]; + if (targetPosSide === left || targetPosSide === right) { + abutted.push(side); + } + }); + } + + if (left <= targetPos.right && right >= targetPos.left) { + ['top', 'bottom'].forEach(side => { + const targetPosSide = targetPos[side]; + if (targetPosSide === top || targetPosSide === bottom) { + abutted.push(side); + } + }); + } + + const allClasses = []; + const addClasses = []; + + const sides = ['left', 'top', 'right', 'bottom']; + allClasses.push(this.getClass('abutted')); + sides.forEach(side => { + allClasses.push(`${ this.getClass('abutted') }-${ side }`); + }); + + if (abutted.length) { + addClasses.push(this.getClass('abutted')); + } + + abutted.forEach(side => { + addClasses.push(`${ this.getClass('abutted') }-${ side }`); + }); + + defer(() => { + if (!(this.options.addTargetClasses === false)) { + updateClasses(this.target, addClasses, allClasses); + } + updateClasses(this.element, addClasses, allClasses); + }); + + return true; + } +}); diff --git a/src/js/constraint.js b/src/js/constraint.js new file mode 100644 index 00000000..5475b868 --- /dev/null +++ b/src/js/constraint.js @@ -0,0 +1,343 @@ +/* globals TetherBase */ + +const { + getBounds, + extend, + updateClasses, + defer +} = TetherBase.Utils; + +const BOUNDS_FORMAT = ['left', 'top', 'right', 'bottom']; + +function getBoundingRect(tether, to) { + if (to === 'scrollParent') { + to = tether.scrollParent; + } else if (to === 'window') { + to = [pageXOffset, pageYOffset, innerWidth + pageXOffset, innerHeight + pageYOffset]; + } + + if (to === document) { + to = to.documentElement; + } + + if (typeof to.nodeType !== 'undefined') { + const size = getBounds(to); + const pos = size; + const style = getComputedStyle(to); + + to = [pos.left, pos.top, size.width + pos.left, size.height + pos.top]; + + BOUNDS_FORMAT.forEach((side, i) => { + side = side[0].toUpperCase() + side.substr(1); + if (side === 'Top' || side === 'Left') { + to[i] += parseFloat(style[`border${ side }Width`]); + } else { + to[i] -= parseFloat(style[`border${ side }Width`]); + } + }); + } + + return to; +} + +TetherBase.modules.push({ + position({top, left, targetAttachment}) { + if (!this.options.constraints) { + return true; + } + + let {height, width} = this.cache('element-bounds', () => { + return getBounds(this.element); + }); + + if (width === 0 && height === 0 && typeof this.lastSize !== 'undefined') { + // Handle the item getting hidden as a result of our positioning without glitching + // the classes in and out + ({width, height} = this.lastSize); + } + + const targetSize = this.cache('target-bounds', () => { + return this.getTargetBounds(); + }); + + const {height: targetHeight, width: targetWidth} = targetSize; + + const allClasses = [this.getClass('pinned'), this.getClass('out-of-bounds')]; + + this.options.constraints.forEach(constraint => { + const {outOfBoundsClass, pinnedClass} = constraint; + if (outOfBoundsClass) { + allClasses.push(outOfBoundsClass); + } + if (pinnedClass) { + allClasses.push(pinnedClass); + } + }); + + allClasses.forEach(cls => { + ['left', 'top', 'right', 'bottom'].forEach(side => { + allClasses.push(`${ cls }-${ side }`); + }); + }); + + const addClasses = []; + + const tAttachment = extend({}, targetAttachment); + const eAttachment = extend({}, this.attachment); + + this.options.constraints.forEach(constraint => { + let {to, attachment, pin} = constraint; + + if (typeof attachment === 'undefined') { + attachment = ''; + } + + let changeAttachX, changeAttachY; + if (attachment.indexOf(' ') >= 0) { + [changeAttachY, changeAttachX] = attachment.split(' '); + } else { + changeAttachX = changeAttachY = attachment; + } + + const bounds = getBoundingRect(this, to); + + if (changeAttachY === 'target' || changeAttachY === 'both') { + if (top < bounds[1] && tAttachment.top === 'top') { + top += targetHeight; + tAttachment.top = 'bottom'; + } + + if (top + height > bounds[3] && tAttachment.top === 'bottom') { + top -= targetHeight; + tAttachment.top = 'top'; + } + } + + if (changeAttachY === 'together') { + if (top < bounds[1] && tAttachment.top === 'top') { + if (eAttachment.top === 'bottom') { + top += targetHeight; + tAttachment.top = 'bottom'; + + top += height; + eAttachment.top = 'top'; + + } else if (eAttachment.top === 'top') { + top += targetHeight; + tAttachment.top = 'bottom'; + + top -= height; + eAttachment.top = 'bottom'; + } + } + + if (top + height > bounds[3] && tAttachment.top === 'bottom') { + if (eAttachment.top === 'top') { + top -= targetHeight; + tAttachment.top = 'top'; + + top -= height; + eAttachment.top = 'bottom'; + + } else if (eAttachment.top === 'bottom') { + top -= targetHeight; + tAttachment.top = 'top'; + + top += height; + eAttachment.top = 'top'; + } + } + + if (tAttachment.top === 'middle') { + if (top + height > bounds[3] && eAttachment.top === 'top') { + top -= height; + eAttachment.top = 'bottom'; + + } else if (top < bounds[1] && eAttachment.top === 'bottom') { + top += height; + eAttachment.top = 'top'; + } + } + } + + if (changeAttachX === 'target' || changeAttachX === 'both') { + if (left < bounds[0] && tAttachment.left === 'left') { + left += targetWidth; + tAttachment.left = 'right'; + } + + if (left + width > bounds[2] && tAttachment.left === 'right') { + left -= targetWidth; + tAttachment.left = 'left'; + } + } + + if (changeAttachX === 'together') { + if (left < bounds[0] && tAttachment.left === 'left') { + if (eAttachment.left === 'right') { + left += targetWidth; + tAttachment.left = 'right'; + + left += width; + eAttachment.left = 'left'; + + } else if (eAttachment.left === 'left') { + left += targetWidth; + tAttachment.left = 'right'; + + left -= width; + eAttachment.left = 'right'; + } + + } else if (left + width > bounds[2] && tAttachment.left === 'right') { + if (eAttachment.left === 'left') { + left -= targetWidth; + tAttachment.left = 'left'; + + left -= width; + eAttachment.left = 'right'; + + } else if (eAttachment.left === 'right') { + left -= targetWidth; + tAttachment.left = 'left'; + + left += width; + eAttachment.left = 'left'; + } + + } else if (tAttachment.left === 'center') { + if (left + width > bounds[2] && eAttachment.left === 'left') { + left -= width; + eAttachment.left = 'right'; + + } else if (left < bounds[0] && eAttachment.left === 'right') { + left += width; + eAttachment.left = 'left'; + } + } + } + + if (changeAttachY === 'element' || changeAttachY === 'both') { + if (top < bounds[1] && eAttachment.top === 'bottom') { + top += height; + eAttachment.top = 'top'; + } + + if (top + height > bounds[3] && eAttachment.top === 'top') { + top -= height; + eAttachment.top = 'bottom'; + } + } + + if (changeAttachX === 'element' || changeAttachX === 'both') { + if (left < bounds[0] && eAttachment.left === 'right') { + left += width; + eAttachment.left = 'left'; + } + + if (left + width > bounds[2] && eAttachment.left === 'left') { + left -= width; + eAttachment.left = 'right'; + } + } + + if (typeof pin === 'string') { + pin = pin.split(',').map(p => p.trim()); + } else if (pin === true) { + pin = ['top', 'left', 'right', 'bottom']; + } + + pin = pin || []; + + const pinned = []; + const oob = []; + + if (top < bounds[1]) { + if (pin.indexOf('top') >= 0) { + top = bounds[1]; + pinned.push('top'); + } else { + oob.push('top'); + } + } + + if (top + height > bounds[3]) { + if (pin.indexOf('bottom') >= 0) { + top = bounds[3] - height; + pinned.push('bottom'); + } else { + oob.push('bottom'); + } + } + + if (left < bounds[0]) { + if (pin.indexOf('left') >= 0) { + left = bounds[0]; + pinned.push('left'); + } else { + oob.push('left'); + } + } + + if (left + width > bounds[2]) { + if (pin.indexOf('right') >= 0) { + left = bounds[2] - width; + pinned.push('right'); + } else { + oob.push('right'); + } + } + + if (pinned.length) { + let pinnedClass; + if (typeof this.options.pinnedClass !== 'undefined') { + pinnedClass = this.options.pinnedClass; + } else { + pinnedClass = this.getClass('pinned'); + } + + addClasses.push(pinnedClass); + pinned.forEach(side => { + addClasses.push(`${ pinnedClass }-${ side }`); + }); + } + + if (oob.length) { + let oobClass; + if (typeof this.options.outOfBoundsClass !== 'undefined') { + oobClass = this.options.outOfBoundsClass; + } else { + oobClass = this.getClass('out-of-bounds'); + } + + addClasses.push(oobClass); + oob.forEach(side => { + addClasses.push(`${ oobClass }-${ side }`); + }); + } + + if (pinned.indexOf('left') >= 0 || pinned.indexOf('right') >= 0) { + eAttachment.left = tAttachment.left = false; + } + if (pinned.indexOf('top') >= 0 || pinned.indexOf('bottom') >= 0) { + eAttachment.top = tAttachment.top = false; + } + + if (tAttachment.top !== targetAttachment.top || + tAttachment.left !== targetAttachment.left || + eAttachment.top !== this.attachment.top || + eAttachment.left !== this.attachment.left) { + this.updateAttachClasses(eAttachment, tAttachment); + } + }); + + defer(() => { + if (!(this.options.addTargetClasses === false)) { + updateClasses(this.target, addClasses, allClasses); + } + updateClasses(this.element, addClasses, allClasses); + }); + + return {top, left}; + } +}); diff --git a/src/js/markAttachment.js b/src/js/markAttachment.js new file mode 100644 index 00000000..1b13597e --- /dev/null +++ b/src/js/markAttachment.js @@ -0,0 +1,46 @@ +/* globals TetherBase */ + +TetherBase.modules.push({ + initialize() { + this.markers = {}; + + ['target', 'element'].forEach(type => { + const el = document.createElement('div'); + el.className = this.getClass(`${ type }-marker`); + + const dot = document.createElement('div'); + dot.className = this.getClass('marker-dot'); + el.appendChild(dot); + + this[type].appendChild(el); + + this.markers[type] = {dot, el}; + }); + }, + + position({manualOffset, manualTargetOffset}) { + const offsets = { + element: manualOffset, + target: manualTargetOffset + }; + + for (let type in offsets) { + const offset = offsets[type]; + for (let side in offset) { + let val = offset[side]; + const notString = typeof val !== 'string'; + const notPercent = val.indexOf('%') === -1; + const notPixel = val.indexOf('px') === -1; + if (notString || (notPercent && notPixel)) { + val += 'px'; + } + + if (this.markers[type].dot.style[side] !== val) { + this.markers[type].dot.style[side] = val; + } + } + } + + return true; + } +}); diff --git a/src/js/shift.js b/src/js/shift.js new file mode 100644 index 00000000..ecc872d2 --- /dev/null +++ b/src/js/shift.js @@ -0,0 +1,32 @@ +/* globals TetherBase */ + +TetherBase.modules.push({ + position({top, left}) { + if (!this.options.shift) { + return; + } + + let shift = this.options.shift; + if (typeof this.options.shift === 'function') { + shift = this.options.shift.call(this, {top, left}); + } + + let shiftTop, shiftLeft; + if (typeof shift === 'string') { + shift = shift.split(' '); + shift[1] = shift[1] || shift[0]; + + ([shiftTop, shiftLeft] = shift); + + shiftTop = parseFloat(shiftTop, 10); + shiftLeft = parseFloat(shiftLeft, 10); + } else { + ([shiftTop, shiftLeft] = [shift.top, shift.left]); + } + + top += shiftTop; + left += shiftLeft; + + return {top, left}; + } +}); diff --git a/src/js/tether.js b/src/js/tether.js new file mode 100644 index 00000000..65283fac --- /dev/null +++ b/src/js/tether.js @@ -0,0 +1,768 @@ +/* globals TetherBase, performance */ + +if (typeof TetherBase === 'undefined') { + throw new Error('You must include the utils.js file before tether.js'); +} + +const { + getScrollParent, + getBounds, + getOffsetParent, + extend, + addClass, + removeClass, + updateClasses, + defer, + flush, + getScrollBarSize +} = TetherBase.Utils; + +function within(a, b, diff=1) { + return (a + diff >= b && b >= a - diff); +} + +const transformKey = (() => { + const el = document.createElement('div'); + + const transforms = ['transform', 'webkitTransform', 'OTransform', 'MozTransform', 'msTransform']; + for (let i = 0; i < transforms.length; ++i) { + const key = transforms[i]; + if (el.style[key] !== undefined) { + return key; + } + } +})(); + +const tethers = []; + +const position = () => { + tethers.forEach(tether => { + tether.position(false); + }); + flush(); +}; + +function now() { + if (typeof performance !== 'undefined' && typeof performance.now !== 'undefined') { + return performance.now(); + } + return +new Date; +} + +(() => { + let lastCall = null; + let lastDuration = null; + let pendingTimeout = null; + + const tick = () => { + if (typeof lastDuration !== 'undefined' && lastDuration > 16) { + // We voluntarily throttle ourselves if we can't manage 60fps + lastDuration = Math.min(lastDuration - 16, 250); + + // Just in case this is the last event, remember to position just once more + pendingTimeout = setTimeout(tick, 250); + return; + } + + if (typeof lastCall !== 'undefined' && (now() - lastCall) < 10) { + // Some browsers call events a little too frequently, refuse to run more than is reasonable + return; + } + + if (typeof pendingTimeout !== 'undefined') { + clearTimeout(pendingTimeout); + pendingTimeout = null; + } + + lastCall = now(); + position(); + lastDuration = now() - lastCall; + }; + + ['resize', 'scroll', 'touchmove'].forEach(event => { + window.addEventListener(event, tick); + }); +})(); + +const MIRROR_LR = { + center: 'center', + left: 'right', + right: 'left' +}; + +const MIRROR_TB = { + middle: 'middle', + top: 'bottom', + bottom: 'top' +}; + +const OFFSET_MAP = { + top: 0, + left: 0, + middle: '50%', + center: '50%', + bottom: '100%', + right: '100%' +}; + +const autoToFixedAttachment = (attachment, relativeToAttachment) => { + let {left, top} = attachment; + + if (left === 'auto') { + left = MIRROR_LR[relativeToAttachment.left]; + } + + if (top === 'auto') { + top = MIRROR_TB[relativeToAttachment.top]; + } + + return {left, top}; +}; + +const attachmentToOffset = (attachment) => { + let left = attachment.left; + let top = attachment.top; + + if (typeof OFFSET_MAP[attachment.left] !== 'undefined') { + left = OFFSET_MAP[attachment.left]; + } + + if (typeof OFFSET_MAP[attachment.top] !== 'undefined') { + top = OFFSET_MAP[attachment.top]; + } + + return {left, top}; +}; + +function addOffset(...offsets) { + const out = {top: 0, left: 0}; + + offsets.forEach(({top, left}) => { + if (typeof top === 'string') { + top = parseFloat(top, 10); + } + if (typeof left === 'string') { + left = parseFloat(left, 10); + } + + out.top += top; + out.left += left; + }); + + return out; +} + +function offsetToPx(offset, size) { + if (typeof offset.left === 'string' && offset.left.indexOf('%') !== -1) { + offset.left = parseFloat(offset.left, 10) / 100 * size.width; + } + if (typeof offset.top === 'string' && offset.top.indexOf('%') !== -1) { + offset.top = parseFloat(offset.top, 10) / 100 * size.height; + } + + return offset; +} + +const parseOffset = (value) => { + const [top, left] = value.split(' '); + return {top, left}; +}; +const parseAttachment = parseOffset; + +class TetherClass { + + constructor(options) { + this.position = this.position.bind(this); + + tethers.push(this); + + this.history = []; + + this.setOptions(options, false); + + TetherBase.modules.forEach(module => { + if (typeof module.initialize !== 'undefined') { + module.initialize.call(this); + } + }); + + this.position(); + } + + getClass(key='') { + const {classes} = this.options; + if (typeof classes !== 'undefined' && classes[key]) { + return this.options.classes[key]; + } else if (this.options.classPrefix) { + return `${ this.options.classPrefix }-${ key }`; + } else { + return key; + } + } + + setOptions(options, pos=true) { + const defaults = { + offset: '0 0', + targetOffset: '0 0', + targetAttachment: 'auto auto', + classPrefix: 'tether' + }; + + this.options = extend(defaults, options); + + let {element, target, targetModifier} = this.options; + this.element = element; + this.target = target; + this.targetModifier = targetModifier; + + if (this.target === 'viewport') { + this.target = document.body; + this.targetModifier = 'visible'; + } else if (this.target === 'scroll-handle') { + this.target = document.body; + this.targetModifier = 'scroll-handle'; + } + + ['element', 'target'].forEach(key => { + if (typeof this[key] === 'undefined') { + throw new Error('Tether Error: Both element and target must be defined'); + } + + if (typeof this[key].jquery !== 'undefined') { + this[key] = this[key][0]; + } else if (typeof this[key] === 'string') { + this[key] = document.querySelector(this[key]); + } + }); + + addClass(this.element, this.getClass('element')); + if (!(this.options.addTargetClasses === false)) { + addClass(this.target, this.getClass('target')); + } + + if (!this.options.attachment) { + throw new Error('Tether Error: You must provide an attachment'); + } + + this.targetAttachment = parseAttachment(this.options.targetAttachment); + this.attachment = parseAttachment(this.options.attachment); + this.offset = parseOffset(this.options.offset); + this.targetOffset = parseOffset(this.options.targetOffset); + + if (typeof this.scrollParent !== 'undefined') { + this.disable(); + } + + if (this.targetModifier === 'scroll-handle') { + this.scrollParent = this.target; + } else { + this.scrollParent = getScrollParent(this.target); + } + + if(!(this.options.enabled === false)) { + this.enable(pos); + } + } + + getTargetBounds() { + if (typeof this.targetModifier !== 'undefined') { + if (this.targetModifier === 'visible') { + if (this.target === document.body) { + return {top: pageYOffset, left: pageXOffset, height: innerHeight, width: innerWidth}; + } else { + const bounds = getBounds(this.target); + + const out = { + height: bounds.height, + width: bounds.width, + top: bounds.top, + left: bounds.left + }; + + out.height = Math.min(out.height, bounds.height - (pageYOffset - bounds.top)); + out.height = Math.min(out.height, bounds.height - ((bounds.top + bounds.height) - (pageYOffset + innerHeight))); + out.height = Math.min(innerHeight, out.height); + out.height -= 2; + + out.width = Math.min(out.width, bounds.width - (pageXOffset - bounds.left)); + out.width = Math.min(out.width, bounds.width - ((bounds.left + bounds.width) - (pageXOffset + innerWidth))); + out.width = Math.min(innerWidth, out.width); + out.width -= 2; + + if (out.top < pageYOffset) { + out.top = pageYOffset; + } + if (out.left < pageXOffset) { + out.left = pageXOffset; + } + + return out; + } + } else if (this.targetModifier === 'scroll-handle') { + let bounds; + let target = this.target; + if (target === document.body) { + target = document.documentElement; + + bounds = { + left: pageXOffset, + top: pageYOffset, + height: innerHeight, + width: innerWidth + }; + } else { + bounds = getBounds(target); + } + + const style = getComputedStyle(target); + + const hasBottomScroll = ( + target.scrollWidth > target.clientWidth || + [style.overflow, style.overflowX].indexOf('scroll') >= 0 || + this.target !== document.body + ); + + let scrollBottom = 0; + if (hasBottomScroll) { + scrollBottom = 15; + } + + const height = bounds.height - parseFloat(style.borderTopWidth) - parseFloat(style.borderBottomWidth) - scrollBottom; + + const out = { + width: 15, + height: height * 0.975 * (height / target.scrollHeight), + left: bounds.left + bounds.width - parseFloat(style.borderLeftWidth) - 15 + }; + + let fitAdj = 0; + if (height < 408 && this.target === document.body) { + fitAdj = -0.00011 * Math.pow(height, 2) - 0.00727 * height + 22.58; + } + + if (this.target !== document.body) { + out.height = Math.max(out.height, 24); + } + + const scrollPercentage = this.target.scrollTop / (target.scrollHeight - height); + out.top = scrollPercentage * (height - out.height - fitAdj) + bounds.top + parseFloat(style.borderTopWidth); + + if (this.target === document.body) { + out.height = Math.max(out.height, 24); + } + + return out; + } + } else { + return getBounds(this.target); + } + } + + clearCache() { + this._cache = {}; + } + + cache(k, getter) { + // More than one module will often need the same DOM info, so + // we keep a cache which is cleared on each position call + if (typeof this._cache === 'undefined') { + this._cache = {}; + } + + if (typeof this._cache[k] === 'undefined') { + this._cache[k] = getter.call(this); + } + + return this._cache[k]; + } + + enable(pos=true) { + if (!(this.options.addTargetClasses === false)) { + addClass(this.target, this.getClass('enabled')); + } + addClass(this.element, this.getClass('enabled')); + this.enabled = true; + + if (this.scrollParent !== document) { + this.scrollParent.addEventListener('scroll', this.position); + } + + if (pos) { + this.position(); + } + } + + disable() { + removeClass(this.target, this.getClass('enabled')); + removeClass(this.element, this.getClass('enabled')); + this.enabled = false; + + if (typeof this.scrollParent !== 'undefined') { + this.scrollParent.removeEventListener('scroll', this.position); + } + } + + destroy() { + this.disable(); + + tethers.forEach((tether, i) => { + if (tether === this) { + tethers.splice(i, 1); + return; + } + }); + } + + updateAttachClasses(elementAttach, targetAttach) { + elementAttach = elementAttach || this.attachment; + targetAttach = targetAttach || this.targetAttachment; + const sides = ['left', 'top', 'bottom', 'right', 'middle', 'center']; + + if (typeof this._addAttachClasses !== 'undefined' && this._addAttachClasses.length) { + // updateAttachClasses can be called more than once in a position call, so + // we need to clean up after ourselves such that when the last defer gets + // ran it doesn't add any extra classes from previous calls. + this._addAttachClasses.splice(0, this._addAttachClasses.length); + } + + if (typeof this._addAttachClasses === 'undefined') { + this._addAttachClasses = []; + } + const add = this._addAttachClasses; + + if (elementAttach.top) { + add.push(`${ this.getClass('element-attached') }-${ elementAttach.top }`); + } + if (elementAttach.left) { + add.push(`${ this.getClass('element-attached') }-${ elementAttach.left }`); + } + if (targetAttach.top) { + add.push(`${ this.getClass('target-attached') }-${ targetAttach.top }`); + } + if (targetAttach.left) { + add.push(`${ this.getClass('target-attached') }-${ targetAttach.left }`); + } + + const all = []; + sides.forEach(side => { + all.push(`${ this.getClass('element-attached') }-${ side }`); + all.push(`${ this.getClass('target-attached') }-${ side }`); + }); + + defer(() => { + if (!(typeof this._addAttachClasses !== 'undefined')) { + return; + } + + updateClasses(this.element, this._addAttachClasses, all); + if (!(this.options.addTargetClasses === false)) { + updateClasses(this.target, this._addAttachClasses, all); + } + + delete this._addAttachClasses; + }); + } + + position(flushChanges=true) { + // flushChanges commits the changes immediately, leave true unless you are positioning multiple + // tethers (in which case call Tether.Utils.flush yourself when you're done) + + if (!this.enabled) { + return; + } + + this.clearCache(); + + // Turn 'auto' attachments into the appropriate corner or edge + const targetAttachment = autoToFixedAttachment(this.targetAttachment, this.attachment); + + this.updateAttachClasses(this.attachment, targetAttachment); + + const elementPos = this.cache('element-bounds', () => { + return getBounds(this.element); + }); + + let {width, height} = elementPos; + + if (width === 0 && height === 0 && typeof this.lastSize !== 'undefined') { + // We cache the height and width to make it possible to position elements that are + // getting hidden. + ({width, height} = this.lastSize); + } else { + this.lastSize = {width, height}; + } + + const targetPos = this.cache('target-bounds', () => { + return this.getTargetBounds(); + }); + const targetSize = targetPos; + + // Get an actual px offset from the attachment + let offset = offsetToPx(attachmentToOffset(this.attachment), {width, height}); + let targetOffset = offsetToPx(attachmentToOffset(targetAttachment), targetSize); + + const manualOffset = offsetToPx(this.offset, {width, height}); + const manualTargetOffset = offsetToPx(this.targetOffset, targetSize); + + // Add the manually provided offset + offset = addOffset(offset, manualOffset); + targetOffset = addOffset(targetOffset, manualTargetOffset); + + // It's now our goal to make (element position + offset) == (target position + target offset) + let left = targetPos.left + targetOffset.left - offset.left; + let top = targetPos.top + targetOffset.top - offset.top; + + for (let i = 0; i < TetherBase.modules.length; ++i) { + const module = TetherBase.modules[i]; + const ret = module.position.call(this, { + left, + top, + targetAttachment, + targetPos, + elementPos, + offset, + targetOffset, + manualOffset, + manualTargetOffset, + scrollbarSize, + attachment: this.attachment + }); + + if (ret === false) { + return false; + } else if (typeof ret === 'undefined' || typeof ret !== 'object') { + continue; + } else { + ({top, left} = ret); + } + } + + // We describe the position three different ways to give the optimizer + // a chance to decide the best possible way to position the element + // with the fewest repaints. + const next = { + // It's position relative to the page (absolute positioning when + // the element is a child of the body) + page: { + top: top, + left: left + }, + + // It's position relative to the viewport (fixed positioning) + viewport: { + top: top - pageYOffset, + bottom: pageYOffset - top - height + innerHeight, + left: left - pageXOffset, + right: pageXOffset - left - width + innerWidth + } + }; + + let scrollbarSize; + if (document.body.scrollWidth > window.innerWidth) { + scrollbarSize = this.cache('scrollbar-size', getScrollBarSize); + next.viewport.bottom -= scrollbarSize.height; + } + + if (document.body.scrollHeight > window.innerHeight) { + scrollbarSize = this.cache('scrollbar-size', getScrollBarSize); + next.viewport.right -= scrollbarSize.width; + } + + if (['', 'static'].indexOf(document.body.style.position) === -1 || + ['', 'static'].indexOf(document.body.parentElement.style.position) === -1) { + // Absolute positioning in the body will be relative to the page, not the 'initial containing block' + next.page.bottom = document.body.scrollHeight - top - height; + next.page.right = document.body.scrollWidth - left - width; + } + + if (typeof this.options.optimizations !== 'undefined' && + this.options.optimizations.moveElement !== false && + !(typeof this.targetModifier !== 'undefined')) { + const offsetParent = this.cache('target-offsetparent', () => getOffsetParent(this.target)); + const offsetPosition = this.cache('target-offsetparent-bounds', () => getBounds(offsetParent)); + const offsetParentStyle = getComputedStyle(offsetParent); + const offsetParentSize = offsetPosition; + + const offsetBorder = {}; + ['Top', 'Left', 'Bottom', 'Right'].forEach(side => { + offsetBorder[side.toLowerCase()] = parseFloat(offsetParentStyle[`border${ side }Width`]); + }); + + offsetPosition.right = document.body.scrollWidth - offsetPosition.left - offsetParentSize.width + offsetBorder.right; + offsetPosition.bottom = document.body.scrollHeight - offsetPosition.top - offsetParentSize.height + offsetBorder.bottom; + + if (next.page.top >= (offsetPosition.top + offsetBorder.top) && next.page.bottom >= offsetPosition.bottom) { + if (next.page.left >= (offsetPosition.left + offsetBorder.left) && next.page.right >= offsetPosition.right) { + // We're within the visible part of the target's scroll parent + const scrollTop = offsetParent.scrollTop; + const scrollLeft = offsetParent.scrollLeft; + + // It's position relative to the target's offset parent (absolute positioning when + // the element is moved to be a child of the target's offset parent). + next.offset = { + top: next.page.top - offsetPosition.top + scrollTop - offsetBorder.top, + left: next.page.left - offsetPosition.left + scrollLeft - offsetBorder.left + }; + } + } + } + + + // We could also travel up the DOM and try each containing context, rather than only + // looking at the body, but we're gonna get diminishing returns. + + this.move(next); + + this.history.unshift(next); + + if (this.history.length > 3) { + this.history.pop(); + } + + if (flushChanges) { + flush(); + } + + return true; + } + + // THE ISSUE + move(pos) { + if (!(typeof this.element.parentNode !== 'undefined')) { + return; + } + + const same = {}; + + for (let type in pos) { + same[type] = {}; + + for (let key in pos[type]) { + let found = false; + + for (let i = 0; i < this.history.length; ++i) { + const point = this.history[i]; + if (typeof point[type] !== 'undefined' && + !within(point[type][key], pos[type][key])) { + found = true; + break; + } + + } + + if (!found) { + same[type][key] = true; + } + } + } + + let css = {top: '', left: '', right: '', bottom: ''}; + + const transcribe = (_same, _pos) => { + const hasOptimizations = typeof this.options.optimizations !== 'undefined'; + const gpu = hasOptimizations ? this.options.optimizations.gpu : null; + if (gpu !== false) { + let yPos, xPos; + if (_same.top) { + css.top = 0; + yPos = _pos.top; + } else { + css.bottom = 0; + yPos = -_pos.bottom; + } + + if (_same.left) { + css.left = 0; + xPos = _pos.left; + } else { + css.right = 0; + xPos = -_pos.right; + } + + css[transformKey] = `translateX(${ Math.round(xPos) }px) translateY(${ Math.round(yPos) }px)`; + + if (transformKey !== 'msTransform') { + // The Z transform will keep this in the GPU (faster, and prevents artifacts), + // but IE9 doesn't support 3d transforms and will choke. + css[transformKey] += " translateZ(0)"; + } + + } else { + if (_same.top) { + css.top = `${ _pos.top }px`; + } else { + css.bottom = `${ _pos.bottom }px`; + } + + if (_same.left) { + css.left = `${ _pos.left }px`; + } else { + css.right = `${ _pos.right }px`; + } + } + }; + + let moved = false; + if ((same.page.top || same.page.bottom) && (same.page.left || same.page.right)) { + css.position = 'absolute'; + transcribe(same.page, pos.page); + + } else if ((same.viewport.top || same.viewport.bottom) && (same.viewport.left || same.viewport.right)) { + css.position = 'fixed'; + transcribe(same.viewport, pos.viewport); + + } else if (typeof same.offset !== 'undefined' && same.offset.top && same.offset.left) { + css.position = 'absolute'; + const offsetParent = this.cache('target-offsetparent', () => getOffsetParent(this.target)); + + if (getOffsetParent(this.element) !== offsetParent) { + defer(() => { + this.element.parentNode.removeChild(this.element); + offsetParent.appendChild(this.element); + }); + } + + transcribe(same.offset, pos.offset); + moved = true; + + } else { + css.position = 'absolute'; + transcribe({top: true, left: true}, pos.page); + } + + if(!moved && this.element.parentNode.tagName !== 'BODY') { + this.element.parentNode.removeChild(this.element); + document.body.appendChild(this.element); + } + + // Any css change will trigger a repaint, so let's avoid one if nothing changed + const writeCSS = {}; + let write = false; + for (let key in css) { + let val = css[key]; + let elVal = this.element.style[key]; + + if (elVal !== '' && val !== '' && ['top', 'left', 'bottom', 'right'].indexOf(key) >= 0) { + elVal = parseFloat(elVal); + val = parseFloat(val); + } + + if (elVal !== val) { + write = true; + writeCSS[key] = val; + } + } + + if (write) { + defer(() => { + extend(this.element.style, writeCSS); + }); + } + } +} + +TetherClass.modules = []; + +TetherBase.position = position; + +let Tether = extend(TetherClass, TetherBase); diff --git a/src/js/utils.js b/src/js/utils.js new file mode 100644 index 00000000..d2deddbf --- /dev/null +++ b/src/js/utils.js @@ -0,0 +1,326 @@ +let TetherBase; +if (typeof TetherBase === 'undefined') { + TetherBase = {modules: []}; +} + +function getScrollParent(el) { + const {position} = getComputedStyle(el); + + if (position === 'fixed') { + return el; + } + + let parent = el; + while (parent = parent.parentNode) { + let style; + try { + style = getComputedStyle(parent); + } catch (err) {} + + if (typeof style === 'undefined') { + return parent; + } + + const {overflow, overflowX, overflowY} = style; + if (/(auto|scroll)/.test(overflow + overflowY + overflowX)) { + if (position !== 'absolute' || ['relative', 'absolute', 'fixed'].indexOf(style.position) >= 0) { + return parent; + } + } + } + + return document.body; +} + +const uniqueId = (() => { + let id = 0; + return () => ++id; +})(); + +const zeroPosCache = {}; +const getOrigin = (doc) => { + // getBoundingClientRect is unfortunately too accurate. It introduces a pixel or two of + // jitter as the user scrolls that messes with our ability to detect if two positions + // are equivilant or not. We place an element at the top left of the page that will + // get the same jitter, so we can cancel the two out. + let node = doc._tetherZeroElement; + if (typeof node === 'undefined') { + node = doc.createElement('div'); + node.setAttribute('data-tether-id', uniqueId()); + extend(node.style, { + top: 0, + left: 0, + position: 'absolute' + }); + + doc.body.appendChild(node); + + doc._tetherZeroElement = node; + } + + const id = node.getAttribute('data-tether-id'); + if (typeof zeroPosCache[id] === 'undefined') { + zeroPosCache[id] = {}; + + const rect = node.getBoundingClientRect(); + for (let k in rect) { + // Can't use extend, as on IE9, elements don't resolve to be hasOwnProperty + zeroPosCache[id][k] = rect[k]; + } + + // Clear the cache when this position call is done + defer(() => { + delete zeroPosCache[id]; + }); + } + + return zeroPosCache[id]; +}; + +function getBounds(el) { + let doc; + if (el === document) { + doc = document; + el = document.documentElement; + } else { + doc = el.ownerDocument; + } + + const docEl = doc.documentElement; + + const box = {}; + // The original object returned by getBoundingClientRect is immutable, so we clone it + // We can't use extend because the properties are not considered part of the object by hasOwnProperty in IE9 + const rect = el.getBoundingClientRect(); + for (let k in rect) { + box[k] = rect[k]; + } + + const origin = getOrigin(doc); + + box.top -= origin.top; + box.left -= origin.left; + + if (typeof box.width === 'undefined') { + box.width = document.body.scrollWidth - box.left - box.right; + } + if (typeof box.height === 'undefined') { + box.height = document.body.scrollHeight - box.top - box.bottom; + } + + box.top = box.top - docEl.clientTop; + box.left = box.left - docEl.clientLeft; + box.right = doc.body.clientWidth - box.width - box.left; + box.bottom = doc.body.clientHeight - box.height - box.top; + + return box; +} + +function getOffsetParent(el) { + return el.offsetParent || document.documentElement; +} + +function getScrollBarSize() { + const inner = document.createElement('div'); + inner.style.width = '100%'; + inner.style.height = '200px'; + + const outer = document.createElement('div'); + extend(outer.style, { + position: 'absolute', + top: 0, + left: 0, + pointerEvents: 'none', + visibility: 'hidden', + width: '200px', + height: '150px', + overflow: 'hidden' + }); + + outer.appendChild(inner); + + document.body.appendChild(outer); + + const widthContained = inner.offsetWidth; + outer.style.overflow = 'scroll'; + let widthScroll = inner.offsetWidth; + + if (widthContained === widthScroll) { + widthScroll = outer.clientWidth; + } + + document.body.removeChild(outer); + + const width = widthContained - widthScroll; + + return {width, height: width}; +} + +function extend(out={}) { + const args = []; + + Array.prototype.push.apply(args, arguments); + + args.slice(1).forEach(obj => { + if (obj) { + for (let key in obj) { + if ({}.hasOwnProperty.call(obj, key)) { + out[key] = obj[key]; + } + } + } + }); + + return out; +} + +function removeClass(el, name) { + if (typeof el.classList !== 'undefined') { + name.split(' ').forEach(cls => { + if (cls.trim()) { + el.classList.remove(cls); + } + }); + } else { + const regex = new RegExp(`(^| )${ name.split(' ').join('|') }( |$)`, 'gi'); + const className = getClassName(el).replace(regex, ' '); + setClassName(el, className); + } +} + +function addClass(el, name) { + if (typeof el.classList !== 'undefined') { + name.split(' ').forEach(cls => { + if (cls.trim()) { + el.classList.add(cls); + } + }); + } else { + removeClass(el, name); + const cls = getClassName(el) + ` #{name}`; + setClassName(el, cls); + } +} + +function hasClass(el, name) { + if (typeof el.classList !== 'undefined') { + return el.classList.contains(name); + } + const className = getClassName(el); + return new RegExp(`(^| )${ name }( |$)`, 'gi').test(className); +} + +function getClassName(el) { + if (el.className instanceof SVGAnimatedString) { + return el.className.baseVal; + } + return el.className; +} + +function setClassName(el, className) { + el.setAttribute('class', className); +} + + +function updateClasses(el, add, all) { + // Of the set of 'all' classes, we need the 'add' classes, and only the + // 'add' classes to be set. + all.forEach(cls => { + if (add.indexOf(cls) === -1 && hasClass(el, cls)) { + removeClass(el, cls); + } + }); + + add.forEach(cls => { + if (!hasClass(el, cls)) { + addClass(el, cls); + } + }); +} + +const deferred = []; + +const defer = (fn) => { + deferred.push(fn); +}; + +const flush = () => { + let fn; + while(fn = deferred.pop()) { + fn(); + } +}; + +class Evented { + on(event, handler, ctx, once=false) { + if (typeof this.bindings === 'undefined') { + this.bindings = {}; + } + if (typeof this.bindings[event] === 'undefined') { + this.bindings[event] = []; + } + this.bindings[event].push({handler, ctx, once}); + } + + once(event, handler, ctx) { + this.on(event, handler, ctx, true); + } + + off(event, handler) { + if (typeof this.bindings !== 'undefined' && + typeof this.bindings[event] !== 'undefined') { + return; + } + + if (typeof handler === 'undefined') { + delete this.bindings[event]; + } else { + let i = 0; + while (i < this.bindings[event].length) { + if (this.bindings[event][i].handler === handler) { + this.bindings[event].splice(i, 1); + } else { + ++i; + } + } + } + } + + trigger(event, ...args) { + if (typeof this.bindings !== 'undefined' && this.bindings[event]) { + let i = 0; + while (i < this.bindings[event].length) { + const {handler, ctx, once} = this.bindings[event][i]; + + let context = ctx; + if (typeof context === 'undefined') { + context = this; + } + + handler.apply(context, args); + + if (once) { + this.bindings[event].splice(i, 1); + } else { + ++i; + } + } + } + } +} + +TetherBase.Utils = { + getScrollParent, + getBounds, + getOffsetParent, + extend, + addClass, + removeClass, + hasClass, + updateClasses, + defer, + flush, + uniqueId, + Evented, + getScrollBarSize +}; diff --git a/tether.js b/tether.js deleted file mode 100644 index 6a083be0..00000000 --- a/tether.js +++ /dev/null @@ -1,1467 +0,0 @@ -/*! tether 0.7.2 */ - - -(function(root, factory) { - if (typeof define === 'function' && define.amd) { - define(factory); - } else if (typeof exports === 'object') { - module.exports = factory(require,exports,module); - } else { - root.Tether = factory(); - } -}(this, function(require,exports,module) { - -(function() { - var Evented, addClass, defer, deferred, extend, flush, getBounds, getClassName, getOffsetParent, getOrigin, getScrollBarSize, getScrollParent, hasClass, node, removeClass, setClassName, uniqueId, updateClasses, zeroPosCache, - __hasProp = {}.hasOwnProperty, - __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }, - __slice = [].slice; - - if (this.Tether == null) { - this.Tether = { - modules: [] - }; - } - - getScrollParent = function(el) { - var parent, position, scrollParent, style, _ref; - position = getComputedStyle(el).position; - if (position === 'fixed') { - return el; - } - scrollParent = void 0; - parent = el; - while (parent = parent.parentNode) { - try { - style = getComputedStyle(parent); - } catch (_error) {} - if (style == null) { - return parent; - } - if (/(auto|scroll)/.test(style['overflow'] + style['overflowY'] + style['overflowX'])) { - if (position !== 'absolute' || ((_ref = style['position']) === 'relative' || _ref === 'absolute' || _ref === 'fixed')) { - return parent; - } - } - } - return document.body; - }; - - uniqueId = (function() { - var id; - id = 0; - return function() { - return id++; - }; - })(); - - zeroPosCache = {}; - - getOrigin = function(doc) { - var id, k, node, v, _ref; - node = doc._tetherZeroElement; - if (node == null) { - node = doc.createElement('div'); - node.setAttribute('data-tether-id', uniqueId()); - extend(node.style, { - top: 0, - left: 0, - position: 'absolute' - }); - doc.body.appendChild(node); - doc._tetherZeroElement = node; - } - id = node.getAttribute('data-tether-id'); - if (zeroPosCache[id] == null) { - zeroPosCache[id] = {}; - _ref = node.getBoundingClientRect(); - for (k in _ref) { - v = _ref[k]; - zeroPosCache[id][k] = v; - } - defer(function() { - return zeroPosCache[id] = void 0; - }); - } - return zeroPosCache[id]; - }; - - node = null; - - getBounds = function(el) { - var box, doc, docEl, k, origin, v, _ref; - if (el === document) { - doc = document; - el = document.documentElement; - } else { - doc = el.ownerDocument; - } - docEl = doc.documentElement; - box = {}; - _ref = el.getBoundingClientRect(); - for (k in _ref) { - v = _ref[k]; - box[k] = v; - } - origin = getOrigin(doc); - box.top -= origin.top; - box.left -= origin.left; - if (box.width == null) { - box.width = document.body.scrollWidth - box.left - box.right; - } - if (box.height == null) { - box.height = document.body.scrollHeight - box.top - box.bottom; - } - box.top = box.top - docEl.clientTop; - box.left = box.left - docEl.clientLeft; - box.right = doc.body.clientWidth - box.width - box.left; - box.bottom = doc.body.clientHeight - box.height - box.top; - return box; - }; - - getOffsetParent = function(el) { - return el.offsetParent || document.documentElement; - }; - - getScrollBarSize = function() { - var inner, outer, width, widthContained, widthScroll; - inner = document.createElement('div'); - inner.style.width = '100%'; - inner.style.height = '200px'; - outer = document.createElement('div'); - extend(outer.style, { - position: 'absolute', - top: 0, - left: 0, - pointerEvents: 'none', - visibility: 'hidden', - width: '200px', - height: '150px', - overflow: 'hidden' - }); - outer.appendChild(inner); - document.body.appendChild(outer); - widthContained = inner.offsetWidth; - outer.style.overflow = 'scroll'; - widthScroll = inner.offsetWidth; - if (widthContained === widthScroll) { - widthScroll = outer.clientWidth; - } - document.body.removeChild(outer); - width = widthContained - widthScroll; - return { - width: width, - height: width - }; - }; - - extend = function(out) { - var args, key, obj, val, _i, _len, _ref; - if (out == null) { - out = {}; - } - args = []; - Array.prototype.push.apply(args, arguments); - _ref = args.slice(1); - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - obj = _ref[_i]; - if (obj) { - for (key in obj) { - if (!__hasProp.call(obj, key)) continue; - val = obj[key]; - out[key] = val; - } - } - } - return out; - }; - - removeClass = function(el, name) { - var className, cls, _i, _len, _ref, _results; - if (el.classList != null) { - _ref = name.split(' '); - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - cls = _ref[_i]; - if (cls.trim()) { - _results.push(el.classList.remove(cls)); - } - } - return _results; - } else { - className = getClassName(el).replace(new RegExp("(^| )" + (name.split(' ').join('|')) + "( |$)", 'gi'), ' '); - return setClassName(el, className); - } - }; - - addClass = function(el, name) { - var cls, _i, _len, _ref, _results; - if (el.classList != null) { - _ref = name.split(' '); - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - cls = _ref[_i]; - if (cls.trim()) { - _results.push(el.classList.add(cls)); - } - } - return _results; - } else { - removeClass(el, name); - cls = getClassName(el) + (" " + name); - return setClassName(el, cls); - } - }; - - hasClass = function(el, name) { - if (el.classList != null) { - return el.classList.contains(name); - } else { - return new RegExp("(^| )" + name + "( |$)", 'gi').test(getClassName(el)); - } - }; - - getClassName = function(el) { - if (el.className instanceof SVGAnimatedString) { - return el.className.baseVal; - } else { - return el.className; - } - }; - - setClassName = function(el, className) { - return el.setAttribute('class', className); - }; - - updateClasses = function(el, add, all) { - var cls, _i, _j, _len, _len1, _results; - for (_i = 0, _len = all.length; _i < _len; _i++) { - cls = all[_i]; - if (__indexOf.call(add, cls) < 0) { - if (hasClass(el, cls)) { - removeClass(el, cls); - } - } - } - _results = []; - for (_j = 0, _len1 = add.length; _j < _len1; _j++) { - cls = add[_j]; - if (!hasClass(el, cls)) { - _results.push(addClass(el, cls)); - } else { - _results.push(void 0); - } - } - return _results; - }; - - deferred = []; - - defer = function(fn) { - return deferred.push(fn); - }; - - flush = function() { - var fn, _results; - _results = []; - while (fn = deferred.pop()) { - _results.push(fn()); - } - return _results; - }; - - Evented = (function() { - function Evented() {} - - Evented.prototype.on = function(event, handler, ctx, once) { - var _base; - if (once == null) { - once = false; - } - if (this.bindings == null) { - this.bindings = {}; - } - if ((_base = this.bindings)[event] == null) { - _base[event] = []; - } - return this.bindings[event].push({ - handler: handler, - ctx: ctx, - once: once - }); - }; - - Evented.prototype.once = function(event, handler, ctx) { - return this.on(event, handler, ctx, true); - }; - - Evented.prototype.off = function(event, handler) { - var i, _ref, _results; - if (((_ref = this.bindings) != null ? _ref[event] : void 0) == null) { - return; - } - if (handler == null) { - return delete this.bindings[event]; - } else { - i = 0; - _results = []; - while (i < this.bindings[event].length) { - if (this.bindings[event][i].handler === handler) { - _results.push(this.bindings[event].splice(i, 1)); - } else { - _results.push(i++); - } - } - return _results; - } - }; - - Evented.prototype.trigger = function() { - var args, ctx, event, handler, i, once, _ref, _ref1, _results; - event = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; - if ((_ref = this.bindings) != null ? _ref[event] : void 0) { - i = 0; - _results = []; - while (i < this.bindings[event].length) { - _ref1 = this.bindings[event][i], handler = _ref1.handler, ctx = _ref1.ctx, once = _ref1.once; - handler.apply(ctx != null ? ctx : this, args); - if (once) { - _results.push(this.bindings[event].splice(i, 1)); - } else { - _results.push(i++); - } - } - return _results; - } - }; - - return Evented; - - })(); - - this.Tether.Utils = { - getScrollParent: getScrollParent, - getBounds: getBounds, - getOffsetParent: getOffsetParent, - extend: extend, - addClass: addClass, - removeClass: removeClass, - hasClass: hasClass, - updateClasses: updateClasses, - defer: defer, - flush: flush, - uniqueId: uniqueId, - Evented: Evented, - getScrollBarSize: getScrollBarSize - }; - -}).call(this); - -(function() { - var MIRROR_LR, MIRROR_TB, OFFSET_MAP, Tether, addClass, addOffset, attachmentToOffset, autoToFixedAttachment, defer, extend, flush, getBounds, getOffsetParent, getOuterSize, getScrollBarSize, getScrollParent, getSize, now, offsetToPx, parseAttachment, parseOffset, position, removeClass, tethers, transformKey, updateClasses, within, _Tether, _ref, - __slice = [].slice, - __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; - - if (this.Tether == null) { - throw new Error("You must include the utils.js file before tether.js"); - } - - Tether = this.Tether; - - _ref = Tether.Utils, getScrollParent = _ref.getScrollParent, getSize = _ref.getSize, getOuterSize = _ref.getOuterSize, getBounds = _ref.getBounds, getOffsetParent = _ref.getOffsetParent, extend = _ref.extend, addClass = _ref.addClass, removeClass = _ref.removeClass, updateClasses = _ref.updateClasses, defer = _ref.defer, flush = _ref.flush, getScrollBarSize = _ref.getScrollBarSize; - - within = function(a, b, diff) { - if (diff == null) { - diff = 1; - } - return (a + diff >= b && b >= a - diff); - }; - - transformKey = (function() { - var el, key, _i, _len, _ref1; - el = document.createElement('div'); - _ref1 = ['transform', 'webkitTransform', 'OTransform', 'MozTransform', 'msTransform']; - for (_i = 0, _len = _ref1.length; _i < _len; _i++) { - key = _ref1[_i]; - if (el.style[key] !== void 0) { - return key; - } - } - })(); - - tethers = []; - - position = function() { - var tether, _i, _len; - for (_i = 0, _len = tethers.length; _i < _len; _i++) { - tether = tethers[_i]; - tether.position(false); - } - return flush(); - }; - - now = function() { - var _ref1; - return (_ref1 = typeof performance !== "undefined" && performance !== null ? typeof performance.now === "function" ? performance.now() : void 0 : void 0) != null ? _ref1 : +(new Date); - }; - - (function() { - var event, lastCall, lastDuration, pendingTimeout, tick, _i, _len, _ref1, _results; - lastCall = null; - lastDuration = null; - pendingTimeout = null; - tick = function() { - if ((lastDuration != null) && lastDuration > 16) { - lastDuration = Math.min(lastDuration - 16, 250); - pendingTimeout = setTimeout(tick, 250); - return; - } - if ((lastCall != null) && (now() - lastCall) < 10) { - return; - } - if (pendingTimeout != null) { - clearTimeout(pendingTimeout); - pendingTimeout = null; - } - lastCall = now(); - position(); - return lastDuration = now() - lastCall; - }; - _ref1 = ['resize', 'scroll', 'touchmove']; - _results = []; - for (_i = 0, _len = _ref1.length; _i < _len; _i++) { - event = _ref1[_i]; - _results.push(window.addEventListener(event, tick)); - } - return _results; - })(); - - MIRROR_LR = { - center: 'center', - left: 'right', - right: 'left' - }; - - MIRROR_TB = { - middle: 'middle', - top: 'bottom', - bottom: 'top' - }; - - OFFSET_MAP = { - top: 0, - left: 0, - middle: '50%', - center: '50%', - bottom: '100%', - right: '100%' - }; - - autoToFixedAttachment = function(attachment, relativeToAttachment) { - var left, top; - left = attachment.left, top = attachment.top; - if (left === 'auto') { - left = MIRROR_LR[relativeToAttachment.left]; - } - if (top === 'auto') { - top = MIRROR_TB[relativeToAttachment.top]; - } - return { - left: left, - top: top - }; - }; - - attachmentToOffset = function(attachment) { - var _ref1, _ref2; - return { - left: (_ref1 = OFFSET_MAP[attachment.left]) != null ? _ref1 : attachment.left, - top: (_ref2 = OFFSET_MAP[attachment.top]) != null ? _ref2 : attachment.top - }; - }; - - addOffset = function() { - var left, offsets, out, top, _i, _len, _ref1; - offsets = 1 <= arguments.length ? __slice.call(arguments, 0) : []; - out = { - top: 0, - left: 0 - }; - for (_i = 0, _len = offsets.length; _i < _len; _i++) { - _ref1 = offsets[_i], top = _ref1.top, left = _ref1.left; - if (typeof top === 'string') { - top = parseFloat(top, 10); - } - if (typeof left === 'string') { - left = parseFloat(left, 10); - } - out.top += top; - out.left += left; - } - return out; - }; - - offsetToPx = function(offset, size) { - if (typeof offset.left === 'string' && offset.left.indexOf('%') !== -1) { - offset.left = parseFloat(offset.left, 10) / 100 * size.width; - } - if (typeof offset.top === 'string' && offset.top.indexOf('%') !== -1) { - offset.top = parseFloat(offset.top, 10) / 100 * size.height; - } - return offset; - }; - - parseAttachment = parseOffset = function(value) { - var left, top, _ref1; - _ref1 = value.split(' '), top = _ref1[0], left = _ref1[1]; - return { - top: top, - left: left - }; - }; - - _Tether = (function() { - _Tether.modules = []; - - function _Tether(options) { - this.position = __bind(this.position, this); - var module, _i, _len, _ref1, _ref2; - tethers.push(this); - this.history = []; - this.setOptions(options, false); - _ref1 = Tether.modules; - for (_i = 0, _len = _ref1.length; _i < _len; _i++) { - module = _ref1[_i]; - if ((_ref2 = module.initialize) != null) { - _ref2.call(this); - } - } - this.position(); - } - - _Tether.prototype.getClass = function(key) { - var _ref1, _ref2; - if ((_ref1 = this.options.classes) != null ? _ref1[key] : void 0) { - return this.options.classes[key]; - } else if (((_ref2 = this.options.classes) != null ? _ref2[key] : void 0) !== false) { - if (this.options.classPrefix) { - return "" + this.options.classPrefix + "-" + key; - } else { - return key; - } - } else { - return ''; - } - }; - - _Tether.prototype.setOptions = function(options, position) { - var defaults, key, _i, _len, _ref1, _ref2; - this.options = options; - if (position == null) { - position = true; - } - defaults = { - offset: '0 0', - targetOffset: '0 0', - targetAttachment: 'auto auto', - classPrefix: 'tether' - }; - this.options = extend(defaults, this.options); - _ref1 = this.options, this.element = _ref1.element, this.target = _ref1.target, this.targetModifier = _ref1.targetModifier; - if (this.target === 'viewport') { - this.target = document.body; - this.targetModifier = 'visible'; - } else if (this.target === 'scroll-handle') { - this.target = document.body; - this.targetModifier = 'scroll-handle'; - } - _ref2 = ['element', 'target']; - for (_i = 0, _len = _ref2.length; _i < _len; _i++) { - key = _ref2[_i]; - if (this[key] == null) { - throw new Error("Tether Error: Both element and target must be defined"); - } - if (this[key].jquery != null) { - this[key] = this[key][0]; - } else if (typeof this[key] === 'string') { - this[key] = document.querySelector(this[key]); - } - } - addClass(this.element, this.getClass('element')); - if (this.options.addTargetClasses !== false) { - addClass(this.target, this.getClass('target')); - } - if (!this.options.attachment) { - throw new Error("Tether Error: You must provide an attachment"); - } - this.targetAttachment = parseAttachment(this.options.targetAttachment); - this.attachment = parseAttachment(this.options.attachment); - this.offset = parseOffset(this.options.offset); - this.targetOffset = parseOffset(this.options.targetOffset); - if (this.scrollParent != null) { - this.disable(); - } - if (this.targetModifier === 'scroll-handle') { - this.scrollParent = this.target; - } else { - this.scrollParent = getScrollParent(this.target); - } - if (this.options.enabled !== false) { - return this.enable(position); - } - }; - - _Tether.prototype.getTargetBounds = function() { - var bounds, fitAdj, hasBottomScroll, height, out, scrollBottom, scrollPercentage, style, target; - if (this.targetModifier != null) { - switch (this.targetModifier) { - case 'visible': - if (this.target === document.body) { - return { - top: pageYOffset, - left: pageXOffset, - height: innerHeight, - width: innerWidth - }; - } else { - bounds = getBounds(this.target); - out = { - height: bounds.height, - width: bounds.width, - top: bounds.top, - left: bounds.left - }; - out.height = Math.min(out.height, bounds.height - (pageYOffset - bounds.top)); - out.height = Math.min(out.height, bounds.height - ((bounds.top + bounds.height) - (pageYOffset + innerHeight))); - out.height = Math.min(innerHeight, out.height); - out.height -= 2; - out.width = Math.min(out.width, bounds.width - (pageXOffset - bounds.left)); - out.width = Math.min(out.width, bounds.width - ((bounds.left + bounds.width) - (pageXOffset + innerWidth))); - out.width = Math.min(innerWidth, out.width); - out.width -= 2; - if (out.top < pageYOffset) { - out.top = pageYOffset; - } - if (out.left < pageXOffset) { - out.left = pageXOffset; - } - return out; - } - break; - case 'scroll-handle': - target = this.target; - if (target === document.body) { - target = document.documentElement; - bounds = { - left: pageXOffset, - top: pageYOffset, - height: innerHeight, - width: innerWidth - }; - } else { - bounds = getBounds(target); - } - style = getComputedStyle(target); - hasBottomScroll = target.scrollWidth > target.clientWidth || 'scroll' === [style.overflow, style.overflowX] || this.target !== document.body; - scrollBottom = 0; - if (hasBottomScroll) { - scrollBottom = 15; - } - height = bounds.height - parseFloat(style.borderTopWidth) - parseFloat(style.borderBottomWidth) - scrollBottom; - out = { - width: 15, - height: height * 0.975 * (height / target.scrollHeight), - left: bounds.left + bounds.width - parseFloat(style.borderLeftWidth) - 15 - }; - fitAdj = 0; - if (height < 408 && this.target === document.body) { - fitAdj = -0.00011 * Math.pow(height, 2) - 0.00727 * height + 22.58; - } - if (this.target !== document.body) { - out.height = Math.max(out.height, 24); - } - scrollPercentage = this.target.scrollTop / (target.scrollHeight - height); - out.top = scrollPercentage * (height - out.height - fitAdj) + bounds.top + parseFloat(style.borderTopWidth); - if (this.target === document.body) { - out.height = Math.max(out.height, 24); - } - return out; - } - } else { - return getBounds(this.target); - } - }; - - _Tether.prototype.clearCache = function() { - return this._cache = {}; - }; - - _Tether.prototype.cache = function(k, getter) { - if (this._cache == null) { - this._cache = {}; - } - if (this._cache[k] == null) { - this._cache[k] = getter.call(this); - } - return this._cache[k]; - }; - - _Tether.prototype.enable = function(position) { - if (position == null) { - position = true; - } - if (this.options.addTargetClasses !== false) { - addClass(this.target, this.getClass('enabled')); - } - addClass(this.element, this.getClass('enabled')); - this.enabled = true; - if (this.scrollParent !== document) { - this.scrollParent.addEventListener('scroll', this.position); - } - if (position) { - return this.position(); - } - }; - - _Tether.prototype.disable = function() { - removeClass(this.target, this.getClass('enabled')); - removeClass(this.element, this.getClass('enabled')); - this.enabled = false; - if (this.scrollParent != null) { - return this.scrollParent.removeEventListener('scroll', this.position); - } - }; - - _Tether.prototype.destroy = function() { - var i, tether, _i, _len, _results; - this.disable(); - _results = []; - for (i = _i = 0, _len = tethers.length; _i < _len; i = ++_i) { - tether = tethers[i]; - if (tether === this) { - tethers.splice(i, 1); - break; - } else { - _results.push(void 0); - } - } - return _results; - }; - - _Tether.prototype.updateAttachClasses = function(elementAttach, targetAttach) { - var add, all, side, sides, _i, _j, _len, _len1, _ref1, - _this = this; - if (elementAttach == null) { - elementAttach = this.attachment; - } - if (targetAttach == null) { - targetAttach = this.targetAttachment; - } - sides = ['left', 'top', 'bottom', 'right', 'middle', 'center']; - if ((_ref1 = this._addAttachClasses) != null ? _ref1.length : void 0) { - this._addAttachClasses.splice(0, this._addAttachClasses.length); - } - add = this._addAttachClasses != null ? this._addAttachClasses : this._addAttachClasses = []; - if (elementAttach.top) { - add.push("" + (this.getClass('element-attached')) + "-" + elementAttach.top); - } - if (elementAttach.left) { - add.push("" + (this.getClass('element-attached')) + "-" + elementAttach.left); - } - if (targetAttach.top) { - add.push("" + (this.getClass('target-attached')) + "-" + targetAttach.top); - } - if (targetAttach.left) { - add.push("" + (this.getClass('target-attached')) + "-" + targetAttach.left); - } - all = []; - for (_i = 0, _len = sides.length; _i < _len; _i++) { - side = sides[_i]; - all.push("" + (this.getClass('element-attached')) + "-" + side); - } - for (_j = 0, _len1 = sides.length; _j < _len1; _j++) { - side = sides[_j]; - all.push("" + (this.getClass('target-attached')) + "-" + side); - } - return defer(function() { - if (_this._addAttachClasses == null) { - return; - } - updateClasses(_this.element, _this._addAttachClasses, all); - if (_this.options.addTargetClasses !== false) { - updateClasses(_this.target, _this._addAttachClasses, all); - } - return _this._addAttachClasses = void 0; - }); - }; - - _Tether.prototype.position = function(flushChanges) { - var elementPos, elementStyle, height, left, manualOffset, manualTargetOffset, module, next, offset, offsetBorder, offsetParent, offsetParentSize, offsetParentStyle, offsetPosition, ret, scrollLeft, scrollTop, scrollbarSize, side, targetAttachment, targetOffset, targetPos, targetSize, top, width, _i, _j, _len, _len1, _ref1, _ref2, _ref3, _ref4, _ref5, _ref6, - _this = this; - if (flushChanges == null) { - flushChanges = true; - } - if (!this.enabled) { - return; - } - this.clearCache(); - targetAttachment = autoToFixedAttachment(this.targetAttachment, this.attachment); - this.updateAttachClasses(this.attachment, targetAttachment); - elementPos = this.cache('element-bounds', function() { - return getBounds(_this.element); - }); - width = elementPos.width, height = elementPos.height; - if (width === 0 && height === 0 && (this.lastSize != null)) { - _ref1 = this.lastSize, width = _ref1.width, height = _ref1.height; - } else { - this.lastSize = { - width: width, - height: height - }; - } - targetSize = targetPos = this.cache('target-bounds', function() { - return _this.getTargetBounds(); - }); - offset = offsetToPx(attachmentToOffset(this.attachment), { - width: width, - height: height - }); - targetOffset = offsetToPx(attachmentToOffset(targetAttachment), targetSize); - manualOffset = offsetToPx(this.offset, { - width: width, - height: height - }); - manualTargetOffset = offsetToPx(this.targetOffset, targetSize); - offset = addOffset(offset, manualOffset); - targetOffset = addOffset(targetOffset, manualTargetOffset); - left = targetPos.left + targetOffset.left - offset.left; - top = targetPos.top + targetOffset.top - offset.top; - _ref2 = Tether.modules; - for (_i = 0, _len = _ref2.length; _i < _len; _i++) { - module = _ref2[_i]; - ret = module.position.call(this, { - left: left, - top: top, - targetAttachment: targetAttachment, - targetPos: targetPos, - attachment: this.attachment, - elementPos: elementPos, - offset: offset, - targetOffset: targetOffset, - manualOffset: manualOffset, - manualTargetOffset: manualTargetOffset, - scrollbarSize: scrollbarSize - }); - if (ret === false) { - return false; - } else if ((ret == null) || typeof ret !== 'object') { - continue; - } else { - top = ret.top, left = ret.left; - } - } - next = { - page: { - top: top, - left: left - }, - viewport: { - top: top - pageYOffset, - bottom: pageYOffset - top - height + innerHeight, - left: left - pageXOffset, - right: pageXOffset - left - width + innerWidth - } - }; - if (document.body.scrollWidth > window.innerWidth) { - scrollbarSize = this.cache('scrollbar-size', getScrollBarSize); - next.viewport.bottom -= scrollbarSize.height; - } - if (document.body.scrollHeight > window.innerHeight) { - scrollbarSize = this.cache('scrollbar-size', getScrollBarSize); - next.viewport.right -= scrollbarSize.width; - } - if (((_ref3 = document.body.style.position) !== '' && _ref3 !== 'static') || ((_ref4 = document.body.parentElement.style.position) !== '' && _ref4 !== 'static')) { - next.page.bottom = document.body.scrollHeight - top - height; - next.page.right = document.body.scrollWidth - left - width; - } - if (((_ref5 = this.options.optimizations) != null ? _ref5.moveElement : void 0) !== false && (this.targetModifier == null)) { - offsetParent = this.cache('target-offsetparent', function() { - return getOffsetParent(_this.target); - }); - offsetPosition = this.cache('target-offsetparent-bounds', function() { - return getBounds(offsetParent); - }); - offsetParentStyle = getComputedStyle(offsetParent); - elementStyle = getComputedStyle(this.element); - offsetParentSize = offsetPosition; - offsetBorder = {}; - _ref6 = ['Top', 'Left', 'Bottom', 'Right']; - for (_j = 0, _len1 = _ref6.length; _j < _len1; _j++) { - side = _ref6[_j]; - offsetBorder[side.toLowerCase()] = parseFloat(offsetParentStyle["border" + side + "Width"]); - } - offsetPosition.right = document.body.scrollWidth - offsetPosition.left - offsetParentSize.width + offsetBorder.right; - offsetPosition.bottom = document.body.scrollHeight - offsetPosition.top - offsetParentSize.height + offsetBorder.bottom; - if (next.page.top >= (offsetPosition.top + offsetBorder.top) && next.page.bottom >= offsetPosition.bottom) { - if (next.page.left >= (offsetPosition.left + offsetBorder.left) && next.page.right >= offsetPosition.right) { - scrollTop = offsetParent.scrollTop; - scrollLeft = offsetParent.scrollLeft; - next.offset = { - top: next.page.top - offsetPosition.top + scrollTop - offsetBorder.top, - left: next.page.left - offsetPosition.left + scrollLeft - offsetBorder.left - }; - } - } - } - this.move(next); - this.history.unshift(next); - if (this.history.length > 3) { - this.history.pop(); - } - if (flushChanges) { - flush(); - } - return true; - }; - - _Tether.prototype.move = function(position) { - var css, elVal, found, key, moved, offsetParent, point, same, transcribe, type, val, write, writeCSS, _i, _len, _ref1, _ref2, - _this = this; - if (this.element.parentNode == null) { - return; - } - same = {}; - for (type in position) { - same[type] = {}; - for (key in position[type]) { - found = false; - _ref1 = this.history; - for (_i = 0, _len = _ref1.length; _i < _len; _i++) { - point = _ref1[_i]; - if (!within((_ref2 = point[type]) != null ? _ref2[key] : void 0, position[type][key])) { - found = true; - break; - } - } - if (!found) { - same[type][key] = true; - } - } - } - css = { - top: '', - left: '', - right: '', - bottom: '' - }; - transcribe = function(same, pos) { - var xPos, yPos, _ref3; - if (((_ref3 = _this.options.optimizations) != null ? _ref3.gpu : void 0) !== false) { - if (same.top) { - css.top = 0; - yPos = pos.top; - } else { - css.bottom = 0; - yPos = -pos.bottom; - } - if (same.left) { - css.left = 0; - xPos = pos.left; - } else { - css.right = 0; - xPos = -pos.right; - } - css[transformKey] = "translateX(" + (Math.round(xPos)) + "px) translateY(" + (Math.round(yPos)) + "px)"; - if (transformKey !== 'msTransform') { - return css[transformKey] += " translateZ(0)"; - } - } else { - if (same.top) { - css.top = "" + pos.top + "px"; - } else { - css.bottom = "" + pos.bottom + "px"; - } - if (same.left) { - return css.left = "" + pos.left + "px"; - } else { - return css.right = "" + pos.right + "px"; - } - } - }; - moved = false; - if ((same.page.top || same.page.bottom) && (same.page.left || same.page.right)) { - css.position = 'absolute'; - transcribe(same.page, position.page); - } else if ((same.viewport.top || same.viewport.bottom) && (same.viewport.left || same.viewport.right)) { - css.position = 'fixed'; - transcribe(same.viewport, position.viewport); - } else if ((same.offset != null) && same.offset.top && same.offset.left) { - css.position = 'absolute'; - offsetParent = this.cache('target-offsetparent', function() { - return getOffsetParent(_this.target); - }); - if (getOffsetParent(this.element) !== offsetParent) { - defer(function() { - _this.element.parentNode.removeChild(_this.element); - return offsetParent.appendChild(_this.element); - }); - } - transcribe(same.offset, position.offset); - moved = true; - } else { - css.position = 'absolute'; - transcribe({ - top: true, - left: true - }, position.page); - } - if (!moved && this.element.parentNode.tagName !== 'BODY') { - this.element.parentNode.removeChild(this.element); - document.body.appendChild(this.element); - } - writeCSS = {}; - write = false; - for (key in css) { - val = css[key]; - elVal = this.element.style[key]; - if (elVal !== '' && val !== '' && (key === 'top' || key === 'left' || key === 'bottom' || key === 'right')) { - elVal = parseFloat(elVal); - val = parseFloat(val); - } - if (elVal !== val) { - write = true; - writeCSS[key] = css[key]; - } - } - if (write) { - return defer(function() { - return extend(_this.element.style, writeCSS); - }); - } - }; - - return _Tether; - - })(); - - Tether.position = position; - - this.Tether = extend(_Tether, Tether); - -}).call(this); - -(function() { - var BOUNDS_FORMAT, MIRROR_ATTACH, defer, extend, getBoundingRect, getBounds, getOuterSize, getSize, updateClasses, _ref, - __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; - - _ref = this.Tether.Utils, getOuterSize = _ref.getOuterSize, getBounds = _ref.getBounds, getSize = _ref.getSize, extend = _ref.extend, updateClasses = _ref.updateClasses, defer = _ref.defer; - - MIRROR_ATTACH = { - left: 'right', - right: 'left', - top: 'bottom', - bottom: 'top', - middle: 'middle' - }; - - BOUNDS_FORMAT = ['left', 'top', 'right', 'bottom']; - - getBoundingRect = function(tether, to) { - var i, pos, side, size, style, _i, _len; - if (to === 'scrollParent') { - to = tether.scrollParent; - } else if (to === 'window') { - to = [pageXOffset, pageYOffset, innerWidth + pageXOffset, innerHeight + pageYOffset]; - } - if (to === document) { - to = to.documentElement; - } - if (to.nodeType != null) { - pos = size = getBounds(to); - style = getComputedStyle(to); - to = [pos.left, pos.top, size.width + pos.left, size.height + pos.top]; - for (i = _i = 0, _len = BOUNDS_FORMAT.length; _i < _len; i = ++_i) { - side = BOUNDS_FORMAT[i]; - side = side[0].toUpperCase() + side.substr(1); - if (side === 'Top' || side === 'Left') { - to[i] += parseFloat(style["border" + side + "Width"]); - } else { - to[i] -= parseFloat(style["border" + side + "Width"]); - } - } - } - return to; - }; - - this.Tether.modules.push({ - position: function(_arg) { - var addClasses, allClasses, attachment, bounds, changeAttachX, changeAttachY, cls, constraint, eAttachment, height, left, oob, oobClass, p, pin, pinned, pinnedClass, removeClass, side, tAttachment, targetAttachment, targetHeight, targetSize, targetWidth, to, top, width, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _m, _n, _ref1, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7, _ref8, - _this = this; - top = _arg.top, left = _arg.left, targetAttachment = _arg.targetAttachment; - if (!this.options.constraints) { - return true; - } - removeClass = function(prefix) { - var side, _i, _len, _results; - _this.removeClass(prefix); - _results = []; - for (_i = 0, _len = BOUNDS_FORMAT.length; _i < _len; _i++) { - side = BOUNDS_FORMAT[_i]; - _results.push(_this.removeClass("" + prefix + "-" + side)); - } - return _results; - }; - _ref1 = this.cache('element-bounds', function() { - return getBounds(_this.element); - }), height = _ref1.height, width = _ref1.width; - if (width === 0 && height === 0 && (this.lastSize != null)) { - _ref2 = this.lastSize, width = _ref2.width, height = _ref2.height; - } - targetSize = this.cache('target-bounds', function() { - return _this.getTargetBounds(); - }); - targetHeight = targetSize.height; - targetWidth = targetSize.width; - tAttachment = {}; - eAttachment = {}; - allClasses = [this.getClass('pinned'), this.getClass('out-of-bounds')]; - _ref3 = this.options.constraints; - for (_i = 0, _len = _ref3.length; _i < _len; _i++) { - constraint = _ref3[_i]; - if (constraint.outOfBoundsClass) { - allClasses.push(constraint.outOfBoundsClass); - } - if (constraint.pinnedClass) { - allClasses.push(constraint.pinnedClass); - } - } - for (_j = 0, _len1 = allClasses.length; _j < _len1; _j++) { - cls = allClasses[_j]; - _ref4 = ['left', 'top', 'right', 'bottom']; - for (_k = 0, _len2 = _ref4.length; _k < _len2; _k++) { - side = _ref4[_k]; - allClasses.push("" + cls + "-" + side); - } - } - addClasses = []; - tAttachment = extend({}, targetAttachment); - eAttachment = extend({}, this.attachment); - _ref5 = this.options.constraints; - for (_l = 0, _len3 = _ref5.length; _l < _len3; _l++) { - constraint = _ref5[_l]; - to = constraint.to, attachment = constraint.attachment, pin = constraint.pin; - if (attachment == null) { - attachment = ''; - } - if (__indexOf.call(attachment, ' ') >= 0) { - _ref6 = attachment.split(' '), changeAttachY = _ref6[0], changeAttachX = _ref6[1]; - } else { - changeAttachX = changeAttachY = attachment; - } - bounds = getBoundingRect(this, to); - if (changeAttachY === 'target' || changeAttachY === 'both') { - if (top < bounds[1] && tAttachment.top === 'top') { - top += targetHeight; - tAttachment.top = 'bottom'; - } - if (top + height > bounds[3] && tAttachment.top === 'bottom') { - top -= targetHeight; - tAttachment.top = 'top'; - } - } - if (changeAttachY === 'together') { - if (top < bounds[1] && tAttachment.top === 'top') { - if (eAttachment.top === 'bottom') { - top += targetHeight; - tAttachment.top = 'bottom'; - top += height; - eAttachment.top = 'top'; - } else if (eAttachment.top === 'top') { - top += targetHeight; - tAttachment.top = 'bottom'; - top -= height; - eAttachment.top = 'bottom'; - } - } - if (top + height > bounds[3] && tAttachment.top === 'bottom') { - if (eAttachment.top === 'top') { - top -= targetHeight; - tAttachment.top = 'top'; - top -= height; - eAttachment.top = 'bottom'; - } else if (eAttachment.top === 'bottom') { - top -= targetHeight; - tAttachment.top = 'top'; - top += height; - eAttachment.top = 'top'; - } - } - if (tAttachment.top === 'middle') { - if (top + height > bounds[3] && eAttachment.top === 'top') { - top -= height; - eAttachment.top = 'bottom'; - } else if (top < bounds[1] && eAttachment.top === 'bottom') { - top += height; - eAttachment.top = 'top'; - } - } - } - if (changeAttachX === 'target' || changeAttachX === 'both') { - if (left < bounds[0] && tAttachment.left === 'left') { - left += targetWidth; - tAttachment.left = 'right'; - } - if (left + width > bounds[2] && tAttachment.left === 'right') { - left -= targetWidth; - tAttachment.left = 'left'; - } - } - if (changeAttachX === 'together') { - if (left < bounds[0] && tAttachment.left === 'left') { - if (eAttachment.left === 'right') { - left += targetWidth; - tAttachment.left = 'right'; - left += width; - eAttachment.left = 'left'; - } else if (eAttachment.left === 'left') { - left += targetWidth; - tAttachment.left = 'right'; - left -= width; - eAttachment.left = 'right'; - } - } else if (left + width > bounds[2] && tAttachment.left === 'right') { - if (eAttachment.left === 'left') { - left -= targetWidth; - tAttachment.left = 'left'; - left -= width; - eAttachment.left = 'right'; - } else if (eAttachment.left === 'right') { - left -= targetWidth; - tAttachment.left = 'left'; - left += width; - eAttachment.left = 'left'; - } - } else if (tAttachment.left === 'center') { - if (left + width > bounds[2] && eAttachment.left === 'left') { - left -= width; - eAttachment.left = 'right'; - } else if (left < bounds[0] && eAttachment.left === 'right') { - left += width; - eAttachment.left = 'left'; - } - } - } - if (changeAttachY === 'element' || changeAttachY === 'both') { - if (top < bounds[1] && eAttachment.top === 'bottom') { - top += height; - eAttachment.top = 'top'; - } - if (top + height > bounds[3] && eAttachment.top === 'top') { - top -= height; - eAttachment.top = 'bottom'; - } - } - if (changeAttachX === 'element' || changeAttachX === 'both') { - if (left < bounds[0] && eAttachment.left === 'right') { - left += width; - eAttachment.left = 'left'; - } - if (left + width > bounds[2] && eAttachment.left === 'left') { - left -= width; - eAttachment.left = 'right'; - } - } - if (typeof pin === 'string') { - pin = (function() { - var _len4, _m, _ref7, _results; - _ref7 = pin.split(','); - _results = []; - for (_m = 0, _len4 = _ref7.length; _m < _len4; _m++) { - p = _ref7[_m]; - _results.push(p.trim()); - } - return _results; - })(); - } else if (pin === true) { - pin = ['top', 'left', 'right', 'bottom']; - } - pin || (pin = []); - pinned = []; - oob = []; - if (top < bounds[1]) { - if (__indexOf.call(pin, 'top') >= 0) { - top = bounds[1]; - pinned.push('top'); - } else { - oob.push('top'); - } - } - if (top + height > bounds[3]) { - if (__indexOf.call(pin, 'bottom') >= 0) { - top = bounds[3] - height; - pinned.push('bottom'); - } else { - oob.push('bottom'); - } - } - if (left < bounds[0]) { - if (__indexOf.call(pin, 'left') >= 0) { - left = bounds[0]; - pinned.push('left'); - } else { - oob.push('left'); - } - } - if (left + width > bounds[2]) { - if (__indexOf.call(pin, 'right') >= 0) { - left = bounds[2] - width; - pinned.push('right'); - } else { - oob.push('right'); - } - } - if (pinned.length) { - pinnedClass = (_ref7 = this.options.pinnedClass) != null ? _ref7 : this.getClass('pinned'); - addClasses.push(pinnedClass); - for (_m = 0, _len4 = pinned.length; _m < _len4; _m++) { - side = pinned[_m]; - addClasses.push("" + pinnedClass + "-" + side); - } - } - if (oob.length) { - oobClass = (_ref8 = this.options.outOfBoundsClass) != null ? _ref8 : this.getClass('out-of-bounds'); - addClasses.push(oobClass); - for (_n = 0, _len5 = oob.length; _n < _len5; _n++) { - side = oob[_n]; - addClasses.push("" + oobClass + "-" + side); - } - } - if (__indexOf.call(pinned, 'left') >= 0 || __indexOf.call(pinned, 'right') >= 0) { - eAttachment.left = tAttachment.left = false; - } - if (__indexOf.call(pinned, 'top') >= 0 || __indexOf.call(pinned, 'bottom') >= 0) { - eAttachment.top = tAttachment.top = false; - } - if (tAttachment.top !== targetAttachment.top || tAttachment.left !== targetAttachment.left || eAttachment.top !== this.attachment.top || eAttachment.left !== this.attachment.left) { - this.updateAttachClasses(eAttachment, tAttachment); - } - } - defer(function() { - if (_this.options.addTargetClasses !== false) { - updateClasses(_this.target, addClasses, allClasses); - } - return updateClasses(_this.element, addClasses, allClasses); - }); - return { - top: top, - left: left - }; - } - }); - -}).call(this); - -(function() { - var defer, getBounds, updateClasses, _ref; - - _ref = this.Tether.Utils, getBounds = _ref.getBounds, updateClasses = _ref.updateClasses, defer = _ref.defer; - - this.Tether.modules.push({ - position: function(_arg) { - var abutted, addClasses, allClasses, bottom, height, left, right, side, sides, targetPos, top, width, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref1, _ref2, _ref3, _ref4, _ref5, - _this = this; - top = _arg.top, left = _arg.left; - _ref1 = this.cache('element-bounds', function() { - return getBounds(_this.element); - }), height = _ref1.height, width = _ref1.width; - targetPos = this.getTargetBounds(); - bottom = top + height; - right = left + width; - abutted = []; - if (top <= targetPos.bottom && bottom >= targetPos.top) { - _ref2 = ['left', 'right']; - for (_i = 0, _len = _ref2.length; _i < _len; _i++) { - side = _ref2[_i]; - if ((_ref3 = targetPos[side]) === left || _ref3 === right) { - abutted.push(side); - } - } - } - if (left <= targetPos.right && right >= targetPos.left) { - _ref4 = ['top', 'bottom']; - for (_j = 0, _len1 = _ref4.length; _j < _len1; _j++) { - side = _ref4[_j]; - if ((_ref5 = targetPos[side]) === top || _ref5 === bottom) { - abutted.push(side); - } - } - } - allClasses = []; - addClasses = []; - sides = ['left', 'top', 'right', 'bottom']; - allClasses.push(this.getClass('abutted')); - for (_k = 0, _len2 = sides.length; _k < _len2; _k++) { - side = sides[_k]; - allClasses.push("" + (this.getClass('abutted')) + "-" + side); - } - if (abutted.length) { - addClasses.push(this.getClass('abutted')); - } - for (_l = 0, _len3 = abutted.length; _l < _len3; _l++) { - side = abutted[_l]; - addClasses.push("" + (this.getClass('abutted')) + "-" + side); - } - defer(function() { - if (_this.options.addTargetClasses !== false) { - updateClasses(_this.target, addClasses, allClasses); - } - return updateClasses(_this.element, addClasses, allClasses); - }); - return true; - } - }); - -}).call(this); - -(function() { - this.Tether.modules.push({ - position: function(_arg) { - var left, result, shift, shiftLeft, shiftTop, top, _ref; - top = _arg.top, left = _arg.left; - if (!this.options.shift) { - return; - } - result = function(val) { - if (typeof val === 'function') { - return val.call(this, { - top: top, - left: left - }); - } else { - return val; - } - }; - shift = result(this.options.shift); - if (typeof shift === 'string') { - shift = shift.split(' '); - shift[1] || (shift[1] = shift[0]); - shiftTop = shift[0], shiftLeft = shift[1]; - shiftTop = parseFloat(shiftTop, 10); - shiftLeft = parseFloat(shiftLeft, 10); - } else { - _ref = [shift.top, shift.left], shiftTop = _ref[0], shiftLeft = _ref[1]; - } - top += shiftTop; - left += shiftLeft; - return { - top: top, - left: left - }; - } - }); - -}).call(this); - -return this.Tether; - -})); diff --git a/tether.min.js b/tether.min.js deleted file mode 100644 index b93d4512..00000000 --- a/tether.min.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! tether 0.7.2 */ -!function(t,e){"function"==typeof define&&define.amd?define(e):"object"==typeof exports?module.exports=e(require,exports,module):t.Tether=e()}(this,function(t,e,o){return function(){var t,e,o,i,n,s,l,r,h,a,f,p,u,d,g,c,m,b,v,y={}.hasOwnProperty,w=[].indexOf||function(t){for(var e=0,o=this.length;o>e;e++)if(e in this&&this[e]===t)return e;return-1},C=[].slice;null==this.Tether&&(this.Tether={modules:[]}),p=function(t){var e,o,i,n,s;if(o=getComputedStyle(t).position,"fixed"===o)return t;for(i=void 0,e=t;e=e.parentNode;){try{n=getComputedStyle(e)}catch(l){}if(null==n)return e;if(/(auto|scroll)/.test(n.overflow+n.overflowY+n.overflowX)&&("absolute"!==o||"relative"===(s=n.position)||"absolute"===s||"fixed"===s))return e}return document.body},m=function(){var t;return t=0,function(){return t++}}(),v={},a=function(t){var e,i,s,l,r;if(s=t._tetherZeroElement,null==s&&(s=t.createElement("div"),s.setAttribute("data-tether-id",m()),n(s.style,{top:0,left:0,position:"absolute"}),t.body.appendChild(s),t._tetherZeroElement=s),e=s.getAttribute("data-tether-id"),null==v[e]){v[e]={},r=s.getBoundingClientRect();for(i in r)l=r[i],v[e][i]=l;o(function(){return v[e]=void 0})}return v[e]},d=null,l=function(t){var e,o,i,n,s,l,r;t===document?(o=document,t=document.documentElement):o=t.ownerDocument,i=o.documentElement,e={},r=t.getBoundingClientRect();for(n in r)l=r[n],e[n]=l;return s=a(o),e.top-=s.top,e.left-=s.left,null==e.width&&(e.width=document.body.scrollWidth-e.left-e.right),null==e.height&&(e.height=document.body.scrollHeight-e.top-e.bottom),e.top=e.top-i.clientTop,e.left=e.left-i.clientLeft,e.right=o.body.clientWidth-e.width-e.left,e.bottom=o.body.clientHeight-e.height-e.top,e},h=function(t){return t.offsetParent||document.documentElement},f=function(){var t,e,o,i,s;return t=document.createElement("div"),t.style.width="100%",t.style.height="200px",e=document.createElement("div"),n(e.style,{position:"absolute",top:0,left:0,pointerEvents:"none",visibility:"hidden",width:"200px",height:"150px",overflow:"hidden"}),e.appendChild(t),document.body.appendChild(e),i=t.offsetWidth,e.style.overflow="scroll",s=t.offsetWidth,i===s&&(s=e.clientWidth),document.body.removeChild(e),o=i-s,{width:o,height:o}},n=function(t){var e,o,i,n,s,l,r;for(null==t&&(t={}),e=[],Array.prototype.push.apply(e,arguments),r=e.slice(1),s=0,l=r.length;l>s;s++)if(i=r[s])for(o in i)y.call(i,o)&&(n=i[o],t[o]=n);return t},g=function(t,e){var o,i,n,s,l,h;if(null!=t.classList){for(l=e.split(" "),h=[],n=0,s=l.length;s>n;n++)i=l[n],i.trim()&&h.push(t.classList.remove(i));return h}return o=r(t).replace(new RegExp("(^| )"+e.split(" ").join("|")+"( |$)","gi")," "),c(t,o)},e=function(t,e){var o,i,n,s,l;if(null!=t.classList){for(s=e.split(" "),l=[],i=0,n=s.length;n>i;i++)o=s[i],o.trim()&&l.push(t.classList.add(o));return l}return g(t,e),o=r(t)+(" "+e),c(t,o)},u=function(t,e){return null!=t.classList?t.classList.contains(e):new RegExp("(^| )"+e+"( |$)","gi").test(r(t))},r=function(t){return t.className instanceof SVGAnimatedString?t.className.baseVal:t.className},c=function(t,e){return t.setAttribute("class",e)},b=function(t,o,i){var n,s,l,r,h,a;for(s=0,r=i.length;r>s;s++)n=i[s],w.call(o,n)<0&&u(t,n)&&g(t,n);for(a=[],l=0,h=o.length;h>l;l++)n=o[l],a.push(u(t,n)?void 0:e(t,n));return a},i=[],o=function(t){return i.push(t)},s=function(){var t,e;for(e=[];t=i.pop();)e.push(t());return e},t=function(){function t(){}return t.prototype.on=function(t,e,o,i){var n;return null==i&&(i=!1),null==this.bindings&&(this.bindings={}),null==(n=this.bindings)[t]&&(n[t]=[]),this.bindings[t].push({handler:e,ctx:o,once:i})},t.prototype.once=function(t,e,o){return this.on(t,e,o,!0)},t.prototype.off=function(t,e){var o,i,n;if(null!=(null!=(i=this.bindings)?i[t]:void 0)){if(null==e)return delete this.bindings[t];for(o=0,n=[];o=e&&e>=t-o},x=function(){var t,e,o,i,n;for(t=document.createElement("div"),n=["transform","webkitTransform","OTransform","MozTransform","msTransform"],o=0,i=n.length;i>o;o++)if(e=n[o],void 0!==t.style[e])return e}(),T=[],C=function(){var t,e,o;for(e=0,o=T.length;o>e;e++)t=T[e],t.position(!1);return f()},b=function(){var t;return null!=(t="undefined"!=typeof performance&&null!==performance&&"function"==typeof performance.now?performance.now():void 0)?t:+new Date},function(){var t,e,o,i,n,s,l,r,h;for(e=null,o=null,i=null,n=function(){if(null!=o&&o>16)return o=Math.min(o-16,250),void(i=setTimeout(n,250));if(!(null!=e&&b()-e<10))return null!=i&&(clearTimeout(i),i=null),e=b(),C(),o=b()-e},r=["resize","scroll","touchmove"],h=[],s=0,l=r.length;l>s;s++)t=r[s],h.push(window.addEventListener(t,n));return h}(),t={center:"center",left:"right",right:"left"},e={middle:"middle",top:"bottom",bottom:"top"},o={top:0,left:0,middle:"50%",center:"50%",bottom:"100%",right:"100%"},r=function(o,i){var n,s;return n=o.left,s=o.top,"auto"===n&&(n=t[i.left]),"auto"===s&&(s=e[i.top]),{left:n,top:s}},l=function(t){var e,i;return{left:null!=(e=o[t.left])?e:t.left,top:null!=(i=o[t.top])?i:t.top}},s=function(){var t,e,o,i,n,s,l;for(e=1<=arguments.length?M.call(arguments,0):[],o={top:0,left:0},n=0,s=e.length;s>n;n++)l=e[n],i=l.top,t=l.left,"string"==typeof i&&(i=parseFloat(i,10)),"string"==typeof t&&(t=parseFloat(t,10)),o.top+=i,o.left+=t;return o},v=function(t,e){return"string"==typeof t.left&&-1!==t.left.indexOf("%")&&(t.left=parseFloat(t.left,10)/100*e.width),"string"==typeof t.top&&-1!==t.top.indexOf("%")&&(t.top=parseFloat(t.top,10)/100*e.height),t},y=w=function(t){var e,o,i;return i=t.split(" "),o=i[0],e=i[1],{top:o,left:e}},S=function(){function t(t){this.position=P(this.position,this);var e,o,n,s,l;for(T.push(this),this.history=[],this.setOptions(t,!1),s=i.modules,o=0,n=s.length;n>o;o++)e=s[o],null!=(l=e.initialize)&&l.call(this);this.position()}return t.modules=[],t.prototype.getClass=function(t){var e,o;return(null!=(e=this.options.classes)?e[t]:void 0)?this.options.classes[t]:(null!=(o=this.options.classes)?o[t]:void 0)!==!1?this.options.classPrefix?""+this.options.classPrefix+"-"+t:t:""},t.prototype.setOptions=function(t,e){var o,i,s,l,r,h;for(this.options=t,null==e&&(e=!0),o={offset:"0 0",targetOffset:"0 0",targetAttachment:"auto auto",classPrefix:"tether"},this.options=a(o,this.options),r=this.options,this.element=r.element,this.target=r.target,this.targetModifier=r.targetModifier,"viewport"===this.target?(this.target=document.body,this.targetModifier="visible"):"scroll-handle"===this.target&&(this.target=document.body,this.targetModifier="scroll-handle"),h=["element","target"],s=0,l=h.length;l>s;s++){if(i=h[s],null==this[i])throw new Error("Tether Error: Both element and target must be defined");null!=this[i].jquery?this[i]=this[i][0]:"string"==typeof this[i]&&(this[i]=document.querySelector(this[i]))}if(n(this.element,this.getClass("element")),this.options.addTargetClasses!==!1&&n(this.target,this.getClass("target")),!this.options.attachment)throw new Error("Tether Error: You must provide an attachment");return this.targetAttachment=y(this.options.targetAttachment),this.attachment=y(this.options.attachment),this.offset=w(this.options.offset),this.targetOffset=w(this.options.targetOffset),null!=this.scrollParent&&this.disable(),"scroll-handle"===this.targetModifier?this.scrollParent=this.target:this.scrollParent=c(this.target),this.options.enabled!==!1?this.enable(e):void 0},t.prototype.getTargetBounds=function(){var t,e,o,i,n,s,l,r,h;if(null==this.targetModifier)return p(this.target);switch(this.targetModifier){case"visible":return this.target===document.body?{top:pageYOffset,left:pageXOffset,height:innerHeight,width:innerWidth}:(t=p(this.target),n={height:t.height,width:t.width,top:t.top,left:t.left},n.height=Math.min(n.height,t.height-(pageYOffset-t.top)),n.height=Math.min(n.height,t.height-(t.top+t.height-(pageYOffset+innerHeight))),n.height=Math.min(innerHeight,n.height),n.height-=2,n.width=Math.min(n.width,t.width-(pageXOffset-t.left)),n.width=Math.min(n.width,t.width-(t.left+t.width-(pageXOffset+innerWidth))),n.width=Math.min(innerWidth,n.width),n.width-=2,n.toph.clientWidth||"scroll"===[r.overflow,r.overflowX]||this.target!==document.body,s=0,o&&(s=15),i=t.height-parseFloat(r.borderTopWidth)-parseFloat(r.borderBottomWidth)-s,n={width:15,height:.975*i*(i/h.scrollHeight),left:t.left+t.width-parseFloat(r.borderLeftWidth)-15},e=0,408>i&&this.target===document.body&&(e=-11e-5*Math.pow(i,2)-.00727*i+22.58),this.target!==document.body&&(n.height=Math.max(n.height,24)),l=this.target.scrollTop/(h.scrollHeight-i),n.top=l*(i-n.height-e)+t.top+parseFloat(r.borderTopWidth),this.target===document.body&&(n.height=Math.max(n.height,24)),n}},t.prototype.clearCache=function(){return this._cache={}},t.prototype.cache=function(t,e){return null==this._cache&&(this._cache={}),null==this._cache[t]&&(this._cache[t]=e.call(this)),this._cache[t]},t.prototype.enable=function(t){return null==t&&(t=!0),this.options.addTargetClasses!==!1&&n(this.target,this.getClass("enabled")),n(this.element,this.getClass("enabled")),this.enabled=!0,this.scrollParent!==document&&this.scrollParent.addEventListener("scroll",this.position),t?this.position():void 0},t.prototype.disable=function(){return O(this.target,this.getClass("enabled")),O(this.element,this.getClass("enabled")),this.enabled=!1,null!=this.scrollParent?this.scrollParent.removeEventListener("scroll",this.position):void 0},t.prototype.destroy=function(){var t,e,o,i,n;for(this.disable(),n=[],t=o=0,i=T.length;i>o;t=++o){if(e=T[t],e===this){T.splice(t,1);break}n.push(void 0)}return n},t.prototype.updateAttachClasses=function(t,e){var o,i,n,s,l,r,a,f,p,u=this;for(null==t&&(t=this.attachment),null==e&&(e=this.targetAttachment),s=["left","top","bottom","right","middle","center"],(null!=(p=this._addAttachClasses)?p.length:void 0)&&this._addAttachClasses.splice(0,this._addAttachClasses.length),o=null!=this._addAttachClasses?this._addAttachClasses:this._addAttachClasses=[],t.top&&o.push(""+this.getClass("element-attached")+"-"+t.top),t.left&&o.push(""+this.getClass("element-attached")+"-"+t.left),e.top&&o.push(""+this.getClass("target-attached")+"-"+e.top),e.left&&o.push(""+this.getClass("target-attached")+"-"+e.left),i=[],l=0,a=s.length;a>l;l++)n=s[l],i.push(""+this.getClass("element-attached")+"-"+n);for(r=0,f=s.length;f>r;r++)n=s[r],i.push(""+this.getClass("target-attached")+"-"+n);return h(function(){return null!=u._addAttachClasses?(A(u.element,u._addAttachClasses,i),u.options.addTargetClasses!==!1&&A(u.target,u._addAttachClasses,i),u._addAttachClasses=void 0):void 0})},t.prototype.position=function(t){var e,o,n,h,a,d,c,m,b,y,w,C,O,T,x,A,E,S,W,M,P,z,B,_,F,L,Y,H,X,N,j,R,U,q,k,D=this;if(null==t&&(t=!0),this.enabled){for(this.clearCache(),M=r(this.targetAttachment,this.attachment),this.updateAttachClasses(this.attachment,M),e=this.cache("element-bounds",function(){return p(D.element)}),F=e.width,n=e.height,0===F&&0===n&&null!=this.lastSize?(N=this.lastSize,F=N.width,n=N.height):this.lastSize={width:F,height:n},B=z=this.cache("target-bounds",function(){return D.getTargetBounds()}),b=v(l(this.attachment),{width:F,height:n}),P=v(l(M),B),a=v(this.offset,{width:F,height:n}),d=v(this.targetOffset,B),b=s(b,a),P=s(P,d),h=z.left+P.left-b.left,_=z.top+P.top-b.top,j=i.modules,L=0,H=j.length;H>L;L++){if(c=j[L],x=c.position.call(this,{left:h,top:_,targetAttachment:M,targetPos:z,attachment:this.attachment,elementPos:e,offset:b,targetOffset:P,manualOffset:a,manualTargetOffset:d,scrollbarSize:S}),x===!1)return!1;null!=x&&"object"==typeof x&&(_=x.top,h=x.left)}if(m={page:{top:_,left:h},viewport:{top:_-pageYOffset,bottom:pageYOffset-_-n+innerHeight,left:h-pageXOffset,right:pageXOffset-h-F+innerWidth}},document.body.scrollWidth>window.innerWidth&&(S=this.cache("scrollbar-size",g),m.viewport.bottom-=S.height),document.body.scrollHeight>window.innerHeight&&(S=this.cache("scrollbar-size",g),m.viewport.right-=S.width),(""!==(R=document.body.style.position)&&"static"!==R||""!==(U=document.body.parentElement.style.position)&&"static"!==U)&&(m.page.bottom=document.body.scrollHeight-_-n,m.page.right=document.body.scrollWidth-h-F),(null!=(q=this.options.optimizations)?q.moveElement:void 0)!==!1&&null==this.targetModifier){for(w=this.cache("target-offsetparent",function(){return u(D.target)}),T=this.cache("target-offsetparent-bounds",function(){return p(w)}),O=getComputedStyle(w),o=getComputedStyle(this.element),C=T,y={},k=["Top","Left","Bottom","Right"],Y=0,X=k.length;X>Y;Y++)W=k[Y],y[W.toLowerCase()]=parseFloat(O["border"+W+"Width"]);T.right=document.body.scrollWidth-T.left-C.width+y.right,T.bottom=document.body.scrollHeight-T.top-C.height+y.bottom,m.page.top>=T.top+y.top&&m.page.bottom>=T.bottom&&m.page.left>=T.left+y.left&&m.page.right>=T.right&&(E=w.scrollTop,A=w.scrollLeft,m.offset={top:m.page.top-T.top+E-y.top,left:m.page.left-T.left+A-y.left})}return this.move(m),this.history.unshift(m),this.history.length>3&&this.history.pop(),t&&f(),!0}},t.prototype.move=function(t){var e,o,i,n,s,l,r,f,p,d,g,c,m,b,v,y,w,C=this;if(null!=this.element.parentNode){f={};for(d in t){f[d]={};for(n in t[d]){for(i=!1,y=this.history,b=0,v=y.length;v>b;b++)if(r=y[b],!E(null!=(w=r[d])?w[n]:void 0,t[d][n])){i=!0;break}i||(f[d][n]=!0)}}e={top:"",left:"",right:"",bottom:""},p=function(t,o){var i,n,s;return(null!=(s=C.options.optimizations)?s.gpu:void 0)===!1?(t.top?e.top=""+o.top+"px":e.bottom=""+o.bottom+"px",t.left?e.left=""+o.left+"px":e.right=""+o.right+"px"):(t.top?(e.top=0,n=o.top):(e.bottom=0,n=-o.bottom),t.left?(e.left=0,i=o.left):(e.right=0,i=-o.right),e[x]="translateX("+Math.round(i)+"px) translateY("+Math.round(n)+"px)","msTransform"!==x?e[x]+=" translateZ(0)":void 0)},s=!1,(f.page.top||f.page.bottom)&&(f.page.left||f.page.right)?(e.position="absolute",p(f.page,t.page)):(f.viewport.top||f.viewport.bottom)&&(f.viewport.left||f.viewport.right)?(e.position="fixed",p(f.viewport,t.viewport)):null!=f.offset&&f.offset.top&&f.offset.left?(e.position="absolute",l=this.cache("target-offsetparent",function(){return u(C.target)}),u(this.element)!==l&&h(function(){return C.element.parentNode.removeChild(C.element),l.appendChild(C.element)}),p(f.offset,t.offset),s=!0):(e.position="absolute",p({top:!0,left:!0},t.page)),s||"BODY"===this.element.parentNode.tagName||(this.element.parentNode.removeChild(this.element),document.body.appendChild(this.element)),m={},c=!1;for(n in e)g=e[n],o=this.element.style[n],""===o||""===g||"top"!==n&&"left"!==n&&"bottom"!==n&&"right"!==n||(o=parseFloat(o),g=parseFloat(g)),o!==g&&(c=!0,m[n]=e[n]);return c?h(function(){return a(C.element.style,m)}):void 0}},t}(),i.position=C,this.Tether=a(S,i)}.call(this),function(){var t,e,o,i,n,s,l,r,h,a,f=[].indexOf||function(t){for(var e=0,o=this.length;o>e;e++)if(e in this&&this[e]===t)return e;return-1};a=this.Tether.Utils,l=a.getOuterSize,s=a.getBounds,r=a.getSize,i=a.extend,h=a.updateClasses,o=a.defer,e={left:"right",right:"left",top:"bottom",bottom:"top",middle:"middle"},t=["left","top","right","bottom"],n=function(e,o){var i,n,l,r,h,a,f;if("scrollParent"===o?o=e.scrollParent:"window"===o&&(o=[pageXOffset,pageYOffset,innerWidth+pageXOffset,innerHeight+pageYOffset]),o===document&&(o=o.documentElement),null!=o.nodeType)for(n=r=s(o),h=getComputedStyle(o),o=[n.left,n.top,r.width+n.left,r.height+n.top],i=a=0,f=t.length;f>a;i=++a)l=t[i],l=l[0].toUpperCase()+l.substr(1),"Top"===l||"Left"===l?o[i]+=parseFloat(h["border"+l+"Width"]):o[i]-=parseFloat(h["border"+l+"Width"]);return o},this.Tether.modules.push({position:function(e){var l,r,a,p,u,d,g,c,m,b,v,y,w,C,O,T,x,A,E,S,W,M,P,z,B,_,F,L,Y,H,X,N,j,R,U,q,k,D,Z,V,$,G,I,J,K,Q,tt,et=this;if(_=e.top,v=e.left,W=e.targetAttachment,!this.options.constraints)return!0;for(A=function(e){var o,i,n,s;for(et.removeClass(e),s=[],i=0,n=t.length;n>i;i++)o=t[i],s.push(et.removeClass(""+e+"-"+o));return s},V=this.cache("element-bounds",function(){return s(et.element)}),b=V.height,F=V.width,0===F&&0===b&&null!=this.lastSize&&($=this.lastSize,F=$.width,b=$.height),P=this.cache("target-bounds",function(){return et.getTargetBounds()}),M=P.height,z=P.width,S={},m={},r=[this.getClass("pinned"),this.getClass("out-of-bounds")],G=this.options.constraints,L=0,N=G.length;N>L;L++)c=G[L],c.outOfBoundsClass&&r.push(c.outOfBoundsClass),c.pinnedClass&&r.push(c.pinnedClass);for(Y=0,j=r.length;j>Y;Y++)for(g=r[Y],I=["left","top","right","bottom"],H=0,R=I.length;R>H;H++)E=I[H],r.push(""+g+"-"+E);for(l=[],S=i({},W),m=i({},this.attachment),J=this.options.constraints,X=0,U=J.length;U>X;X++){if(c=J[X],B=c.to,a=c.attachment,O=c.pin,null==a&&(a=""),f.call(a," ")>=0?(K=a.split(" "),d=K[0],u=K[1]):u=d=a,p=n(this,B),("target"===d||"both"===d)&&(_p[3]&&"bottom"===S.top&&(_-=M,S.top="top")),"together"===d&&(_p[3]&&"bottom"===S.top&&("top"===m.top?(_-=M,S.top="top",_-=b,m.top="bottom"):"bottom"===m.top&&(_-=M,S.top="top",_+=b,m.top="top")),"middle"===S.top&&(_+b>p[3]&&"top"===m.top?(_-=b,m.top="bottom"):_p[2]&&"right"===S.left&&(v-=z,S.left="left")),"together"===u&&(vp[2]&&"right"===S.left?"left"===m.left?(v-=z,S.left="left",v-=F,m.left="right"):"right"===m.left&&(v-=z,S.left="left",v+=F,m.left="left"):"center"===S.left&&(v+F>p[2]&&"left"===m.left?(v-=F,m.left="right"):vp[3]&&"top"===m.top&&(_-=b,m.top="bottom")),("element"===u||"both"===u)&&(vp[2]&&"left"===m.left&&(v-=F,m.left="right")),"string"==typeof O?O=function(){var t,e,o,i;for(o=O.split(","),i=[],e=0,t=o.length;t>e;e++)C=o[e],i.push(C.trim());return i}():O===!0&&(O=["top","left","right","bottom"]),O||(O=[]),T=[],y=[],_=0?(_=p[1],T.push("top")):y.push("top")),_+b>p[3]&&(f.call(O,"bottom")>=0?(_=p[3]-b,T.push("bottom")):y.push("bottom")),v=0?(v=p[0],T.push("left")):y.push("left")),v+F>p[2]&&(f.call(O,"right")>=0?(v=p[2]-F,T.push("right")):y.push("right")),T.length)for(x=null!=(Q=this.options.pinnedClass)?Q:this.getClass("pinned"),l.push(x),D=0,q=T.length;q>D;D++)E=T[D],l.push(""+x+"-"+E);if(y.length)for(w=null!=(tt=this.options.outOfBoundsClass)?tt:this.getClass("out-of-bounds"),l.push(w),Z=0,k=y.length;k>Z;Z++)E=y[Z],l.push(""+w+"-"+E);(f.call(T,"left")>=0||f.call(T,"right")>=0)&&(m.left=S.left=!1),(f.call(T,"top")>=0||f.call(T,"bottom")>=0)&&(m.top=S.top=!1),(S.top!==W.top||S.left!==W.left||m.top!==this.attachment.top||m.left!==this.attachment.left)&&this.updateAttachClasses(m,S)}return o(function(){return et.options.addTargetClasses!==!1&&h(et.target,l,r),h(et.element,l,r)}),{top:_,left:v}}})}.call(this),function(){var t,e,o,i;i=this.Tether.Utils,e=i.getBounds,o=i.updateClasses,t=i.defer,this.Tether.modules.push({position:function(i){var n,s,l,r,h,a,f,p,u,d,g,c,m,b,v,y,w,C,O,T,x,A,E,S,W,M=this;if(g=i.top,a=i.left,x=this.cache("element-bounds",function(){return e(M.element)}),h=x.height,c=x.width,d=this.getTargetBounds(),r=g+h,f=a+c,n=[],g<=d.bottom&&r>=d.top)for(A=["left","right"],m=0,w=A.length;w>m;m++)p=A[m],((E=d[p])===a||E===f)&&n.push(p);if(a<=d.right&&f>=d.left)for(S=["top","bottom"],b=0,C=S.length;C>b;b++)p=S[b],((W=d[p])===g||W===r)&&n.push(p);for(l=[],s=[],u=["left","top","right","bottom"],l.push(this.getClass("abutted")),v=0,O=u.length;O>v;v++)p=u[v],l.push(""+this.getClass("abutted")+"-"+p);for(n.length&&s.push(this.getClass("abutted")),y=0,T=n.length;T>y;y++)p=n[y],s.push(""+this.getClass("abutted")+"-"+p);return t(function(){return M.options.addTargetClasses!==!1&&o(M.target,s,l),o(M.element,s,l)}),!0}})}.call(this),function(){this.Tether.modules.push({position:function(t){var e,o,i,n,s,l,r;return l=t.top,e=t.left,this.options.shift?(o=function(t){return"function"==typeof t?t.call(this,{top:l,left:e}):t},i=o(this.options.shift),"string"==typeof i?(i=i.split(" "),i[1]||(i[1]=i[0]),s=i[0],n=i[1],s=parseFloat(s,10),n=parseFloat(n,10)):(r=[i.top,i.left],s=r[0],n=r[1]),l+=s,e+=n,{top:l,left:e}):void 0}})}.call(this),this.Tether}); \ No newline at end of file