forked from ampproject/amphtml
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstyles.js
133 lines (126 loc) · 3.98 KB
/
styles.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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/**
* Copyright 2015 The AMP HTML Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS-IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {setStyles, setStyle} from './style';
import {platformFor} from './platform';
/**
* Adds the given css text to the given document.
*
* The style tags will be at the beginning of the head before all author
* styles. One element can be the main runtime CSS. This is guaranteed
* to always be the first stylesheet in the doc.
*
* @param {!Document} doc The document that should get the new styles.
* @param {string} cssText
* @param {function()} cb Called when the new styles are available.
* Not using a promise, because this is synchronous when possible.
* for better performance.
* @param {boolean=} opt_isRuntimeCss If true, this style tag will be inserted
* as the first element in head and all style elements will be positioned
* after.
* @param {string=} opt_ext
*/
export function installStyles(doc, cssText, cb, opt_isRuntimeCss, opt_ext) {
if (platformFor(doc.defaultView).isIos() && opt_isRuntimeCss) {
setStyle(doc.documentElement, 'cursor', 'pointer');
}
const style = doc.createElement('style');
style.textContent = cssText;
let afterElement = null;
// Make sure that we place style tags after the main runtime CSS. Otherwise
// the order is random.
if (opt_isRuntimeCss) {
style.setAttribute('amp-runtime', '');
} else {
style.setAttribute('amp-extension', opt_ext || '');
afterElement = doc.querySelector('style[amp-runtime]');
}
insertAfterOrAtStart(doc.head, style, afterElement);
// Styles aren't always available synchronously. E.g. if there is a
// pending style download, it will have to finish before the new
// style is visible.
// For this reason we poll until the style becomes available.
const done = () => {
const sheets = doc.styleSheets;
for (let i = 0; i < sheets.length; i++) {
const sheet = sheets[i];
if (sheet.ownerNode == style) {
return true;
}
}
return false;
};
// Sync case.
if (done()) {
cb();
return;
}
// Poll until styles are available.
const interval = setInterval(() => {
if (done()) {
clearInterval(interval);
cb();
}
}, 4);
}
/**
* Sets the document's body opacity to 1.
* If the body is not yet available (because our script was loaded
* synchronously), polls until it is.
* @param {!Document} doc The document who's body we should make visible.
* @param {?Promise=} extensionsPromise A loading promise for special extensions
* which must load before the body can be made visible
*/
export function makeBodyVisible(doc, extensionsPromise) {
let interval;
const set = () => {
if (doc.body) {
setStyles(doc.body, {
opacity: 1,
visibility: 'visible',
animation: 'none'
});
clearInterval(interval);
}
};
const poll = () => {
interval = setInterval(set, 4);
set();
};
if (extensionsPromise) {
extensionsPromise.then(poll, poll);
} else {
poll();
}
}
/**
* Insert the element in the root after the element named after or
* if that is null at the beginning.
* @param {!Element} root
* @param {!Element} element
* @param {?Element} after
*/
function insertAfterOrAtStart(root, element, after) {
if (after) {
if (after.nextSibling) {
root.insertBefore(element, after.nextSibling);
} else {
root.appendChild(element);
}
} else {
// Add at the start.
root.insertBefore(element, root.firstChild);
}
}