mapshaper 0.6.117 → 0.6.119
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/README.md +12 -0
- package/mapshaper.js +1228 -288
- package/package.json +1 -1
- package/www/donate.html +215 -0
- package/www/index.html +5 -1
- package/www/mapshaper-gui.js +214 -17
- package/www/mapshaper.js +1228 -288
- package/www/page.css +17 -0
package/package.json
CHANGED
package/www/donate.html
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
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">
|
|
6
|
+
<title>Support mapshaper</title>
|
|
7
|
+
<meta name="description" content="Support the development of mapshaper, free open-source software for editing geographic data.">
|
|
8
|
+
<link rel="icon" type="image/png" href="images/icon.png">
|
|
9
|
+
|
|
10
|
+
<style>
|
|
11
|
+
@font-face {
|
|
12
|
+
font-family: 'SourceSans3';
|
|
13
|
+
src: url('assets/SourceSans3-VariableFont_wght.ttf') format('truetype');
|
|
14
|
+
font-display: swap;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
html, body {
|
|
18
|
+
margin: 0;
|
|
19
|
+
padding: 0;
|
|
20
|
+
background-color: #f8fdff;
|
|
21
|
+
font: 16px/1.55 'SourceSans3', Arial, sans-serif;
|
|
22
|
+
color: #333;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
a { color: #10699b; }
|
|
26
|
+
a:hover { color: #1A6A96; }
|
|
27
|
+
|
|
28
|
+
.page-header {
|
|
29
|
+
background-color: #1385B7;
|
|
30
|
+
color: white;
|
|
31
|
+
padding: 0 11px;
|
|
32
|
+
height: 29px;
|
|
33
|
+
display: flex;
|
|
34
|
+
align-items: center;
|
|
35
|
+
justify-content: space-between;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.mapshaper-logo,
|
|
39
|
+
.mapshaper-logo:hover {
|
|
40
|
+
font-weight: 600;
|
|
41
|
+
font-size: 17px;
|
|
42
|
+
color: white;
|
|
43
|
+
text-decoration: none;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.mapshaper-logo .logo-highlight {
|
|
47
|
+
color: #ffa;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.header-back {
|
|
51
|
+
color: white;
|
|
52
|
+
text-decoration: none;
|
|
53
|
+
font-size: 14px;
|
|
54
|
+
height: 29px;
|
|
55
|
+
display: inline-flex;
|
|
56
|
+
align-items: center;
|
|
57
|
+
padding: 0 10px;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.header-back:hover {
|
|
61
|
+
background-color: #1A6A96;
|
|
62
|
+
color: white;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
main {
|
|
66
|
+
max-width: 640px;
|
|
67
|
+
margin: 0 auto;
|
|
68
|
+
padding: 40px 24px 80px;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
h1 {
|
|
72
|
+
font-weight: 600;
|
|
73
|
+
font-size: 32px;
|
|
74
|
+
margin: 0 0 12px;
|
|
75
|
+
color: #222;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.tagline {
|
|
79
|
+
font-size: 17px;
|
|
80
|
+
color: #555;
|
|
81
|
+
margin: 0 0 32px;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.donate-buttons {
|
|
85
|
+
display: flex;
|
|
86
|
+
gap: 12px;
|
|
87
|
+
flex-wrap: wrap;
|
|
88
|
+
margin: 24px 0 12px;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.btn {
|
|
92
|
+
display: inline-block;
|
|
93
|
+
padding: 12px 22px;
|
|
94
|
+
background-color: #1385B7;
|
|
95
|
+
color: white;
|
|
96
|
+
text-decoration: none;
|
|
97
|
+
font-weight: 600;
|
|
98
|
+
font-size: 16px;
|
|
99
|
+
border-radius: 3px;
|
|
100
|
+
transition: background-color 0.15s;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.btn:hover {
|
|
104
|
+
background-color: #1A6A96;
|
|
105
|
+
color: white;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.btn.btn-secondary {
|
|
109
|
+
background-color: #444;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.btn.btn-secondary:hover {
|
|
113
|
+
background-color: #222;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.donate-note {
|
|
117
|
+
font-size: 14px;
|
|
118
|
+
color: #666;
|
|
119
|
+
margin: 0 0 32px;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
h2 {
|
|
123
|
+
font-weight: 600;
|
|
124
|
+
font-size: 20px;
|
|
125
|
+
margin: 32px 0 12px;
|
|
126
|
+
color: #222;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
ul.support-list {
|
|
130
|
+
padding-left: 20px;
|
|
131
|
+
margin: 8px 0 24px;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
ul.support-list li {
|
|
135
|
+
margin-bottom: 6px;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.feedback-cta {
|
|
139
|
+
background-color: #fff;
|
|
140
|
+
border-left: 3px solid #1385B7;
|
|
141
|
+
padding: 14px 18px;
|
|
142
|
+
margin: 24px 0;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.signature {
|
|
146
|
+
margin-top: 32px;
|
|
147
|
+
color: #555;
|
|
148
|
+
font-style: italic;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.footer-note {
|
|
152
|
+
margin-top: 48px;
|
|
153
|
+
padding-top: 24px;
|
|
154
|
+
border-top: 1px solid #e0e8ec;
|
|
155
|
+
font-size: 14px;
|
|
156
|
+
color: #777;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
@media (max-width: 480px) {
|
|
160
|
+
main { padding: 24px 18px 60px; }
|
|
161
|
+
h1 { font-size: 26px; }
|
|
162
|
+
.donate-buttons { flex-direction: column; align-items: stretch; }
|
|
163
|
+
.btn { text-align: center; }
|
|
164
|
+
}
|
|
165
|
+
</style>
|
|
166
|
+
</head>
|
|
167
|
+
<body>
|
|
168
|
+
|
|
169
|
+
<header class="page-header">
|
|
170
|
+
<a href="index.html" class="mapshaper-logo">map<span class="logo-highlight">shaper</span></a>
|
|
171
|
+
<a href="index.html" class="header-back">← Back to mapshaper</a>
|
|
172
|
+
</header>
|
|
173
|
+
|
|
174
|
+
<main>
|
|
175
|
+
|
|
176
|
+
<h1>Support mapshaper</h1>
|
|
177
|
+
|
|
178
|
+
<p class="tagline">Mapshaper is free, open-source software for editing geographic data — used worldwide for everything from classroom exercises to professional map work.</p>
|
|
179
|
+
|
|
180
|
+
<div class="donate-buttons">
|
|
181
|
+
<a href="https://ko-fi.com/mapshaper" class="btn">Donate via Ko-fi</a>
|
|
182
|
+
<a href="https://github.com/sponsors/mbloch" class="btn btn-secondary">Sponsor on GitHub</a>
|
|
183
|
+
</div>
|
|
184
|
+
|
|
185
|
+
<p class="donate-note">Ko-fi accepts one-time or recurring donations — no account required. GitHub Sponsors offers recurring sponsorship.</p>
|
|
186
|
+
|
|
187
|
+
<h2>What your donation supports</h2>
|
|
188
|
+
<ul class="support-list">
|
|
189
|
+
<li>Development time — bug fixes, new features, performance improvements</li>
|
|
190
|
+
<li>Responding to user issues and requests</li>
|
|
191
|
+
</ul>
|
|
192
|
+
|
|
193
|
+
<h2>Recent improvements</h2>
|
|
194
|
+
<ul class="support-list">
|
|
195
|
+
<li><strong>GeoPackage</strong> import and export</li>
|
|
196
|
+
<li><strong>FlatGeobuf</strong> import and export</li>
|
|
197
|
+
<li><strong>SVG import</strong> — for round-tripping maps originally exported from Mapshaper</li>
|
|
198
|
+
<li><strong>Performance improvements</strong> for large datasets</li>
|
|
199
|
+
</ul>
|
|
200
|
+
<p><a href="https://github.com/mbloch/mapshaper/blob/master/CHANGELOG.md">See the full changelog →</a></p>
|
|
201
|
+
|
|
202
|
+
<div class="feedback-cta">
|
|
203
|
+
<strong>Want to help shape the roadmap?</strong> Take a <a href="https://tally.so/r/44Njok">one-minute survey</a> and tell me what you'd like to see improved.
|
|
204
|
+
</div>
|
|
205
|
+
|
|
206
|
+
<p class="signature">— Matthew Bloch, maintainer</p>
|
|
207
|
+
|
|
208
|
+
<div class="footer-note">
|
|
209
|
+
Mapshaper’s basemap services are generously provided by <a href="https://www.mapbox.com">Mapbox</a>.
|
|
210
|
+
</div>
|
|
211
|
+
|
|
212
|
+
</main>
|
|
213
|
+
|
|
214
|
+
</body>
|
|
215
|
+
</html>
|
package/www/index.html
CHANGED
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
<span class="console-btn header-btn btn">Console</span><span class="display-btn header-btn btn">Display</span><span class="separator"></span><span class="separator"></span></span><span class="simplify-btn header-btn btn">Simplify</span><span class="separator"></span><span class="export-btn header-btn btn">Export</span>
|
|
64
64
|
</div>
|
|
65
65
|
<div id="splash-buttons" class="page-header-buttons">
|
|
66
|
-
<a href="https://github.com/mbloch/mapshaper/wiki"><span id="wiki-btn" class="header-btn btn">Wiki</span></a><span class="separator"></span><a href="https://github.com/mbloch/mapshaper"><span id="github-btn" class="header-btn btn">GitHub</span></a>
|
|
66
|
+
<a href="https://github.com/mbloch/mapshaper/wiki"><span id="wiki-btn" class="header-btn btn">Wiki</span></a><span class="separator"></span><a href="https://github.com/mbloch/mapshaper"><span id="github-btn" class="header-btn btn">GitHub</span></a><span class="separator"></span><a href="donate.html"><span id="donate-btn" class="header-btn btn">Donate</span></a>
|
|
67
67
|
</div>
|
|
68
68
|
</div>
|
|
69
69
|
|
|
@@ -287,6 +287,10 @@ a smoother appearance.</div></div></div></div>
|
|
|
287
287
|
<div class="dropped-file-list"></div>
|
|
288
288
|
<div class="option-menu">
|
|
289
289
|
<div id="path-import-options">
|
|
290
|
+
<div id="gpkg-import-options" class="hidden">
|
|
291
|
+
<h4>GeoPackage layers</h4>
|
|
292
|
+
<div class="gpkg-layer-list option-menu"></div>
|
|
293
|
+
</div>
|
|
290
294
|
</div>
|
|
291
295
|
<div style="margin-top: 10px"><input type="text" class="text-input advanced-options" placeholder="import options">
|
|
292
296
|
<a href="https://github.com/mbloch/mapshaper/wiki/Command-Reference#-i-input" target="mapshaper_import_docs">
|
package/www/mapshaper-gui.js
CHANGED
|
@@ -1956,6 +1956,28 @@
|
|
|
1956
1956
|
}
|
|
1957
1957
|
}
|
|
1958
1958
|
|
|
1959
|
+
async function getGeoPackageFeatureTables(content) {
|
|
1960
|
+
var geopackage, gpkg, source;
|
|
1961
|
+
await loadGeopackageLib();
|
|
1962
|
+
geopackage = window.modules && window.modules['@ngageoint/geopackage'];
|
|
1963
|
+
if (!geopackage || !geopackage.GeoPackageAPI) {
|
|
1964
|
+
throw Error('GeoPackage library is not loaded');
|
|
1965
|
+
}
|
|
1966
|
+
if (content instanceof Uint8Array) {
|
|
1967
|
+
source = content;
|
|
1968
|
+
} else if (content instanceof ArrayBuffer) {
|
|
1969
|
+
source = new Uint8Array(content);
|
|
1970
|
+
} else {
|
|
1971
|
+
source = content;
|
|
1972
|
+
}
|
|
1973
|
+
gpkg = await geopackage.GeoPackageAPI.open(source);
|
|
1974
|
+
try {
|
|
1975
|
+
return gpkg.getFeatureTables() || [];
|
|
1976
|
+
} finally {
|
|
1977
|
+
gpkg.close();
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1980
|
+
|
|
1959
1981
|
// @cb function(<FileList>)
|
|
1960
1982
|
function DropControl(gui, el, cb) {
|
|
1961
1983
|
var area = El(el);
|
|
@@ -2105,6 +2127,10 @@
|
|
|
2105
2127
|
var importTotal = 0;
|
|
2106
2128
|
var useQuickView = false;
|
|
2107
2129
|
var queuedFiles = [];
|
|
2130
|
+
var gpkgLayerEntries = [];
|
|
2131
|
+
var gpkgSelectAllBtn = null;
|
|
2132
|
+
var gpkgListRequestId = 0;
|
|
2133
|
+
var gpkgListPending = false;
|
|
2108
2134
|
var manifestFiles = opts.files || [];
|
|
2109
2135
|
var catalog;
|
|
2110
2136
|
|
|
@@ -2192,6 +2218,7 @@
|
|
|
2192
2218
|
|
|
2193
2219
|
function clearQueuedFiles() {
|
|
2194
2220
|
queuedFiles = [];
|
|
2221
|
+
clearGeoPackageLayerSelectionMenu();
|
|
2195
2222
|
gui.container.removeClass('queued-files');
|
|
2196
2223
|
gui.container.findChild('.dropped-file-list').empty();
|
|
2197
2224
|
}
|
|
@@ -2223,12 +2250,13 @@
|
|
|
2223
2250
|
});
|
|
2224
2251
|
if (queuedFiles.length > 0) {
|
|
2225
2252
|
showQueuedFiles();
|
|
2253
|
+
updateGeoPackageLayerSelectionMenu();
|
|
2226
2254
|
} else {
|
|
2227
2255
|
gui.clearMode();
|
|
2228
2256
|
}
|
|
2229
2257
|
});
|
|
2230
2258
|
});
|
|
2231
|
-
|
|
2259
|
+
updateImportSubmitState();
|
|
2232
2260
|
}
|
|
2233
2261
|
|
|
2234
2262
|
function receiveDroppedItems(arr) {
|
|
@@ -2277,6 +2305,7 @@
|
|
|
2277
2305
|
gui.container.classed('queued-files', queuedFiles.length > 0);
|
|
2278
2306
|
El('#path-import-options').classed('hidden', !filesMayContainPaths(queuedFiles));
|
|
2279
2307
|
showQueuedFiles();
|
|
2308
|
+
updateGeoPackageLayerSelectionMenu();
|
|
2280
2309
|
}
|
|
2281
2310
|
|
|
2282
2311
|
function hideImportMenu() {
|
|
@@ -2313,13 +2342,14 @@
|
|
|
2313
2342
|
var optStr = GUI.formatCommandOptions(importOpts);
|
|
2314
2343
|
fileData = null;
|
|
2315
2344
|
for (var group of groups) {
|
|
2345
|
+
var groupImportOpts = getGroupImportOpts(group, importOpts);
|
|
2316
2346
|
if (group.size > 4e7) {
|
|
2317
2347
|
gui.showProgressMessage('Importing');
|
|
2318
2348
|
await wait(35);
|
|
2319
2349
|
}
|
|
2320
2350
|
if (group[internal.PACKAGE_EXT]) {
|
|
2321
2351
|
await importSessionData(group[internal.PACKAGE_EXT].content, gui);
|
|
2322
|
-
} else if (await importDataset(group,
|
|
2352
|
+
} else if (await importDataset(group, groupImportOpts)) {
|
|
2323
2353
|
importCount++;
|
|
2324
2354
|
gui.session.fileImported(group.filename, optStr);
|
|
2325
2355
|
}
|
|
@@ -2328,6 +2358,8 @@
|
|
|
2328
2358
|
|
|
2329
2359
|
async function importDataset(group, importOpts) {
|
|
2330
2360
|
var dataset;
|
|
2361
|
+
var datasets;
|
|
2362
|
+
var imported = false;
|
|
2331
2363
|
if (group.gpkg) {
|
|
2332
2364
|
await loadGeopackageLib();
|
|
2333
2365
|
}
|
|
@@ -2336,21 +2368,25 @@
|
|
|
2336
2368
|
} else {
|
|
2337
2369
|
dataset = internal.importContent(group, importOpts);
|
|
2338
2370
|
}
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2371
|
+
datasets = Array.isArray(dataset) ? dataset : [dataset];
|
|
2372
|
+
for (var d of datasets) {
|
|
2373
|
+
if (datasetIsEmpty(d)) continue;
|
|
2374
|
+
if (group.layername) {
|
|
2375
|
+
d.layers.forEach(lyr => lyr.name = group.layername);
|
|
2376
|
+
}
|
|
2377
|
+
// TODO: add popup here
|
|
2378
|
+
// save import options for use by repair control, etc.
|
|
2379
|
+
d.info.import_options = importOpts;
|
|
2380
|
+
try {
|
|
2381
|
+
await considerReprojecting(gui, d, importOpts);
|
|
2382
|
+
} catch(e) {
|
|
2383
|
+
gui.alert(e.message, 'Projection error');
|
|
2384
|
+
return false;
|
|
2385
|
+
}
|
|
2386
|
+
model.addDataset(d);
|
|
2387
|
+
imported = true;
|
|
2351
2388
|
}
|
|
2352
|
-
|
|
2353
|
-
return true;
|
|
2389
|
+
return imported;
|
|
2354
2390
|
}
|
|
2355
2391
|
|
|
2356
2392
|
|
|
@@ -2358,7 +2394,7 @@
|
|
|
2358
2394
|
function filesMayContainPaths(files) {
|
|
2359
2395
|
return utils$1.some(files, function(f) {
|
|
2360
2396
|
var type = internal.guessInputFileType(f.name);
|
|
2361
|
-
return type == 'shp' || type == 'json' || internal.isZipFile(f.name);
|
|
2397
|
+
return type == 'shp' || type == 'json' || type == 'gpkg' || internal.isZipFile(f.name);
|
|
2362
2398
|
});
|
|
2363
2399
|
}
|
|
2364
2400
|
|
|
@@ -2383,6 +2419,167 @@
|
|
|
2383
2419
|
return importOpts;
|
|
2384
2420
|
}
|
|
2385
2421
|
|
|
2422
|
+
function getGroupImportOpts(group, importOpts) {
|
|
2423
|
+
var layersByFile, filename, selected;
|
|
2424
|
+
if (!group.gpkg) return importOpts;
|
|
2425
|
+
layersByFile = getSelectedGeoPackageLayersByFile();
|
|
2426
|
+
filename = group.gpkg.filename;
|
|
2427
|
+
selected = layersByFile[filename];
|
|
2428
|
+
if (!selected || selected.length === 0) return importOpts;
|
|
2429
|
+
return Object.assign({}, importOpts, {
|
|
2430
|
+
gpkg_layers: selected
|
|
2431
|
+
});
|
|
2432
|
+
}
|
|
2433
|
+
|
|
2434
|
+
function clearGeoPackageLayerSelectionMenu() {
|
|
2435
|
+
gpkgLayerEntries = [];
|
|
2436
|
+
gpkgSelectAllBtn = null;
|
|
2437
|
+
gpkgListPending = false;
|
|
2438
|
+
var container = El('#gpkg-import-options');
|
|
2439
|
+
if (!container.node()) return;
|
|
2440
|
+
container.addClass('hidden');
|
|
2441
|
+
container.findChild('.gpkg-layer-list').empty();
|
|
2442
|
+
}
|
|
2443
|
+
|
|
2444
|
+
function getQueuedGeoPackageFiles() {
|
|
2445
|
+
return queuedFiles.filter(function(file) {
|
|
2446
|
+
return internal.guessInputFileType(file.name) == 'gpkg';
|
|
2447
|
+
});
|
|
2448
|
+
}
|
|
2449
|
+
|
|
2450
|
+
async function updateGeoPackageLayerSelectionMenu() {
|
|
2451
|
+
var gpkgFiles = getQueuedGeoPackageFiles();
|
|
2452
|
+
var requestId = ++gpkgListRequestId;
|
|
2453
|
+
clearGeoPackageLayerSelectionMenu();
|
|
2454
|
+
if (useQuickView || gpkgFiles.length === 0) {
|
|
2455
|
+
updateImportSubmitState();
|
|
2456
|
+
return;
|
|
2457
|
+
}
|
|
2458
|
+
gpkgListPending = true;
|
|
2459
|
+
updateImportSubmitState();
|
|
2460
|
+
try {
|
|
2461
|
+
var tablesByFile = await Promise.all(gpkgFiles.map(async function(file) {
|
|
2462
|
+
return {
|
|
2463
|
+
file: file,
|
|
2464
|
+
tables: await getGeoPackageFeatureTables(file.content)
|
|
2465
|
+
};
|
|
2466
|
+
}));
|
|
2467
|
+
if (requestId != gpkgListRequestId) return;
|
|
2468
|
+
renderGeoPackageLayerSelectionMenu(tablesByFile);
|
|
2469
|
+
} catch (e) {
|
|
2470
|
+
console.error(e);
|
|
2471
|
+
if (requestId == gpkgListRequestId) {
|
|
2472
|
+
clearGeoPackageLayerSelectionMenu();
|
|
2473
|
+
gui.alert(e.message || 'Unable to read GeoPackage layers', 'Import error');
|
|
2474
|
+
}
|
|
2475
|
+
} finally {
|
|
2476
|
+
if (requestId == gpkgListRequestId) {
|
|
2477
|
+
gpkgListPending = false;
|
|
2478
|
+
updateImportSubmitState();
|
|
2479
|
+
}
|
|
2480
|
+
}
|
|
2481
|
+
}
|
|
2482
|
+
|
|
2483
|
+
function renderGeoPackageLayerSelectionMenu(tablesByFile) {
|
|
2484
|
+
var container = El('#gpkg-import-options');
|
|
2485
|
+
var list = container.findChild('.gpkg-layer-list').empty();
|
|
2486
|
+
gpkgLayerEntries = [];
|
|
2487
|
+
gpkgSelectAllBtn = null;
|
|
2488
|
+
tablesByFile.forEach(function(item) {
|
|
2489
|
+
var filename = item.file.name;
|
|
2490
|
+
var tables = item.tables || [];
|
|
2491
|
+
if (tables.length === 0) return;
|
|
2492
|
+
tables.forEach(function(tableName) {
|
|
2493
|
+
var label = El('label').addClass('gpkg-layer-item');
|
|
2494
|
+
var box = El('input')
|
|
2495
|
+
.attr('type', 'checkbox')
|
|
2496
|
+
.attr('data-gpkg-file', filename)
|
|
2497
|
+
.attr('data-gpkg-layer', tableName)
|
|
2498
|
+
.node();
|
|
2499
|
+
box.checked = true;
|
|
2500
|
+
box.addEventListener('click', updateGeoPackageSelectAllToggle);
|
|
2501
|
+
label.appendChild(box);
|
|
2502
|
+
label.appendChild(El('span').text(' ' + tableName));
|
|
2503
|
+
list.appendChild(label);
|
|
2504
|
+
var entry = {
|
|
2505
|
+
filename: filename,
|
|
2506
|
+
layer: tableName,
|
|
2507
|
+
checkbox: box
|
|
2508
|
+
};
|
|
2509
|
+
gpkgLayerEntries.push(entry);
|
|
2510
|
+
});
|
|
2511
|
+
});
|
|
2512
|
+
if (gpkgLayerEntries.length === 0) {
|
|
2513
|
+
container.addClass('hidden');
|
|
2514
|
+
return;
|
|
2515
|
+
}
|
|
2516
|
+
if (gpkgLayerEntries.length > 1) {
|
|
2517
|
+
list.node().insertBefore(initGeoPackageSelectAllToggle().node(), list.node().firstChild);
|
|
2518
|
+
}
|
|
2519
|
+
container.removeClass('hidden');
|
|
2520
|
+
updateGeoPackageSelectAllToggle();
|
|
2521
|
+
}
|
|
2522
|
+
|
|
2523
|
+
function initGeoPackageSelectAllToggle() {
|
|
2524
|
+
var toggle = El('label').addClass('gpkg-layer-item');
|
|
2525
|
+
var btn = El('input')
|
|
2526
|
+
.attr('type', 'checkbox')
|
|
2527
|
+
.attr('value', 'toggle')
|
|
2528
|
+
.node();
|
|
2529
|
+
btn.checked = true;
|
|
2530
|
+
btn.addEventListener('click', function() {
|
|
2531
|
+
var state = getGeoPackageSelectionState();
|
|
2532
|
+
setGeoPackageLayerSelection(state != 'all');
|
|
2533
|
+
updateGeoPackageSelectAllToggle();
|
|
2534
|
+
});
|
|
2535
|
+
toggle.appendChild(btn);
|
|
2536
|
+
toggle.appendChild(El('span').text(' Select all'));
|
|
2537
|
+
gpkgSelectAllBtn = btn;
|
|
2538
|
+
return toggle;
|
|
2539
|
+
}
|
|
2540
|
+
|
|
2541
|
+
function setGeoPackageLayerSelection(checked) {
|
|
2542
|
+
gpkgLayerEntries.forEach(function(entry) {
|
|
2543
|
+
entry.checkbox.checked = !!checked;
|
|
2544
|
+
});
|
|
2545
|
+
}
|
|
2546
|
+
|
|
2547
|
+
function getGeoPackageSelectionState() {
|
|
2548
|
+
var count = getSelectedGeoPackageLayerCount();
|
|
2549
|
+
if (gpkgLayerEntries.length > 0 && count == gpkgLayerEntries.length) return 'all';
|
|
2550
|
+
if (count === 0) return 'none';
|
|
2551
|
+
return 'some';
|
|
2552
|
+
}
|
|
2553
|
+
|
|
2554
|
+
function getSelectedGeoPackageLayerCount() {
|
|
2555
|
+
return gpkgLayerEntries.reduce(function(memo, entry) {
|
|
2556
|
+
return memo + (entry.checkbox.checked ? 1 : 0);
|
|
2557
|
+
}, 0);
|
|
2558
|
+
}
|
|
2559
|
+
|
|
2560
|
+
function getSelectedGeoPackageLayersByFile() {
|
|
2561
|
+
return gpkgLayerEntries.reduce(function(memo, entry) {
|
|
2562
|
+
if (!entry.checkbox.checked) return memo;
|
|
2563
|
+
if (!memo[entry.filename]) memo[entry.filename] = [];
|
|
2564
|
+
memo[entry.filename].push(entry.layer);
|
|
2565
|
+
return memo;
|
|
2566
|
+
}, {});
|
|
2567
|
+
}
|
|
2568
|
+
|
|
2569
|
+
function updateGeoPackageSelectAllToggle() {
|
|
2570
|
+
if (gpkgSelectAllBtn) {
|
|
2571
|
+
gpkgSelectAllBtn.checked = getGeoPackageSelectionState() == 'all';
|
|
2572
|
+
}
|
|
2573
|
+
updateImportSubmitState();
|
|
2574
|
+
}
|
|
2575
|
+
|
|
2576
|
+
function updateImportSubmitState() {
|
|
2577
|
+
var disabled = queuedFiles.length === 0 ||
|
|
2578
|
+
gpkgListPending ||
|
|
2579
|
+
(gpkgLayerEntries.length > 0 && getSelectedGeoPackageLayerCount() === 0);
|
|
2580
|
+
submitBtn.classed('disabled', disabled);
|
|
2581
|
+
}
|
|
2582
|
+
|
|
2386
2583
|
// @file a File object
|
|
2387
2584
|
async function readContentFileAsync(file, cb) {
|
|
2388
2585
|
var reader = new FileReader();
|