| 'use strict'; |
| |
| var _getIterator2 = require('babel-runtime/core-js/get-iterator'); |
| |
| var _getIterator3 = _interopRequireDefault(_getIterator2); |
| |
| var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); |
| |
| var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); |
| |
| var _createClass2 = require('babel-runtime/helpers/createClass'); |
| |
| var _createClass3 = _interopRequireDefault(_createClass2); |
| |
| var _intervalFunction = require('./interval-function'); |
| |
| var _intervalFunction2 = _interopRequireDefault(_intervalFunction); |
| |
| function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } |
| |
| (function (window, document) { |
| 'use strict'; |
| |
| if (typeof window.ResizeObserver !== 'undefined') { |
| return; |
| } |
| |
| document.resizeObservers = []; |
| |
| /** |
| * The content rect is defined in section 2.3 ResizeObserverEntry of the spec |
| * @param target the element to calculate the content rect for |
| * @return {{top: (Number|number), left: (Number|number), width: number, height: number}} |
| * |
| * Note: |
| * Avoid using margins on the observed element. The calculation can return incorrect values when margins are involved. |
| * |
| * The following CSS will report incorrect width (Chrome OSX): |
| * |
| * <div id="outer" style="width: 300px; height:300px; background-color: green;overflow:auto;"> |
| * <div id="observed" style="width: 400px; height:400px; background-color: yellow; margin:30px; border: 20px solid red; padding:10px;"> |
| * </div> |
| * </div> |
| * |
| * The calculated width is 280. The actual (correct) width is 340 since Chrome clips the margin. |
| * |
| * Use an outer container if you really need a "margin": |
| * |
| * <div id="outer" style="width: 300px; height:300px; background-color: green;overflow:auto; padding:30px;"> |
| * <div id="observed" style="width: 400px; height:400px; background-color: yellow; margin: 0; border: 20px solid red; padding:10px;"> |
| * </div> |
| * </div> |
| * |
| * A more detailed explanation can be fund here: |
| * http://stackoverflow.com/questions/21064101/understanding-offsetwidth-clientwidth-scrollwidth-and-height-respectively |
| */ |
| var getContentRect = function getContentRect(target) { |
| var cs = window.getComputedStyle(target); |
| var r = target.getBoundingClientRect(); |
| var top = parseFloat(cs.paddingTop) || 0; |
| var left = parseFloat(cs.paddingLeft) || 0; |
| var width = r.width - ((parseFloat(cs.marginLeft) || 0) + (parseFloat(cs.marginRight) || 0) + (parseFloat(cs.borderLeftWidth) || 0) + (parseFloat(cs.borderRightWidth) || 0) + left + (parseFloat(cs.paddingRight) || 0)); |
| var height = r.height - ((parseFloat(cs.marginTop) || 0) + (parseFloat(cs.marginBottom) || 0) + (parseFloat(cs.borderTopWidth) || 0) + (parseFloat(cs.borderBottomWidth) || 0) + top + (parseFloat(cs.paddingBottom) || 0)); |
| return { width: width, height: height, top: top, left: left }; |
| }; |
| |
| var dimensionHasChanged = function dimensionHasChanged(target, lastWidth, lastHeight) { |
| var _getContentRect = getContentRect(target), |
| width = _getContentRect.width, |
| height = _getContentRect.height; |
| |
| return width !== lastWidth || height !== lastHeight; |
| }; |
| |
| /** |
| * ResizeObservation holds observation information for a single Element. |
| * @param target |
| * @return {{target: *, broadcastWidth, broadcastHeight, isOrphan: (function()), isActive: (function())}} |
| * @constructor |
| */ |
| var ResizeObservation = function ResizeObservation(target) { |
| var _getContentRect2 = getContentRect(target), |
| width = _getContentRect2.width, |
| height = _getContentRect2.height; |
| |
| return { |
| target: target, |
| broadcastWidth: width, |
| broadcastHeight: height, |
| |
| isOrphan: function isOrphan() { |
| return !this.target || !this.target.parentNode; |
| }, |
| isActive: function isActive() { |
| return dimensionHasChanged(this.target, this.broadcastWidth, this.broadcastHeight); |
| } |
| }; |
| }; |
| |
| /** |
| * A snapshot of the observed element |
| * @param target |
| * @param rect |
| * @return {{target: *, contentRect: *}} |
| * @constructor |
| */ |
| var ResizeObserverEntry = function ResizeObserverEntry(target, rect) { |
| return { |
| target: target, |
| contentRect: rect |
| }; |
| }; |
| |
| /** |
| * The ResizeObserver is used to observe changes to Element's content rect. |
| */ |
| |
| var ResizeObserver = function () { |
| |
| /** |
| * Constructor for instantiating new Resize observers. |
| * @param callback void (sequence<ResizeObserverEntry> entries). The function which will be called on each resize. |
| * @throws {TypeError} |
| */ |
| function ResizeObserver(callback) { |
| (0, _classCallCheck3.default)(this, ResizeObserver); |
| |
| |
| if (typeof callback !== 'function') { |
| throw new TypeError('callback parameter must be a function'); |
| } |
| |
| this.callback_ = callback; |
| this.observationTargets_ = []; |
| this.activeTargets_ = []; |
| |
| document.resizeObservers.push(this); |
| } |
| |
| /** |
| * A list of ResizeObservations. It represents all Elements being observed. |
| * |
| * @return {Array} |
| */ |
| |
| |
| (0, _createClass3.default)(ResizeObserver, [{ |
| key: 'observe', |
| |
| |
| /** |
| * Adds target to the list of observed elements. |
| * @param {HTMLElement} target The target to observe |
| */ |
| value: function observe(target) { |
| if (target) { |
| if (!(target instanceof HTMLElement)) { |
| throw new TypeError('target parameter must be an HTMLElement'); |
| } |
| if (!this.observationTargets_.find(function (t) { |
| return t.target === target; |
| })) { |
| this.observationTargets_.push(ResizeObservation(target)); |
| resizeController.start(); |
| } |
| } |
| } |
| |
| /** |
| * Removes target from the list of observed elements. |
| * @param target The target to remove |
| */ |
| |
| }, { |
| key: 'unobserve', |
| value: function unobserve(target) { |
| var i = this.observationTargets_.findIndex(function (t) { |
| return t.target === target; |
| }); |
| if (i > -1) { |
| this.observationTargets_.splice(i, 1); |
| } |
| } |
| |
| /** |
| * Stops the ResizeObserver instance from receiving notifications of resize changes. |
| * Until the observe() method is used again, observer's callback will not be invoked. |
| */ |
| |
| }, { |
| key: 'disconnect', |
| value: function disconnect() { |
| this.observationTargets_ = []; |
| this.activeTargets_ = []; |
| } |
| |
| /** |
| * Removes the ResizeObserver from the list of observers |
| */ |
| |
| }, { |
| key: 'destroy', |
| value: function destroy() { |
| var _this = this; |
| |
| this.disconnect(); |
| var i = document.resizeObservers.findIndex(function (o) { |
| return o === _this; |
| }); |
| if (i > -1) { |
| document.resizeObservers.splice(i, 1); |
| } |
| } |
| }, { |
| key: 'deleteOrphansAndPopulateActiveTargets_', |
| value: function deleteOrphansAndPopulateActiveTargets_() { |
| |
| // Works, but two iterations |
| //this.observationTargets_ = this.observationTargets_.filter( resizeObervation => !resizeObervation.isOrphan()); |
| //this.activeTargets_ = this.observationTargets_.filter( resizeObervation => resizeObervation.isActive()); |
| |
| // Same result as above, one iteration |
| /* |
| this.activeTargets_ = []; |
| let n = this.observationTargets_.length-1; |
| while(n >= 0) { |
| if(this.observationTargets_[n].isOrphan()) { |
| this.observationTargets_.splice(n, 1); |
| } |
| else if(this.observationTargets_[n].isActive()) { |
| this.activeTargets_.push(this.observationTargets_[n]); |
| } |
| n -= 1; |
| } |
| */ |
| |
| // Same result as above - but reduce is cooler :-) |
| this.activeTargets_ = this.observationTargets_.reduceRight(function (prev, resizeObservation, index, arr) { |
| if (resizeObservation.isOrphan()) { |
| arr.splice(index, 1); |
| } else if (resizeObservation.isActive()) { |
| prev.push(resizeObservation); |
| } |
| return prev; |
| }, []); |
| } |
| }, { |
| key: 'broadcast_', |
| value: function broadcast_() { |
| this.deleteOrphansAndPopulateActiveTargets_(); |
| if (this.activeTargets_.length > 0) { |
| var entries = []; |
| var _iteratorNormalCompletion = true; |
| var _didIteratorError = false; |
| var _iteratorError = undefined; |
| |
| try { |
| for (var _iterator = (0, _getIterator3.default)(this.activeTargets_), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { |
| var resizeObservation = _step.value; |
| |
| var rect = getContentRect(resizeObservation.target); |
| resizeObservation.broadcastWidth = rect.width; |
| resizeObservation.broadcastHeight = rect.height; |
| entries.push(ResizeObserverEntry(resizeObservation.target, rect)); |
| } |
| } catch (err) { |
| _didIteratorError = true; |
| _iteratorError = err; |
| } finally { |
| try { |
| if (!_iteratorNormalCompletion && _iterator.return) { |
| _iterator.return(); |
| } |
| } finally { |
| if (_didIteratorError) { |
| throw _iteratorError; |
| } |
| } |
| } |
| |
| this.callback_(entries); |
| this.activeTargets_ = []; |
| } |
| } |
| }, { |
| key: 'observationTargets', |
| get: function get() { |
| return this.observationTargets_; |
| } |
| |
| /** |
| * A list of ResizeObservations. It represents all Elements whose size has |
| * changed since last observation broadcast that are eligible for broadcast. |
| * |
| * @return {Array} |
| */ |
| |
| }, { |
| key: 'activeTargets', |
| get: function get() { |
| return this.activeTargets_; |
| } |
| }]); |
| return ResizeObserver; |
| }(); |
| |
| //let interval = require('./interval-function'); |
| |
| /** |
| * Broadcasts Element.resize events |
| * @return {{start: (function()), stop: (function())}} |
| * @constructor |
| */ |
| |
| |
| var ResizeController = function ResizeController() { |
| |
| var shouldStop = function shouldStop() { |
| return document.resizeObservers.findIndex(function (resizeObserver) { |
| return resizeObserver.observationTargets.length > 0; |
| }) > -1; |
| }; |
| |
| var execute = function execute() { |
| //console.log('***** Execute'); |
| var _iteratorNormalCompletion2 = true; |
| var _didIteratorError2 = false; |
| var _iteratorError2 = undefined; |
| |
| try { |
| for (var _iterator2 = (0, _getIterator3.default)(document.resizeObservers), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { |
| var resizeObserver = _step2.value; |
| |
| resizeObserver.broadcast_(); |
| } |
| } catch (err) { |
| _didIteratorError2 = true; |
| _iteratorError2 = err; |
| } finally { |
| try { |
| if (!_iteratorNormalCompletion2 && _iterator2.return) { |
| _iterator2.return(); |
| } |
| } finally { |
| if (_didIteratorError2) { |
| throw _iteratorError2; |
| } |
| } |
| } |
| |
| return shouldStop(); |
| }; |
| |
| var interval = (0, _intervalFunction2.default)(200); |
| |
| return { |
| start: function start() { |
| if (!interval.started) { |
| //console.log('***** Start poll'); |
| interval.start(execute); |
| } |
| } |
| }; |
| }; |
| |
| window.ResizeObserver = ResizeObserver; |
| |
| var resizeController = ResizeController(); |
| //console.log('***** ResizeObserver ready'); |
| })(window, document); |
| /** |
| * An API for observing changes to Element’s size. |
| * |
| * @See https://wicg.github.io/ResizeObserver/ |
| * @ee https://github.com/pelotoncycle/resize-observer |
| * |
| */ |