forked from ibm-js/delite
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcss.js
229 lines (207 loc) · 6.53 KB
/
css.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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
/**
* CSS loading plugin for widgets.
*
* This plugin will load and wait for a css file. This can be handy to load the css
* specific to a widget.
*
* This plugin uses the link load event and a work-around on old webkit browsers.
* The work-around watches a stylesheet until its rules are
* available (not null or undefined).
*
* This plugin will return the path of the inserted css file relative to requirejs baseUrl.
*
* @example:
* To load the css file `myproj/comp.css`:
* ```
* require(["delite/css!myproj/comp.css"], function (){
* // Code placed here will wait for myproj/comp.css before running.
* });
* ```
*
* Or as a widget dependency:
* ```
* define(["delite/css!myproj/comp.css"], function (){
* // My widget factory
* });
* ```
*
* @module delite/css
*/
define([
"requirejs-dplugins/has",
"dojo/Deferred",
"module"
], function (has, Deferred, module) {
"use strict";
has.add("event-link-onload-api", function (global) {
var wk = global.navigator.userAgent.match(/AppleWebKit\/([\d.]+)/);
return !wk || parseInt(wk[1], 10) > 535;
});
var cache = {},
lastInsertedLink;
/**
* Return a promise that resolves when the specified link has finished loading.
* @param {HTMLLinkElement} link - The link element to be notified for.
* @returns {module:dojo/promise/Promise} - A promise.
*/
var listenOnLoad = function (link) {
var def = new Deferred(),
loadHandler = has("event-link-onload-api") ?
function () {
// We're using "readystatechange" because IE happily support both
link.onreadystatechange = link.onload = function () {
if (!link.readyState || link.readyState === "complete") {
link.onreadystatechange = link.onload = null;
def.resolve();
}
};
} :
function () {
// watches a stylesheet for loading signs.
var sheet = link.sheet || link.styleSheet,
styleSheets = document.styleSheets;
if (sheet && Array.prototype.lastIndexOf.call(styleSheets, sheet) !== -1) {
def.resolve();
} else {
setTimeout(loadHandler, 25);
}
};
loadHandler();
return def.promise;
};
var loadCss = {
id: module.id,
/*jshint maxcomplexity: 11*/
/**
* Loads a css file.
* @param {string} path - The css file to load.
* @param {Function} require - A local require function to use to load other modules.
* @param {Function} callback - A function to call when the specified stylesheets have been loaded.
* @method
*/
load: function (path, require, callback) {
if (has("builder")) {
buildFunctions.addOnce(loadList, path);
callback();
return;
}
// Replace single css bundles by corresponding layer.
var config = module.config();
if (config.layersMap) {
path = config.layersMap[path] || path;
}
var head = document.head || document.getElementsByTagName("head")[0],
url = require.toUrl(path),
link;
// if the url has not already been injected/loaded, create a new promise.
if (!cache[url]) {
// hook up load detector(s)
link = document.createElement("link");
link.rel = "stylesheet";
link.type = "text/css";
link.href = url;
head.insertBefore(link, lastInsertedLink ? lastInsertedLink.nextSibling : head.firstChild);
lastInsertedLink = link;
cache[url] = listenOnLoad(link);
}
cache[url].then(function () {
// The stylesheet has been loaded, so call the callback
callback(path);
});
}
};
if (has("builder")) {
// build variables
var loadList = [],
writePluginFiles;
var buildFunctions = {
/**
* Write the layersMap configuration to the corresponding modules layer.
* The configuration will look like this:
* ```js
* require.config({
* config: {
* "delite/css": {
* layersMap: {
* "module1.css": "path/to/layer.css",
* "module2.css": "path/to/layer.css"
* }
* }
* }
* });
* ```
*
* @param {Function} write - This function takes a string as argument
* and writes it to the modules layer.
* @param {string} mid - Current module id.
* @param {string} dest - Current css layer path.
* @param {Array} loadList - List of css files contained in current css layer.
*/
writeConfig: function (write, mid, dest, loadList) {
var cssConf = {
config: {}
};
cssConf.config[mid] = {
layersMap: {}
};
loadList.forEach(function (path) {
cssConf.config[mid].layersMap[path] = dest;
});
write("require.config(" + JSON.stringify(cssConf) + ");");
},
/**
* Concat and optimize all css files required by a modules layer and write the result.
* The node module `clean-css` is responsible for optimizing the css and correcting
* images paths.
*
* @param {Function} writePluginFiles - The write function provided by the builder to `writeFile`.
* and writes it to the modules layer.
* @param {string} dest - Current css layer path.
* @param {Array} loadList - List of css files contained in current css layer.
*/
writeLayer: function (writePluginFiles, dest, loadList) {
// This is a node-require so it is synchronous.
var path = require.toUrl(module.id).replace(/[^\/]*$/, "node_modules/clean-css");
var CleanCSS = require.nodeRequire(require.getNodePath(path));
var result = "";
loadList.forEach(function (src) {
result += new CleanCSS({
relativeTo: "./",
target: dest
}).minify("@import url(" + src + ");");
});
writePluginFiles(dest, result);
},
/**
* Add the string to `ary` if it's not already in it.
* @param {Array} ary - Destination array.
* @param {string} element - Element to add.
*/
addOnce: function (ary, element) {
if (ary.indexOf(element) === -1) {
ary.push(element);
}
}
};
loadCss.writeFile = function (pluginName, resource, require, write) {
writePluginFiles = write;
};
loadCss.onLayerEnd = function (write, data) {
function getLayerPath() {
return data.path.replace(/^(?:\.\/)?(([^\/]*\/)*)[^\/]*$/, "$1css/layer.css");
}
if (data.name && data.path) {
var dest = getLayerPath();
// Write layer file
buildFunctions.writeLayer(writePluginFiles, dest, loadList);
// Write css config on the layer
buildFunctions.writeConfig(write, module.id, dest, loadList);
// Reset loadList
loadList = [];
}
};
// Expose build functions to be used by delite/theme
loadCss.buildFunctions = buildFunctions;
}
return loadCss;
});