@abi-software/flatmap-viewer 2.3.0-a.4 → 2.3.0-a.6
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.rst +1 -1
- package/package.json +2 -1
- package/src/annotation.js +173 -135
package/README.rst
CHANGED
|
@@ -38,7 +38,7 @@ The map server endpoint is specified as ``MAP_ENDPOINT`` in ``src/main.js``. It
|
|
|
38
38
|
Package Installation
|
|
39
39
|
====================
|
|
40
40
|
|
|
41
|
-
* ``npm install @abi-software/flatmap-viewer@2.3.0-a.
|
|
41
|
+
* ``npm install @abi-software/flatmap-viewer@2.3.0-a.6``
|
|
42
42
|
|
|
43
43
|
Documentation
|
|
44
44
|
-------------
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abi-software/flatmap-viewer",
|
|
3
|
-
"version": "2.3.0-a.
|
|
3
|
+
"version": "2.3.0-a.6",
|
|
4
4
|
"description": "Flatmap viewer using Maplibre GL",
|
|
5
5
|
"repository": "https://github.com/AnatomicMaps/flatmap-viewer.git",
|
|
6
6
|
"main": "src/main.js",
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
"css-loader": "^6.5.1",
|
|
42
42
|
"eslint": "^8.7.0",
|
|
43
43
|
"express": "^4.17.1",
|
|
44
|
+
"file-loader": "^6.2.0",
|
|
44
45
|
"html-webpack-plugin": "^4.5.2",
|
|
45
46
|
"strip-ansi": "^7.0.1",
|
|
46
47
|
"style-loader": "^1.0.0",
|
package/src/annotation.js
CHANGED
|
@@ -31,9 +31,9 @@ import 'jspanel4/dist/jspanel.css';
|
|
|
31
31
|
//==============================================================================
|
|
32
32
|
|
|
33
33
|
const FETCH_TIMEOUT = 3000; // 3 seconds
|
|
34
|
-
const UPDATE_TIMEOUT =
|
|
34
|
+
const UPDATE_TIMEOUT = 3000; // 5 seconds
|
|
35
35
|
const LOGIN_TIMEOUT = 30000; // 30 seconds
|
|
36
|
-
const LOGOUT_TIMEOUT =
|
|
36
|
+
const LOGOUT_TIMEOUT = 3000; // 5 seconds
|
|
37
37
|
|
|
38
38
|
const STATUS_MESSAGE_TIMEOUT = 3000;
|
|
39
39
|
|
|
@@ -68,6 +68,18 @@ const ANNOTATION_FIELDS = [
|
|
|
68
68
|
|
|
69
69
|
//==============================================================================
|
|
70
70
|
|
|
71
|
+
function startSpinner(panel)
|
|
72
|
+
{
|
|
73
|
+
panel.headerlogo.innerHTML = '<span class="fa fa-spinner fa-spin ml-2"></span>';
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function stopSpinner(panel)
|
|
77
|
+
{
|
|
78
|
+
panel.headerlogo.innerHTML = '';
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
//==============================================================================
|
|
82
|
+
|
|
71
83
|
export class Annotator
|
|
72
84
|
{
|
|
73
85
|
constructor(flatmap)
|
|
@@ -101,61 +113,51 @@ export class Annotator
|
|
|
101
113
|
this.__setStatusMessage('', 0);
|
|
102
114
|
}
|
|
103
115
|
|
|
104
|
-
__authorise(panel
|
|
105
|
-
|
|
116
|
+
async __authorise(panel)
|
|
117
|
+
//======================
|
|
106
118
|
{
|
|
119
|
+
/*
|
|
120
|
+
const testUser = {name: 'Testing...'};
|
|
121
|
+
this.__setUser(testUser);
|
|
122
|
+
callback(testUser);
|
|
123
|
+
|
|
124
|
+
*/
|
|
107
125
|
const abortController = new AbortController();
|
|
108
|
-
const url = `${this.__flatmap._baseUrl}login`;
|
|
109
|
-
panel.headerlogo.innerHTML = '<span class="fa fa-spinner fa-spin ml-2"></span>';
|
|
110
|
-
fetch(url, {
|
|
111
|
-
headers: { "Content-Type": "application/json; charset=utf-8" },
|
|
112
|
-
signal: abortController.signal
|
|
113
|
-
}).then((response) => {
|
|
114
|
-
panel.headerlogo.innerHTML = '';
|
|
115
|
-
if (response.ok) {
|
|
116
|
-
return response.json();
|
|
117
|
-
} else {
|
|
118
|
-
callback({error: `${response.status} ${response.statusText}`});
|
|
119
|
-
}
|
|
120
|
-
}).then((response) => {
|
|
121
|
-
if ('error' in response) {
|
|
122
|
-
callback({error: response.error});
|
|
123
|
-
} else {
|
|
124
|
-
this.__setUser(response);
|
|
125
|
-
this.__authorised = true;
|
|
126
|
-
callback(response);
|
|
127
|
-
}
|
|
128
|
-
});
|
|
129
126
|
setTimeout((panel) => {
|
|
130
127
|
if (this.user === 'undefined') {
|
|
131
128
|
console.log("Aborting login...");
|
|
132
129
|
abortController.abort();
|
|
133
|
-
panel
|
|
130
|
+
stopSpinner(panel);
|
|
134
131
|
this.__setStatusMessage('Unable to login...');
|
|
135
132
|
}
|
|
136
133
|
},
|
|
137
134
|
LOGIN_TIMEOUT, panel);
|
|
138
|
-
}
|
|
139
135
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
this.__clearUser();
|
|
144
|
-
const abortController = new AbortController();
|
|
145
|
-
const url = `${this.__flatmap._baseUrl}logout`;
|
|
146
|
-
fetch(url, {
|
|
136
|
+
const url = `${this.__flatmap._baseUrl}login`;
|
|
137
|
+
startSpinner(panel);
|
|
138
|
+
const response = await fetch(url, {
|
|
147
139
|
headers: { "Content-Type": "application/json; charset=utf-8" },
|
|
148
140
|
signal: abortController.signal
|
|
149
|
-
})
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
141
|
+
});
|
|
142
|
+
stopSpinner(panel);
|
|
143
|
+
if (response.ok) {
|
|
144
|
+
const user_data = await response.json();
|
|
145
|
+
if ('error' in user_data) {
|
|
146
|
+
return Promise.resolve({error: response.error});
|
|
153
147
|
} else {
|
|
154
|
-
|
|
148
|
+
this.__setUser(user_data);
|
|
149
|
+
this.__authorised = true;
|
|
150
|
+
return user_data;
|
|
155
151
|
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
}
|
|
152
|
+
} else {
|
|
153
|
+
return Promise.resolve({error: `${response.status} ${response.statusText}`});
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
async __unauthorise()
|
|
158
|
+
//===================
|
|
159
|
+
{
|
|
160
|
+
const abortController = new AbortController();
|
|
159
161
|
setTimeout(() => {
|
|
160
162
|
if (this.__authorised) {
|
|
161
163
|
console.log("Aborting logout...");
|
|
@@ -164,6 +166,18 @@ export class Annotator
|
|
|
164
166
|
}
|
|
165
167
|
},
|
|
166
168
|
LOGOUT_TIMEOUT);
|
|
169
|
+
|
|
170
|
+
const url = `${this.__flatmap._baseUrl}logout`;
|
|
171
|
+
const response = fetch(url, {
|
|
172
|
+
headers: { "Content-Type": "application/json; charset=utf-8" },
|
|
173
|
+
signal: abortController.signal
|
|
174
|
+
});
|
|
175
|
+
if (response.ok) {
|
|
176
|
+
this.__authorised = false;
|
|
177
|
+
return await response.json();
|
|
178
|
+
} else {
|
|
179
|
+
return Promise.resolve({error: `${response.status} ${response.statusText}`});
|
|
180
|
+
}
|
|
167
181
|
}
|
|
168
182
|
|
|
169
183
|
__setStatusMessage(message, timeout=STATUS_MESSAGE_TIMEOUT)
|
|
@@ -223,23 +237,25 @@ export class Annotator
|
|
|
223
237
|
return html.join('\n');
|
|
224
238
|
}
|
|
225
239
|
|
|
226
|
-
__editFormHtml(
|
|
227
|
-
|
|
240
|
+
__editFormHtml(provenanceData)
|
|
241
|
+
//============================
|
|
228
242
|
{
|
|
229
243
|
const html = [];
|
|
230
244
|
html.push('<div id="flatmap-annotation-formdata">');
|
|
231
245
|
for (const field of ANNOTATION_FIELDS) {
|
|
232
246
|
html.push('<div class="flatmap-annotation-entry">');
|
|
233
247
|
html.push(` <label for="${field.key}">${field.prompt}:</label>`);
|
|
234
|
-
const value = field.update ? annotation[field.key] || '' : '';
|
|
235
248
|
if (field.kind === 'textbox') {
|
|
249
|
+
const value = field.update ? provenanceData[field.key] || '' : '';
|
|
236
250
|
html.push(` <textarea rows="5" cols="40" id="${field.key}" name="${field.key}">${value.trim()}</textarea>`)
|
|
237
251
|
} else if (!('kind' in field) || field.kind !== 'list') {
|
|
252
|
+
const value = field.update ? provenanceData[field.key] || '' : '';
|
|
238
253
|
html.push(` <input type="text" size="40" id="${field.key}" name="${field.key}" value="${value.trim()}"/>`)
|
|
239
254
|
} else { // field.kind === 'list'
|
|
255
|
+
const listValues = field.update ? provenanceData[field.key] || [] : [];
|
|
240
256
|
html.push(' <div class="multiple">')
|
|
241
257
|
for (let n = 1; n <= field.size; n++) {
|
|
242
|
-
const fieldValue = (n <=
|
|
258
|
+
const fieldValue = (n <= listValues.length) ? listValues[n-1].trim() : '';
|
|
243
259
|
html.push(` <input type="text" size="40" id="${field.key}_${n}" name="${field.key}" value="${fieldValue}"/>`)
|
|
244
260
|
}
|
|
245
261
|
html.push(' </div>')
|
|
@@ -251,30 +267,52 @@ export class Annotator
|
|
|
251
267
|
return html.join('\n');
|
|
252
268
|
}
|
|
253
269
|
|
|
254
|
-
|
|
270
|
+
__provenanceData(annotations)
|
|
271
|
+
//===========================
|
|
272
|
+
{
|
|
273
|
+
const provenanceData = {};
|
|
274
|
+
for (const annotation of annotations) { // In order of most recent to oldest
|
|
275
|
+
if (annotation['rdf:type'] === 'prov:Entity') {
|
|
276
|
+
for (const field of ANNOTATION_FIELDS) {
|
|
277
|
+
if (field.update) {
|
|
278
|
+
const value = annotation[field.key];
|
|
279
|
+
if (value !== undefined && !(field.key in provenanceData)) {
|
|
280
|
+
provenanceData[field.key] = value;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return provenanceData;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
__changedAnnotation(provenanceData)
|
|
255
290
|
//=================================
|
|
256
291
|
{
|
|
257
292
|
const newProperties = {};
|
|
258
293
|
let propertiesChanged = false;
|
|
259
294
|
for (const field of ANNOTATION_FIELDS) {
|
|
260
|
-
const lastValue = field.update ? lastAnnotation[field.key] || '' : '';
|
|
261
295
|
if (!('kind' in field) || field.kind !== 'list') {
|
|
296
|
+
const lastValue = field.update ? provenanceData[field.key] || '' : '';
|
|
262
297
|
const inputField = document.getElementById(field.key);
|
|
263
|
-
|
|
264
|
-
if (
|
|
298
|
+
const newValue = inputField.value.trim();
|
|
299
|
+
if (newValue !== lastValue.trim()) {
|
|
300
|
+
newProperties[field.key] = newValue;
|
|
265
301
|
propertiesChanged = true;
|
|
266
302
|
}
|
|
267
303
|
} else { // field.kind === 'list'
|
|
268
|
-
|
|
269
|
-
const changedList = false;
|
|
304
|
+
const listValues = [];
|
|
270
305
|
for (let n = 1; n <= field.size; n++) {
|
|
271
|
-
const lastListValue = (n <= lastValue.length) ? lastValue[n-1].trim() : '';
|
|
272
306
|
const inputField = document.getElementById(`${field.key}_${n}`);
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
307
|
+
listValues.push(inputField.value.trim());
|
|
308
|
+
}
|
|
309
|
+
const lastValue = field.update ? provenanceData[field.key] || [] : [];
|
|
310
|
+
const oldValues = lastValue.map(v => v.trim()).filter(v => (v !== '')).sort();
|
|
311
|
+
const newValues = listValues.map(v => v.trim()).filter(v => (v !== '')).sort();
|
|
312
|
+
if (oldValues.length !== newValues.length
|
|
313
|
+
|| oldValues.filter(v => !newValues.includes(v)).length > 0) {
|
|
314
|
+
newProperties[field.key] = newValues;
|
|
315
|
+
propertiesChanged = true;
|
|
278
316
|
}
|
|
279
317
|
}
|
|
280
318
|
}
|
|
@@ -284,32 +322,38 @@ export class Annotator
|
|
|
284
322
|
}
|
|
285
323
|
}
|
|
286
324
|
|
|
287
|
-
__updateRemoteAnnotation(
|
|
288
|
-
|
|
325
|
+
async __updateRemoteAnnotation(panel, annotation)
|
|
326
|
+
//===============================================
|
|
289
327
|
{
|
|
290
328
|
const abortController = new AbortController();
|
|
329
|
+
|
|
330
|
+
setTimeout((panel) => {
|
|
331
|
+
if (panel.status !== 'closed') {
|
|
332
|
+
console.log("Aborting remote update...");
|
|
333
|
+
abortController.abort();
|
|
334
|
+
stopSpinner(panel);
|
|
335
|
+
this.__setStatusMessage('Cannot update annotation...');
|
|
336
|
+
}
|
|
337
|
+
}, UPDATE_TIMEOUT, panel);
|
|
338
|
+
|
|
291
339
|
const url = this.__flatmap.addBaseUrl_(`/annotations/${this.__currentFeatureId}`);
|
|
292
|
-
fetch(url, {
|
|
340
|
+
const response = await fetch(url, {
|
|
293
341
|
headers: { "Content-Type": "application/json; charset=utf-8" },
|
|
294
342
|
method: 'POST',
|
|
295
343
|
body: JSON.stringify(annotation),
|
|
296
344
|
signal: abortController.signal
|
|
297
|
-
}).then((response) => {
|
|
298
|
-
if (response.ok) {
|
|
299
|
-
return response.json();
|
|
300
|
-
} else {
|
|
301
|
-
callback({error: `${response.status} ${response.statusText}`});
|
|
302
|
-
}
|
|
303
|
-
}).then((response) => {
|
|
304
|
-
callback(response);
|
|
305
345
|
});
|
|
306
|
-
|
|
346
|
+
if (response.ok) {
|
|
347
|
+
return await response.json();
|
|
348
|
+
} else {
|
|
349
|
+
return Promise.resolve({error: `${response.status} ${response.statusText}`});
|
|
350
|
+
}
|
|
307
351
|
}
|
|
308
352
|
|
|
309
|
-
__saveAnnotation(panel,
|
|
310
|
-
|
|
353
|
+
async __saveAnnotation(panel, provenanceData)
|
|
354
|
+
//===========================================
|
|
311
355
|
{
|
|
312
|
-
const changedProperties = this.__changedAnnotation(
|
|
356
|
+
const changedProperties = this.__changedAnnotation(provenanceData);
|
|
313
357
|
if (this.__currentFeatureId !== undefined && changedProperties.changed) {
|
|
314
358
|
const annotation = {
|
|
315
359
|
...changedProperties.properties,
|
|
@@ -317,26 +361,15 @@ export class Annotator
|
|
|
317
361
|
'dct:subject': `flatmaps:${this.__flatmap.uuid}/${this.__currentFeatureId}`,
|
|
318
362
|
'dct:creator': this.user
|
|
319
363
|
}
|
|
320
|
-
panel
|
|
321
|
-
const
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
}
|
|
329
|
-
});
|
|
330
|
-
setTimeout((panel) => {
|
|
331
|
-
if (panel.status !== 'closed') {
|
|
332
|
-
console.log("Aborting remote update...");
|
|
333
|
-
remoteUpdate.abort();
|
|
334
|
-
panel.headerlogo.innerHTML = '';
|
|
335
|
-
this.__setStatusMessage('Cannot update annotation...');
|
|
336
|
-
}
|
|
337
|
-
}, UPDATE_TIMEOUT, panel);
|
|
364
|
+
startSpinner(panel);
|
|
365
|
+
const response = await this.__updateRemoteAnnotation(panel, annotation);
|
|
366
|
+
stopSpinner(panel);
|
|
367
|
+
if ('error' in response) {
|
|
368
|
+
this.__setStatusMessage(response.error);
|
|
369
|
+
} else {
|
|
370
|
+
panel.close();
|
|
371
|
+
}
|
|
338
372
|
} else {
|
|
339
|
-
this.__
|
|
340
373
|
this.__setStatusMessage('No changes to save...');
|
|
341
374
|
}
|
|
342
375
|
}
|
|
@@ -345,9 +378,9 @@ export class Annotator
|
|
|
345
378
|
//====================================
|
|
346
379
|
{
|
|
347
380
|
this.__haveAnnotation = true;
|
|
381
|
+
const provenanceData = this.__provenanceData(response);
|
|
348
382
|
this.__existingAnnotation.innerHTML = this.__annotationHtml(response);
|
|
349
|
-
|
|
350
|
-
this.__annotationForm.innerHTML = this.__editFormHtml(lastAnnotation);
|
|
383
|
+
this.__annotationForm.innerHTML = this.__editFormHtml(provenanceData);
|
|
351
384
|
|
|
352
385
|
// Lock focus to focusable elements within the panel
|
|
353
386
|
const inputElements = panel.content.querySelectorAll('input, textarea, button');
|
|
@@ -370,16 +403,52 @@ export class Annotator
|
|
|
370
403
|
}
|
|
371
404
|
} else if (e.key === 'Enter') {
|
|
372
405
|
if (e.target === saveButton) {
|
|
373
|
-
this.__saveAnnotation(panel,
|
|
406
|
+
this.__saveAnnotation(panel, provenanceData);
|
|
374
407
|
}
|
|
375
408
|
}
|
|
376
409
|
}.bind(this));
|
|
377
410
|
|
|
378
411
|
saveButton.addEventListener('mousedown', function (e) {
|
|
379
|
-
this.__saveAnnotation(panel,
|
|
412
|
+
this.__saveAnnotation(panel, provenanceData);
|
|
380
413
|
}.bind(this));
|
|
381
414
|
}
|
|
382
415
|
|
|
416
|
+
__panelCallback(panel)
|
|
417
|
+
//====================
|
|
418
|
+
{
|
|
419
|
+
this.__annotationForm = document.getElementById('flatmap-annotation-form');
|
|
420
|
+
// Data entry only once authorised
|
|
421
|
+
this.__annotationForm.hidden = true;
|
|
422
|
+
|
|
423
|
+
// Populate once we have content from server
|
|
424
|
+
this.__existingAnnotation = document.getElementById('flatmap-annotation-existing');
|
|
425
|
+
this.__statusMessage = document.getElementById('flatmap-annotation-status');
|
|
426
|
+
|
|
427
|
+
this.__authoriseLock = document.getElementById('flatmap-annotation-lock');
|
|
428
|
+
this.__authoriseLock.addEventListener('click', (e) => {
|
|
429
|
+
const lockClasses = this.__authoriseLock.classList;
|
|
430
|
+
if (lockClasses.contains('fa-lock')) {
|
|
431
|
+
this.__authorise(panel).then((response) => {
|
|
432
|
+
if ('error' in response) {
|
|
433
|
+
this.__setStatusMessage(response.error);
|
|
434
|
+
} else {
|
|
435
|
+
this.__annotationForm.hidden = false;
|
|
436
|
+
this.__firstInputField.focus();
|
|
437
|
+
lockClasses.remove('fa-lock');
|
|
438
|
+
lockClasses.add('fa-unlock');
|
|
439
|
+
}
|
|
440
|
+
});
|
|
441
|
+
} else {
|
|
442
|
+
this.__unauthorise().then((response) => {
|
|
443
|
+
console.log(`Annotator logout: ${response}`);
|
|
444
|
+
});
|
|
445
|
+
this.__annotationForm.hidden = true;
|
|
446
|
+
lockClasses.remove('fa-unlock');
|
|
447
|
+
lockClasses.add('fa-lock');
|
|
448
|
+
}
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
|
|
383
452
|
annotate(feature, closedCallback)
|
|
384
453
|
//===============================
|
|
385
454
|
{
|
|
@@ -399,8 +468,8 @@ export class Annotator
|
|
|
399
468
|
panelContent.push(' <div id="flatmap-annotation-existing"></div>');
|
|
400
469
|
panelContent.push('</div>');
|
|
401
470
|
|
|
402
|
-
const annotator = this; // To use in panel code
|
|
403
|
-
const flatmap = this.__flatmap; // To use in panel code
|
|
471
|
+
const annotator = this; // To use in panel creation code
|
|
472
|
+
const flatmap = this.__flatmap; // To use in panel creation code
|
|
404
473
|
const contentFetchAbort = new AbortController();
|
|
405
474
|
this.__panel = jsPanel.create({
|
|
406
475
|
theme: 'light',
|
|
@@ -433,12 +502,12 @@ export class Annotator
|
|
|
433
502
|
},
|
|
434
503
|
bodyMethod: 'json',
|
|
435
504
|
beforeSend: (fetchConfig, panel) => {
|
|
436
|
-
panel
|
|
505
|
+
startSpinner(panel);
|
|
437
506
|
setTimeout((panel) => {
|
|
438
507
|
if (!annotator.__haveAnnotation) {
|
|
439
508
|
console.log("Aborting content fetch...");
|
|
440
509
|
contentFetchAbort.abort();
|
|
441
|
-
panel
|
|
510
|
+
stopSpinner(panel);
|
|
442
511
|
annotator.__setStatusMessage('Cannot fetch annotation...');
|
|
443
512
|
annotator.__authoriseLock.className = '';
|
|
444
513
|
}
|
|
@@ -446,45 +515,14 @@ export class Annotator
|
|
|
446
515
|
},
|
|
447
516
|
done: (response, panel) => {
|
|
448
517
|
annotator.__finishPanelContent(panel, response);
|
|
449
|
-
panel
|
|
518
|
+
stopSpinner(panel);
|
|
450
519
|
}
|
|
451
520
|
},
|
|
452
|
-
callback: (
|
|
453
|
-
annotator.__annotationForm = document.getElementById('flatmap-annotation-form');
|
|
454
|
-
// Data entry only once authorised
|
|
455
|
-
annotator.__annotationForm.hidden = true;
|
|
456
|
-
|
|
457
|
-
// Populate once we have content from server
|
|
458
|
-
annotator.__existingAnnotation = document.getElementById('flatmap-annotation-existing');
|
|
459
|
-
annotator.__statusMessage = document.getElementById('flatmap-annotation-status');
|
|
460
|
-
|
|
461
|
-
annotator.__authoriseLock = document.getElementById('flatmap-annotation-lock');
|
|
462
|
-
annotator.__authoriseLock.addEventListener('click', (e) => {
|
|
463
|
-
const lockClasses = annotator.__authoriseLock.classList;
|
|
464
|
-
if (lockClasses.contains('fa-lock')) {
|
|
465
|
-
annotator.__authorise(panel, (response) => {
|
|
466
|
-
if ('error' in response) {
|
|
467
|
-
annotator.__setStatusMessage(response.error);
|
|
468
|
-
} else {
|
|
469
|
-
annotator.__annotationForm.hidden = false;
|
|
470
|
-
annotator.__firstInputField.focus();
|
|
471
|
-
lockClasses.remove('fa-lock');
|
|
472
|
-
lockClasses.add('fa-unlock');
|
|
473
|
-
}
|
|
474
|
-
});
|
|
475
|
-
} else {
|
|
476
|
-
annotator.__unauthorise();
|
|
477
|
-
annotator.__annotationForm.hidden = true;
|
|
478
|
-
lockClasses.remove('fa-unlock');
|
|
479
|
-
lockClasses.add('fa-lock');
|
|
480
|
-
}
|
|
481
|
-
});
|
|
482
|
-
|
|
483
|
-
// should we warn if unsaved changes when closing??
|
|
484
|
-
document.addEventListener('jspanelclosed', closedCallback, false);
|
|
485
|
-
}
|
|
521
|
+
callback: annotator.__panelCallback.bind(annotator)
|
|
486
522
|
});
|
|
487
523
|
|
|
524
|
+
// should we warn if unsaved changes when closing??
|
|
525
|
+
document.addEventListener('jspanelclosed', closedCallback, false);
|
|
488
526
|
}
|
|
489
527
|
|
|
490
528
|
}
|