1 | var path = require('path');
|
2 |
|
3 | var Metalsmith = require('metalsmith');
|
4 | var handlebars = require('handlebars');
|
5 | var templates = require('metalsmith-layouts');
|
6 | var marked = require('marked');
|
7 | var pkg = require('../package.json');
|
8 |
|
9 | var markupRegEx = /([^\/^\.]*)\.html$/;
|
10 | var cleanupJSRegEx = /.*(\/\/ NOCOMPILE|goog\.require\(.*\);)[\r\n]*/g;
|
11 | var requiresRegEx = /.*goog\.require\('(ol\.\S*)'\);/g;
|
12 | var isCssRegEx = /\.css$/;
|
13 | var isJsRegEx = /\.js(\?.*)?$/;
|
14 |
|
15 | var srcDir = path.join(__dirname, '..', 'examples');
|
16 | var destDir = path.join(__dirname, '..', 'build', 'examples');
|
17 | var templatesDir = path.join(__dirname, '..', 'config', 'examples');
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 | function getRequires(src) {
|
27 | var requires = [];
|
28 | var match = requiresRegEx.exec(src);
|
29 | while (match) {
|
30 | requires.push(match[1]);
|
31 | match = requiresRegEx.exec(src);
|
32 | }
|
33 | return requires;
|
34 | }
|
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 |
|
45 | function getLinkToApiHtml(requires) {
|
46 | var lis = requires.map(function(symb) {
|
47 | var href = '../apidoc/' + symb + '.html';
|
48 | return '<li><a href="' + href + '" title="API documentation for ' +
|
49 | symb + '">' + symb + '</a></li>';
|
50 | });
|
51 | return '<ul class="inline">' + lis.join() + '</ul>';
|
52 | }
|
53 |
|
54 |
|
55 |
|
56 |
|
57 |
|
58 |
|
59 |
|
60 |
|
61 |
|
62 |
|
63 |
|
64 |
|
65 |
|
66 |
|
67 |
|
68 |
|
69 | function augmentExamples(files, metalsmith, done) {
|
70 | setImmediate(done);
|
71 | for (var filename in files) {
|
72 | var file = files[filename];
|
73 | var match = filename.match(markupRegEx);
|
74 | if (match && filename !== 'index.html') {
|
75 | if (!file.layout) {
|
76 | throw new Error(filename + ': Missing "layout" in YAML front-matter');
|
77 | }
|
78 | var id = match[1];
|
79 |
|
80 |
|
81 | var jsFilename = id + '.js';
|
82 | if (!(jsFilename in files)) {
|
83 | throw new Error('No .js file found for ' + filename);
|
84 | }
|
85 | var jsSource = files[jsFilename].contents.toString()
|
86 |
|
87 | .replace(/'data\//g, '\'https://openlayers.org/en/v' + pkg.version + '/examples/data/');
|
88 | if (file.cloak) {
|
89 | for (var key in file.cloak) {
|
90 | jsSource = jsSource.replace(new RegExp(key, 'g'), file.cloak[key]);
|
91 | }
|
92 | }
|
93 | var requires = getRequires(jsSource);
|
94 | file.requires = requires;
|
95 | file.js = {
|
96 | tag: '<script src="loader.js?id=' + id + '"></script>',
|
97 | source: jsSource.replace(cleanupJSRegEx, ''),
|
98 | apiHtml: getLinkToApiHtml(requires)
|
99 | };
|
100 |
|
101 |
|
102 | var cssFilename = id + '.css';
|
103 | if (cssFilename in files) {
|
104 | file.css = {
|
105 | tag: '<link rel="stylesheet" href="' + cssFilename + '">',
|
106 | source: files[cssFilename].contents.toString()
|
107 | };
|
108 | }
|
109 |
|
110 |
|
111 | if (file.resources) {
|
112 | var resources = [];
|
113 | var remoteResources = [];
|
114 | var codePenResources = [];
|
115 | for (var i = 0, ii = file.resources.length; i < ii; ++i) {
|
116 | var resource = file.resources[i];
|
117 | var remoteResource = resource.indexOf('//') === -1 ?
|
118 | 'https://openlayers.org/en/v' + pkg.version + '/examples/' +
|
119 | resource : resource;
|
120 | codePenResources[i] = remoteResource;
|
121 | if (isJsRegEx.test(resource)) {
|
122 | resources[i] = '<script src="' + resource + '"></script>';
|
123 | remoteResources[i] = '<script src="' + remoteResource +
|
124 | '"></script>';
|
125 | } else if (isCssRegEx.test(resource)) {
|
126 | if (resource.indexOf('bootstrap.min.css') === -1) {
|
127 | resources[i] = '<link rel="stylesheet" href="' + resource + '">';
|
128 | }
|
129 | remoteResources[i] = '<link rel="stylesheet" href="' +
|
130 | remoteResource + '">';
|
131 | } else {
|
132 | throw new Error('Invalid value for resource: ' +
|
133 | resource + ' is not .js or .css: ' + filename);
|
134 | }
|
135 | }
|
136 | file.extraHead = {
|
137 | local: resources.join('\n'),
|
138 | remote: remoteResources.join('\n')
|
139 | };
|
140 | file.extraResources = file.resources.length ?
|
141 | ',' + codePenResources.join(',') : '';
|
142 | }
|
143 | }
|
144 | }
|
145 | }
|
146 |
|
147 |
|
148 |
|
149 |
|
150 |
|
151 |
|
152 |
|
153 |
|
154 | function createWordIndex(exampleInfos) {
|
155 | var index = {};
|
156 | var keys = ['shortdesc', 'title', 'tags', 'requires'];
|
157 | exampleInfos.forEach(function(info, i) {
|
158 | keys.forEach(function(key) {
|
159 | var text = info[key];
|
160 | if (Array.isArray(text)) {
|
161 | text = text.join(' ');
|
162 | }
|
163 | var words = text ? text.split(/\W+/) : [];
|
164 | words.forEach(function(word) {
|
165 | if (word) {
|
166 | word = word.toLowerCase();
|
167 | var counts = index[word];
|
168 | if (counts) {
|
169 | if (index in counts) {
|
170 | counts[i] += 1;
|
171 | } else {
|
172 | counts[i] = 1;
|
173 | }
|
174 | } else {
|
175 | counts = {};
|
176 | counts[i] = 1;
|
177 | index[word] = counts;
|
178 | }
|
179 | }
|
180 | });
|
181 | });
|
182 | });
|
183 | return index;
|
184 | }
|
185 |
|
186 |
|
187 |
|
188 |
|
189 |
|
190 |
|
191 |
|
192 |
|
193 |
|
194 |
|
195 |
|
196 |
|
197 |
|
198 | function createIndex(files, metalsmith, done) {
|
199 | setImmediate(done);
|
200 | var exampleInfos = [];
|
201 | for (var filename in files) {
|
202 | var example = files[filename];
|
203 | if (markupRegEx.test(filename) && filename !== 'index.html') {
|
204 | exampleInfos.push({
|
205 | link: filename,
|
206 | example: filename,
|
207 | title: example.title,
|
208 | shortdesc: example.shortdesc,
|
209 | tags: example.tags,
|
210 | requires: example.requires
|
211 | });
|
212 | }
|
213 | }
|
214 | var info = {
|
215 | examples: exampleInfos,
|
216 | index: createWordIndex(exampleInfos)
|
217 | };
|
218 | files['index.js'] = {
|
219 | contents: new Buffer('var info = ' + JSON.stringify(info)),
|
220 | mode: '0644'
|
221 | };
|
222 | }
|
223 |
|
224 | function main(callback) {
|
225 | var smith = new Metalsmith('.')
|
226 | .source(srcDir)
|
227 | .destination(destDir)
|
228 | .concurrency(25)
|
229 | .metadata({
|
230 | olVersion: pkg.version
|
231 | })
|
232 | .use(augmentExamples)
|
233 | .use(createIndex)
|
234 | .use(templates({
|
235 | engine: 'handlebars',
|
236 | directory: templatesDir,
|
237 | helpers: {
|
238 | md: function(str) {
|
239 | return new handlebars.SafeString(marked(str));
|
240 | },
|
241 | indent: function(text, options) {
|
242 | if (!text) {
|
243 | return text;
|
244 | }
|
245 | var count = options.hash.spaces || 2;
|
246 | var spaces = new Array(count + 1).join(' ');
|
247 | return text.split('\n').map(function(line) {
|
248 | return line ? spaces + line : '';
|
249 | }).join('\n');
|
250 | }
|
251 | }
|
252 | }))
|
253 | .build(function(err) {
|
254 | callback(err);
|
255 | });
|
256 | return smith;
|
257 | }
|
258 |
|
259 | if (require.main === module) {
|
260 | main(function(err) {
|
261 | if (err) {
|
262 | process.stderr.write(
|
263 | 'Building examples failed. See the full trace below.\n\n' +
|
264 | err.stack + '\n');
|
265 | process.exit(1);
|
266 | } else {
|
267 | process.exit(0);
|
268 | }
|
269 | });
|
270 | }
|
271 |
|
272 | module.exports = main;
|