retold-remote 0.0.23 → 0.0.26
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/css/retold-remote.css +343 -20
- package/docs/.nojekyll +0 -0
- package/docs/README.md +64 -12
- package/docs/_cover.md +6 -6
- package/docs/_sidebar.md +2 -0
- package/docs/_topbar.md +1 -1
- package/docs/_version.json +7 -0
- package/docs/collections.md +30 -0
- package/docs/css/docuserve.css +327 -0
- package/docs/ebook-reader.md +75 -1
- package/docs/image-explorer.md +62 -2
- package/docs/index.html +39 -0
- package/docs/retold-catalog.json +254 -0
- package/docs/retold-keyword-index.json +31216 -0
- package/docs/server-setup.md +122 -91
- package/docs/stack-launcher.md +218 -0
- package/docs/synology.md +585 -0
- package/docs/ultravisor-configuration.md +5 -5
- package/docs/ultravisor-integration.md +4 -2
- package/package.json +20 -14
- package/source/Pict-Application-RetoldRemote.js +22 -0
- package/source/RetoldRemote-ExtensionMaps.js +1 -1
- package/source/cli/RetoldRemote-Server-Setup.js +460 -7
- package/source/cli/RetoldRemote-Stack-Launcher.js +563 -0
- package/source/cli/RetoldRemote-Stack-Run.js +41 -0
- package/source/cli/commands/RetoldRemote-Command-Serve.js +129 -54
- package/source/providers/CollectionManager-AddItems.js +166 -0
- package/source/providers/Pict-Provider-GalleryNavigation.js +55 -0
- package/source/providers/Pict-Provider-OperationStatus.js +597 -0
- package/source/providers/keyboard-handlers/KeyHandler-ImageExplorer.js +20 -1
- package/source/providers/keyboard-handlers/KeyHandler-Viewer.js +23 -0
- package/source/server/RetoldRemote-AudioWaveformService.js +49 -3
- package/source/server/RetoldRemote-CollectionExportService.js +763 -0
- package/source/server/RetoldRemote-CollectionService.js +5 -0
- package/source/server/RetoldRemote-EbookService.js +218 -3
- package/source/server/RetoldRemote-ImageService.js +221 -46
- package/source/server/RetoldRemote-MediaService.js +63 -4
- package/source/server/RetoldRemote-MetadataCache.js +25 -5
- package/source/server/RetoldRemote-OperationBroadcaster.js +363 -0
- package/source/server/RetoldRemote-SubimageService.js +680 -0
- package/source/server/RetoldRemote-ToolDetector.js +50 -0
- package/source/server/RetoldRemote-UltravisorBeacon.js +18 -3
- package/source/server/RetoldRemote-UltravisorDispatcher.js +65 -491
- package/source/server/RetoldRemote-UltravisorOperations.js +133 -20
- package/source/server/RetoldRemote-VideoFrameService.js +302 -9
- package/source/views/MediaViewer-EbookViewer.js +419 -1
- package/source/views/MediaViewer-PdfViewer.js +1050 -0
- package/source/views/PictView-Remote-AudioExplorer.js +77 -1
- package/source/views/PictView-Remote-CollectionsPanel.js +213 -0
- package/source/views/PictView-Remote-Gallery.js +365 -64
- package/source/views/PictView-Remote-ImageExplorer.js +1529 -44
- package/source/views/PictView-Remote-ImageViewer.js +2 -2
- package/source/views/PictView-Remote-Layout.js +58 -0
- package/source/views/PictView-Remote-MediaViewer.js +100 -25
- package/source/views/PictView-Remote-RegionsBrowser.js +554 -0
- package/source/views/PictView-Remote-SubimagesPanel.js +353 -0
- package/source/views/PictView-Remote-TopBar.js +1 -0
- package/source/views/PictView-Remote-VideoExplorer.js +77 -1
- package/web-application/css/docuserve.css +277 -23
- package/web-application/css/retold-remote.css +343 -20
- package/web-application/docs/README.md +64 -12
- package/web-application/docs/_cover.md +6 -6
- package/web-application/docs/_sidebar.md +2 -0
- package/web-application/docs/_topbar.md +1 -1
- package/web-application/docs/collections.md +30 -0
- package/web-application/docs/ebook-reader.md +75 -1
- package/web-application/docs/image-explorer.md +62 -2
- package/web-application/docs/server-setup.md +122 -91
- package/web-application/docs/stack-launcher.md +218 -0
- package/web-application/docs/synology.md +585 -0
- package/web-application/docs/ultravisor-configuration.md +5 -5
- package/web-application/docs/ultravisor-integration.md +4 -2
- package/web-application/js/pict-docuserve.min.js +12 -12
- package/web-application/js/pict.min.js +2 -2
- package/web-application/js/pict.min.js.map +1 -1
- package/web-application/retold-remote.js +6596 -1784
- package/web-application/retold-remote.js.map +1 -1
- package/web-application/retold-remote.min.js +75 -23
- package/web-application/retold-remote.min.js.map +1 -1
|
@@ -29,6 +29,9 @@ class RetoldRemoteCommandServe extends libCommandLineCommand
|
|
|
29
29
|
this.options.CommandOptions.push(
|
|
30
30
|
{ Name: '-u, --ultravisor [url]', Description: 'Connect to Ultravisor mesh. URL defaults to http://localhost:54321 if omitted.', Default: '' });
|
|
31
31
|
|
|
32
|
+
this.options.CommandOptions.push(
|
|
33
|
+
{ Name: '--stack', Description: 'Run the full stack: spawn Ultravisor as a child process and connect to it. Uses XDG-style data paths under ~/.local/share and ~/.cache.', Default: false });
|
|
34
|
+
|
|
32
35
|
this.options.CommandOptions.push(
|
|
33
36
|
{ Name: '-l, --logfile [path]', Description: 'Write logs to a file (auto-generates timestamped name if path omitted).', Default: '' });
|
|
34
37
|
|
|
@@ -78,14 +81,26 @@ class RetoldRemoteCommandServe extends libCommandLineCommand
|
|
|
78
81
|
}
|
|
79
82
|
|
|
80
83
|
let tmpSelf = this;
|
|
81
|
-
let tmpSetupServer = require('../RetoldRemote-Server-Setup.js');
|
|
82
|
-
|
|
83
84
|
let tmpHashedFilenames = !(this.CommandOptions.noHash);
|
|
85
|
+
let tmpStackMode = !!this.CommandOptions.stack;
|
|
86
|
+
|
|
87
|
+
// Resolve XDG-style stack paths once (used by --stack mode)
|
|
88
|
+
let libStackLauncher = require('../RetoldRemote-Stack-Launcher.js');
|
|
89
|
+
let tmpStackPaths = libStackLauncher.resolveStackPaths();
|
|
90
|
+
|
|
91
|
+
// Cache root: explicit > stack default > package default
|
|
92
|
+
let tmpCacheRoot = null;
|
|
93
|
+
if (this.CommandOptions.cachePath)
|
|
94
|
+
{
|
|
95
|
+
tmpCacheRoot = libPath.resolve(this.CommandOptions.cachePath);
|
|
96
|
+
}
|
|
97
|
+
else if (tmpStackMode)
|
|
98
|
+
{
|
|
99
|
+
tmpCacheRoot = tmpStackPaths.RetoldCache;
|
|
100
|
+
}
|
|
84
101
|
|
|
85
|
-
let tmpCacheRoot = this.CommandOptions.cachePath
|
|
86
|
-
? libPath.resolve(this.CommandOptions.cachePath)
|
|
87
|
-
: null;
|
|
88
102
|
let tmpCacheServer = this.CommandOptions.cacheServer || null;
|
|
103
|
+
|
|
89
104
|
// -u with no URL → true (Commander behavior for [optional]), default to localhost
|
|
90
105
|
let tmpUltravisorOpt = this.CommandOptions.ultravisor;
|
|
91
106
|
let tmpUltravisorURL = null;
|
|
@@ -98,65 +113,125 @@ class RetoldRemoteCommandServe extends libCommandLineCommand
|
|
|
98
113
|
tmpUltravisorURL = tmpUltravisorOpt;
|
|
99
114
|
}
|
|
100
115
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
return fCallback(pError);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
tmpSelf.log.info('');
|
|
120
|
-
tmpSelf.log.info('==========================================================');
|
|
121
|
-
tmpSelf.log.info(` Retold Remote running on http://localhost:${pServerInfo.Port}`);
|
|
122
|
-
tmpSelf.log.info('==========================================================');
|
|
123
|
-
tmpSelf.log.info(` Content: ${tmpContentPath}`);
|
|
124
|
-
tmpSelf.log.info(` Assets: ${tmpDistPath}`);
|
|
125
|
-
tmpSelf.log.info(` Browse: http://localhost:${pServerInfo.Port}/`);
|
|
126
|
-
if (pServerInfo.UltravisorBeacon && pServerInfo.UltravisorBeacon.isEnabled())
|
|
127
|
-
{
|
|
128
|
-
tmpSelf.log.info(` Beacon: registered with Ultravisor at ${tmpUltravisorURL}`);
|
|
129
|
-
}
|
|
130
|
-
else if (tmpUltravisorURL)
|
|
116
|
+
// In stack mode, automatically set the ultravisor URL
|
|
117
|
+
if (tmpStackMode && !tmpUltravisorURL)
|
|
118
|
+
{
|
|
119
|
+
tmpUltravisorURL = 'http://localhost:54321';
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Hold the stack info so we can clean up on exit
|
|
123
|
+
let tmpStackInfo = null;
|
|
124
|
+
|
|
125
|
+
// Bind the actual server startup so we can call it after (optionally) launching ultravisor
|
|
126
|
+
let _startRetoldRemote = () =>
|
|
127
|
+
{
|
|
128
|
+
let tmpSetupServer = require('../RetoldRemote-Server-Setup.js');
|
|
129
|
+
|
|
130
|
+
tmpSetupServer(
|
|
131
131
|
{
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
132
|
+
ContentPath: tmpContentPath,
|
|
133
|
+
DistPath: tmpDistPath,
|
|
134
|
+
Port: tmpPort,
|
|
135
|
+
HashedFilenames: tmpHashedFilenames,
|
|
136
|
+
CacheRoot: tmpCacheRoot,
|
|
137
|
+
CacheServer: tmpCacheServer,
|
|
138
|
+
UltravisorURL: tmpUltravisorURL
|
|
139
|
+
},
|
|
140
|
+
function (pError, pServerInfo)
|
|
141
141
|
{
|
|
142
|
+
if (pError)
|
|
143
|
+
{
|
|
144
|
+
tmpSelf.log.error(`Failed to start server: ${pError.message}`);
|
|
145
|
+
if (tmpStackInfo)
|
|
146
|
+
{
|
|
147
|
+
libStackLauncher.stop(tmpStackInfo, () => {});
|
|
148
|
+
}
|
|
149
|
+
return fCallback(pError);
|
|
150
|
+
}
|
|
151
|
+
|
|
142
152
|
tmpSelf.log.info('');
|
|
143
|
-
tmpSelf.log.info('
|
|
153
|
+
tmpSelf.log.info('==========================================================');
|
|
154
|
+
tmpSelf.log.info(` Retold Remote running on http://localhost:${pServerInfo.Port}`);
|
|
155
|
+
tmpSelf.log.info('==========================================================');
|
|
156
|
+
tmpSelf.log.info(` Content: ${tmpContentPath}`);
|
|
157
|
+
tmpSelf.log.info(` Cache: ${tmpCacheRoot || '(default)'}`);
|
|
158
|
+
tmpSelf.log.info(` Browse: http://localhost:${pServerInfo.Port}/`);
|
|
144
159
|
if (pServerInfo.UltravisorBeacon && pServerInfo.UltravisorBeacon.isEnabled())
|
|
145
160
|
{
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
161
|
+
tmpSelf.log.info(` Beacon: registered with Ultravisor at ${tmpUltravisorURL}`);
|
|
162
|
+
}
|
|
163
|
+
else if (tmpUltravisorURL)
|
|
164
|
+
{
|
|
165
|
+
tmpSelf.log.info(` Beacon: not connected (Ultravisor may be unreachable)`);
|
|
150
166
|
}
|
|
151
|
-
|
|
167
|
+
if (tmpStackMode)
|
|
152
168
|
{
|
|
153
|
-
|
|
169
|
+
tmpSelf.log.info(` Stack: ultravisor + retold-remote (orator-conversion embedded)`);
|
|
154
170
|
}
|
|
171
|
+
tmpSelf.log.info('==========================================================');
|
|
172
|
+
tmpSelf.log.info('');
|
|
173
|
+
tmpSelf.log.info(' Press Ctrl+C to stop.');
|
|
174
|
+
tmpSelf.log.info('');
|
|
175
|
+
|
|
176
|
+
// Graceful shutdown: disconnect beacon and stop child processes before exit
|
|
177
|
+
let _shutdown = () =>
|
|
178
|
+
{
|
|
179
|
+
tmpSelf.log.info('');
|
|
180
|
+
tmpSelf.log.info('Shutting down...');
|
|
181
|
+
|
|
182
|
+
let _finish = () =>
|
|
183
|
+
{
|
|
184
|
+
if (tmpStackInfo)
|
|
185
|
+
{
|
|
186
|
+
libStackLauncher.stop(tmpStackInfo, () => process.exit(0));
|
|
187
|
+
}
|
|
188
|
+
else
|
|
189
|
+
{
|
|
190
|
+
process.exit(0);
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
if (pServerInfo.UltravisorBeacon && pServerInfo.UltravisorBeacon.isEnabled())
|
|
195
|
+
{
|
|
196
|
+
pServerInfo.UltravisorBeacon.disconnectBeacon(_finish);
|
|
197
|
+
}
|
|
198
|
+
else
|
|
199
|
+
{
|
|
200
|
+
_finish();
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
process.on('SIGINT', _shutdown);
|
|
205
|
+
process.on('SIGTERM', _shutdown);
|
|
206
|
+
|
|
207
|
+
// Intentionally do NOT call fCallback() here.
|
|
208
|
+
// The server should keep running.
|
|
155
209
|
});
|
|
210
|
+
};
|
|
156
211
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
212
|
+
// In stack mode, launch ultravisor first, then start retold-remote
|
|
213
|
+
if (tmpStackMode)
|
|
214
|
+
{
|
|
215
|
+
libStackLauncher.start(
|
|
216
|
+
{
|
|
217
|
+
Logger: tmpSelf.log,
|
|
218
|
+
UltravisorPort: 54321
|
|
219
|
+
},
|
|
220
|
+
(pStackError, pStackInfo) =>
|
|
221
|
+
{
|
|
222
|
+
if (pStackError)
|
|
223
|
+
{
|
|
224
|
+
tmpSelf.log.error(`Stack launch failed: ${pStackError.message}`);
|
|
225
|
+
return fCallback(pStackError);
|
|
226
|
+
}
|
|
227
|
+
tmpStackInfo = pStackInfo;
|
|
228
|
+
_startRetoldRemote();
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
else
|
|
232
|
+
{
|
|
233
|
+
_startRetoldRemote();
|
|
234
|
+
}
|
|
160
235
|
}
|
|
161
236
|
}
|
|
162
237
|
|
|
@@ -47,6 +47,30 @@ module.exports =
|
|
|
47
47
|
return this.addAudioSnippetToCollection(tmpTargetGUID);
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
// If the image explorer is active with a selection, add as subimage
|
|
51
|
+
if (tmpRemote.ActiveMode === 'image-explorer')
|
|
52
|
+
{
|
|
53
|
+
let tmpIEX = this.pict.views['RetoldRemote-ImageExplorer'];
|
|
54
|
+
if (tmpIEX)
|
|
55
|
+
{
|
|
56
|
+
let tmpActiveSelection = tmpIEX.getActiveSelection();
|
|
57
|
+
if (tmpActiveSelection)
|
|
58
|
+
{
|
|
59
|
+
return this.addSubimageToCollection(tmpTargetGUID, tmpActiveSelection, tmpIEX._currentPath);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// If viewing a document (PDF/EPUB) with a pending region, add as document-region
|
|
65
|
+
if (tmpRemote.ActiveMode === 'viewer' && tmpRemote.CurrentViewerMediaType === 'document')
|
|
66
|
+
{
|
|
67
|
+
let tmpMediaViewer = this.pict.views['RetoldRemote-MediaViewer'];
|
|
68
|
+
if (tmpMediaViewer && tmpMediaViewer._pendingDocumentRegion)
|
|
69
|
+
{
|
|
70
|
+
return this.addDocumentRegionToCollection(tmpTargetGUID, tmpMediaViewer._pendingDocumentRegion, tmpRemote.CurrentViewerFile);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
50
74
|
let tmpCurrentItem = this._resolveCurrentItem();
|
|
51
75
|
|
|
52
76
|
if (!tmpCurrentItem || !tmpCurrentItem.Path)
|
|
@@ -329,6 +353,148 @@ module.exports =
|
|
|
329
353
|
return true;
|
|
330
354
|
},
|
|
331
355
|
|
|
356
|
+
/**
|
|
357
|
+
* Add a subimage region (crop) to a collection.
|
|
358
|
+
*
|
|
359
|
+
* @param {string} pGUID - Collection GUID
|
|
360
|
+
* @param {object} pRegion - { X, Y, Width, Height, Label?, ID? } in image pixels
|
|
361
|
+
* @param {string} [pFilePath] - Explicit file path (defaults to current viewer file)
|
|
362
|
+
* @returns {boolean} true if the add was initiated
|
|
363
|
+
*/
|
|
364
|
+
addSubimageToCollection: function addSubimageToCollection(pGUID, pRegion, pFilePath)
|
|
365
|
+
{
|
|
366
|
+
let tmpRemote = this._getRemote();
|
|
367
|
+
let tmpTargetGUID = pGUID || tmpRemote.LastUsedCollectionGUID;
|
|
368
|
+
if (!tmpTargetGUID || !pRegion)
|
|
369
|
+
{
|
|
370
|
+
return false;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
let tmpFilePath = pFilePath || tmpRemote.CurrentViewerFile;
|
|
374
|
+
if (!tmpFilePath)
|
|
375
|
+
{
|
|
376
|
+
return false;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
let tmpFileName = tmpFilePath.replace(/^.*\//, '');
|
|
380
|
+
let tmpLabel = pRegion.Label
|
|
381
|
+
? pRegion.Label
|
|
382
|
+
: tmpFileName + ': ' + pRegion.Width + '\u00d7' + pRegion.Height + ' at ' + pRegion.X + ',' + pRegion.Y;
|
|
383
|
+
|
|
384
|
+
let tmpItem =
|
|
385
|
+
{
|
|
386
|
+
Type: 'image-crop',
|
|
387
|
+
Path: tmpFilePath,
|
|
388
|
+
CropRegion:
|
|
389
|
+
{
|
|
390
|
+
X: pRegion.X,
|
|
391
|
+
Y: pRegion.Y,
|
|
392
|
+
Width: pRegion.Width,
|
|
393
|
+
Height: pRegion.Height
|
|
394
|
+
},
|
|
395
|
+
Label: tmpLabel,
|
|
396
|
+
Note: ''
|
|
397
|
+
};
|
|
398
|
+
|
|
399
|
+
// If we have a hash for this file, include it
|
|
400
|
+
let tmpProvider = this.pict.providers['RetoldRemote-Provider'];
|
|
401
|
+
if (tmpProvider)
|
|
402
|
+
{
|
|
403
|
+
let tmpHash = tmpProvider.getHashForPath(tmpFilePath);
|
|
404
|
+
if (tmpHash)
|
|
405
|
+
{
|
|
406
|
+
tmpItem.Hash = tmpHash;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
this.addItemsToCollection(tmpTargetGUID, [tmpItem]);
|
|
411
|
+
return true;
|
|
412
|
+
},
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* Add a document region (text selection or visual area) to a collection.
|
|
416
|
+
*
|
|
417
|
+
* @param {string} pGUID - Collection GUID
|
|
418
|
+
* @param {object} pRegion - Region object with Type, Label, and type-specific fields
|
|
419
|
+
* @param {string} [pFilePath] - Explicit file path (defaults to current viewer file)
|
|
420
|
+
* @returns {boolean} true if the add was initiated
|
|
421
|
+
*/
|
|
422
|
+
addDocumentRegionToCollection: function addDocumentRegionToCollection(pGUID, pRegion, pFilePath)
|
|
423
|
+
{
|
|
424
|
+
let tmpRemote = this._getRemote();
|
|
425
|
+
let tmpTargetGUID = pGUID || tmpRemote.LastUsedCollectionGUID;
|
|
426
|
+
if (!tmpTargetGUID || !pRegion)
|
|
427
|
+
{
|
|
428
|
+
return false;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
let tmpFilePath = pFilePath || tmpRemote.CurrentViewerFile;
|
|
432
|
+
if (!tmpFilePath)
|
|
433
|
+
{
|
|
434
|
+
return false;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
let tmpFileName = tmpFilePath.replace(/^.*\//, '');
|
|
438
|
+
let tmpIsText = (pRegion.Type === 'text-selection');
|
|
439
|
+
|
|
440
|
+
// Build label
|
|
441
|
+
let tmpLabel = pRegion.Label || '';
|
|
442
|
+
if (!tmpLabel)
|
|
443
|
+
{
|
|
444
|
+
if (tmpIsText && pRegion.SelectedText)
|
|
445
|
+
{
|
|
446
|
+
tmpLabel = pRegion.SelectedText.substring(0, 50);
|
|
447
|
+
if (pRegion.SelectedText.length > 50) tmpLabel += '\u2026';
|
|
448
|
+
}
|
|
449
|
+
else
|
|
450
|
+
{
|
|
451
|
+
tmpLabel = tmpFileName;
|
|
452
|
+
}
|
|
453
|
+
if (pRegion.PageNumber)
|
|
454
|
+
{
|
|
455
|
+
tmpLabel = 'p.' + pRegion.PageNumber + ': ' + tmpLabel;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
let tmpItem =
|
|
460
|
+
{
|
|
461
|
+
Type: 'document-region',
|
|
462
|
+
Path: tmpFilePath,
|
|
463
|
+
Label: tmpLabel,
|
|
464
|
+
Note: '',
|
|
465
|
+
DocumentRegionType: pRegion.Type || 'visual-region',
|
|
466
|
+
PageNumber: pRegion.PageNumber || null,
|
|
467
|
+
CFI: pRegion.CFI || null,
|
|
468
|
+
SelectedText: pRegion.SelectedText || null
|
|
469
|
+
};
|
|
470
|
+
|
|
471
|
+
// Include crop region for visual selections
|
|
472
|
+
if (!tmpIsText && pRegion.X !== undefined)
|
|
473
|
+
{
|
|
474
|
+
tmpItem.CropRegion =
|
|
475
|
+
{
|
|
476
|
+
X: pRegion.X,
|
|
477
|
+
Y: pRegion.Y,
|
|
478
|
+
Width: pRegion.Width,
|
|
479
|
+
Height: pRegion.Height
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// File hash
|
|
484
|
+
let tmpProvider = this.pict.providers['RetoldRemote-Provider'];
|
|
485
|
+
if (tmpProvider)
|
|
486
|
+
{
|
|
487
|
+
let tmpHash = tmpProvider.getHashForPath(tmpFilePath);
|
|
488
|
+
if (tmpHash)
|
|
489
|
+
{
|
|
490
|
+
tmpItem.Hash = tmpHash;
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
this.addItemsToCollection(tmpTargetGUID, [tmpItem]);
|
|
495
|
+
return true;
|
|
496
|
+
},
|
|
497
|
+
|
|
332
498
|
/**
|
|
333
499
|
* Format a timestamp in seconds to a human-readable string.
|
|
334
500
|
*
|
|
@@ -556,6 +556,15 @@ class GalleryNavigationProvider extends libPictProvider
|
|
|
556
556
|
tmpRemote.CurrentViewerFile = '';
|
|
557
557
|
tmpRemote.CurrentViewerMediaType = '';
|
|
558
558
|
|
|
559
|
+
// Notify the layout so any active sidebar tab (Info, Regions, etc.)
|
|
560
|
+
// transitions to its empty state instead of retaining stale content
|
|
561
|
+
// from the file the user just closed.
|
|
562
|
+
let tmpLayout = this.pict.views['ContentEditor-Layout'];
|
|
563
|
+
if (tmpLayout && typeof tmpLayout.notifyCurrentFileChanged === 'function')
|
|
564
|
+
{
|
|
565
|
+
tmpLayout.notifyCurrentFileChanged('');
|
|
566
|
+
}
|
|
567
|
+
|
|
559
568
|
// Exit collection browsing mode
|
|
560
569
|
tmpRemote.BrowsingCollection = false;
|
|
561
570
|
tmpRemote.BrowsingCollectionIndex = -1;
|
|
@@ -630,6 +639,52 @@ class GalleryNavigationProvider extends libPictProvider
|
|
|
630
639
|
tmpAEX.showExplorer(pItem.Path, pItem.AudioStart, pItem.AudioEnd);
|
|
631
640
|
}
|
|
632
641
|
}
|
|
642
|
+
else if (pItem.Type === 'document-region')
|
|
643
|
+
{
|
|
644
|
+
// Navigate to the document, then to the specific location
|
|
645
|
+
let tmpApp = this.pict.PictApplication;
|
|
646
|
+
if (tmpApp && tmpApp.navigateToFile)
|
|
647
|
+
{
|
|
648
|
+
tmpApp.navigateToFile(pItem.Path);
|
|
649
|
+
|
|
650
|
+
// After the viewer loads, navigate to the specific page/CFI
|
|
651
|
+
let tmpSelf = this;
|
|
652
|
+
setTimeout(() =>
|
|
653
|
+
{
|
|
654
|
+
let tmpMediaViewer = tmpSelf.pict.views['RetoldRemote-MediaViewer'];
|
|
655
|
+
if (tmpMediaViewer)
|
|
656
|
+
{
|
|
657
|
+
if (pItem.CFI && tmpMediaViewer._activeRendition)
|
|
658
|
+
{
|
|
659
|
+
tmpMediaViewer._activeRendition.display(pItem.CFI);
|
|
660
|
+
}
|
|
661
|
+
else if (pItem.PageNumber && typeof tmpMediaViewer._renderPdfPage === 'function')
|
|
662
|
+
{
|
|
663
|
+
tmpMediaViewer._renderPdfPage(pItem.PageNumber);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
}, 1000);
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
else if (pItem.Type === 'image-crop' && pItem.CropRegion)
|
|
670
|
+
{
|
|
671
|
+
let tmpIEX = this.pict.views['RetoldRemote-ImageExplorer'];
|
|
672
|
+
if (tmpIEX)
|
|
673
|
+
{
|
|
674
|
+
tmpIEX.showExplorer(pItem.Path);
|
|
675
|
+
// Zoom to the crop region after the viewer loads
|
|
676
|
+
let tmpCrop = pItem.CropRegion;
|
|
677
|
+
setTimeout(() =>
|
|
678
|
+
{
|
|
679
|
+
if (tmpIEX._osdViewer && tmpIEX._dziData)
|
|
680
|
+
{
|
|
681
|
+
let tmpImageRect = new OpenSeadragon.Rect(tmpCrop.X, tmpCrop.Y, tmpCrop.Width, tmpCrop.Height);
|
|
682
|
+
let tmpViewportRect = tmpIEX._osdViewer.viewport.imageToViewportRectangle(tmpImageRect);
|
|
683
|
+
tmpIEX._osdViewer.viewport.fitBounds(tmpViewportRect);
|
|
684
|
+
}
|
|
685
|
+
}, 800);
|
|
686
|
+
}
|
|
687
|
+
}
|
|
633
688
|
else if (pItem.Type === 'video-frame' && pItem.FrameCacheKey && pItem.FrameFilename)
|
|
634
689
|
{
|
|
635
690
|
// Show the cached frame image directly in the viewer
|