// Copyright 2007 The Closure Library Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS-IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /** * @fileoverview Utility class that monitors viewport size changes. * * @author attila@google.com (Attila Bodis) * @see ../demos/viewportsizemonitor.html */ goog.provide('goog.dom.ViewportSizeMonitor'); goog.require('goog.dom'); goog.require('goog.events'); goog.require('goog.events.EventTarget'); goog.require('goog.events.EventType'); goog.require('goog.math.Size'); /** * This class can be used to monitor changes in the viewport size. Instances * dispatch a {@link goog.events.EventType.RESIZE} event when the viewport size * changes. Handlers can call {@link goog.dom.ViewportSizeMonitor#getSize} to * get the new viewport size. * * Use this class if you want to execute resize/reflow logic each time the * user resizes the browser window. This class is guaranteed to only dispatch * {@code RESIZE} events when the pixel dimensions of the viewport change. * (Internet Explorer fires resize events if any element on the page is resized, * even if the viewport dimensions are unchanged, which can lead to infinite * resize loops.) * * Example usage: *
 *    var vsm = new goog.dom.ViewportSizeMonitor();
 *    goog.events.listen(vsm, goog.events.EventType.RESIZE, function(e) {
 *      alert('Viewport size changed to ' + vsm.getSize());
 *    });
 *  
* * Manually verified on IE6, IE7, FF2, Opera 11, Safari 4 and Chrome. * * @param {Window=} opt_window The window to monitor; defaults to the window in * which this code is executing. * @constructor * @extends {goog.events.EventTarget} */ goog.dom.ViewportSizeMonitor = function(opt_window) { goog.dom.ViewportSizeMonitor.base(this, 'constructor'); /** * The window to monitor. Defaults to the window in which the code is running. * @private {Window} */ this.window_ = opt_window || window; /** * Event listener key for window the window resize handler, as returned by * {@link goog.events.listen}. * @private {goog.events.Key} */ this.listenerKey_ = goog.events.listen( this.window_, goog.events.EventType.RESIZE, this.handleResize_, false, this); /** * The most recently recorded size of the viewport, in pixels. * @private {goog.math.Size} */ this.size_ = goog.dom.getViewportSize(this.window_); }; goog.inherits(goog.dom.ViewportSizeMonitor, goog.events.EventTarget); /** * Returns a viewport size monitor for the given window. A new one is created * if it doesn't exist already. This prevents the unnecessary creation of * multiple spooling monitors for a window. * @param {Window=} opt_window The window to monitor; defaults to the window in * which this code is executing. * @return {!goog.dom.ViewportSizeMonitor} Monitor for the given window. */ goog.dom.ViewportSizeMonitor.getInstanceForWindow = function(opt_window) { var currentWindow = opt_window || window; var uid = goog.getUid(currentWindow); return goog.dom.ViewportSizeMonitor.windowInstanceMap_[uid] = goog.dom.ViewportSizeMonitor.windowInstanceMap_[uid] || new goog.dom.ViewportSizeMonitor(currentWindow); }; /** * Removes and disposes a viewport size monitor for the given window if one * exists. * @param {Window=} opt_window The window whose monitor should be removed; * defaults to the window in which this code is executing. */ goog.dom.ViewportSizeMonitor.removeInstanceForWindow = function(opt_window) { var uid = goog.getUid(opt_window || window); goog.dispose(goog.dom.ViewportSizeMonitor.windowInstanceMap_[uid]); delete goog.dom.ViewportSizeMonitor.windowInstanceMap_[uid]; }; /** * Map of window hash code to viewport size monitor for that window, if * created. * @type {Object} * @private */ goog.dom.ViewportSizeMonitor.windowInstanceMap_ = {}; /** * Returns the most recently recorded size of the viewport, in pixels. May * return null if no window resize event has been handled yet. * @return {goog.math.Size} The viewport dimensions, in pixels. */ goog.dom.ViewportSizeMonitor.prototype.getSize = function() { // Return a clone instead of the original to preserve encapsulation. return this.size_ ? this.size_.clone() : null; }; /** @override */ goog.dom.ViewportSizeMonitor.prototype.disposeInternal = function() { goog.dom.ViewportSizeMonitor.superClass_.disposeInternal.call(this); if (this.listenerKey_) { goog.events.unlistenByKey(this.listenerKey_); this.listenerKey_ = null; } this.window_ = null; this.size_ = null; }; /** * Handles window resize events by measuring the dimensions of the * viewport and dispatching a {@link goog.events.EventType.RESIZE} event if the * current dimensions are different from the previous ones. * @param {goog.events.Event} event The window resize event to handle. * @private */ goog.dom.ViewportSizeMonitor.prototype.handleResize_ = function(event) { var size = goog.dom.getViewportSize(this.window_); if (!goog.math.Size.equals(size, this.size_)) { this.size_ = size; this.dispatchEvent(goog.events.EventType.RESIZE); } };