Path: blob/trunk/third_party/closure/goog/net/iframeloadmonitor.js
2868 views
// Copyright 2008 The Closure Library Authors. All Rights Reserved.1//2// Licensed under the Apache License, Version 2.0 (the "License");3// you may not use this file except in compliance with the License.4// You may obtain a copy of the License at5//6// http://www.apache.org/licenses/LICENSE-2.07//8// Unless required by applicable law or agreed to in writing, software9// distributed under the License is distributed on an "AS-IS" BASIS,10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.11// See the License for the specific language governing permissions and12// limitations under the License.1314/**15* @fileoverview Class that can be used to determine when an iframe is loaded.16*/1718goog.provide('goog.net.IframeLoadMonitor');1920goog.require('goog.dom');21goog.require('goog.events');22goog.require('goog.events.EventTarget');23goog.require('goog.events.EventType');24goog.require('goog.userAgent');25262728/**29* The correct way to determine whether a same-domain iframe has completed30* loading is different in IE and Firefox. This class abstracts above these31* differences, providing a consistent interface for:32* <ol>33* <li> Determing if an iframe is currently loaded34* <li> Listening for an iframe that is not currently loaded, to finish loading35* </ol>36*37* @param {HTMLIFrameElement} iframe An iframe.38* @param {boolean=} opt_hasContent Whether to wait for the loaded iframe to39* have content in its document body.40* @extends {goog.events.EventTarget}41* @constructor42* @final43*/44goog.net.IframeLoadMonitor = function(iframe, opt_hasContent) {45goog.net.IframeLoadMonitor.base(this, 'constructor');4647/**48* Iframe whose load state is monitored by this IframeLoadMonitor49* @type {HTMLIFrameElement}50* @private51*/52this.iframe_ = iframe;5354/**55* Whether to wait for the loaded iframe to have content in its document body.56* @type {boolean}57* @private58*/59this.hasContent_ = !!opt_hasContent;6061/**62* Whether or not the iframe is loaded.63* @type {boolean}64* @private65*/66this.isLoaded_ = this.isLoadedHelper_();6768if (!this.isLoaded_) {69// IE 6 (and lower?) does not reliably fire load events, so listen to70// readystatechange.71// IE 7 does not reliably fire readystatechange events but listening on load72// seems to work just fine.73var isIe6OrLess =74goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('7');75var loadEvtType = isIe6OrLess ? goog.events.EventType.READYSTATECHANGE :76goog.events.EventType.LOAD;77this.onloadListenerKey_ = goog.events.listen(78this.iframe_, loadEvtType, this.handleLoad_, false, this);7980// Sometimes we still don't get the event callback, so we'll poll just to81// be safe.82this.intervalId_ = window.setInterval(83goog.bind(this.handleLoad_, this),84goog.net.IframeLoadMonitor.POLL_INTERVAL_MS_);85}86};87goog.inherits(goog.net.IframeLoadMonitor, goog.events.EventTarget);888990/**91* Event type dispatched by a goog.net.IframeLoadMonitor when it internal iframe92* finishes loading for the first time after construction of the93* goog.net.IframeLoadMonitor94* @type {string}95*/96goog.net.IframeLoadMonitor.LOAD_EVENT = 'ifload';979899/**100* Poll interval for polling iframe load states in milliseconds.101* @type {number}102* @private103*/104goog.net.IframeLoadMonitor.POLL_INTERVAL_MS_ = 100;105106107/**108* Key for iframe load listener, or null if not currently listening on the109* iframe for a load event.110* @type {goog.events.Key}111* @private112*/113goog.net.IframeLoadMonitor.prototype.onloadListenerKey_ = null;114115116/**117* Returns whether or not the iframe is loaded.118* @return {boolean} whether or not the iframe is loaded.119*/120goog.net.IframeLoadMonitor.prototype.isLoaded = function() {121return this.isLoaded_;122};123124125/**126* Stops the poll timer if this IframeLoadMonitor is currently polling.127* @private128*/129goog.net.IframeLoadMonitor.prototype.maybeStopTimer_ = function() {130if (this.intervalId_) {131window.clearInterval(this.intervalId_);132this.intervalId_ = null;133}134};135136137/**138* Returns the iframe whose load state this IframeLoader monitors.139* @return {HTMLIFrameElement} the iframe whose load state this IframeLoader140* monitors.141*/142goog.net.IframeLoadMonitor.prototype.getIframe = function() {143return this.iframe_;144};145146147/** @override */148goog.net.IframeLoadMonitor.prototype.disposeInternal = function() {149delete this.iframe_;150this.maybeStopTimer_();151goog.events.unlistenByKey(this.onloadListenerKey_);152goog.net.IframeLoadMonitor.superClass_.disposeInternal.call(this);153};154155156/**157* Returns whether or not the iframe is loaded. Determines this by inspecting158* browser dependent properties of the iframe.159* @return {boolean} whether or not the iframe is loaded.160* @private161*/162goog.net.IframeLoadMonitor.prototype.isLoadedHelper_ = function() {163var isLoaded = false;164165try {166if (!this.hasContent_ && goog.userAgent.IE &&167!goog.userAgent.isVersionOrHigher('11')) {168// IE versions before IE11 will reliably have readyState set to complete169// if the iframe is loaded.170isLoaded = this.iframe_.readyState == 'complete';171} else {172// For other browsers, check whether the document body exists to determine173// whether the iframe has loaded. Older versions of Firefox may fire the174// LOAD event early for an empty frame and then, a few hundred175// milliseconds later, replace the contentDocument. If the hasContent176// check is requested, the iframe is considered loaded only once there is177// content in the body.178var body = goog.dom.getFrameContentDocument(this.iframe_).body;179isLoaded = this.hasContent_ ? !!body && !!body.firstChild : !!body;180}181} catch (e) {182// Ignore these errors. This just means that the iframe is not loaded183// IE will throw error reading readyState if the iframe is not appended184// to the dom yet.185// Firefox will throw error getting the iframe body if the iframe is not186// fully loaded.187}188return isLoaded;189};190191192/**193* Handles an event indicating that the loading status of the iframe has194* changed. In Firefox this is a goog.events.EventType.LOAD event, in IE195* this is a goog.events.EventType.READYSTATECHANGED196* @private197*/198goog.net.IframeLoadMonitor.prototype.handleLoad_ = function() {199// Only do the handler if the iframe is loaded.200if (this.isLoadedHelper_()) {201this.maybeStopTimer_();202goog.events.unlistenByKey(this.onloadListenerKey_);203this.onloadListenerKey_ = null;204this.isLoaded_ = true;205this.dispatchEvent(goog.net.IframeLoadMonitor.LOAD_EVENT);206}207};208209210