feat(jqLite): add private jqDocumentComplete function

This helper function can be used to execute a callback only after the
document has completed its loading, i.e. after the `load` event fires
or immediately if the page has already loaded and
`document.readyState === 'complete'`.
This commit is contained in:
Peter Bacon Darwin
2014-10-12 17:52:44 +01:00
parent b6f4d4b8d4
commit 0dd316efea
4 changed files with 61 additions and 0 deletions

View File

@@ -140,6 +140,7 @@
"addEventListenerFn": false,
"removeEventListenerFn": false,
"jqLiteIsTextNode": false,
"jqLiteDocumentLoaded": false,
/* apis.js */
"hashKey": false,

View File

@@ -453,6 +453,20 @@ function jqLiteRemove(element, keepData) {
if (parent) parent.removeChild(element);
}
function jqLiteDocumentLoaded(action, win) {
win = win || window;
if (win.document.readyState === 'complete') {
// Force the action to be run async for consistent behaviour
// from the action's point of view
// i.e. it will definitely not be in a $apply
win.setTimeout(action);
} else {
// No need to unbind this handler as load is only ever called once
jqLite(win).on('load', action);
}
}
//////////////////////////////////////////
// Functions which are declared directly.
//////////////////////////////////////////

View File

@@ -119,6 +119,7 @@
"JQLitePrototype": false,
"addEventListenerFn": false,
"removeEventListenerFn": false,
"jqLiteDocumentLoaded": false,
/* apis.js */
"hashKey": false,

View File

@@ -1993,4 +1993,49 @@ describe('jqLite', function() {
});
});
describe('jqLiteDocumentLoaded', function() {
function createMockWindow(readyState) {
return {
document: {readyState: readyState || 'loading'},
setTimeout: jasmine.createSpy('window.setTimeout'),
addEventListener: jasmine.createSpy('window.addEventListener'),
removeEventListener: jasmine.createSpy('window.removeEventListener')
};
}
it('should execute the callback via a timeout if the document has already completed loading', function() {
function onLoadCallback() { }
var mockWindow = createMockWindow('complete');
jqLiteDocumentLoaded(onLoadCallback, mockWindow);
expect(mockWindow.addEventListener).not.toHaveBeenCalled();
expect(mockWindow.setTimeout.mostRecentCall.args[0]).toBe(onLoadCallback);
});
it('should register a listener for the `load` event', function() {
var onLoadCallback = jasmine.createSpy('onLoadCallback');
var mockWindow = createMockWindow();
jqLiteDocumentLoaded(onLoadCallback, mockWindow);
expect(mockWindow.addEventListener).toHaveBeenCalledOnce();
});
it('should execute the callback only once the document completes loading', function() {
var onLoadCallback = jasmine.createSpy('onLoadCallback');
var mockWindow = createMockWindow();
jqLiteDocumentLoaded(onLoadCallback, mockWindow);
expect(onLoadCallback).not.toHaveBeenCalled();
jqLite(mockWindow).triggerHandler('load');
expect(onLoadCallback).toHaveBeenCalledOnce();
});
});
});