mapshaper 0.7.2 → 0.7.4
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.
- package/LICENSE +1 -1
- package/bin/mapshaper-gui +31 -7
- package/mapshaper.js +45 -42
- package/package.json +8 -7
- package/www/geopackage.js +10 -10
- package/www/index.html +32 -4
- package/www/mapshaper-gui.js +529 -83
- package/www/mapshaper.js +45 -42
- package/www/modules.js +5 -5
- package/www/page.css +157 -0
- package/www/docs/_assets/cmd-search.js +0 -213
- package/www/docs/_assets/docs.css +0 -722
- package/www/docs/_assets/docs.js +0 -75
- package/www/docs/_assets/highlight.css +0 -10
- package/www/docs/essentials/command-line.html +0 -127
- package/www/docs/essentials/command-line.html.md +0 -112
- package/www/docs/essentials/web-app.html +0 -138
- package/www/docs/essentials/web-app.html.md +0 -106
- package/www/docs/examples/basics.html +0 -275
- package/www/docs/examples/basics.html.md +0 -370
- package/www/docs/examples/data/Makefile +0 -31
- package/www/docs/examples/data/globe.msx +0 -0
- package/www/docs/examples/data/globe.svg +0 -616
- package/www/docs/examples/data/globe.txt +0 -21
- package/www/docs/examples/data/globe.zip +0 -0
- package/www/docs/examples/data/ne_50m_admin_0_countries.geojson +0 -1
- package/www/docs/examples/data/ne_50m_admin_1_states_provinces_lakes.geojson +0 -1
- package/www/docs/examples/data/us-states.msx +0 -0
- package/www/docs/examples/data/us-states.svg +0 -56
- package/www/docs/examples/data/us-states.txt +0 -6
- package/www/docs/examples/data/us-states.zip +0 -0
- package/www/docs/examples/globe.html +0 -108
- package/www/docs/examples/globe.html.md +0 -64
- package/www/docs/examples/us-states.html +0 -88
- package/www/docs/examples/us-states.html.md +0 -44
- package/www/docs/formats/csv.html +0 -127
- package/www/docs/formats/csv.html.md +0 -97
- package/www/docs/formats/dbf.html +0 -87
- package/www/docs/formats/dbf.html.md +0 -39
- package/www/docs/formats/flatgeobuf.html +0 -85
- package/www/docs/formats/flatgeobuf.html.md +0 -41
- package/www/docs/formats/geojson.html +0 -107
- package/www/docs/formats/geojson.html.md +0 -65
- package/www/docs/formats/geopackage.html +0 -87
- package/www/docs/formats/geopackage.html.md +0 -42
- package/www/docs/formats/json.html +0 -83
- package/www/docs/formats/json.html.md +0 -35
- package/www/docs/formats/kml.html +0 -82
- package/www/docs/formats/kml.html.md +0 -39
- package/www/docs/formats/overview.html +0 -191
- package/www/docs/formats/overview.html.md +0 -34
- package/www/docs/formats/shapefile.html +0 -123
- package/www/docs/formats/shapefile.html.md +0 -84
- package/www/docs/formats/snapshot.html +0 -87
- package/www/docs/formats/snapshot.html.md +0 -39
- package/www/docs/formats/svg.html +0 -99
- package/www/docs/formats/svg.html.md +0 -51
- package/www/docs/formats/topojson.html +0 -102
- package/www/docs/formats/topojson.html.md +0 -54
- package/www/docs/gallery/index.html +0 -80
- package/www/docs/gallery/index.html.md +0 -29
- package/www/docs/guides/combining-layers.html +0 -109
- package/www/docs/guides/combining-layers.html.md +0 -89
- package/www/docs/guides/expressions.html +0 -600
- package/www/docs/guides/expressions.html.md +0 -376
- package/www/docs/guides/programmatic.html +0 -117
- package/www/docs/guides/programmatic.html.md +0 -91
- package/www/docs/guides/projections.html +0 -158
- package/www/docs/guides/projections.html.md +0 -118
- package/www/docs/guides/simplification.html +0 -110
- package/www/docs/guides/simplification.html.md +0 -96
- package/www/docs/guides/topology.html +0 -90
- package/www/docs/guides/topology.html.md +0 -63
- package/www/docs/images/cal-counties.png +0 -0
- package/www/docs/images/simplification-detail.png +0 -0
- package/www/docs/images/simplification-dp.png +0 -0
- package/www/docs/images/simplification-mod2.png +0 -0
- package/www/docs/images/tiger-counties.png +0 -0
- package/www/docs/index.html +0 -101
- package/www/docs/index.html.md +0 -59
- package/www/docs/reference.html +0 -1302
- package/www/docs/reference.html.md +0 -1817
- package/www/docs/whats-new.html +0 -77
- package/www/docs/whats-new.html.md +0 -59
- package/www/llms-full.txt +0 -4053
- package/www/llms.txt +0 -55
package/www/mapshaper.js
CHANGED
|
@@ -12416,8 +12416,8 @@
|
|
|
12416
12416
|
return obj;
|
|
12417
12417
|
};
|
|
12418
12418
|
|
|
12419
|
-
async function writeFiles(exports, opts) {
|
|
12420
|
-
return _writeFiles(exports, opts);
|
|
12419
|
+
async function writeFiles(exports$1, opts) {
|
|
12420
|
+
return _writeFiles(exports$1, opts);
|
|
12421
12421
|
}
|
|
12422
12422
|
|
|
12423
12423
|
// Used by GUI to replace the CLI version of writeFiles()
|
|
@@ -12426,24 +12426,24 @@
|
|
|
12426
12426
|
_writeFiles = func;
|
|
12427
12427
|
}
|
|
12428
12428
|
|
|
12429
|
-
var _writeFiles = function(exports, opts) {
|
|
12430
|
-
if (exports.length > 0 === false) {
|
|
12429
|
+
var _writeFiles = function(exports$1, opts) {
|
|
12430
|
+
if (exports$1.length > 0 === false) {
|
|
12431
12431
|
message("No files to save");
|
|
12432
12432
|
} else if (opts.dry_run) ; else if (opts.stdout) {
|
|
12433
12433
|
// Using async writeFile() function -- synchronous output to stdout can
|
|
12434
12434
|
// trigger EAGAIN error, e.g. when piped to less.
|
|
12435
|
-
require$1('rw').writeFile('/dev/stdout', exports[0].content, function() {});
|
|
12435
|
+
require$1('rw').writeFile('/dev/stdout', exports$1[0].content, function() {});
|
|
12436
12436
|
} else {
|
|
12437
12437
|
if (opts.zip) {
|
|
12438
|
-
exports = [{
|
|
12438
|
+
exports$1 = [{
|
|
12439
12439
|
// TODO: add output subdirectory, if relevant
|
|
12440
12440
|
filename: opts.zipfile || 'output.zip',
|
|
12441
|
-
content: zipSync(exports)
|
|
12441
|
+
content: zipSync(exports$1)
|
|
12442
12442
|
}];
|
|
12443
12443
|
}
|
|
12444
|
-
var paths = getOutputPaths(utils.pluck(exports, 'filename'), opts);
|
|
12444
|
+
var paths = getOutputPaths(utils.pluck(exports$1, 'filename'), opts);
|
|
12445
12445
|
var inputFiles = getStashedVar('input_files');
|
|
12446
|
-
exports.forEach(function(obj, i) {
|
|
12446
|
+
exports$1.forEach(function(obj, i) {
|
|
12447
12447
|
var path = paths[i];
|
|
12448
12448
|
if (obj.content instanceof ArrayBuffer) {
|
|
12449
12449
|
// replacing content so ArrayBuffers can be gc'd
|
|
@@ -14993,10 +14993,10 @@
|
|
|
14993
14993
|
return d;
|
|
14994
14994
|
}
|
|
14995
14995
|
|
|
14996
|
-
var cache
|
|
14996
|
+
var cache = {};
|
|
14997
14997
|
|
|
14998
14998
|
function getParseRxp(fmt) {
|
|
14999
|
-
if (fmt in cache
|
|
14999
|
+
if (fmt in cache) return cache[fmt];
|
|
15000
15000
|
var rxp = fmt;
|
|
15001
15001
|
rxp = rxp.replace('[-]', '(?<prefix>-)?'); // optional -
|
|
15002
15002
|
rxp = rxp.replace(/\[[NSEW, +-]{2,}\]/, '(?<prefix>$&)');
|
|
@@ -15020,11 +15020,11 @@
|
|
|
15020
15020
|
rxp = '^' + rxp + '$';
|
|
15021
15021
|
try {
|
|
15022
15022
|
// TODO: make sure all DMS codes have been matched
|
|
15023
|
-
cache
|
|
15023
|
+
cache[fmt] = new RegExp(rxp);
|
|
15024
15024
|
} catch(e) {
|
|
15025
15025
|
stop$1('Invalid DMS format string:', fmt);
|
|
15026
15026
|
}
|
|
15027
|
-
return cache
|
|
15027
|
+
return cache[fmt];
|
|
15028
15028
|
}
|
|
15029
15029
|
|
|
15030
15030
|
function formatNumber(val, integers, decimals) {
|
|
@@ -21150,15 +21150,6 @@
|
|
|
21150
21150
|
getSphereEffectParams: getSphereEffectParams
|
|
21151
21151
|
});
|
|
21152
21152
|
|
|
21153
|
-
var cache = {};
|
|
21154
|
-
function fetchFileSync(url) {
|
|
21155
|
-
if (url in cache) return cache[url];
|
|
21156
|
-
var res = require$1('sync-request')('GET', url, {timeout: 2000});
|
|
21157
|
-
var content = res.getBody().toString();
|
|
21158
|
-
cache[url] = content;
|
|
21159
|
-
return content;
|
|
21160
|
-
}
|
|
21161
|
-
|
|
21162
21153
|
// convert object properties to definitions for images and hatch fills
|
|
21163
21154
|
function convertPropertiesToDefinitions(obj, defs) {
|
|
21164
21155
|
procNode(obj);
|
|
@@ -21183,6 +21174,13 @@
|
|
|
21183
21174
|
function convertSvgImage(obj, defs) {
|
|
21184
21175
|
// Same-origin policy prevents embedding images in the web UI
|
|
21185
21176
|
var href = obj.properties.href;
|
|
21177
|
+
// Remote URLs were previously fetched at export time so the SVG could be
|
|
21178
|
+
// embedded inline. That capability has been removed (it required a
|
|
21179
|
+
// synchronous-HTTP dependency built on a child-process hack); download
|
|
21180
|
+
// the asset first and reference it by local path instead.
|
|
21181
|
+
if (href.indexOf('http') === 0) {
|
|
21182
|
+
stop$1('Remote SVG asset references are not supported. Download the file first and reference it by a local path:', href);
|
|
21183
|
+
}
|
|
21186
21184
|
// look for a previously added definition to use
|
|
21187
21185
|
// (assumes that images that share the same href can also use the same defn)
|
|
21188
21186
|
var item = utils.find(defs, function(item) {return item.href == href;});
|
|
@@ -21200,12 +21198,12 @@
|
|
|
21200
21198
|
}
|
|
21201
21199
|
}
|
|
21202
21200
|
|
|
21203
|
-
// Returns the content of an SVG file from a local path
|
|
21204
|
-
// Returns '' if unable to get the content
|
|
21201
|
+
// Returns the content of an SVG file from a local path.
|
|
21202
|
+
// Returns '' if unable to get the content; the caller leaves the original
|
|
21203
|
+
// <image> tag in the output so the SVG renderer can attempt to load it.
|
|
21205
21204
|
function serializeSvgImage(href, id) {
|
|
21206
21205
|
var svg = '';
|
|
21207
21206
|
try {
|
|
21208
|
-
// try to download the SVG content and use that
|
|
21209
21207
|
svg = convertSvgToDefn(getSvgContent(href), id) + '\n';
|
|
21210
21208
|
svg = '<!-- ' + href + '-->\n' + svg; // add href as a comment, to aid in debugging
|
|
21211
21209
|
} catch(e) {
|
|
@@ -21216,20 +21214,12 @@
|
|
|
21216
21214
|
return svg;
|
|
21217
21215
|
}
|
|
21218
21216
|
|
|
21219
|
-
// href: A
|
|
21220
|
-
// TODO: download SVG files asynchronously
|
|
21221
|
-
// (currently, files are downloaded synchronously, which is obviously undesirable)
|
|
21222
|
-
//
|
|
21217
|
+
// href: A local path
|
|
21223
21218
|
function getSvgContent(href) {
|
|
21224
|
-
|
|
21225
|
-
|
|
21226
|
-
content = fetchFileSync(href);
|
|
21227
|
-
} else if (require$1('fs').existsSync(href)) {
|
|
21228
|
-
content = require$1('fs').readFileSync(href, 'utf8');
|
|
21229
|
-
} else {
|
|
21230
|
-
stop$1("Invalid SVG location:", href);
|
|
21219
|
+
if (require$1('fs').existsSync(href)) {
|
|
21220
|
+
return require$1('fs').readFileSync(href, 'utf8');
|
|
21231
21221
|
}
|
|
21232
|
-
|
|
21222
|
+
stop$1("Invalid SVG location:", href);
|
|
21233
21223
|
}
|
|
21234
21224
|
|
|
21235
21225
|
function convertSvgToDefn(svg, id) {
|
|
@@ -21372,12 +21362,27 @@ ${svg}
|
|
|
21372
21362
|
var geojson = exportDatasetAsGeoJSON(d, opts);
|
|
21373
21363
|
var features = geojson.features || geojson.geometries || (geojson.type ? [geojson] : []);
|
|
21374
21364
|
var children = importGeoJSONFeatures(features, opts);
|
|
21365
|
+
// Drop empty placeholder <g/> elements (features whose geometry was null in the
|
|
21366
|
+
// source data, collapsed during simplification, or otherwise produced no
|
|
21367
|
+
// visible output). Keep the layer's records in lockstep so that data-*
|
|
21368
|
+
// attributes added via -o svg-data= remain correctly aligned.
|
|
21369
|
+
var records = lyr.data ? lyr.data.getRecords() : null;
|
|
21370
|
+
var keptRecords = records ? [] : null;
|
|
21371
|
+
children = children.filter(function(child, i) {
|
|
21372
|
+
if (isEmptyPlaceholder(child)) return false;
|
|
21373
|
+
if (keptRecords) keptRecords.push(records[i]);
|
|
21374
|
+
return true;
|
|
21375
|
+
});
|
|
21375
21376
|
if (opts.svg_data && lyr.data) {
|
|
21376
|
-
addDataAttributesToSVG(children, lyr.data, opts.svg_data);
|
|
21377
|
+
addDataAttributesToSVG(children, keptRecords, lyr.data.getFields(), opts.svg_data);
|
|
21377
21378
|
}
|
|
21378
21379
|
return children;
|
|
21379
21380
|
}
|
|
21380
21381
|
|
|
21382
|
+
function isEmptyPlaceholder(o) {
|
|
21383
|
+
return o.tag == 'g' && (!o.children || o.children.length === 0);
|
|
21384
|
+
}
|
|
21385
|
+
|
|
21381
21386
|
function validateSvgDataFields(layers, fieldsArg) {
|
|
21382
21387
|
var missingFields = fieldsArg.reduce(function(memo, field) {
|
|
21383
21388
|
if (!fieldExists(layers, field)) {
|
|
@@ -21397,15 +21402,13 @@ ${svg}
|
|
|
21397
21402
|
}
|
|
21398
21403
|
}
|
|
21399
21404
|
|
|
21400
|
-
function addDataAttributesToSVG(children,
|
|
21401
|
-
var allFields = table.getFields();
|
|
21405
|
+
function addDataAttributesToSVG(children, records, allFields, fieldsArg) {
|
|
21402
21406
|
var dataFields = fieldsArg.indexOf('*') > -1 ? allFields.concat() : fieldsArg;
|
|
21403
21407
|
var missingFields = utils.difference(dataFields, allFields);
|
|
21404
21408
|
if (missingFields.length > 0) {
|
|
21405
21409
|
dataFields = utils.difference(dataFields, missingFields);
|
|
21406
21410
|
// stop("Missing data field(s):", missingFields.join(', '));
|
|
21407
21411
|
}
|
|
21408
|
-
var records = table.getRecords();
|
|
21409
21412
|
var data = exportDataAttributesForSVG(records, dataFields);
|
|
21410
21413
|
if (children.length != data.length) {
|
|
21411
21414
|
error("Mismatch between number of SVG symbols and data attributes");
|
|
@@ -52127,7 +52130,7 @@ ${svg}
|
|
|
52127
52130
|
});
|
|
52128
52131
|
}
|
|
52129
52132
|
|
|
52130
|
-
var version = "0.7.
|
|
52133
|
+
var version = "0.7.4";
|
|
52131
52134
|
|
|
52132
52135
|
// Parse command line args into commands and run them
|
|
52133
52136
|
// Function takes an optional Node-style callback. A Promise is returned if no callback is given.
|
package/www/modules.js
CHANGED
|
@@ -13503,7 +13503,7 @@
|
|
|
13503
13503
|
function requireEncodings () {
|
|
13504
13504
|
if (hasRequiredEncodings) return encodings;
|
|
13505
13505
|
hasRequiredEncodings = 1;
|
|
13506
|
-
(function (exports) {
|
|
13506
|
+
(function (exports$1) {
|
|
13507
13507
|
"use strict";
|
|
13508
13508
|
|
|
13509
13509
|
// Update this array if you add/rename/remove files in this directory.
|
|
@@ -13525,7 +13525,7 @@
|
|
|
13525
13525
|
var module = modules[i];
|
|
13526
13526
|
for (var enc in module)
|
|
13527
13527
|
if (Object.prototype.hasOwnProperty.call(module, enc))
|
|
13528
|
-
exports[enc] = module[enc];
|
|
13528
|
+
exports$1[enc] = module[enc];
|
|
13529
13529
|
}
|
|
13530
13530
|
} (encodings));
|
|
13531
13531
|
return encodings;
|
|
@@ -18975,7 +18975,7 @@
|
|
|
18975
18975
|
tcxGen: tcxGen
|
|
18976
18976
|
});
|
|
18977
18977
|
|
|
18978
|
-
var __filename = '/Users/matthewbloch/mb4/mapshaper/node_modules/mproj/dist';
|
|
18978
|
+
var __filename$1 = '/Users/matthewbloch/mb4/mapshaper/node_modules/mproj/dist';
|
|
18979
18979
|
|
|
18980
18980
|
var mproj$2 = {exports: {}};
|
|
18981
18981
|
|
|
@@ -19247,7 +19247,7 @@
|
|
|
19247
19247
|
function requireMproj () {
|
|
19248
19248
|
if (hasRequiredMproj) return mproj$2.exports;
|
|
19249
19249
|
hasRequiredMproj = 1;
|
|
19250
|
-
(function (module, exports) {
|
|
19250
|
+
(function (module, exports$1) {
|
|
19251
19251
|
(function(){
|
|
19252
19252
|
|
|
19253
19253
|
// add math.h functions to library scope
|
|
@@ -19967,7 +19967,7 @@
|
|
|
19967
19967
|
var fs = require$$0,
|
|
19968
19968
|
path = require$$1,
|
|
19969
19969
|
// path to library assumes mproj script is in the dist/ directory
|
|
19970
|
-
dir = path.join(path.dirname(__filename), '../nad'),
|
|
19970
|
+
dir = path.join(path.dirname(__filename$1), '../nad'),
|
|
19971
19971
|
pathUC = path.join(dir, libFile.toUpperCase()),
|
|
19972
19972
|
pathLC = path.join(dir, libFile.toLowerCase()),
|
|
19973
19973
|
contents;
|
package/www/page.css
CHANGED
|
@@ -165,6 +165,13 @@ body.map-view {
|
|
|
165
165
|
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
+
/* When the page is preloaded with data (CLI files, ?files= or ?catalog= URL
|
|
169
|
+
params), suppress the splash header links so they don't flash into view
|
|
170
|
+
for ~a second before the editor mounts and hides them. */
|
|
171
|
+
.mapshaper-preload #splash-buttons {
|
|
172
|
+
display: none;
|
|
173
|
+
}
|
|
174
|
+
|
|
168
175
|
.page-header-buttons {
|
|
169
176
|
z-index: 20;
|
|
170
177
|
position: absolute;
|
|
@@ -1197,6 +1204,156 @@ img.close-btn:hover,
|
|
|
1197
1204
|
pointer-events: initial;
|
|
1198
1205
|
}
|
|
1199
1206
|
|
|
1207
|
+
/* --- Messages inbox --------------- */
|
|
1208
|
+
|
|
1209
|
+
.messages-btn.btn {
|
|
1210
|
+
/* SVG-only button; align like the hamburger so its baseline doesn't drag
|
|
1211
|
+
the row's text-bearing buttons down. */
|
|
1212
|
+
padding: 8px 8px 4px 8px;
|
|
1213
|
+
user-select: none;
|
|
1214
|
+
vertical-align: top;
|
|
1215
|
+
cursor: pointer;
|
|
1216
|
+
position: relative;
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
.messages-btn.btn.hidden {
|
|
1220
|
+
display: none;
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
.messages-btn svg {
|
|
1224
|
+
display: block;
|
|
1225
|
+
fill: currentColor;
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
.messages-badge {
|
|
1229
|
+
position: absolute;
|
|
1230
|
+
top: 2px;
|
|
1231
|
+
right: -1px;
|
|
1232
|
+
min-width: 14px;
|
|
1233
|
+
height: 14px;
|
|
1234
|
+
padding: 0 3px;
|
|
1235
|
+
border-radius: 7px;
|
|
1236
|
+
background-color: #d63333;
|
|
1237
|
+
color: #fff;
|
|
1238
|
+
font-size: 10px;
|
|
1239
|
+
line-height: 14px;
|
|
1240
|
+
font-weight: 600;
|
|
1241
|
+
text-align: center;
|
|
1242
|
+
box-sizing: border-box;
|
|
1243
|
+
pointer-events: none;
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
.messages-badge.warn {
|
|
1247
|
+
background-color: #d68f33;
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
/* Quick pulse to draw attention when a new message arrives. The animation
|
|
1251
|
+
is added by JS for ~2s and then removed, so it doesn't cycle forever. */
|
|
1252
|
+
.messages-btn.pulse .messages-badge {
|
|
1253
|
+
animation: messages-pulse 0.9s ease-out 2;
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
@keyframes messages-pulse {
|
|
1257
|
+
0% { transform: scale(1); box-shadow: 0 0 0 0 rgba(214, 51, 51, 0.55); }
|
|
1258
|
+
60% { transform: scale(1.15); box-shadow: 0 0 0 6px rgba(214, 51, 51, 0); }
|
|
1259
|
+
100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(214, 51, 51, 0); }
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
.messages-panel {
|
|
1263
|
+
pointer-events: none;
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
.messages-panel .info-box {
|
|
1267
|
+
pointer-events: initial;
|
|
1268
|
+
width: 360px;
|
|
1269
|
+
max-width: 90vw;
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
.messages-empty {
|
|
1273
|
+
color: #888;
|
|
1274
|
+
font-size: 13px;
|
|
1275
|
+
font-style: italic;
|
|
1276
|
+
padding: 4px 0 8px 0;
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
.messages-list {
|
|
1280
|
+
max-height: 50vh;
|
|
1281
|
+
overflow: hidden;
|
|
1282
|
+
overflow-y: auto;
|
|
1283
|
+
margin: 0 -4px 6px -4px;
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
.message-item {
|
|
1287
|
+
position: relative;
|
|
1288
|
+
border-left: 3px solid #888;
|
|
1289
|
+
background-color: #f4f7fa;
|
|
1290
|
+
padding: 6px 22px 6px 9px;
|
|
1291
|
+
margin: 4px 4px;
|
|
1292
|
+
border-radius: 3px;
|
|
1293
|
+
font-size: 13px;
|
|
1294
|
+
line-height: 1.35;
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
.message-item.severity-warn {
|
|
1298
|
+
border-left-color: #d68f33;
|
|
1299
|
+
background-color: #fbf3e6;
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
.message-item.severity-error {
|
|
1303
|
+
border-left-color: #d63333;
|
|
1304
|
+
background-color: #fbecec;
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
.message-item .message-title {
|
|
1308
|
+
font-weight: 600;
|
|
1309
|
+
display: block;
|
|
1310
|
+
margin-bottom: 1px;
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
.message-item .message-body {
|
|
1314
|
+
white-space: pre-wrap;
|
|
1315
|
+
word-wrap: break-word;
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
.message-item .message-time {
|
|
1319
|
+
color: #888;
|
|
1320
|
+
font-size: 11px;
|
|
1321
|
+
margin-top: 2px;
|
|
1322
|
+
display: block;
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1325
|
+
.message-item .message-dismiss {
|
|
1326
|
+
position: absolute;
|
|
1327
|
+
top: 3px;
|
|
1328
|
+
right: 5px;
|
|
1329
|
+
width: 16px;
|
|
1330
|
+
height: 16px;
|
|
1331
|
+
line-height: 14px;
|
|
1332
|
+
text-align: center;
|
|
1333
|
+
color: #888;
|
|
1334
|
+
cursor: pointer;
|
|
1335
|
+
font-size: 14px;
|
|
1336
|
+
user-select: none;
|
|
1337
|
+
border-radius: 8px;
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1340
|
+
.message-item .message-dismiss:hover {
|
|
1341
|
+
color: #333;
|
|
1342
|
+
background-color: rgba(0, 0, 0, 0.05);
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1345
|
+
.messages-footer {
|
|
1346
|
+
text-align: right;
|
|
1347
|
+
padding-top: 4px;
|
|
1348
|
+
border-top: 1px solid #eee;
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
.messages-footer .messages-clear-btn {
|
|
1352
|
+
font-size: 12px;
|
|
1353
|
+
min-width: 0;
|
|
1354
|
+
padding: 3px 9px;
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1200
1357
|
.basemap-container {
|
|
1201
1358
|
z-index: -1;
|
|
1202
1359
|
position: absolute;
|
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
// Jump-to-command dropdown for the command reference page.
|
|
2
|
-
//
|
|
3
|
-
// The build script wraps each command in <section class="cmd-section"
|
|
4
|
-
// data-id="-clip" data-name="-clip" data-options="..."> and tags the H2
|
|
5
|
-
// above each group as <h2 class="cmd-category">. We use that to populate a
|
|
6
|
-
// dropdown of matching commands beneath the search input. Selecting an item
|
|
7
|
-
// jumps to the corresponding section -- the page itself is never filtered.
|
|
8
|
-
|
|
9
|
-
(function () {
|
|
10
|
-
'use strict';
|
|
11
|
-
|
|
12
|
-
var input = document.querySelector('.cmd-search-input');
|
|
13
|
-
var panel = document.querySelector('.cmd-search-results');
|
|
14
|
-
if (!input || !panel) return;
|
|
15
|
-
|
|
16
|
-
var statusEl = panel.querySelector('.cmd-search-status');
|
|
17
|
-
var listEl = panel.querySelector('.cmd-search-list');
|
|
18
|
-
var sections = Array.prototype.slice.call(
|
|
19
|
-
document.querySelectorAll('.cmd-section')
|
|
20
|
-
);
|
|
21
|
-
if (!sections.length) return;
|
|
22
|
-
|
|
23
|
-
// Build a flat command index. We walk the article in document order so we
|
|
24
|
-
// can attach the most recent h2.cmd-category to each section.
|
|
25
|
-
var article = sections[0].closest('.docs-article') || document;
|
|
26
|
-
var commands = (function () {
|
|
27
|
-
var out = [];
|
|
28
|
-
var currentCat = '';
|
|
29
|
-
var nodes = article.querySelectorAll('h2.cmd-category, section.cmd-section');
|
|
30
|
-
for (var i = 0; i < nodes.length; i++) {
|
|
31
|
-
var n = nodes[i];
|
|
32
|
-
if (n.tagName === 'H2') {
|
|
33
|
-
currentCat = (n.textContent || '').trim();
|
|
34
|
-
} else {
|
|
35
|
-
var name = n.dataset.name || '';
|
|
36
|
-
var opts = n.dataset.options || '';
|
|
37
|
-
var id = n.dataset.id || '';
|
|
38
|
-
if (!id) continue;
|
|
39
|
-
out.push({
|
|
40
|
-
id: id,
|
|
41
|
-
name: name,
|
|
42
|
-
options: opts,
|
|
43
|
-
category: currentCat,
|
|
44
|
-
haystack: (name + ' ' + opts).toLowerCase(),
|
|
45
|
-
el: n
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
return out;
|
|
50
|
-
})();
|
|
51
|
-
|
|
52
|
-
var MAX_RESULTS = 60;
|
|
53
|
-
var activeIdx = -1;
|
|
54
|
-
var results = [];
|
|
55
|
-
|
|
56
|
-
function render() {
|
|
57
|
-
var raw = input.value.trim();
|
|
58
|
-
var tokens = raw.toLowerCase().split(/\s+/).filter(Boolean);
|
|
59
|
-
|
|
60
|
-
if (!tokens.length) {
|
|
61
|
-
close();
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// Score-free matching: every token must appear in the name + options
|
|
66
|
-
// string. We deliberately don't search the full body text -- the dropdown
|
|
67
|
-
// is for jumping to a known command, not for free-text search.
|
|
68
|
-
results = commands.filter(function (c) {
|
|
69
|
-
return tokens.every(function (t) { return c.haystack.indexOf(t) !== -1; });
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
var truncated = results.length > MAX_RESULTS;
|
|
73
|
-
var shown = truncated ? results.slice(0, MAX_RESULTS) : results;
|
|
74
|
-
|
|
75
|
-
listEl.innerHTML = shown.map(function (c, i) {
|
|
76
|
-
return '<li role="option" id="cmd-result-' + i + '" class="cmd-result">' +
|
|
77
|
-
'<a href="#' + escapeAttr(c.id) + '" class="cmd-result-link" tabindex="-1">' +
|
|
78
|
-
'<span class="cmd-result-name">' + escapeHtml(c.name) + '</span>' +
|
|
79
|
-
(c.category
|
|
80
|
-
? '<span class="cmd-result-cat">' + escapeHtml(c.category) + '</span>'
|
|
81
|
-
: '') +
|
|
82
|
-
'</a>' +
|
|
83
|
-
'</li>';
|
|
84
|
-
}).join('');
|
|
85
|
-
|
|
86
|
-
if (!results.length) {
|
|
87
|
-
statusEl.textContent = 'No commands match \u201c' + raw + '\u201d.';
|
|
88
|
-
} else if (truncated) {
|
|
89
|
-
statusEl.textContent = 'Showing first ' + MAX_RESULTS + ' of ' +
|
|
90
|
-
results.length + ' matches.';
|
|
91
|
-
} else if (results.length === 1) {
|
|
92
|
-
statusEl.textContent = '1 match (press Enter to jump).';
|
|
93
|
-
} else {
|
|
94
|
-
statusEl.textContent = results.length + ' matches.';
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
open();
|
|
98
|
-
setActive(results.length ? 0 : -1);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function open() {
|
|
102
|
-
panel.hidden = false;
|
|
103
|
-
input.setAttribute('aria-expanded', 'true');
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
function close() {
|
|
107
|
-
panel.hidden = true;
|
|
108
|
-
input.setAttribute('aria-expanded', 'false');
|
|
109
|
-
input.removeAttribute('aria-activedescendant');
|
|
110
|
-
activeIdx = -1;
|
|
111
|
-
results = [];
|
|
112
|
-
listEl.innerHTML = '';
|
|
113
|
-
statusEl.textContent = '';
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
function setActive(idx) {
|
|
117
|
-
var items = listEl.querySelectorAll('.cmd-result');
|
|
118
|
-
if (activeIdx >= 0 && items[activeIdx]) {
|
|
119
|
-
items[activeIdx].classList.remove('is-active');
|
|
120
|
-
}
|
|
121
|
-
activeIdx = idx;
|
|
122
|
-
if (idx < 0 || !items[idx]) {
|
|
123
|
-
input.removeAttribute('aria-activedescendant');
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
items[idx].classList.add('is-active');
|
|
127
|
-
input.setAttribute('aria-activedescendant', 'cmd-result-' + idx);
|
|
128
|
-
// Keep the highlighted item visible inside the (scrollable) dropdown.
|
|
129
|
-
var el = items[idx];
|
|
130
|
-
var top = el.offsetTop;
|
|
131
|
-
var bottom = top + el.offsetHeight;
|
|
132
|
-
if (top < listEl.scrollTop) {
|
|
133
|
-
listEl.scrollTop = top;
|
|
134
|
-
} else if (bottom > listEl.scrollTop + listEl.clientHeight) {
|
|
135
|
-
listEl.scrollTop = bottom - listEl.clientHeight;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
function jumpTo(idx) {
|
|
140
|
-
if (idx < 0 || idx >= results.length) return;
|
|
141
|
-
var c = results[idx];
|
|
142
|
-
// Use the anchor's href so the browser updates location.hash and triggers
|
|
143
|
-
// its native scroll-to-anchor behaviour (which respects scroll-margin-top).
|
|
144
|
-
var link = listEl.querySelectorAll('.cmd-result-link')[idx];
|
|
145
|
-
if (link) link.click();
|
|
146
|
-
close();
|
|
147
|
-
input.blur();
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
function escapeHtml(s) {
|
|
151
|
-
return String(s).replace(/[&<>"']/g, function (c) {
|
|
152
|
-
return ({ '&': '&', '<': '<', '>': '>',
|
|
153
|
-
'"': '"', "'": ''' })[c];
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
function escapeAttr(s) { return escapeHtml(s); }
|
|
157
|
-
|
|
158
|
-
input.addEventListener('input', render);
|
|
159
|
-
input.addEventListener('focus', function () {
|
|
160
|
-
if (input.value.trim()) render();
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
input.addEventListener('keydown', function (e) {
|
|
164
|
-
if (e.key === 'ArrowDown') {
|
|
165
|
-
if (panel.hidden) { render(); return; }
|
|
166
|
-
e.preventDefault();
|
|
167
|
-
if (results.length) setActive((activeIdx + 1) % results.length);
|
|
168
|
-
} else if (e.key === 'ArrowUp') {
|
|
169
|
-
if (panel.hidden) return;
|
|
170
|
-
e.preventDefault();
|
|
171
|
-
if (results.length) {
|
|
172
|
-
setActive(activeIdx <= 0 ? results.length - 1 : activeIdx - 1);
|
|
173
|
-
}
|
|
174
|
-
} else if (e.key === 'Enter') {
|
|
175
|
-
if (panel.hidden || activeIdx < 0) return;
|
|
176
|
-
e.preventDefault();
|
|
177
|
-
jumpTo(activeIdx);
|
|
178
|
-
} else if (e.key === 'Escape') {
|
|
179
|
-
if (!panel.hidden) {
|
|
180
|
-
e.preventDefault();
|
|
181
|
-
close();
|
|
182
|
-
} else if (input.value) {
|
|
183
|
-
e.preventDefault();
|
|
184
|
-
input.value = '';
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
// Mouse interaction with the dropdown.
|
|
190
|
-
listEl.addEventListener('mousemove', function (e) {
|
|
191
|
-
var li = e.target.closest('.cmd-result');
|
|
192
|
-
if (!li) return;
|
|
193
|
-
var idx = Array.prototype.indexOf.call(listEl.children, li);
|
|
194
|
-
if (idx !== activeIdx) setActive(idx);
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
listEl.addEventListener('click', function (e) {
|
|
198
|
-
var link = e.target.closest('.cmd-result-link');
|
|
199
|
-
if (!link) return;
|
|
200
|
-
// Let cmd/ctrl/middle-click open in new tab as normal; otherwise
|
|
201
|
-
// intercept so we can close the dropdown after navigation.
|
|
202
|
-
if (e.metaKey || e.ctrlKey || e.shiftKey || e.button === 1) return;
|
|
203
|
-
// Default <a> click handles the scroll; just tidy up the UI.
|
|
204
|
-
setTimeout(close, 0);
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
// Click outside the wrap closes the dropdown.
|
|
208
|
-
document.addEventListener('click', function (e) {
|
|
209
|
-
if (panel.hidden) return;
|
|
210
|
-
if (e.target.closest('.cmd-search-wrap')) return;
|
|
211
|
-
close();
|
|
212
|
-
});
|
|
213
|
-
})();
|