ol-stac 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/.eslintignore +2 -0
  2. package/.github/workflows/deploy.yml +67 -0
  3. package/.github/workflows/publish.yml +32 -0
  4. package/.github/workflows/release.yml +21 -0
  5. package/.github/workflows/test.yml +85 -0
  6. package/CHANGELOG.md +14 -0
  7. package/DEVELOPING.md +104 -0
  8. package/LICENSE.md +201 -0
  9. package/README.md +43 -0
  10. package/config/jsdoc/api/conf.json +38 -0
  11. package/config/jsdoc/api/index.md +1 -0
  12. package/config/jsdoc/api/readme.md +65 -0
  13. package/config/jsdoc/api/template/README.md +3 -0
  14. package/config/jsdoc/api/template/publish.js +743 -0
  15. package/config/jsdoc/api/template/static/scripts/linenumber.js +11 -0
  16. package/config/jsdoc/api/template/static/scripts/main.js +305 -0
  17. package/config/jsdoc/api/template/static/scripts/prettify/Apache-License-2.0.txt +202 -0
  18. package/config/jsdoc/api/template/static/scripts/prettify/lang-css.js +2 -0
  19. package/config/jsdoc/api/template/static/scripts/prettify/prettify.js +28 -0
  20. package/config/jsdoc/api/template/static/styles/carbon.css +65 -0
  21. package/config/jsdoc/api/template/static/styles/jaguar.css +512 -0
  22. package/config/jsdoc/api/template/static/styles/prettify-jsdoc.css +111 -0
  23. package/config/jsdoc/api/template/static/styles/prettify-tomorrow.css +132 -0
  24. package/config/jsdoc/api/template/static/theme +1 -0
  25. package/config/jsdoc/api/template/tmpl/container.tmpl +205 -0
  26. package/config/jsdoc/api/template/tmpl/details.tmpl +84 -0
  27. package/config/jsdoc/api/template/tmpl/example.tmpl +2 -0
  28. package/config/jsdoc/api/template/tmpl/examples.tmpl +16 -0
  29. package/config/jsdoc/api/template/tmpl/exceptions.tmpl +30 -0
  30. package/config/jsdoc/api/template/tmpl/layout.tmpl +92 -0
  31. package/config/jsdoc/api/template/tmpl/mainpage.tmpl +14 -0
  32. package/config/jsdoc/api/template/tmpl/members.tmpl +38 -0
  33. package/config/jsdoc/api/template/tmpl/method.tmpl +132 -0
  34. package/config/jsdoc/api/template/tmpl/navigation.tmpl +59 -0
  35. package/config/jsdoc/api/template/tmpl/observables.tmpl +39 -0
  36. package/config/jsdoc/api/template/tmpl/params.tmpl +109 -0
  37. package/config/jsdoc/api/template/tmpl/properties.tmpl +85 -0
  38. package/config/jsdoc/api/template/tmpl/returns.tmpl +72 -0
  39. package/config/jsdoc/api/template/tmpl/source.tmpl +8 -0
  40. package/config/jsdoc/api/template/tmpl/stability.tmpl +7 -0
  41. package/config/jsdoc/api/template/tmpl/tutorial.tmpl +19 -0
  42. package/config/jsdoc/api/template/tmpl/type.tmpl +7 -0
  43. package/config/jsdoc/info/conf.json +22 -0
  44. package/config/jsdoc/info/publish.js +175 -0
  45. package/config/jsdoc/package.json +4 -0
  46. package/config/jsdoc/plugins/api.cjs +181 -0
  47. package/config/jsdoc/plugins/default-export.cjs +35 -0
  48. package/config/jsdoc/plugins/define-plugin.cjs +33 -0
  49. package/config/jsdoc/plugins/events.cjs +39 -0
  50. package/config/jsdoc/plugins/inline-options.cjs +102 -0
  51. package/config/jsdoc/plugins/markdown.cjs +119 -0
  52. package/config/jsdoc/plugins/observable.cjs +69 -0
  53. package/config/jsdoc/plugins/virtual-plugin.cjs +16 -0
  54. package/config/rollup-full-build.js +24 -0
  55. package/config/tsconfig-build.json +25 -0
  56. package/examples/.eslintrc +29 -0
  57. package/examples/index.html +100 -0
  58. package/examples/index.js +109 -0
  59. package/examples/planetary-computer.html +14 -0
  60. package/examples/planetary-computer.js +53 -0
  61. package/examples/resources/Jugl.js +15 -0
  62. package/examples/resources/common.js +111 -0
  63. package/examples/stac-collection-webmaplinks.html +9 -0
  64. package/examples/stac-collection-webmaplinks.js +55 -0
  65. package/examples/stac-item-from-object.html +9 -0
  66. package/examples/stac-item-from-object.js +102 -0
  67. package/examples/stac-item-tileserver.html +9 -0
  68. package/examples/stac-item-tileserver.js +34 -0
  69. package/examples/stac-item.html +9 -0
  70. package/examples/stac-item.js +45 -0
  71. package/examples/stac-itemcollection.html +11 -0
  72. package/examples/stac-itemcollection.js +39 -0
  73. package/examples/templates/example.html +206 -0
  74. package/examples/templates/readme.md +3 -0
  75. package/examples/webpack/config.mjs +69 -0
  76. package/examples/webpack/example-builder.js +410 -0
  77. package/package.json +107 -0
  78. package/site/build.js +26 -0
  79. package/site/layouts/default.hbs +78 -0
  80. package/site/src/doc/faq.md +8 -0
  81. package/site/src/doc/index.md +22 -0
  82. package/site/src/doc/quickstart.md +121 -0
  83. package/site/src/doc/tutorials/index.md +8 -0
  84. package/site/src/download/index.hbs +62 -0
  85. package/site/src/favicon.ico +0 -0
  86. package/site/src/index.hbs +71 -0
  87. package/site/src/theme/index.css +26 -0
  88. package/site/src/theme/site.css +531 -0
  89. package/src/ol/events/ErrorEvent.js +25 -0
  90. package/src/ol/layer/STAC.js +780 -0
  91. package/src/ol/layer/stacUtil.js +169 -0
  92. package/src/ol/source/GeoTIFF2.js +47 -0
  93. package/tasks/.eslintrc +5 -0
  94. package/tasks/build-website.sh +90 -0
  95. package/tasks/create-release.js +107 -0
  96. package/tasks/generate-index.js +125 -0
  97. package/tasks/generate-info.js +189 -0
  98. package/tasks/get-latest-release.js +36 -0
  99. package/tasks/newest-tag.js +52 -0
  100. package/tasks/prepare-package.js +46 -0
  101. package/tasks/publish.sh +90 -0
  102. package/test/README.md +56 -0
  103. package/test/browser/.eslintrc +14 -0
  104. package/test/browser/karma.config.cjs +94 -0
  105. package/test/browser/spec/ol/layer/STAC.test.js +18 -0
  106. package/test/browser/test-extensions.js +419 -0
  107. package/tsconfig.json +62 -0
