pagevisibilitymonitor.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. // Copyright 2013 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 This event monitor wraps the Page Visibility API.
  16. * @see http://www.w3.org/TR/page-visibility/
  17. */
  18. goog.provide('goog.labs.dom.PageVisibilityEvent');
  19. goog.provide('goog.labs.dom.PageVisibilityMonitor');
  20. goog.provide('goog.labs.dom.PageVisibilityState');
  21. goog.require('goog.dom');
  22. goog.require('goog.dom.vendor');
  23. goog.require('goog.events');
  24. goog.require('goog.events.Event');
  25. goog.require('goog.events.EventTarget');
  26. goog.require('goog.events.EventType');
  27. goog.require('goog.memoize');
  28. /**
  29. * The different visibility states.
  30. * @enum {string}
  31. */
  32. goog.labs.dom.PageVisibilityState = {
  33. HIDDEN: 'hidden',
  34. VISIBLE: 'visible',
  35. PRERENDER: 'prerender',
  36. UNLOADED: 'unloaded'
  37. };
  38. /**
  39. * This event handler allows you to catch page visibility change events.
  40. * @param {!goog.dom.DomHelper=} opt_domHelper
  41. * @constructor
  42. * @extends {goog.events.EventTarget}
  43. * @final
  44. */
  45. goog.labs.dom.PageVisibilityMonitor = function(opt_domHelper) {
  46. goog.labs.dom.PageVisibilityMonitor.base(this, 'constructor');
  47. /**
  48. * @private {!goog.dom.DomHelper}
  49. */
  50. this.domHelper_ = opt_domHelper || goog.dom.getDomHelper();
  51. /**
  52. * @private {?string}
  53. */
  54. this.eventType_ = this.getBrowserEventType_();
  55. // Some browsers do not support visibilityChange and therefore we don't bother
  56. // setting up events.
  57. if (this.eventType_) {
  58. /**
  59. * @private {goog.events.Key}
  60. */
  61. this.eventKey_ = goog.events.listen(
  62. this.domHelper_.getDocument(), this.eventType_,
  63. goog.bind(this.handleChange_, this));
  64. }
  65. };
  66. goog.inherits(goog.labs.dom.PageVisibilityMonitor, goog.events.EventTarget);
  67. /**
  68. * @return {?string} The visibility change event type, or null if not supported.
  69. * Memoized for performance.
  70. * @private
  71. */
  72. goog.labs.dom.PageVisibilityMonitor.prototype
  73. .getBrowserEventType_ = goog.memoize(function() {
  74. var isSupported =
  75. /** @type {!goog.labs.dom.PageVisibilityMonitor} */ (this).isSupported();
  76. var isPrefixed =
  77. /** @type {!goog.labs.dom.PageVisibilityMonitor} */ (this).isPrefixed_();
  78. if (isSupported) {
  79. return isPrefixed ?
  80. goog.dom.vendor.getPrefixedEventType(
  81. goog.events.EventType.VISIBILITYCHANGE) :
  82. goog.events.EventType.VISIBILITYCHANGE;
  83. } else {
  84. return null;
  85. }
  86. });
  87. /**
  88. * @return {?string} The browser-specific document.hidden property. Memoized
  89. * for performance.
  90. * @private
  91. */
  92. goog.labs.dom.PageVisibilityMonitor.prototype.getHiddenPropertyName_ =
  93. goog.memoize(function() {
  94. return goog.dom.vendor.getPrefixedPropertyName(
  95. 'hidden',
  96. /** @type {!goog.labs.dom.PageVisibilityMonitor} */
  97. (this).domHelper_.getDocument());
  98. });
  99. /**
  100. * @return {boolean} Whether the visibility API is prefixed.
  101. * @private
  102. */
  103. goog.labs.dom.PageVisibilityMonitor.prototype.isPrefixed_ = function() {
  104. return this.getHiddenPropertyName_() != 'hidden';
  105. };
  106. /**
  107. * @return {?string} The browser-specific document.visibilityState property.
  108. * Memoized for performance.
  109. * @private
  110. */
  111. goog.labs.dom.PageVisibilityMonitor.prototype.getVisibilityStatePropertyName_ =
  112. goog.memoize(function() {
  113. return goog.dom.vendor.getPrefixedPropertyName(
  114. 'visibilityState',
  115. /** @type {!goog.labs.dom.PageVisibilityMonitor} */
  116. (this).domHelper_.getDocument());
  117. });
  118. /**
  119. * @return {boolean} Whether the visibility API is supported.
  120. */
  121. goog.labs.dom.PageVisibilityMonitor.prototype.isSupported = function() {
  122. return !!this.getHiddenPropertyName_();
  123. };
  124. /**
  125. * @return {boolean} Whether the page is visible.
  126. */
  127. goog.labs.dom.PageVisibilityMonitor.prototype.isHidden = function() {
  128. return !!this.domHelper_.getDocument()[this.getHiddenPropertyName_()];
  129. };
  130. /**
  131. * @return {?goog.labs.dom.PageVisibilityState} The page visibility state, or
  132. * null if not supported.
  133. */
  134. goog.labs.dom.PageVisibilityMonitor.prototype.getVisibilityState = function() {
  135. if (!this.isSupported()) {
  136. return null;
  137. }
  138. return this.domHelper_.getDocument()[this.getVisibilityStatePropertyName_()];
  139. };
  140. /**
  141. * Handles the events on the element.
  142. * @param {goog.events.BrowserEvent} e The underlying browser event.
  143. * @private
  144. */
  145. goog.labs.dom.PageVisibilityMonitor.prototype.handleChange_ = function(e) {
  146. var state = this.getVisibilityState();
  147. var visibilityEvent = new goog.labs.dom.PageVisibilityEvent(
  148. this.isHidden(),
  149. /** @type {goog.labs.dom.PageVisibilityState} */ (state));
  150. this.dispatchEvent(visibilityEvent);
  151. };
  152. /** @override */
  153. goog.labs.dom.PageVisibilityMonitor.prototype.disposeInternal = function() {
  154. goog.events.unlistenByKey(this.eventKey_);
  155. goog.labs.dom.PageVisibilityMonitor.base(this, 'disposeInternal');
  156. };
  157. /**
  158. * A page visibility change event.
  159. * @param {boolean} hidden Whether the page is hidden.
  160. * @param {goog.labs.dom.PageVisibilityState} visibilityState A more detailed
  161. * visibility state.
  162. * @constructor
  163. * @extends {goog.events.Event}
  164. * @final
  165. */
  166. goog.labs.dom.PageVisibilityEvent = function(hidden, visibilityState) {
  167. goog.labs.dom.PageVisibilityEvent.base(
  168. this, 'constructor', goog.events.EventType.VISIBILITYCHANGE);
  169. /**
  170. * Whether the page is hidden.
  171. * @type {boolean}
  172. */
  173. this.hidden = hidden;
  174. /**
  175. * A more detailed visibility state.
  176. * @type {goog.labs.dom.PageVisibilityState}
  177. */
  178. this.visibilityState = visibilityState;
  179. };
  180. goog.inherits(goog.labs.dom.PageVisibilityEvent, goog.events.Event);