UNPKG

viewer

Version:

A viewer for documents converted with the Box View API

184 lines (163 loc) 5.61 kB
/** * @fileoverview Resizer component used to watch an element and fire * an event when the object's width or height changes * @author lakenen */ /** * resizer component definition */ Crocodoc.addComponent('resizer', function (scope) { 'use strict'; var util = scope.getUtility('common'); // shorter way of defining // 'fullscreenchange webkitfullscreenchange mozfullscreenchange MSFullscreenChange' var FULLSCREENCHANGE_EVENT = ['', ' webkit', ' moz', ' '] .join('fullscreenchange') + // @NOTE: IE 11 uses upper-camel-case for this, which is apparently necessary 'MSFullscreenChange'; var $window = $(window), $document = $(document), element, frameWidth = 0, currentClientWidth, currentClientHeight, currentOffsetWidth, currentOffsetHeight, inIframe = (function () { try { return window.self !== window.top; } catch (e) { return true; } })(); /** * Fire the resize event with the proper data * @returns {void} * @private */ function broadcast() { scope.broadcast('resize', { // shortcuts for offsetWidth/height width: currentOffsetWidth, height: currentOffsetHeight, // client width is width of the inner, visible area clientWidth: currentClientWidth, clientHeight: currentClientHeight, // offset width is the width of the element, including border, // padding, and scrollbars offsetWidth: currentOffsetWidth, offsetHeight: currentOffsetHeight }); } /** * Apply `position: relative` style to the element if necessary * @returns {void} * @private */ function fixElementPosition() { var style = util.getComputedStyle(element); // if the element is not positioned, add position relative so the // iframe can be positioned properly if (style && style.position === 'static') { $(element).css({ position: 'relative' }); } } /** * Initialize an iframe to fire events on resize * @returns {void} * @private */ function initResizer() { var $iframe = $('<iframe frameborder="0">'), $div = $('<div>'); $iframe.add($div).css({ opacity: 0, visiblility: 'hidden', position: 'absolute', width: '100%', height: '100%', top: 0, left: 0, border: 0 }); $iframe.prependTo($div.prependTo(element)); fixElementPosition(); $window = $($iframe[0].contentWindow); $window.on('resize', checkResize); } /** * Check if the element has resized, and broadcast the resize event if so * @returns {void} * @private */ function checkResize() { var newOffsetHeight = element.offsetHeight, newOffsetWidth = element.offsetWidth; // check if we're in a frame if (inIframe) { // firefox has an issue where styles aren't calculated in hidden iframes // if the iframe was hidden and is now visible, broadcast a // layoutchange event if (frameWidth === 0 && window.innerWidth !== 0) { frameWidth = window.innerWidth; // fix the element position again if necessary fixElementPosition(); scope.broadcast('layoutchange'); return; } } //on touch devices, the offset height is sometimes zero as content is loaded if (newOffsetHeight) { if (newOffsetHeight !== currentOffsetHeight || newOffsetWidth !== currentOffsetWidth) { currentOffsetHeight = newOffsetHeight; currentOffsetWidth = newOffsetWidth; currentClientHeight = element.clientHeight; currentClientWidth = element.clientWidth; broadcast(); } } } return { messages: [ 'layoutchange' ], /** * Handle framework messages * @returns {void} */ onmessage: function () { // force trigger resize when layout changes // @NOTE: we do this because the clientWidth/Height // could be different based on the layout (and whether // or not the new layout changes scrollbars) currentOffsetHeight = null; checkResize(); }, /** * Initialize the Resizer component with an element to watch * @param {HTMLElement} el The element to watch * @returns {void} */ init: function (el) { element = $(el).get(0); // use the documentElement for viewport dimensions // if we are using the window as the viewport if (element === window) { element = document.documentElement; $window.on('resize', checkResize); } else { initResizer(); } $document.on(FULLSCREENCHANGE_EVENT, checkResize); checkResize(); }, /** * Destroy the Resizer component * @returns {void} */ destroy: function () { $document.off(FULLSCREENCHANGE_EVENT, checkResize); $window.off('resize', checkResize); } }; });