@@ -0,0 +1,410 @@
1
+ import assert from 'assert';
2
+ import frontMatter from 'front-matter';
3
+ import fs from 'fs';
4
+ import fse from 'fs-extra';
5
+ import handlebars from 'handlebars';
6
+ import path, {dirname} from 'path';
7
+ import sources from 'webpack-sources';
8
+ import {fileURLToPath} from 'url';
9
+ import {marked} from 'marked';
10
+
11
+ const RawSource = sources.RawSource;
12
+ const baseDir = dirname(fileURLToPath(import.meta.url));
13
+
14
+ const isCssRegEx = /\.css(\?.*)?$/;
15
+ const isJsRegEx = /\.js(\?.*)?$/;
16
+ const importRegEx = /\s?import .*? from '([^']+)'/g;
17
+ const isTemplateJs = /\/(?:bootstrap(?:\.bundle)?)(?:\.min)?\.js(?:\?.*)?$/;
18
+ const isTemplateCss =
19
+ /\/(?:bootstrap|fontawesome-free@[\d.]+\/css\/(?:fontawesome|brands|solid))(?:\.min)?\.css(?:\?.*)?$/;
20
+
21
+ const exampleDirContents = fs
22
+ .readdirSync(path.join(baseDir, '..'))
23
+ .filter((name) => /^(?!index).*\.html$/.test(name))
24
+ .map((name) => name.replace(/\.html$/, ''));
25
+
26
+ function getPackageInfo() {
27
+ return fse.readJSON(path.resolve(baseDir, '../../package.json'));
28
+ }
29
+
30
+ handlebars.registerHelper(
31
+ 'md',
32
+ (str) =>
33
+ new handlebars.SafeString(marked(str, {headerIds: false, mangle: false}))
34
+ );
35
+
36
+ /**
37
+ * Used to doube-escape the title when stored as data-* attribute.
38
+ */
39
+ handlebars.registerHelper('escape', (text) => {
40
+ return handlebars.Utils.escapeExpression(text);
41
+ });
42
+
43
+ handlebars.registerHelper('indent', (text, options) => {
44
+ if (!text) {
45
+ return text;
46
+ }
47
+ const count = options.hash.spaces || 2;
48
+ const spaces = new Array(count + 1).join(' ');
49
+ return text
50
+ .split('\n')
51
+ .map((line) => (line ? spaces + line : ''))
52
+ .join('\n');
53
+ });
54
+
55
+ /**
56
+ * Returns the object with the keys inserted in alphabetic order.
57
+ * When exporting with `JSON.stringify(obj)` the keys are sorted.
58
+ * @param {Object<string, *>} obj Any object
59
+ * @return {Object<string, *>} New object
60
+ */
61
+ function sortObjectByKey(obj) {
62
+ return Object.keys(obj)
63
+ .sort() // sort twice to get predictable, case insensitive order
64
+ .sort((a, b) => a.localeCompare(b, 'en', {sensitivity: 'base'}))
65
+ .reduce((idx, tag) => {
66
+ idx[tag] = obj[tag];
67
+ return idx;
68
+ }, {});
69
+ }
70
+
71
+ /**
72
+ * Create an index of tags belonging to examples
73
+ * @param {Array<Object>} exampleData Array of example data objects.
74
+ * @return {Object} Word index.
75
+ */
76
+ function createTagIndex(exampleData) {
77
+ const index = {};
78
+ exampleData.forEach((data, i) => {
79
+ data.tags.forEach((tag) => {
80
+ tag = tag.toLowerCase();
81
+ let tagIndex = index[tag];
82
+ if (!tagIndex) {
83
+ tagIndex = [];
84
+ index[tag] = tagIndex;
85
+ }
86
+ tagIndex.push(i);
87
+ });
88
+ });
89
+ return index;
90
+ }
91
+
92
+ /**
93
+ * Create an inverted index of keywords from examples. Property names are
94
+ * lowercased words. Property values are objects mapping example index to word
95
+ * count.
96
+ * @param {Array<Object>} exampleData Array of example data objects.
97
+ * @return {Object} Word index.
98
+ */
99
+ function createWordIndex(exampleData) {
100
+ const index = {};
101
+ const keys = ['shortdesc', 'title', 'tags'];
102
+ exampleData.forEach((data, i) => {
103
+ keys.forEach((key) => {
104
+ let text = data[key] || '';
105
+ if (Array.isArray(text)) {
106
+ text = text.join(' ');
107
+ }
108
+ const words = text.toLowerCase().split(/\W+/);
109
+ words.forEach((word) => {
110
+ if (word) {
111
+ let counts = index[word];
112
+ if (!counts) {
113
+ counts = {};
114
+ index[word] = counts;
115
+ }
116
+ counts[i] = (counts[i] || 0) + 1;
117
+ }
118
+ });
119
+ });
120
+ });
121
+ return index;
122
+ }
123
+
124
+ /**
125
+ * Gets dependencies from the js source.
126
+ * @param {string} jsSource Source.
127
+ * @param {Object} pkg Package info.
128
+ * @return {Object<string, string>} dependencies
129
+ */
130
+ function getDependencies(jsSource, pkg) {
131
+ const dependencies = {
132
+ ol: pkg.version,
133
+ };
134
+
135
+ let importMatch;
136
+ while ((importMatch = importRegEx.exec(jsSource))) {
137
+ const imp = importMatch[1];
138
+ if (!imp.startsWith('ol/') && imp != 'ol') {
139
+ const parts = imp.split('/');
140
+ const dep = imp.startsWith('@') ? parts.slice(0, 2).join('/') : parts[0];
141
+ if (dep in pkg.devDependencies) {
142
+ dependencies[dep] = pkg.devDependencies[dep];
143
+ } else if (dep in pkg.dependencies) {
144
+ dependencies[dep] = pkg.dependencies[dep];
145
+ }
146
+ }
147
+ }
148
+ return dependencies;
149
+ }
150
+
151
+ export default class ExampleBuilder {
152
+ /**
153
+ * A webpack plugin that builds the html files for our examples.
154
+ * @param {Object} config Plugin configuration. Requires a `templates` property
155
+ * with the path to templates and a `common` property with the name of the
156
+ * common chunk.
157
+ */
158
+ constructor(config) {
159
+ this.name = 'ExampleBuilder';
160
+ this.templates = config.templates;
161
+ this.common = config.common;
162
+ }
163
+
164
+ /**
165
+ * Called by webpack.
166
+ * @param {Object} compiler The webpack compiler.
167
+ */
168
+ apply(compiler) {
169
+ compiler.hooks.compilation.tap(this.name, (compilation) => {
170
+ compilation.hooks.additionalAssets.tapPromise(this.name, async () => {
171
+ await this.addAssets(compilation.assets, compiler.context);
172
+ });
173
+ });
174
+ }
175
+
176
+ async addAssets(assets, dir) {
177
+ const jsAssetRE = /^[\w-]+\.js$/;
178
+ const names = [];
179
+ for (const filename in assets) {
180
+ if (!jsAssetRE.test(filename)) {
181
+ continue;
182
+ }
183
+
184
+ const name = filename.replace(/\.js$/, '');
185
+ if (!exampleDirContents.includes(name)) {
186
+ continue;
187
+ }
188
+
189
+ names.push(name);
190
+ }
191
+
192
+ if (names.length === 0) {
193
+ return;
194
+ }
195
+
196
+ const exampleData = await Promise.all(
197
+ names.map((name) => this.parseExample(dir, name))
198
+ );
199
+
200
+ const examples = exampleData.map((data) => ({
201
+ link: data.filename,
202
+ title: data.title,
203
+ shortdesc: data.shortdesc,
204
+ tags: data.tags,
205
+ }));
206
+
207
+ examples.sort((a, b) =>
208
+ a.title.localeCompare(b.title, 'en', {sensitivity: 'base'})
209
+ );
210
+ const tagIndex = createTagIndex(examples);
211
+ const info = {
212
+ examples: examples,
213
+ // Tags for main page... TODO: implement index tag links
214
+ // tagIndex: sortObjectByKey(tagIndex),
215
+ wordIndex: sortObjectByKey(createWordIndex(examples)),
216
+ };
217
+ exampleData.forEach((data) => {
218
+ data.tags = data.tags.map((tag) => {
219
+ const tagExamples = tagIndex[tag.toLowerCase()];
220
+ return {
221
+ tag: tag,
222
+ examples: tagExamples.map((exampleIdx) => {
223
+ const example = examples[exampleIdx];
224
+ return {
225
+ link: example.link,
226
+ title: example.title,
227
+ isCurrent: data.filename === example.link,
228
+ };
229
+ }),
230
+ };
231
+ });
232
+ });
233
+
234
+ const pkg = await getPackageInfo();
235
+ await Promise.all(
236
+ exampleData.map(async (data) => {
237
+ const newAssets = await this.render(data, pkg);
238
+ for (const file in newAssets) {
239
+ assets[file] = new RawSource(newAssets[file]);
240
+ }
241
+ })
242
+ );
243
+
244
+ const indexSource = `const info = ${JSON.stringify(info)};`;
245
+ assets['examples-info.js'] = new RawSource(indexSource);
246
+ }
247
+
248
+ async parseExample(dir, name) {
249
+ const htmlName = `${name}.html`;
250
+ const htmlPath = path.join(dir, htmlName);
251
+ const htmlSource = await fse.readFile(htmlPath, {encoding: 'utf8'});
252
+ const {attributes: data, body} = frontMatter(
253
+ this.ensureNewLineAtEnd(htmlSource)
254
+ );
255
+ assert(!!data.layout, `missing layout in ${htmlPath}`);
256
+ return Object.assign(data, {
257
+ contents: body,
258
+ filename: htmlName,
259
+ dir: dir,
260
+ name: name,
261
+ // process tags
262
+ tags: data.tags ? data.tags.replace(/[\s"]+/g, '').split(',') : [],
263
+ });
264
+ }
265
+
266
+ /**
267
+ * @param {string} source A string
268
+ * @return {string} Same string without a newline character at end
269
+ */
270
+ ensureNewLineAtEnd(source) {
271
+ if (source[source.length - 1] !== '\n') {
272
+ source += '\n';
273
+ }
274
+ return source;
275
+ }
276
+
277
+ /**
278
+ * @param {string} source Source code
279
+ * @return {string} Transformed source
280
+ */
281
+ transformJsSource(source) {
282
+ return (
283
+ source
284
+ // remove "../src/" prefix to have the same import syntax as the documentation
285
+ .replace(/'\.\.\/src\//g, "'")
286
+ );
287
+ }
288
+
289
+ /**
290
+ * @param {string} source Source file
291
+ * @param {Array<{key: string, value: string}>|undefined} cloak Replacement rules
292
+ * @return {string} The source with all keys replaced by value
293
+ */
294
+ cloakSource(source, cloak) {
295
+ if (cloak) {
296
+ for (const entry of cloak) {
297
+ source = source.replaceAll(entry.key, entry.value);
298
+ }
299
+ }
300
+ return source;
301
+ }
302
+
303
+ async render(data, pkg) {
304
+ const assets = {};
305
+ const readOptions = {encoding: 'utf8'};
306
+
307
+ // add in script tag
308
+ const jsName = `${data.name}.js`;
309
+ const jsPath = path.join(data.dir, jsName);
310
+ let jsSource = await fse.readFile(jsPath, {encoding: 'utf8'});
311
+ jsSource = this.transformJsSource(this.cloakSource(jsSource, data.cloak));
312
+ data.js = {
313
+ local: [],
314
+ remote: [],
315
+ source: jsSource,
316
+ };
317
+
318
+ let jsSources = jsSource;
319
+ if (data.sources) {
320
+ data.extraSources = await Promise.all(
321
+ data.sources.map(async (sourceConfig) => {
322
+ const fileName = sourceConfig.path;
323
+ const extraSourcePath = path.join(data.dir, fileName);
324
+ let source = await fse.readFile(extraSourcePath, readOptions);
325
+ let ext = fileName.match(/\.(\w+)$/)[1];
326
+ if (ext === 'mjs') {
327
+ ext = 'js';
328
+ }
329
+ if (ext === 'js') {
330
+ source = this.transformJsSource(source);
331
+ jsSources += '\n' + source;
332
+ }
333
+ source = this.cloakSource(source, data.cloak);
334
+ assets[fileName] = source;
335
+ return {
336
+ name: sourceConfig.as || fileName,
337
+ source: source,
338
+ type: ext,
339
+ };
340
+ })
341
+ );
342
+ }
343
+
344
+ data.olVersion = pkg.version;
345
+ data.pkgJson = JSON.stringify(
346
+ {
347
+ name: data.name,
348
+ dependencies: getDependencies(jsSources, pkg),
349
+ devDependencies: {
350
+ vite: '^3.2.3',
351
+ },
352
+ scripts: {
353
+ start: 'vite',
354
+ build: 'vite build',
355
+ },
356
+ },
357
+ null,
358
+ 2
359
+ );
360
+
361
+ data.css = {
362
+ local: [],
363
+ remote: [],
364
+ source: undefined,
365
+ };
366
+
367
+ // add additional resources
368
+ if (data.resources) {
369
+ data.resources.forEach((resource) => {
370
+ const absoluteUrl = /^https?:\/\//.test(resource)
371
+ ? resource
372
+ : `https://m-mohr.github.io/ol-stac/en/v${pkg.version}/examples/${resource}`;
373
+ if (isJsRegEx.test(resource)) {
374
+ if (!isTemplateJs.test(resource)) {
375
+ data.js.local.push(resource);
376
+ }
377
+ data.js.remote.push(absoluteUrl);
378
+ } else if (isCssRegEx.test(resource)) {
379
+ if (!isTemplateCss.test(resource)) {
380
+ data.css.local.push(resource);
381
+ }
382
+ data.css.remote.push(absoluteUrl);
383
+ } else {
384
+ throw new Error(
385
+ `Invalid resource: '${resource}' is not .js or .css: ${data.filename}`
386
+ );
387
+ }
388
+ });
389
+ }
390
+
391
+ data.js.local.push(`${this.common}.js`, jsName);
392
+
393
+ // check for example css
394
+ const cssName = `${data.name}.css`;
395
+ const cssPath = path.join(data.dir, cssName);
396
+ try {
397
+ assets[cssName] = await fse.readFile(cssPath, readOptions);
398
+ data.css.local.push(cssName);
399
+ data.css.source = this.ensureNewLineAtEnd(assets[cssName]);
400
+ } catch (err) {
401
+ // pass, no css for this example
402
+ }
403
+
404
+ const templatePath = path.join(this.templates, data.layout);
405
+ const templateSource = await fse.readFile(templatePath, readOptions);
406
+
407
+ assets[data.filename] = handlebars.compile(templateSource)(data);
408
+ return assets;
409
+ }
410
+ }
package/package.json ADDED
@@ -0,0 +1,107 @@
1
+ {
2
+ "name": "ol-stac",
3
+ "version": "0.0.0",
4
+ "description": "An \"automagical\" STAC LayerGroup for OpenLayers",
5
+ "homepage": "https://mohr.ws",
6
+ "scripts": {
7
+ "lint": "eslint tasks test src/ol examples config",
8
+ "pretest": "npm run lint && npm run typecheck",
9
+ "test-browser": "npm run karma -- --single-run --log-level error",
10
+ "test": "npm run test-browser -- --force",
11
+ "karma": "karma start test/browser/karma.config.cjs",
12
+ "start": "npm run serve-examples",
13
+ "serve-examples": "webpack serve --config examples/webpack/config.mjs --mode development",
14
+ "build-examples": "shx rm -rf build/examples && webpack --config examples/webpack/config.mjs --mode production",
15
+ "build-package": "npm run build-full && npm run generate-types && node tasks/prepare-package.js",
16
+ "build-index": "shx rm -f build/index.js && npm run transpile && node tasks/generate-index.js",
17
+ "build-full": "shx rm -rf build/full && npm run build-index && npx rollup --config config/rollup-full-build.js",
18
+ "generate-types": "tsc --project config/tsconfig-build.json --declaration --declarationMap --emitDeclarationOnly --outdir build/ol",
19
+ "transpile": "shx rm -rf build/ol && shx mkdir -p build/ol && shx cp -rf src/ol build",
20
+ "typecheck": "tsc --pretty",
21
+ "apidoc-debug": "shx rm -rf build/apidoc && node --inspect-brk=9229 ./node_modules/jsdoc/jsdoc.js --readme config/jsdoc/api/index.md --configure config/jsdoc/api/conf.json --package package.json --destination build/apidoc",
22
+ "apidoc": "shx rm -rf build/apidoc && jsdoc --readme config/jsdoc/api/index.md --configure config/jsdoc/api/conf.json --package package.json --destination build/apidoc"
23
+ },
24
+ "type": "module",
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "git://github.com/m-mohr/ol-stac.git"
28
+ },
29
+ "license": "Apache-2.0",
30
+ "bugs": {
31
+ "url": "https://github.com/m-mohr/ol-stac/issues"
32
+ },
33
+ "dependencies": {
34
+ "ol": "^7.0.0",
35
+ "stac-js": "0.0.8"
36
+ },
37
+ "devDependencies": {
38
+ "@metalsmith/in-place": "^5.0.0",
39
+ "@metalsmith/layouts": "^2.5.1",
40
+ "@metalsmith/markdown": "^1.6.0",
41
+ "@octokit/rest": "^20.0.1",
42
+ "@openlayers/eslint-plugin": "^4.0.0",
43
+ "@rollup/plugin-commonjs": "^25.0.0",
44
+ "@rollup/plugin-node-resolve": "^15.0.0",
45
+ "@rollup/plugin-terser": "^0.4.3",
46
+ "copy-webpack-plugin": "^11.0.0",
47
+ "es-main": "^1.0.2",
48
+ "eslint": "^8.0.1",
49
+ "eslint-config-openlayers": "^18.0.0",
50
+ "expect.js": "0.3.1",
51
+ "front-matter": "^4.0.0",
52
+ "fs-extra": "^11.1.0",
53
+ "handlebars": "4.7.8",
54
+ "jsdoc": "4.0.2",
55
+ "jsdoc-plugin-intersection": "^1.0.4",
56
+ "jsdoc-plugin-typescript": "^2.2.0",
57
+ "json-stringify-safe": "^5.0.1",
58
+ "jstransformer-handlebars": "^1.2.0",
59
+ "karma": "^6.3.8",
60
+ "karma-chrome-launcher": "^3.1.0",
61
+ "karma-mocha": "2.0.1",
62
+ "karma-source-map-support": "^1.4.0",
63
+ "karma-webpack": "^5.0.0",
64
+ "marked": "7.0.2",
65
+ "metalsmith": "^2.5.0",
66
+ "mocha": "10.2.0",
67
+ "pixelmatch": "^5.1.0",
68
+ "pngjs": "^7.0.0",
69
+ "proj4": "2.9.0",
70
+ "puppeteer": "21.0.3",
71
+ "rollup": "^3.28.0",
72
+ "rollup-plugin-external-globals": "^0.8.0",
73
+ "semver": "^7.3.7",
74
+ "shx": "^0.3.2",
75
+ "sinon": "^15.0.0",
76
+ "source-map-loader": "^4.0.0",
77
+ "typescript": "5.1.6",
78
+ "walk": "^2.3.9",
79
+ "webpack": "^5.27.2",
80
+ "webpack-cli": "^5.0.0",
81
+ "webpack-dev-middleware": "^6.0.0",
82
+ "webpack-dev-server": "^4.0.0-beta.2",
83
+ "webpack-sources": "^3.2.0",
84
+ "yargs": "^17.0.0"
85
+ },
86
+ "eslintConfig": {
87
+ "extends": "openlayers",
88
+ "plugins": [
89
+ "@openlayers"
90
+ ],
91
+ "rules": {
92
+ "jsdoc/no-bad-blocks": "off",
93
+ "import/no-commonjs": "error",
94
+ "@openlayers/no-exclusive-tests": [
95
+ "error",
96
+ {
97
+ "include": "test/**/*.test.js"
98
+ }
99
+ ]
100
+ }
101
+ },
102
+ "browserslist": [
103
+ "> 1%",
104
+ "last 2 versions",
105
+ "not dead"
106
+ ]
107
+ }
package/site/build.js ADDED
@@ -0,0 +1,26 @@
1
+ import Metalsmith from 'metalsmith';
2
+ import inPlace from '@metalsmith/in-place';
3
+ import layouts from '@metalsmith/layouts';
4
+ import markdown from '@metalsmith/markdown';
5
+ import {dirname} from 'node:path';
6
+ import {env} from 'node:process';
7
+ import {fileURLToPath} from 'node:url';
8
+
9
+ const baseDir = dirname(fileURLToPath(import.meta.url));
10
+
11
+ const builder = Metalsmith(baseDir)
12
+ .source('./src')
13
+ .destination('./build')
14
+ .clean(true)
15
+ .metadata({
16
+ version: env.OL_VERSION || 'dev',
17
+ })
18
+ .use(inPlace({transform: 'handlebars'}))
19
+ .use(markdown())
20
+ .use(layouts());
21
+
22
+ builder.build(async (err) => {
23
+ if (err) {
24
+ throw err;
25
+ }
26
+ });
@@ -0,0 +1,78 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name='viewport' content='width=device-width, initial-scale=1.0'>
6
+ <title>OL STAC - {{ title }}</title>
7
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.28.0/components/prism-core.min.js"></script>
8
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.28.0/plugins/autoloader/prism-autoloader.min.js"></script>
9
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.28.0/plugins/toolbar/prism-toolbar.min.js"></script>
10
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.28.0/plugins/copy-to-clipboard/prism-copy-to-clipboard.min.js"></script>
11
+ <link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Quattrocento+Sans:400,400italic,700" crossorigin="anonymous">
12
+ <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/css/bootstrap.min.css" crossorigin="anonymous">
13
+ <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.1.2/css/fontawesome.min.css" crossorigin="anonymous">
14
+ <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.1.2/css/solid.css" crossorigin="anonymous">
15
+ <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.1.2/css/brands.css" crossorigin="anonymous">
16
+ <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/ol/ol.css">
17
+ <link rel="stylesheet" type="text/css" href="/ol-stac/theme/site.css">
18
+ {{#each head}}
19
+ {{{ this }}}
20
+ {{/each}}
21
+ </head>
22
+ <body>
23
+ <header class="navbar navbar-expand-md navbar-dark mb-3 px-3 py-0 fixed-top" role="navigation">
24
+ <a class="navbar-brand" href="/">OL STAC</a>
25
+ <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#olmenu" aria-controls="olmenu" aria-expanded="false" aria-label="Toggle navigation">
26
+ <span class="navbar-toggler-icon"></span>
27
+ </button>
28
+
29
+ <!-- menu items that get hidden below 768px width -->
30
+ <nav class="collapse navbar-collapse" id="olmenu">
31
+ <ul class="nav navbar-nav ms-auto">
32
+ <li class="nav-item dropdown">
33
+ <a class="nav-link dropdown-toggle" href="#" id="docdropdown" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Docs</a>
34
+ <div class="dropdown-menu dropdown-menu-end mb-3" aria-labelledby="docdropdown">
35
+ <a class="dropdown-item" href="/ol-stac/doc/">Docs</a>
36
+ <div class="dropdown-divider"></div>
37
+ <a class="dropdown-item" href="/ol-stac/doc/quickstart.html"><i class="fa fa-check fa-fw me-2 fa-lg"></i>Quick Start</a>
38
+ <a class="dropdown-item" href="/ol-stac/doc/faq.html"><i class="fa fa-question fa-fw me-2 fa-lg"></i>FAQ</a>
39
+ <a class="dropdown-item" href="/ol-stac/doc/tutorials/"><i class="fa fa-book fa-fw me-2 fa-lg"></i>Tutorials</a>
40
+ </div>
41
+ </li>
42
+ <li class="nav-item"><a class="nav-link" href="/ol-stac/en/latest/examples/">Examples</a></li>
43
+ <li class="nav-item dropdown">
44
+ <a class="nav-link dropdown-toggle" href="#" id="apidropdown" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
45
+ <i class="fa fa-sitemap me-1"></i>API
46
+ </a>
47
+ <div class="dropdown-menu dropdown-menu-end mb-3" aria-labelledby="apidropdown">
48
+ <a class="dropdown-item" href="/ol-stac/en/latest/apidoc/"><i class="fa fa-sitemap fa-fw me-2 fa-lg"></i>{{ version }} (latest)</a>
49
+ </div>
50
+ </li>
51
+ <li class="nav-item dropdown">
52
+ <a class="nav-link dropdown-toggle" href="#" id="codedropdown" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Code</a>
53
+ <div class="dropdown-menu dropdown-menu-end mb-3" aria-labelledby="codedropdown">
54
+ <a class="dropdown-item" href="https://github.com/m-mohr/ol-stac"><i class="fab fa-github fa-fw me-2 fa-lg"></i>Repository</a>
55
+ <a class="dropdown-item" href="/ol-stac/download/"><i class="fa fa-download fa-fw me-2 fa-lg"></i>Download</a>
56
+ </div>
57
+ </li>
58
+ </ul>
59
+ </nav>
60
+ </header>
61
+
62
+ {{#if uncontained}}
63
+ {{{ contents }}}
64
+ {{else}}
65
+ <div class="container">
66
+ {{{ contents }}}
67
+ </div>
68
+ {{/if}}
69
+ <footer>
70
+ Code licensed under the <a href='https://www.tldrlegal.com/license/apache-license-2-0-apache-2-0'>Apache 2.0</a>.
71
+ All documentation <a href='http://creativecommons.org/licenses/by/3.0/'>CC BY 3.0</a>.
72
+ </footer>
73
+ <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.bundle.min.js"></script>
74
+ {{#each scripts}}
75
+ {{{this}}}
76
+ {{/each}}
77
+ </body>
78
+ </html>
@@ -0,0 +1,8 @@
1
+ ---
2
+ title: Frequently Asked Questions (FAQ)
3
+ layout: default.hbs
4
+ ---
5
+
6
+ # Frequently Asked Questions (FAQ)
7
+
8
+ tbd
@@ -0,0 +1,22 @@
1
+ ---
2
+ title: Documentation
3
+ layout: default.hbs
4
+ ---
5
+
6
+ # Documentation
7
+
8
+ If you're eager to get your first OpenLayers map on a page, dive into the [quick start](./quickstart.html).
9
+
10
+ For a more in-depth overview of OpenLayers core concepts, check out the [tutorials](./tutorials/).
11
+
12
+ Make sure to also check out the [OpenLayers workshop](/workshop/).
13
+
14
+ Find additional reference material in the [API docs](/en/latest/apidoc/) and [examples](/en/latest/examples/).
15
+
16
+ # Frequently Asked Questions (FAQ)
17
+
18
+ We have put together a document that lists [Frequently Asked Questions (FAQ)](./faq.html) and our answers. Common problems that may arise when using OpenLayers are explained there, and chances are you'll find an appropriate solution in this document.
19
+
20
+ # More questions?
21
+
22
+ If you cannot find an answer in the documentation or the FAQ, you can search [Stack Overflow](https://stackoverflow.com/questions/tagged/openlayers). If you cannot find an answer there, ask a new question there, using the tag 'openlayers'.