-
Notifications
You must be signed in to change notification settings - Fork 22
/
import-href.js
95 lines (93 loc) · 3.48 KB
/
import-href.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/**
@license
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
*/
// run a callback when HTMLImports are ready or immediately if
// this api is not available.
function whenImportsReady(cb) {
if (window.HTMLImports) {
HTMLImports.whenReady(cb);
} else {
cb();
}
}
/**
* Convenience method for importing an HTML document imperatively.
*
* This method creates a new `<link rel="import">` element with
* the provided URL and appends it to the document to start loading.
* In the `onload` callback, the `import` property of the `link`
* element will contain the imported document contents.
*
* @param {string} href URL to document to load.
* @param {?function(!Event):void=} onload Callback to notify when an import successfully
* loaded.
* @param {?function(!ErrorEvent):void=} onerror Callback to notify when an import
* unsuccessfully loaded.
* @param {boolean=} optAsync True if the import should be loaded `async`.
* Defaults to `false`.
* @return {!HTMLLinkElement} The link element for the URL to be loaded.
*/
export const importHref = function(href, onload, onerror, optAsync) {
let link = /** @type {HTMLLinkElement} */
(document.head.querySelector('link[href="' + href + '"][import-href]'));
if (!link) {
link = /** @type {HTMLLinkElement} */ (document.createElement('link'));
link.rel = 'import';
link.href = href;
link.setAttribute('import-href', '');
}
// always ensure link has `async` attribute if user specified one,
// even if it was previously not async. This is considered less confusing.
if (optAsync) {
link.setAttribute('async', '');
}
// NOTE: the link may now be in 3 states: (1) pending insertion,
// (2) inflight, (3) already loaded. In each case, we need to add
// event listeners to process callbacks.
let cleanup = function() {
link.removeEventListener('load', loadListener);
link.removeEventListener('error', errorListener);
};
let loadListener = function(event) {
cleanup();
// In case of a successful load, cache the load event on the link so
// that it can be used to short-circuit this method in the future when
// it is called with the same href param.
link.__dynamicImportLoaded = true;
if (onload) {
whenImportsReady(() => {
onload(event);
});
}
};
let errorListener = function(event) {
cleanup();
// In case of an error, remove the link from the document so that it
// will be automatically created again the next time `importHref` is
// called.
if (link.parentNode) {
link.parentNode.removeChild(link);
}
if (onerror) {
whenImportsReady(() => {
onerror(event);
});
}
};
link.addEventListener('load', loadListener);
link.addEventListener('error', errorListener);
if (link.parentNode == null) {
document.head.appendChild(link);
// if the link already loaded, dispatch a fake load event
// so that listeners are called and get a proper event argument.
} else if (link.__dynamicImportLoaded) {
link.dispatchEvent(new Event('load'));
}
return link;
};