diff --git a/lib/visibility.js b/lib/visibility.js index c595740..04eec65 100644 --- a/lib/visibility.js +++ b/lib/visibility.js @@ -62,6 +62,9 @@ return this._doc[this._name(name)] }, + // Callbacks from change method, that wait visibility changes. + _changeCallbacks: [], + // Callbacks from onVisible method, that wait when page become to be // visible. _onVisibleCallbacks: [], @@ -71,12 +74,18 @@ _listening: false, // Listener for visibilitychange event. - _onVisibilityChange: function() { + _onVisibilityChange: function(event) { + var state = this.state(); + + for ( var i = 0; i < this._changeCallbacks.length; i++ ) { + this._changeCallbacks[i].call(this._doc, event, state); + } + if ( !this.hidden() ) { for ( var i = 0; i < this._onVisibleCallbacks.length; i++ ) { - this._onVisibleCallbacks[i]() + this._onVisibleCallbacks[i](); } - this._onVisibleCallbacks = [] + this._onVisibleCallbacks = []; } }, @@ -116,6 +125,21 @@ return this._prop('visibilityState'); }, + // Call callback when visibility will be changed. First argument of + // callback will be original event object, second will be visibility + // state name. + // If Page Visibility API doesn't supported method will be return false + // and callback never will be called. + // It is just proxy to visibilitychange event, but use vendor prefix. + change: function (callback) { + if ( !this.support() ) { + return false; + } + this._changeCallbacks.push(callback); + this._setListener(); + return true; + }, + // Call callback only when page become to visible for user or // call it now if page is visible now or Page Visibility API // doesn't supported. @@ -127,7 +151,7 @@ return true; } this._onVisibleCallbacks.push(callback); - this._setListener() + this._setListener(); } }; diff --git a/spec/visibilitySpec.js b/spec/visibilitySpec.js index 7682b3b..da6b0dd 100644 --- a/spec/visibilitySpec.js +++ b/spec/visibilitySpec.js @@ -4,6 +4,7 @@ describe('Visibility', function () { beforeEach(function () { Visibility._chechedPrefix = null; Visibility._listening = false; + Visibility._changeCallbacks = []; Visibility._doc = document = { addEventListener: function() { } }; @@ -101,6 +102,36 @@ describe('Visibility', function () { expect( Visibility._onVisibilityChange ).toHaveBeenCalled(); }); + it('should return false on change method without API support', function () { + spyOn(Visibility, 'support').andReturn(false); + spyOn(Visibility, '_setListener'); + var callback = jasmine.createSpy(); + + expect( Visibility.change(callback) ).toEqual(false); + + expect( callback ).not.toHaveBeenCalled(); + expect( Visibility._setListener ).not.toHaveBeenCalled(); + }); + + it('should call callback on visible state shanges', function () { + Visibility._chechedPrefix = 'webkit'; + spyOn(Visibility, '_setListener'); + var callback = jasmine.createSpy(); + + expect( Visibility.change(callback) ).toEqual(true); + expect( Visibility._setListener ).toHaveBeenCalled(); + + var event = { }; + document.webkitVisibilityState = 'visible'; + Visibility._onVisibilityChange(event); + expect( callback ).toHaveBeenCalledWith(event, 'visible'); + + document.webkitVisibilityState = 'hidden'; + Visibility._onVisibilityChange(event); + expect( callback.callCount ).toEqual(2); + expect( callback.mostRecentCall.args ).toEqual([event, 'hidden']); + }); + it('should call onVisible callback now without API support', function () { spyOn(Visibility, 'support').andReturn(false); spyOn(Visibility, '_setListener');