iframemask.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. // Copyright 2008 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. /**
  15. * @fileoverview Iframe shims, to protect controls on the underlying page
  16. * from bleeding through popups.
  17. *
  18. * @author gboyer@google.com (Garrett Boyer)
  19. * @author nicksantos@google.com (Nick Santos) (Ported to Closure)
  20. */
  21. goog.provide('goog.ui.IframeMask');
  22. goog.require('goog.Disposable');
  23. goog.require('goog.Timer');
  24. goog.require('goog.dom');
  25. goog.require('goog.dom.iframe');
  26. goog.require('goog.events.EventHandler');
  27. goog.require('goog.structs.Pool');
  28. goog.require('goog.style');
  29. /**
  30. * Controller for an iframe mask. The mask is only valid in the current
  31. * document, or else the document of the given DOM helper.
  32. *
  33. * @param {goog.dom.DomHelper=} opt_domHelper The DOM helper for the relevant
  34. * document.
  35. * @param {goog.structs.Pool=} opt_iframePool An optional source of iframes.
  36. * Iframes will be grabbed from the pool when they're needed and returned
  37. * to the pool (but still attached to the DOM) when they're done.
  38. * @constructor
  39. * @extends {goog.Disposable}
  40. */
  41. goog.ui.IframeMask = function(opt_domHelper, opt_iframePool) {
  42. goog.Disposable.call(this);
  43. /**
  44. * The DOM helper for this document.
  45. * @type {goog.dom.DomHelper}
  46. * @private
  47. */
  48. this.dom_ = opt_domHelper || goog.dom.getDomHelper();
  49. /**
  50. * An Element to snap the mask to. If none is given, defaults to
  51. * a full-screen iframe mask.
  52. * @type {Element}
  53. * @private
  54. */
  55. this.snapElement_ = this.dom_.getDocument().documentElement;
  56. /**
  57. * An event handler for listening to popups and the like.
  58. * @type {goog.events.EventHandler<!goog.ui.IframeMask>}
  59. * @private
  60. */
  61. this.handler_ = new goog.events.EventHandler(this);
  62. /**
  63. * An iframe pool.
  64. * @type {goog.structs.Pool|undefined}
  65. * @private
  66. */
  67. this.iframePool_ = opt_iframePool;
  68. };
  69. goog.inherits(goog.ui.IframeMask, goog.Disposable);
  70. goog.tagUnsealableClass(goog.ui.IframeMask);
  71. /**
  72. * An iframe.
  73. * @type {HTMLIFrameElement}
  74. * @private
  75. */
  76. goog.ui.IframeMask.prototype.iframe_;
  77. /**
  78. * The z-index of the iframe mask.
  79. * @type {number}
  80. * @private
  81. */
  82. goog.ui.IframeMask.prototype.zIndex_ = 1;
  83. /**
  84. * The opacity of the iframe mask, expressed as a value between 0 and 1, with
  85. * 1 being totally opaque.
  86. * @type {number}
  87. * @private
  88. */
  89. goog.ui.IframeMask.prototype.opacity_ = 0;
  90. /**
  91. * Removes the iframe from the DOM.
  92. * @override
  93. * @protected
  94. */
  95. goog.ui.IframeMask.prototype.disposeInternal = function() {
  96. if (this.iframePool_) {
  97. this.iframePool_.releaseObject(
  98. /** @type {HTMLIFrameElement} */ (this.iframe_));
  99. } else {
  100. goog.dom.removeNode(this.iframe_);
  101. }
  102. this.iframe_ = null;
  103. this.handler_.dispose();
  104. this.handler_ = null;
  105. goog.ui.IframeMask.superClass_.disposeInternal.call(this);
  106. };
  107. /**
  108. * CSS for a hidden iframe.
  109. * @type {string}
  110. * @private
  111. */
  112. goog.ui.IframeMask.HIDDEN_CSS_TEXT_ =
  113. 'position:absolute;display:none;z-index:1';
  114. /**
  115. * Removes the mask from the screen.
  116. */
  117. goog.ui.IframeMask.prototype.hideMask = function() {
  118. if (this.iframe_) {
  119. this.iframe_.style.cssText = goog.ui.IframeMask.HIDDEN_CSS_TEXT_;
  120. if (this.iframePool_) {
  121. this.iframePool_.releaseObject(this.iframe_);
  122. this.iframe_ = null;
  123. }
  124. }
  125. };
  126. /**
  127. * Gets the iframe to use as a mask. Creates a new one if one has not been
  128. * created yet.
  129. * @return {!HTMLIFrameElement} The iframe.
  130. * @private
  131. */
  132. goog.ui.IframeMask.prototype.getIframe_ = function() {
  133. if (!this.iframe_) {
  134. this.iframe_ = this.iframePool_ ?
  135. /** @type {HTMLIFrameElement} */ (this.iframePool_.getObject()) :
  136. goog.dom.iframe.createBlank(this.dom_);
  137. this.iframe_.style.cssText = goog.ui.IframeMask.HIDDEN_CSS_TEXT_;
  138. this.dom_.getDocument().body.appendChild(this.iframe_);
  139. }
  140. return this.iframe_;
  141. };
  142. /**
  143. * Applies the iframe mask to the screen.
  144. */
  145. goog.ui.IframeMask.prototype.applyMask = function() {
  146. var iframe = this.getIframe_();
  147. var bounds = goog.style.getBounds(this.snapElement_);
  148. iframe.style.cssText = 'position:absolute;' +
  149. 'left:' + bounds.left + 'px;' +
  150. 'top:' + bounds.top + 'px;' +
  151. 'width:' + bounds.width + 'px;' +
  152. 'height:' + bounds.height + 'px;' +
  153. 'z-index:' + this.zIndex_;
  154. goog.style.setOpacity(iframe, this.opacity_);
  155. iframe.style.display = 'block';
  156. };
  157. /**
  158. * Sets the opacity of the mask. Will take effect the next time the mask
  159. * is applied.
  160. * @param {number} opacity A value between 0 and 1, with 1 being
  161. * totally opaque.
  162. */
  163. goog.ui.IframeMask.prototype.setOpacity = function(opacity) {
  164. this.opacity_ = opacity;
  165. };
  166. /**
  167. * Sets the z-index of the mask. Will take effect the next time the mask
  168. * is applied.
  169. * @param {number} zIndex A z-index value.
  170. */
  171. goog.ui.IframeMask.prototype.setZIndex = function(zIndex) {
  172. this.zIndex_ = zIndex;
  173. };
  174. /**
  175. * Sets the element to use as the bounds of the mask. Takes effect immediately.
  176. * @param {Element} snapElement The snap element, which the iframe will be
  177. * "snapped" around.
  178. */
  179. goog.ui.IframeMask.prototype.setSnapElement = function(snapElement) {
  180. this.snapElement_ = snapElement;
  181. if (this.iframe_ && goog.style.isElementShown(this.iframe_)) {
  182. this.applyMask();
  183. }
  184. };
  185. /**
  186. * Listens on the specified target, hiding and showing the iframe mask
  187. * when the given event types are dispatched.
  188. * @param {goog.events.EventTarget} target The event target to listen on.
  189. * @param {string} showEvent When this event fires, the mask will be applied.
  190. * @param {string} hideEvent When this event fires, the mask will be hidden.
  191. * @param {Element=} opt_snapElement When the mask is applied, it will
  192. * automatically snap to this element. If no element is specified, it will
  193. * use the default snap element.
  194. */
  195. goog.ui.IframeMask.prototype.listenOnTarget = function(
  196. target, showEvent, hideEvent, opt_snapElement) {
  197. var timerKey;
  198. this.handler_.listen(target, showEvent, function() {
  199. if (opt_snapElement) {
  200. this.setSnapElement(opt_snapElement);
  201. }
  202. // Check out the iframe asynchronously, so we don't block the SHOW
  203. // event and cause a bounce.
  204. timerKey = goog.Timer.callOnce(this.applyMask, 0, this);
  205. });
  206. this.handler_.listen(target, hideEvent, function() {
  207. if (timerKey) {
  208. goog.Timer.clear(timerKey);
  209. timerKey = null;
  210. }
  211. this.hideMask();
  212. });
  213. };
  214. /**
  215. * Removes all handlers attached by listenOnTarget.
  216. */
  217. goog.ui.IframeMask.prototype.removeHandlers = function() {
  218. this.handler_.removeAll();
  219. };