retold-remote 0.0.22 → 0.0.25
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 +87 -20
- package/docs/README.md +59 -11
- package/docs/_sidebar.md +1 -0
- package/docs/collections.md +30 -0
- package/docs/ebook-reader.md +75 -1
- package/docs/image-explorer.md +27 -1
- package/docs/server-setup.md +28 -18
- package/docs/stack-launcher.md +218 -0
- package/docs/ultravisor-integration.md +2 -0
- package/package.json +10 -7
- package/source/Pict-Application-RetoldRemote.js +2 -0
- package/source/RetoldRemote-ExtensionMaps.js +1 -1
- package/source/cli/RetoldRemote-Server-Setup.js +240 -2
- package/source/cli/RetoldRemote-Stack-Launcher.js +387 -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 +46 -0
- package/source/providers/keyboard-handlers/KeyHandler-ImageExplorer.js +5 -0
- package/source/providers/keyboard-handlers/KeyHandler-Viewer.js +23 -0
- package/source/server/RetoldRemote-CollectionExportService.js +696 -0
- package/source/server/RetoldRemote-CollectionService.js +5 -0
- package/source/server/RetoldRemote-EbookService.js +194 -3
- package/source/server/RetoldRemote-SubimageService.js +530 -0
- package/source/server/RetoldRemote-ToolDetector.js +50 -0
- package/source/server/RetoldRemote-UltravisorOperations.js +6 -6
- package/source/views/MediaViewer-EbookViewer.js +419 -1
- package/source/views/MediaViewer-PdfViewer.js +963 -0
- package/source/views/PictView-Remote-CollectionsPanel.js +166 -0
- package/source/views/PictView-Remote-ImageExplorer.js +606 -1
- package/source/views/PictView-Remote-ImageViewer.js +2 -2
- package/source/views/PictView-Remote-Layout.js +12 -0
- package/source/views/PictView-Remote-MediaViewer.js +83 -25
- package/source/views/PictView-Remote-SubimagesPanel.js +353 -0
- package/web-application/css/retold-remote.css +87 -20
- package/web-application/docs/README.md +59 -11
- package/web-application/docs/_sidebar.md +1 -0
- package/web-application/docs/collections.md +30 -0
- package/web-application/docs/ebook-reader.md +75 -1
- package/web-application/docs/image-explorer.md +27 -1
- package/web-application/docs/server-setup.md +28 -18
- package/web-application/docs/stack-launcher.md +218 -0
- package/web-application/docs/ultravisor-integration.md +2 -0
- package/web-application/retold-remote.js +399 -45
- package/web-application/retold-remote.js.map +1 -1
- package/web-application/retold-remote.min.js +13 -12
- package/web-application/retold-remote.min.js.map +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f();}else if(typeof define==="function"&&define.amd){define([],f);}else{var g;if(typeof window!=="undefined"){g=window;}else if(typeof global!=="undefined"){g=global;}else if(typeof self!=="undefined"){g=self;}else{g=this;}g.retoldRemote=f();}})(function(){var define,module,exports;return function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a;}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r);},p,p.exports,r,e,n,t);}return n[i].exports;}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o;}return r;}()({1:[function(require,module,exports){},{}],2:[function(require,module,exports){arguments[4][1][0].apply(exports,arguments);},{"dup":1}],3:[function(require,module,exports){'use strict';var bind=require('function-bind');var $apply=require('./functionApply');var $call=require('./functionCall');var $reflectApply=require('./reflectApply');/** @type {import('./actualApply')} */module.exports=$reflectApply||bind.call($call,$apply);},{"./functionApply":4,"./functionCall":5,"./reflectApply":7,"function-bind":22}],4:[function(require,module,exports){'use strict';/** @type {import('./functionApply')} */module.exports=Function.prototype.apply;},{}],5:[function(require,module,exports){'use strict';/** @type {import('./functionCall')} */module.exports=Function.prototype.call;},{}],6:[function(require,module,exports){'use strict';var bind=require('function-bind');var $TypeError=require('es-errors/type');var $call=require('./functionCall');var $actualApply=require('./actualApply');/** @type {(args: [Function, thisArg?: unknown, ...args: unknown[]]) => Function} TODO FIXME, find a way to use import('.') */module.exports=function callBindBasic(args){if(args.length<1||typeof args[0]!=='function'){throw new $TypeError('a function is required');}return $actualApply(bind,$call,args);};},{"./actualApply":3,"./functionCall":5,"es-errors/type":16,"function-bind":22}],7:[function(require,module,exports){'use strict';/** @type {import('./reflectApply')} */module.exports=typeof Reflect!=='undefined'&&Reflect&&Reflect.apply;},{}],8:[function(require,module,exports){'use strict';var GetIntrinsic=require('get-intrinsic');var callBindBasic=require('call-bind-apply-helpers');/** @type {(thisArg: string, searchString: string, position?: number) => number} */var $indexOf=callBindBasic([GetIntrinsic('%String.prototype.indexOf%')]);/** @type {import('.')} */module.exports=function callBoundIntrinsic(name,allowMissing){/* eslint no-extra-parens: 0 */var intrinsic=/** @type {(this: unknown, ...args: unknown[]) => unknown} */GetIntrinsic(name,!!allowMissing);if(typeof intrinsic==='function'&&$indexOf(name,'.prototype.')>-1){return callBindBasic(/** @type {const} */[intrinsic]);}return intrinsic;};},{"call-bind-apply-helpers":6,"get-intrinsic":23}],9:[function(require,module,exports){'use strict';var callBind=require('call-bind-apply-helpers');var gOPD=require('gopd');var hasProtoAccessor;try{// eslint-disable-next-line no-extra-parens, no-proto
|
|
1
|
+
"use strict";function _interopRequireWildcard(e,t){if("function"==typeof WeakMap)var r=new WeakMap(),n=new WeakMap();return(_interopRequireWildcard=function(e,t){if(!t&&e&&e.__esModule)return e;var o,i,f={__proto__:null,default:e};if(null===e||"object"!=typeof e&&"function"!=typeof e)return f;if(o=t?n:r){if(o.has(e))return o.get(e);o.set(e,f);}for(const t in e)"default"!==t&&{}.hasOwnProperty.call(e,t)&&((i=(o=Object.defineProperty)&&Object.getOwnPropertyDescriptor(e,t))&&(i.get||i.set)?o(f,t,i):f[t]=e[t]);return f;})(e,t);}(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f();}else if(typeof define==="function"&&define.amd){define([],f);}else{var g;if(typeof window!=="undefined"){g=window;}else if(typeof global!=="undefined"){g=global;}else if(typeof self!=="undefined"){g=self;}else{g=this;}g.retoldRemote=f();}})(function(){var define,module,exports;return function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a;}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r);},p,p.exports,r,e,n,t);}return n[i].exports;}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o;}return r;}()({1:[function(require,module,exports){},{}],2:[function(require,module,exports){arguments[4][1][0].apply(exports,arguments);},{"dup":1}],3:[function(require,module,exports){'use strict';var bind=require('function-bind');var $apply=require('./functionApply');var $call=require('./functionCall');var $reflectApply=require('./reflectApply');/** @type {import('./actualApply')} */module.exports=$reflectApply||bind.call($call,$apply);},{"./functionApply":4,"./functionCall":5,"./reflectApply":7,"function-bind":22}],4:[function(require,module,exports){'use strict';/** @type {import('./functionApply')} */module.exports=Function.prototype.apply;},{}],5:[function(require,module,exports){'use strict';/** @type {import('./functionCall')} */module.exports=Function.prototype.call;},{}],6:[function(require,module,exports){'use strict';var bind=require('function-bind');var $TypeError=require('es-errors/type');var $call=require('./functionCall');var $actualApply=require('./actualApply');/** @type {(args: [Function, thisArg?: unknown, ...args: unknown[]]) => Function} TODO FIXME, find a way to use import('.') */module.exports=function callBindBasic(args){if(args.length<1||typeof args[0]!=='function'){throw new $TypeError('a function is required');}return $actualApply(bind,$call,args);};},{"./actualApply":3,"./functionCall":5,"es-errors/type":16,"function-bind":22}],7:[function(require,module,exports){'use strict';/** @type {import('./reflectApply')} */module.exports=typeof Reflect!=='undefined'&&Reflect&&Reflect.apply;},{}],8:[function(require,module,exports){'use strict';var GetIntrinsic=require('get-intrinsic');var callBindBasic=require('call-bind-apply-helpers');/** @type {(thisArg: string, searchString: string, position?: number) => number} */var $indexOf=callBindBasic([GetIntrinsic('%String.prototype.indexOf%')]);/** @type {import('.')} */module.exports=function callBoundIntrinsic(name,allowMissing){/* eslint no-extra-parens: 0 */var intrinsic=/** @type {(this: unknown, ...args: unknown[]) => unknown} */GetIntrinsic(name,!!allowMissing);if(typeof intrinsic==='function'&&$indexOf(name,'.prototype.')>-1){return callBindBasic(/** @type {const} */[intrinsic]);}return intrinsic;};},{"call-bind-apply-helpers":6,"get-intrinsic":23}],9:[function(require,module,exports){'use strict';var callBind=require('call-bind-apply-helpers');var gOPD=require('gopd');var hasProtoAccessor;try{// eslint-disable-next-line no-extra-parens, no-proto
|
|
2
2
|
hasProtoAccessor=/** @type {{ __proto__?: typeof Array.prototype }} */[].__proto__===Array.prototype;}catch(e){if(!e||typeof e!=='object'||!('code'in e)||e.code!=='ERR_PROTO_ACCESS'){throw e;}}// eslint-disable-next-line no-extra-parens
|
|
3
3
|
var desc=!!hasProtoAccessor&&gOPD&&gOPD(Object.prototype,/** @type {keyof typeof Object.prototype} */'__proto__');var $Object=Object;var $getPrototypeOf=$Object.getPrototypeOf;/** @type {import('./get')} */module.exports=desc&&typeof desc.get==='function'?callBind([desc.get]):typeof $getPrototypeOf==='function'?/** @type {import('./get')} */function getDunder(value){// eslint-disable-next-line eqeqeq
|
|
4
4
|
return $getPrototypeOf(value==null?value:$Object(value));}:false;},{"call-bind-apply-helpers":6,"gopd":28}],10:[function(require,module,exports){'use strict';/** @type {import('.')} */var $defineProperty=Object.defineProperty||false;if($defineProperty){try{$defineProperty({},'a',{value:1});}catch(e){// IE 8 has a broken defineProperty
|
|
@@ -9553,7 +9553,7 @@ if(psychotic){result.hostname=isAbsolute?'':srcPath.length?srcPath.shift():'';re
|
|
|
9553
9553
|
if(result.pathname!==null||result.search!==null){result.path=(result.pathname?result.pathname:'')+(result.search?result.search:'');}result.auth=relative.auth||result.auth;result.slashes=result.slashes||relative.slashes;result.href=result.format();return result;};Url.prototype.parseHost=function(){var host=this.host;var port=portPattern.exec(host);if(port){port=port[0];if(port!==':'){this.port=port.substr(1);}host=host.substr(0,host.length-port.length);}if(host){this.hostname=host;}};exports.parse=urlParse;exports.resolve=urlResolve;exports.resolveObject=urlResolveObject;exports.format=urlFormat;exports.Url=Url;},{"punycode/":90,"qs":92}],114:[function(require,module,exports){module.exports={"Name":"Retold Remote","MainViewportViewIdentifier":"ContentEditor-Layout","AutoSolveAfterInitialize":true,"AutoRenderMainViewportViewAfterInitialize":false,"AutoRenderViewsAfterInitialize":false};},{}],115:[function(require,module,exports){const libContentEditorApplication=require('retold-content-system').PictContentEditor;const libPictSectionFileBrowser=require('pict-section-filebrowser');// Providers
|
|
9554
9554
|
const libProviderRetoldRemote=require('./providers/Pict-Provider-RetoldRemote.js');const libProviderGalleryNavigation=require('./providers/Pict-Provider-GalleryNavigation.js');const libProviderGalleryFilterSort=require('./providers/Pict-Provider-GalleryFilterSort.js');const libProviderRetoldRemoteIcons=require('./providers/Pict-Provider-RetoldRemoteIcons.js');const libProviderRetoldRemoteTheme=require('./providers/Pict-Provider-RetoldRemoteTheme.js');const libProviderFormattingUtilities=require('./providers/Pict-Provider-FormattingUtilities.js');const libProviderToastNotification=require('./providers/Pict-Provider-ToastNotification.js');const libProviderCollectionManager=require('./providers/Pict-Provider-CollectionManager.js');const libProviderAISortManager=require('./providers/Pict-Provider-AISortManager.js');const libExtensionMaps=require('./RetoldRemote-ExtensionMaps.js');// Views (replace parent views)
|
|
9555
9555
|
const libViewLayout=require('./views/PictView-Remote-Layout.js');const libViewTopBar=require('./views/PictView-Remote-TopBar.js');const libViewSettingsPanel=require('./views/PictView-Remote-SettingsPanel.js');// Views (new)
|
|
9556
|
-
const libViewGallery=require('./views/PictView-Remote-Gallery.js');const libViewMediaViewer=require('./views/PictView-Remote-MediaViewer.js');const libViewImageViewer=require('./views/PictView-Remote-ImageViewer.js');const libViewVideoExplorer=require('./views/PictView-Remote-VideoExplorer.js');const libViewAudioExplorer=require('./views/PictView-Remote-AudioExplorer.js');const libViewImageExplorer=require('./views/PictView-Remote-ImageExplorer.js');const libViewVLCSetup=require('./views/PictView-Remote-VLCSetup.js');const libViewCollectionsPanel=require('./views/PictView-Remote-CollectionsPanel.js');const libViewFileInfoPanel=require('./views/PictView-Remote-FileInfoPanel.js');// Application configuration
|
|
9556
|
+
const libViewGallery=require('./views/PictView-Remote-Gallery.js');const libViewMediaViewer=require('./views/PictView-Remote-MediaViewer.js');const libViewImageViewer=require('./views/PictView-Remote-ImageViewer.js');const libViewVideoExplorer=require('./views/PictView-Remote-VideoExplorer.js');const libViewAudioExplorer=require('./views/PictView-Remote-AudioExplorer.js');const libViewImageExplorer=require('./views/PictView-Remote-ImageExplorer.js');const libViewVLCSetup=require('./views/PictView-Remote-VLCSetup.js');const libViewCollectionsPanel=require('./views/PictView-Remote-CollectionsPanel.js');const libViewFileInfoPanel=require('./views/PictView-Remote-FileInfoPanel.js');const libViewSubimagesPanel=require('./views/PictView-Remote-SubimagesPanel.js');// Application configuration
|
|
9557
9557
|
const _DefaultConfiguration=require('./Pict-Application-RetoldRemote-Configuration.json');/**
|
|
9558
9558
|
* Retold Remote Application
|
|
9559
9559
|
*
|
|
@@ -9564,7 +9564,7 @@ const _DefaultConfiguration=require('./Pict-Application-RetoldRemote-Configurati
|
|
|
9564
9564
|
*/class RetoldRemoteApplication extends libContentEditorApplication{constructor(pFable,pOptions,pServiceHash){let tmpOptions=Object.assign({},_DefaultConfiguration,pOptions);super(pFable,tmpOptions,pServiceHash);// Replace parent views with media-focused versions.
|
|
9565
9565
|
// Re-registering with the same ViewIdentifier replaces the parent's view.
|
|
9566
9566
|
this.pict.addView('ContentEditor-Layout',libViewLayout.default_configuration,libViewLayout);this.pict.addView('ContentEditor-TopBar',libViewTopBar.default_configuration,libViewTopBar);// Add new views
|
|
9567
|
-
this.pict.addView('RetoldRemote-Gallery',libViewGallery.default_configuration,libViewGallery);this.pict.addView('RetoldRemote-MediaViewer',libViewMediaViewer.default_configuration,libViewMediaViewer);this.pict.addView('RetoldRemote-ImageViewer',libViewImageViewer.default_configuration,libViewImageViewer);this.pict.addView('RetoldRemote-SettingsPanel',libViewSettingsPanel.default_configuration,libViewSettingsPanel);this.pict.addView('RetoldRemote-VideoExplorer',libViewVideoExplorer.default_configuration,libViewVideoExplorer);this.pict.addView('RetoldRemote-AudioExplorer',libViewAudioExplorer.default_configuration,libViewAudioExplorer);this.pict.addView('RetoldRemote-ImageExplorer',libViewImageExplorer.default_configuration,libViewImageExplorer);this.pict.addView('RetoldRemote-VLCSetup',libViewVLCSetup.default_configuration,libViewVLCSetup);this.pict.addView('RetoldRemote-CollectionsPanel',libViewCollectionsPanel.default_configuration,libViewCollectionsPanel);this.pict.addView('RetoldRemote-FileInfoPanel',libViewFileInfoPanel.default_configuration,libViewFileInfoPanel);// Add new providers
|
|
9567
|
+
this.pict.addView('RetoldRemote-Gallery',libViewGallery.default_configuration,libViewGallery);this.pict.addView('RetoldRemote-MediaViewer',libViewMediaViewer.default_configuration,libViewMediaViewer);this.pict.addView('RetoldRemote-ImageViewer',libViewImageViewer.default_configuration,libViewImageViewer);this.pict.addView('RetoldRemote-SettingsPanel',libViewSettingsPanel.default_configuration,libViewSettingsPanel);this.pict.addView('RetoldRemote-VideoExplorer',libViewVideoExplorer.default_configuration,libViewVideoExplorer);this.pict.addView('RetoldRemote-AudioExplorer',libViewAudioExplorer.default_configuration,libViewAudioExplorer);this.pict.addView('RetoldRemote-ImageExplorer',libViewImageExplorer.default_configuration,libViewImageExplorer);this.pict.addView('RetoldRemote-VLCSetup',libViewVLCSetup.default_configuration,libViewVLCSetup);this.pict.addView('RetoldRemote-CollectionsPanel',libViewCollectionsPanel.default_configuration,libViewCollectionsPanel);this.pict.addView('RetoldRemote-FileInfoPanel',libViewFileInfoPanel.default_configuration,libViewFileInfoPanel);this.pict.addView('RetoldRemote-SubimagesPanel',libViewSubimagesPanel.default_configuration,libViewSubimagesPanel);// Add new providers
|
|
9568
9568
|
this.pict.addProvider('RetoldRemote-Provider',libProviderRetoldRemote.default_configuration,libProviderRetoldRemote);this.pict.addProvider('RetoldRemote-GalleryNavigation',libProviderGalleryNavigation.default_configuration,libProviderGalleryNavigation);this.pict.addProvider('RetoldRemote-GalleryFilterSort',libProviderGalleryFilterSort.default_configuration,libProviderGalleryFilterSort);this.pict.addProvider('RetoldRemote-Icons',libProviderRetoldRemoteIcons.default_configuration,libProviderRetoldRemoteIcons);this.pict.addProvider('RetoldRemote-Theme',libProviderRetoldRemoteTheme.default_configuration,libProviderRetoldRemoteTheme);this.pict.addProvider('RetoldRemote-FormattingUtilities',libProviderFormattingUtilities.default_configuration,libProviderFormattingUtilities);this.pict.addProvider('RetoldRemote-ToastNotification',libProviderToastNotification.default_configuration,libProviderToastNotification);this.pict.addProvider('RetoldRemote-CollectionManager',libProviderCollectionManager.default_configuration,libProviderCollectionManager);this.pict.addProvider('RetoldRemote-AISortManager',libProviderAISortManager.default_configuration,libProviderAISortManager);}onAfterInitializeAsync(fCallback){// Expose pict on window for inline onclick handlers
|
|
9569
9569
|
if(typeof window!=='undefined'){window.pict=this.pict;}// Initialize RetoldRemote-specific state
|
|
9570
9570
|
this.pict.AppData.RetoldRemote={ActiveMode:'gallery',// 'gallery' or 'viewer'
|
|
@@ -9700,7 +9700,7 @@ tmpDetailRows.parentElement.appendChild(tmpBtn);}/**
|
|
|
9700
9700
|
}}/**
|
|
9701
9701
|
* Load RetoldRemote settings from localStorage.
|
|
9702
9702
|
*/_loadRemoteSettings(){try{let tmpStored=localStorage.getItem('retold-remote-settings');if(tmpStored){let tmpSettings=JSON.parse(tmpStored);let tmpRemote=this.pict.AppData.RetoldRemote;if(tmpSettings.Theme)tmpRemote.Theme=tmpSettings.Theme;if(tmpSettings.ViewMode)tmpRemote.ViewMode=tmpSettings.ViewMode;if(tmpSettings.ThumbnailSize)tmpRemote.ThumbnailSize=tmpSettings.ThumbnailSize;if(tmpSettings.GalleryFilter){tmpRemote.GalleryFilter=tmpSettings.GalleryFilter;tmpRemote.FilterState.MediaType=tmpSettings.GalleryFilter;}if(typeof tmpSettings.ShowHiddenFiles==='boolean')tmpRemote.ShowHiddenFiles=tmpSettings.ShowHiddenFiles;if(typeof tmpSettings.DistractionFreeShowNav==='boolean')tmpRemote.DistractionFreeShowNav=tmpSettings.DistractionFreeShowNav;if(tmpSettings.ImageFitMode)tmpRemote.ImageFitMode=tmpSettings.ImageFitMode;if(typeof tmpSettings.SidebarCollapsed==='boolean')tmpRemote.SidebarCollapsed=tmpSettings.SidebarCollapsed;if(tmpSettings.SidebarWidth)tmpRemote.SidebarWidth=tmpSettings.SidebarWidth;if(tmpSettings.SortField)tmpRemote.SortField=tmpSettings.SortField;if(tmpSettings.SortDirection)tmpRemote.SortDirection=tmpSettings.SortDirection;if(Array.isArray(tmpSettings.FilterPresets))tmpRemote.FilterPresets=tmpSettings.FilterPresets;if(typeof tmpSettings.FilterPanelOpen==='boolean')tmpRemote.FilterPanelOpen=tmpSettings.FilterPanelOpen;if(typeof tmpSettings.AutoplayVideo==='boolean')tmpRemote.AutoplayVideo=tmpSettings.AutoplayVideo;if(typeof tmpSettings.AutoplayAudio==='boolean')tmpRemote.AutoplayAudio=tmpSettings.AutoplayAudio;if(typeof tmpSettings.ListShowExtension==='boolean')tmpRemote.ListShowExtension=tmpSettings.ListShowExtension;if(typeof tmpSettings.ListShowSize==='boolean')tmpRemote.ListShowSize=tmpSettings.ListShowSize;if(typeof tmpSettings.ListShowDate==='boolean')tmpRemote.ListShowDate=tmpSettings.ListShowDate;if(typeof tmpSettings.CollectionsPanelOpen==='boolean')tmpRemote.CollectionsPanelOpen=tmpSettings.CollectionsPanelOpen;if(tmpSettings.CollectionsPanelWidth)tmpRemote.CollectionsPanelWidth=tmpSettings.CollectionsPanelWidth;if(tmpSettings.LastUsedCollectionGUID)tmpRemote.LastUsedCollectionGUID=tmpSettings.LastUsedCollectionGUID;if(tmpSettings.FavoritesGUID)tmpRemote.FavoritesGUID=tmpSettings.FavoritesGUID;if(tmpSettings.AISortSettings&&typeof tmpSettings.AISortSettings==='object'){if(tmpSettings.AISortSettings.AIEndpoint)tmpRemote.AISortSettings.AIEndpoint=tmpSettings.AISortSettings.AIEndpoint;if(tmpSettings.AISortSettings.AIModel)tmpRemote.AISortSettings.AIModel=tmpSettings.AISortSettings.AIModel;if(tmpSettings.AISortSettings.AIProvider)tmpRemote.AISortSettings.AIProvider=tmpSettings.AISortSettings.AIProvider;if(tmpSettings.AISortSettings.NamingTemplate)tmpRemote.AISortSettings.NamingTemplate=tmpSettings.AISortSettings.NamingTemplate;}}}catch(pError){// localStorage may not be available
|
|
9703
|
-
}}}module.exports=RetoldRemoteApplication;},{"./Pict-Application-RetoldRemote-Configuration.json":114,"./RetoldRemote-ExtensionMaps.js":117,"./providers/Pict-Provider-AISortManager.js":121,"./providers/Pict-Provider-CollectionManager.js":122,"./providers/Pict-Provider-FormattingUtilities.js":123,"./providers/Pict-Provider-GalleryFilterSort.js":124,"./providers/Pict-Provider-GalleryNavigation.js":125,"./providers/Pict-Provider-RetoldRemote.js":126,"./providers/Pict-Provider-RetoldRemoteIcons.js":127,"./providers/Pict-Provider-RetoldRemoteTheme.js":128,"./providers/Pict-Provider-ToastNotification.js":129,"./views/PictView-Remote-AudioExplorer.js":
|
|
9703
|
+
}}}module.exports=RetoldRemoteApplication;},{"./Pict-Application-RetoldRemote-Configuration.json":114,"./RetoldRemote-ExtensionMaps.js":117,"./providers/Pict-Provider-AISortManager.js":121,"./providers/Pict-Provider-CollectionManager.js":122,"./providers/Pict-Provider-FormattingUtilities.js":123,"./providers/Pict-Provider-GalleryFilterSort.js":124,"./providers/Pict-Provider-GalleryNavigation.js":125,"./providers/Pict-Provider-RetoldRemote.js":126,"./providers/Pict-Provider-RetoldRemoteIcons.js":127,"./providers/Pict-Provider-RetoldRemoteTheme.js":128,"./providers/Pict-Provider-ToastNotification.js":129,"./views/PictView-Remote-AudioExplorer.js":140,"./views/PictView-Remote-CollectionsPanel.js":141,"./views/PictView-Remote-FileInfoPanel.js":142,"./views/PictView-Remote-Gallery.js":143,"./views/PictView-Remote-ImageExplorer.js":144,"./views/PictView-Remote-ImageViewer.js":145,"./views/PictView-Remote-Layout.js":146,"./views/PictView-Remote-MediaViewer.js":147,"./views/PictView-Remote-SettingsPanel.js":148,"./views/PictView-Remote-SubimagesPanel.js":149,"./views/PictView-Remote-TopBar.js":150,"./views/PictView-Remote-VLCSetup.js":151,"./views/PictView-Remote-VideoExplorer.js":152,"pict-section-filebrowser":63,"retold-content-system":100}],116:[function(require,module,exports){/**
|
|
9704
9704
|
* Retold Remote -- Browser Bundle Entry
|
|
9705
9705
|
*
|
|
9706
9706
|
* Exports the RetoldRemote application class for browser consumption.
|
|
@@ -9732,7 +9732,7 @@ const RawImageExtensions={'nef':true,'nrw':true,// Nikon
|
|
|
9732
9732
|
'dng':true,// Adobe DNG (Leica, DJI, etc.)
|
|
9733
9733
|
'heic':true,'heif':true// Apple / MPEG-H (limited browser support)
|
|
9734
9734
|
};const ImageExtensions={'png':true,'jpg':true,'jpeg':true,'gif':true,'webp':true,'svg':true,'bmp':true,'ico':true,'avif':true,'tiff':true,'tif':true,'heic':true,'heif':true};// Merge raw extensions into ImageExtensions so getCategory() returns 'image'
|
|
9735
|
-
for(let tmpKey in RawImageExtensions){ImageExtensions[tmpKey]=true;}const VideoExtensions={'mp4':true,'webm':true,'mov':true,'mkv':true,'avi':true,'wmv':true,'flv':true,'m4v':true,'ogv':true,'mpg':true,'mpeg':true,'mpe':true,'mpv':true,'m2v':true,'ts':true,'mts':true,'m2ts':true,'vob':true,'3gp':true,'3g2':true,'f4v':true,'rm':true,'rmvb':true,'divx':true,'asf':true,'mxf':true,'dv':true,'nsv':true,'nuv':true,'y4m':true,'wtv':true,'swf':true,'dat':true};const AudioExtensions={'mp3':true,'wav':true,'ogg':true,'flac':true,'aac':true,'m4a':true,'wma':true,'oga':true};const DocumentExtensions={'pdf':true,'epub':true,'mobi':true,'doc':true,'docx':true};/**
|
|
9735
|
+
for(let tmpKey in RawImageExtensions){ImageExtensions[tmpKey]=true;}const VideoExtensions={'mp4':true,'webm':true,'mov':true,'mkv':true,'avi':true,'wmv':true,'flv':true,'m4v':true,'ogv':true,'mpg':true,'mpeg':true,'mpe':true,'mpv':true,'m2v':true,'ts':true,'mts':true,'m2ts':true,'vob':true,'3gp':true,'3g2':true,'f4v':true,'rm':true,'rmvb':true,'divx':true,'asf':true,'mxf':true,'dv':true,'nsv':true,'nuv':true,'y4m':true,'wtv':true,'swf':true,'dat':true};const AudioExtensions={'mp3':true,'wav':true,'ogg':true,'flac':true,'aac':true,'m4a':true,'wma':true,'oga':true};const DocumentExtensions={'pdf':true,'epub':true,'mobi':true,'doc':true,'docx':true,'rtf':true,'odt':true,'wpd':true,'wps':true,'pages':true,'odp':true,'ppt':true,'pptx':true,'ods':true,'xls':true,'xlsx':true};/**
|
|
9736
9736
|
* Get the media category for a file extension.
|
|
9737
9737
|
*
|
|
9738
9738
|
* @param {string} pExtension - Extension with or without leading dot (e.g. '.png' or 'png')
|
|
@@ -9766,7 +9766,9 @@ for(let tmpKey in RawImageExtensions){ImageExtensions[tmpKey]=true;}const VideoE
|
|
|
9766
9766
|
* @returns {boolean} true if the add was initiated
|
|
9767
9767
|
*/addCurrentFileToCollection:function addCurrentFileToCollection(pGUID){let tmpRemote=this._getRemote();let tmpTargetGUID=pGUID||tmpRemote.LastUsedCollectionGUID;if(!tmpTargetGUID){return false;}// If the video explorer is active, delegate to addVideoFrameToCollection
|
|
9768
9768
|
if(tmpRemote.ActiveMode==='video-explorer'){return this.addVideoFrameToCollection(tmpTargetGUID);}// If the audio explorer is active, delegate to addAudioSnippetToCollection
|
|
9769
|
-
if(tmpRemote.ActiveMode==='audio-explorer'){return this.addAudioSnippetToCollection(tmpTargetGUID);}
|
|
9769
|
+
if(tmpRemote.ActiveMode==='audio-explorer'){return this.addAudioSnippetToCollection(tmpTargetGUID);}// If the image explorer is active with a selection, add as subimage
|
|
9770
|
+
if(tmpRemote.ActiveMode==='image-explorer'){let tmpIEX=this.pict.views['RetoldRemote-ImageExplorer'];if(tmpIEX){let tmpActiveSelection=tmpIEX.getActiveSelection();if(tmpActiveSelection){return this.addSubimageToCollection(tmpTargetGUID,tmpActiveSelection,tmpIEX._currentPath);}}}// If viewing a document (PDF/EPUB) with a pending region, add as document-region
|
|
9771
|
+
if(tmpRemote.ActiveMode==='viewer'&&tmpRemote.CurrentViewerMediaType==='document'){let tmpMediaViewer=this.pict.views['RetoldRemote-MediaViewer'];if(tmpMediaViewer&&tmpMediaViewer._pendingDocumentRegion){return this.addDocumentRegionToCollection(tmpTargetGUID,tmpMediaViewer._pendingDocumentRegion,tmpRemote.CurrentViewerFile);}}let tmpCurrentItem=this._resolveCurrentItem();if(!tmpCurrentItem||!tmpCurrentItem.Path){return false;}let tmpFilePath=tmpCurrentItem.Path;// Check if the current item is a folder — prompt for folder vs contents
|
|
9770
9772
|
if(tmpCurrentItem.Type==='folder'||tmpCurrentItem.Type==='archive'){let tmpSelf=this;this.showFolderChoicePrompt(pChoice=>{let tmpFolderItem={Type:pChoice==='contents'?'folder-contents':'folder',Path:tmpFilePath,Label:'',Note:''};tmpSelf.addItemsToCollection(tmpTargetGUID,[tmpFolderItem]);});return true;}// Build the item — detect archive subfiles and video timestamp context
|
|
9771
9773
|
let tmpItem={Type:'file',Path:tmpFilePath,Label:'',Note:''};// Detect archive subfile — path contains an archive extension followed by /
|
|
9772
9774
|
let tmpArchiveMatch=tmpFilePath.match(/^(.*?\.(zip|7z|rar|tar|tgz|cbz|cbr|tar\.gz|tar\.bz2|tar\.xz))\/(.*)/i);if(tmpArchiveMatch){tmpItem.Type='subfile';tmpItem.ArchivePath=tmpArchiveMatch[1];}// If we're viewing a video with the player active, capture current timestamp as video-frame
|
|
@@ -9808,6 +9810,24 @@ let tmpStart=0;let tmpEnd=tmpDuration;if(tmpAEX._selectionStart>=0&&tmpAEX._sele
|
|
|
9808
9810
|
* @returns {boolean} true if the add was initiated
|
|
9809
9811
|
*/addAudioClipToCollection:function addAudioClipToCollection(pGUID,pStartTime,pEndTime){let tmpRemote=this._getRemote();let tmpTargetGUID=pGUID||tmpRemote.LastUsedCollectionGUID;if(!tmpTargetGUID){return false;}// Resolve file path: check audio explorer first, then fall back to viewer file
|
|
9810
9812
|
let tmpFilePath=null;if(tmpRemote.ActiveMode==='audio-explorer'){let tmpAEX=this.pict.views['RetoldRemote-AudioExplorer'];if(tmpAEX&&tmpAEX._currentPath){tmpFilePath=tmpAEX._currentPath;}}if(!tmpFilePath){tmpFilePath=tmpRemote.CurrentViewerFile;}if(!tmpFilePath){return false;}let tmpFileName=tmpFilePath.replace(/^.*\//,'');let tmpItem={Type:'audio-clip',Path:tmpFilePath,AudioStart:pStartTime,AudioEnd:pEndTime,Label:tmpFileName+': '+this._formatTimestamp(pStartTime)+' \u2013 '+this._formatTimestamp(pEndTime),Note:''};this.addItemsToCollection(tmpTargetGUID,[tmpItem]);return true;},/**
|
|
9813
|
+
* Add a subimage region (crop) to a collection.
|
|
9814
|
+
*
|
|
9815
|
+
* @param {string} pGUID - Collection GUID
|
|
9816
|
+
* @param {object} pRegion - { X, Y, Width, Height, Label?, ID? } in image pixels
|
|
9817
|
+
* @param {string} [pFilePath] - Explicit file path (defaults to current viewer file)
|
|
9818
|
+
* @returns {boolean} true if the add was initiated
|
|
9819
|
+
*/addSubimageToCollection:function addSubimageToCollection(pGUID,pRegion,pFilePath){let tmpRemote=this._getRemote();let tmpTargetGUID=pGUID||tmpRemote.LastUsedCollectionGUID;if(!tmpTargetGUID||!pRegion){return false;}let tmpFilePath=pFilePath||tmpRemote.CurrentViewerFile;if(!tmpFilePath){return false;}let tmpFileName=tmpFilePath.replace(/^.*\//,'');let tmpLabel=pRegion.Label?pRegion.Label:tmpFileName+': '+pRegion.Width+'\u00d7'+pRegion.Height+' at '+pRegion.X+','+pRegion.Y;let tmpItem={Type:'image-crop',Path:tmpFilePath,CropRegion:{X:pRegion.X,Y:pRegion.Y,Width:pRegion.Width,Height:pRegion.Height},Label:tmpLabel,Note:''};// If we have a hash for this file, include it
|
|
9820
|
+
let tmpProvider=this.pict.providers['RetoldRemote-Provider'];if(tmpProvider){let tmpHash=tmpProvider.getHashForPath(tmpFilePath);if(tmpHash){tmpItem.Hash=tmpHash;}}this.addItemsToCollection(tmpTargetGUID,[tmpItem]);return true;},/**
|
|
9821
|
+
* Add a document region (text selection or visual area) to a collection.
|
|
9822
|
+
*
|
|
9823
|
+
* @param {string} pGUID - Collection GUID
|
|
9824
|
+
* @param {object} pRegion - Region object with Type, Label, and type-specific fields
|
|
9825
|
+
* @param {string} [pFilePath] - Explicit file path (defaults to current viewer file)
|
|
9826
|
+
* @returns {boolean} true if the add was initiated
|
|
9827
|
+
*/addDocumentRegionToCollection:function addDocumentRegionToCollection(pGUID,pRegion,pFilePath){let tmpRemote=this._getRemote();let tmpTargetGUID=pGUID||tmpRemote.LastUsedCollectionGUID;if(!tmpTargetGUID||!pRegion){return false;}let tmpFilePath=pFilePath||tmpRemote.CurrentViewerFile;if(!tmpFilePath){return false;}let tmpFileName=tmpFilePath.replace(/^.*\//,'');let tmpIsText=pRegion.Type==='text-selection';// Build label
|
|
9828
|
+
let tmpLabel=pRegion.Label||'';if(!tmpLabel){if(tmpIsText&&pRegion.SelectedText){tmpLabel=pRegion.SelectedText.substring(0,50);if(pRegion.SelectedText.length>50)tmpLabel+='\u2026';}else{tmpLabel=tmpFileName;}if(pRegion.PageNumber){tmpLabel='p.'+pRegion.PageNumber+': '+tmpLabel;}}let tmpItem={Type:'document-region',Path:tmpFilePath,Label:tmpLabel,Note:'',DocumentRegionType:pRegion.Type||'visual-region',PageNumber:pRegion.PageNumber||null,CFI:pRegion.CFI||null,SelectedText:pRegion.SelectedText||null};// Include crop region for visual selections
|
|
9829
|
+
if(!tmpIsText&&pRegion.X!==undefined){tmpItem.CropRegion={X:pRegion.X,Y:pRegion.Y,Width:pRegion.Width,Height:pRegion.Height};}// File hash
|
|
9830
|
+
let tmpProvider=this.pict.providers['RetoldRemote-Provider'];if(tmpProvider){let tmpHash=tmpProvider.getHashForPath(tmpFilePath);if(tmpHash){tmpItem.Hash=tmpHash;}}this.addItemsToCollection(tmpTargetGUID,[tmpItem]);return true;},/**
|
|
9811
9831
|
* Format a timestamp in seconds to a human-readable string.
|
|
9812
9832
|
*
|
|
9813
9833
|
* @param {number} pSeconds - Timestamp in seconds
|
|
@@ -10388,7 +10408,10 @@ let tmpGalleryView=this.pict.views['RetoldRemote-Gallery'];if(tmpGalleryView){tm
|
|
|
10388
10408
|
*
|
|
10389
10409
|
* @param {object} pItem - The collection item record
|
|
10390
10410
|
* @param {number} pItemIndex - Index within ActiveCollection.Items
|
|
10391
|
-
*/_navigateToCollectionItem(pItem,pItemIndex){let tmpRemote=this.pict.AppData.RetoldRemote;tmpRemote.BrowsingCollection=true;tmpRemote.BrowsingCollectionIndex=pItemIndex;if(pItem.Type==='video-clip'){let tmpVEX=this.pict.views['RetoldRemote-VideoExplorer'];if(tmpVEX){tmpVEX.showExplorer(pItem.Path,pItem.VideoStart,pItem.VideoEnd);}}else if(pItem.Type==='audio-clip'){let tmpAEX=this.pict.views['RetoldRemote-AudioExplorer'];if(tmpAEX){tmpAEX.showExplorer(pItem.Path,pItem.AudioStart,pItem.AudioEnd);}}else if(pItem.Type==='
|
|
10411
|
+
*/_navigateToCollectionItem(pItem,pItemIndex){let tmpRemote=this.pict.AppData.RetoldRemote;tmpRemote.BrowsingCollection=true;tmpRemote.BrowsingCollectionIndex=pItemIndex;if(pItem.Type==='video-clip'){let tmpVEX=this.pict.views['RetoldRemote-VideoExplorer'];if(tmpVEX){tmpVEX.showExplorer(pItem.Path,pItem.VideoStart,pItem.VideoEnd);}}else if(pItem.Type==='audio-clip'){let tmpAEX=this.pict.views['RetoldRemote-AudioExplorer'];if(tmpAEX){tmpAEX.showExplorer(pItem.Path,pItem.AudioStart,pItem.AudioEnd);}}else if(pItem.Type==='document-region'){// Navigate to the document, then to the specific location
|
|
10412
|
+
let tmpApp=this.pict.PictApplication;if(tmpApp&&tmpApp.navigateToFile){tmpApp.navigateToFile(pItem.Path);// After the viewer loads, navigate to the specific page/CFI
|
|
10413
|
+
let tmpSelf=this;setTimeout(()=>{let tmpMediaViewer=tmpSelf.pict.views['RetoldRemote-MediaViewer'];if(tmpMediaViewer){if(pItem.CFI&&tmpMediaViewer._activeRendition){tmpMediaViewer._activeRendition.display(pItem.CFI);}else if(pItem.PageNumber&&typeof tmpMediaViewer._renderPdfPage==='function'){tmpMediaViewer._renderPdfPage(pItem.PageNumber);}}},1000);}}else if(pItem.Type==='image-crop'&&pItem.CropRegion){let tmpIEX=this.pict.views['RetoldRemote-ImageExplorer'];if(tmpIEX){tmpIEX.showExplorer(pItem.Path);// Zoom to the crop region after the viewer loads
|
|
10414
|
+
let tmpCrop=pItem.CropRegion;setTimeout(()=>{if(tmpIEX._osdViewer&&tmpIEX._dziData){let tmpImageRect=new OpenSeadragon.Rect(tmpCrop.X,tmpCrop.Y,tmpCrop.Width,tmpCrop.Height);let tmpViewportRect=tmpIEX._osdViewer.viewport.imageToViewportRectangle(tmpImageRect);tmpIEX._osdViewer.viewport.fitBounds(tmpViewportRect);}},800);}}else if(pItem.Type==='video-frame'&&pItem.FrameCacheKey&&pItem.FrameFilename){// Show the cached frame image directly in the viewer
|
|
10392
10415
|
let tmpFrameURL='/api/media/video-frame/'+encodeURIComponent(pItem.FrameCacheKey)+'/'+encodeURIComponent(pItem.FrameFilename);let tmpViewer=this.pict.views['RetoldRemote-MediaViewer'];if(tmpViewer){tmpViewer.showDirectImage(tmpFrameURL,pItem.Label||pItem.FrameFilename,pItem.Path);}}else{let tmpApp=this.pict.PictApplication;if(tmpApp&&tmpApp.navigateToFile){tmpApp.navigateToFile(pItem.Path);}}}/**
|
|
10393
10416
|
* Navigate to the next file in the gallery list.
|
|
10394
10417
|
* When browsing a collection, navigates through collection items instead.
|
|
@@ -10800,7 +10823,7 @@ let tmpTopBar=pGalleryNav.pict.views['ContentEditor-TopBar'];if(tmpTopBar&&typeo
|
|
|
10800
10823
|
*
|
|
10801
10824
|
* @param {GalleryNavigationProvider} pGalleryNav - The provider instance
|
|
10802
10825
|
* @param {KeyboardEvent} pEvent - The keyboard event
|
|
10803
|
-
*/function handleImageExplorerKey(pGalleryNav,pEvent){let tmpIEX=pGalleryNav.pict.views['RetoldRemote-ImageExplorer'];if(!tmpIEX){return;}switch(pEvent.key){case'Escape':pEvent.preventDefault();tmpIEX.goBack();break;case'+':case'=':pEvent.preventDefault();tmpIEX.zoomIn();break;case'-':case'_':pEvent.preventDefault();tmpIEX.zoomOut();break;case'0':pEvent.preventDefault();tmpIEX.zoomHome();break;case'a':pEvent.preventDefault();{let tmpCollMgr=pGalleryNav.pict.providers['RetoldRemote-CollectionManager'];if(tmpCollMgr){let tmpQuickGUID=tmpCollMgr.getQuickAddTargetGUID();if(tmpQuickGUID){tmpCollMgr.addCurrentFileToCollection(tmpQuickGUID);}else{let tmpTopBar=pGalleryNav.pict.views['ContentEditor-TopBar'];if(tmpTopBar&&typeof tmpTopBar.showAddToCollectionDropdown==='function'){tmpTopBar.showAddToCollectionDropdown();}}}}break;case'b':pEvent.preventDefault();{let tmpCollManager=pGalleryNav.pict.providers['RetoldRemote-CollectionManager'];if(tmpCollManager){tmpCollManager.togglePanel();}}break;case'h':pEvent.preventDefault();{let tmpFavCollManager=pGalleryNav.pict.providers['RetoldRemote-CollectionManager'];if(tmpFavCollManager){tmpFavCollManager.toggleFavorite();}}break;}}module.exports=handleImageExplorerKey;},{}],134:[function(require,module,exports){/**
|
|
10826
|
+
*/function handleImageExplorerKey(pGalleryNav,pEvent){let tmpIEX=pGalleryNav.pict.views['RetoldRemote-ImageExplorer'];if(!tmpIEX){return;}switch(pEvent.key){case'Escape':pEvent.preventDefault();tmpIEX.goBack();break;case'+':case'=':pEvent.preventDefault();tmpIEX.zoomIn();break;case'-':case'_':pEvent.preventDefault();tmpIEX.zoomOut();break;case'0':pEvent.preventDefault();tmpIEX.zoomHome();break;case'a':pEvent.preventDefault();{let tmpCollMgr=pGalleryNav.pict.providers['RetoldRemote-CollectionManager'];if(tmpCollMgr){let tmpQuickGUID=tmpCollMgr.getQuickAddTargetGUID();if(tmpQuickGUID){tmpCollMgr.addCurrentFileToCollection(tmpQuickGUID);}else{let tmpTopBar=pGalleryNav.pict.views['ContentEditor-TopBar'];if(tmpTopBar&&typeof tmpTopBar.showAddToCollectionDropdown==='function'){tmpTopBar.showAddToCollectionDropdown();}}}}break;case'b':pEvent.preventDefault();{let tmpCollManager=pGalleryNav.pict.providers['RetoldRemote-CollectionManager'];if(tmpCollManager){tmpCollManager.togglePanel();}}break;case'h':pEvent.preventDefault();{let tmpFavCollManager=pGalleryNav.pict.providers['RetoldRemote-CollectionManager'];if(tmpFavCollManager){tmpFavCollManager.toggleFavorite();}}break;case's':pEvent.preventDefault();tmpIEX.toggleSelectionMode();break;}}module.exports=handleImageExplorerKey;},{}],134:[function(require,module,exports){/**
|
|
10804
10827
|
* Sidebar file list keyboard handler.
|
|
10805
10828
|
*
|
|
10806
10829
|
* @param {GalleryNavigationProvider} pGalleryNav - The provider instance
|
|
@@ -10824,7 +10847,8 @@ let tmpEndVEX=pGalleryNav.pict.views['RetoldRemote-VideoExplorer'];if(tmpEndVEX&
|
|
|
10824
10847
|
* @param {GalleryNavigationProvider} pGalleryNav - The provider instance
|
|
10825
10848
|
* @param {KeyboardEvent} pEvent - The keyboard event
|
|
10826
10849
|
*/function handleViewerKey(pGalleryNav,pEvent){let tmpRemote=pGalleryNav.pict.AppData.RetoldRemote;// Video action menu mode — intercept keys for menu options
|
|
10827
|
-
if(tmpRemote.VideoMenuActive&&tmpRemote.CurrentViewerMediaType==='video'){switch(pEvent.key){case'Escape':pEvent.preventDefault();pGalleryNav.closeViewer();return;case'ArrowRight':case'j':pEvent.preventDefault();pGalleryNav.nextFile();return;case'ArrowLeft':case'k':pEvent.preventDefault();pGalleryNav.prevFile();return;case'e':pEvent.preventDefault();let tmpVEX=pGalleryNav.pict.views['RetoldRemote-VideoExplorer'];if(tmpVEX){tmpVEX.showExplorer(tmpRemote.CurrentViewerFile);}return;case' ':case'Enter':pEvent.preventDefault();let tmpViewer=pGalleryNav.pict.views['RetoldRemote-MediaViewer'];if(tmpViewer){tmpViewer.playVideo();}return;case't':pEvent.preventDefault();let tmpMediaViewer=pGalleryNav.pict.views['RetoldRemote-MediaViewer'];if(tmpMediaViewer){tmpMediaViewer.loadVideoMenuFrame();}return;case'v':pEvent.preventDefault();pGalleryNav._streamWithVLC();return;case'a':pEvent.preventDefault();{let tmpMenuCollMgr=pGalleryNav.pict.providers['RetoldRemote-CollectionManager'];if(tmpMenuCollMgr){let tmpMenuQuickGUID=tmpMenuCollMgr.getQuickAddTargetGUID();if(tmpMenuQuickGUID){tmpMenuCollMgr.addCurrentFileToCollection(tmpMenuQuickGUID);}else{let tmpMenuTopBar=pGalleryNav.pict.views['ContentEditor-TopBar'];if(tmpMenuTopBar&&typeof tmpMenuTopBar.showAddToCollectionDropdown==='function'){tmpMenuTopBar.showAddToCollectionDropdown();}}}}return;case'b':pEvent.preventDefault();{let tmpMenuCollManager=pGalleryNav.pict.providers['RetoldRemote-CollectionManager'];if(tmpMenuCollManager){tmpMenuCollManager.togglePanel();}}return;case'h':pEvent.preventDefault();{let tmpMenuFavManager=pGalleryNav.pict.providers['RetoldRemote-CollectionManager'];if(tmpMenuFavManager){tmpMenuFavManager.toggleFavorite();}}return;}return;}switch(pEvent.key){case'Escape':pEvent.preventDefault();pGalleryNav.closeViewer();break;case'ArrowRight':case'j':pEvent.preventDefault();pGalleryNav.nextFile();break;case'ArrowLeft':case'k':pEvent.preventDefault();pGalleryNav.prevFile();break;case'f':pEvent.preventDefault();pGalleryNav._toggleDistractionFree();break;case'i':pEvent.preventDefault();pGalleryNav._toggleFileInfo();break;case' ':pEvent.preventDefault();pGalleryNav._togglePlayPause();break;case'+':case'=':pEvent.preventDefault();pGalleryNav._zoomIn();break;case'-':pEvent.preventDefault();pGalleryNav._zoomOut();break;case'0':pEvent.preventDefault();pGalleryNav._zoomReset();break;case'z':pEvent.preventDefault();pGalleryNav._cycleFitMode();break;case'
|
|
10850
|
+
if(tmpRemote.VideoMenuActive&&tmpRemote.CurrentViewerMediaType==='video'){switch(pEvent.key){case'Escape':pEvent.preventDefault();pGalleryNav.closeViewer();return;case'ArrowRight':case'j':pEvent.preventDefault();pGalleryNav.nextFile();return;case'ArrowLeft':case'k':pEvent.preventDefault();pGalleryNav.prevFile();return;case'e':pEvent.preventDefault();let tmpVEX=pGalleryNav.pict.views['RetoldRemote-VideoExplorer'];if(tmpVEX){tmpVEX.showExplorer(tmpRemote.CurrentViewerFile);}return;case' ':case'Enter':pEvent.preventDefault();let tmpViewer=pGalleryNav.pict.views['RetoldRemote-MediaViewer'];if(tmpViewer){tmpViewer.playVideo();}return;case't':pEvent.preventDefault();let tmpMediaViewer=pGalleryNav.pict.views['RetoldRemote-MediaViewer'];if(tmpMediaViewer){tmpMediaViewer.loadVideoMenuFrame();}return;case'v':pEvent.preventDefault();pGalleryNav._streamWithVLC();return;case'a':pEvent.preventDefault();{let tmpMenuCollMgr=pGalleryNav.pict.providers['RetoldRemote-CollectionManager'];if(tmpMenuCollMgr){let tmpMenuQuickGUID=tmpMenuCollMgr.getQuickAddTargetGUID();if(tmpMenuQuickGUID){tmpMenuCollMgr.addCurrentFileToCollection(tmpMenuQuickGUID);}else{let tmpMenuTopBar=pGalleryNav.pict.views['ContentEditor-TopBar'];if(tmpMenuTopBar&&typeof tmpMenuTopBar.showAddToCollectionDropdown==='function'){tmpMenuTopBar.showAddToCollectionDropdown();}}}}return;case'b':pEvent.preventDefault();{let tmpMenuCollManager=pGalleryNav.pict.providers['RetoldRemote-CollectionManager'];if(tmpMenuCollManager){tmpMenuCollManager.togglePanel();}}return;case'h':pEvent.preventDefault();{let tmpMenuFavManager=pGalleryNav.pict.providers['RetoldRemote-CollectionManager'];if(tmpMenuFavManager){tmpMenuFavManager.toggleFavorite();}}return;}return;}switch(pEvent.key){case'Escape':pEvent.preventDefault();pGalleryNav.closeViewer();break;case'ArrowRight':case'j':pEvent.preventDefault();pGalleryNav.nextFile();break;case'ArrowLeft':case'k':pEvent.preventDefault();pGalleryNav.prevFile();break;case'f':pEvent.preventDefault();pGalleryNav._toggleDistractionFree();break;case'i':pEvent.preventDefault();pGalleryNav._toggleFileInfo();break;case' ':pEvent.preventDefault();pGalleryNav._togglePlayPause();break;case'+':case'=':pEvent.preventDefault();pGalleryNav._zoomIn();break;case'-':pEvent.preventDefault();pGalleryNav._zoomOut();break;case'0':pEvent.preventDefault();pGalleryNav._zoomReset();break;case'z':pEvent.preventDefault();pGalleryNav._cycleFitMode();break;case's':pEvent.preventDefault();{let tmpMediaViewer=pGalleryNav.pict.views['RetoldRemote-MediaViewer'];if(tmpMediaViewer){let tmpViewerMediaType=tmpRemote.CurrentViewerMediaType;if(tmpViewerMediaType==='document'){// Toggle region selection for EPUB or PDF
|
|
10851
|
+
if(typeof tmpMediaViewer.ebookToggleRegionSelect==='function'&&tmpMediaViewer._activeRendition){tmpMediaViewer.ebookToggleRegionSelect();}else if(typeof tmpMediaViewer.pdfToggleRegionSelect==='function'&&tmpMediaViewer._pdfDocument){tmpMediaViewer.pdfToggleRegionSelect();}}}}break;case'Enter':pEvent.preventDefault();pGalleryNav._streamWithVLC();break;case'v':pEvent.preventDefault();pGalleryNav._streamWithVLC();break;case'a':pEvent.preventDefault();{let tmpCollMgr=pGalleryNav.pict.providers['RetoldRemote-CollectionManager'];if(tmpCollMgr){let tmpQuickGUID=tmpCollMgr.getQuickAddTargetGUID();if(tmpQuickGUID){// Quick-add the currently viewed file
|
|
10828
10852
|
tmpCollMgr.addCurrentFileToCollection(tmpQuickGUID);}else{// No active or last-used collection — open the picker
|
|
10829
10853
|
let tmpTopBar=pGalleryNav.pict.views['ContentEditor-TopBar'];if(tmpTopBar&&typeof tmpTopBar.showAddToCollectionDropdown==='function'){tmpTopBar.showAddToCollectionDropdown();}}}}break;case'b':pEvent.preventDefault();{let tmpCollManager=pGalleryNav.pict.providers['RetoldRemote-CollectionManager'];if(tmpCollManager){tmpCollManager.togglePanel();}}break;case'd':pEvent.preventDefault();pGalleryNav._toggleDistractionFree();break;case'e':pEvent.preventDefault();{let tmpMediaType=tmpRemote.CurrentViewerMediaType;if(tmpMediaType==='video'){let tmpVEX=pGalleryNav.pict.views['RetoldRemote-VideoExplorer'];if(tmpVEX){tmpVEX.showExplorer(tmpRemote.CurrentViewerFile);}}else if(tmpMediaType==='audio'){let tmpAEX=pGalleryNav.pict.views['RetoldRemote-AudioExplorer'];if(tmpAEX){tmpAEX.showExplorer(tmpRemote.CurrentViewerFile);}}else if(tmpMediaType==='image'){let tmpIEX=pGalleryNav.pict.views['RetoldRemote-ImageExplorer'];if(tmpIEX){tmpIEX.showExplorer(tmpRemote.CurrentViewerFile);}}}break;case'1':pEvent.preventDefault();pGalleryNav.switchViewerType('image');break;case'2':pEvent.preventDefault();pGalleryNav.switchViewerType('video');break;case'3':pEvent.preventDefault();pGalleryNav.switchViewerType('audio');break;case'4':pEvent.preventDefault();pGalleryNav.switchViewerType('text');break;case'h':pEvent.preventDefault();{let tmpFavCollManager=pGalleryNav.pict.providers['RetoldRemote-CollectionManager'];if(tmpFavCollManager){tmpFavCollManager.toggleFavorite();}}break;}}module.exports=handleViewerKey;},{}],137:[function(require,module,exports){/**
|
|
10830
10854
|
* MediaViewer — Code Viewer Mixin
|
|
@@ -10862,7 +10886,8 @@ let tmpLineCount=pText.split('\n').length;let tmpLineHTML='';for(let i=1;i<=tmpL
|
|
|
10862
10886
|
* MediaViewer — Ebook Viewer Mixin
|
|
10863
10887
|
*
|
|
10864
10888
|
* EPUB/MOBI rendering using epub.js, table of contents,
|
|
10865
|
-
* page navigation,
|
|
10889
|
+
* page navigation, text selection capture, visual rectangle
|
|
10890
|
+
* selection, and MOBI-to-EPUB server-side conversion.
|
|
10866
10891
|
*
|
|
10867
10892
|
* Mixed into RetoldRemoteMediaViewerView.prototype via Object.assign().
|
|
10868
10893
|
* All methods access state through `this` (the view instance).
|
|
@@ -10870,7 +10895,7 @@ let tmpLineCount=pText.split('\n').length;let tmpLineHTML='';for(let i=1;i<=tmpL
|
|
|
10870
10895
|
* @license MIT
|
|
10871
10896
|
*/module.exports={/**
|
|
10872
10897
|
* Build the HTML shell for the ebook reader.
|
|
10873
|
-
*/_buildEbookHTML:function _buildEbookHTML(pURL,pFileName,pFilePath){return'<div class="retold-remote-ebook-wrap">'+'<div class="retold-remote-ebook-toc collapsed" id="RetoldRemote-EbookTOC">'+'<div class="retold-remote-ebook-toc-header">'+'<span>Contents</span>'+'<button class="retold-remote-ebook-toc-close" onclick="pict.views[\'RetoldRemote-MediaViewer\'].toggleEbookTOC()" title="Close">×</button>'+'</div>'+'<div class="retold-remote-ebook-toc-items" id="RetoldRemote-EbookTOCItems"></div>'+'</div>'+'<div class="retold-remote-ebook-reader">'+'<div class="retold-remote-ebook-content" id="RetoldRemote-EbookContent">'+'<div class="retold-remote-ebook-loading">Loading ebook...</div>'+'</div>'+'<div class="retold-remote-ebook-controls">'+'<button class="retold-remote-ebook-toc-btn" onclick="pict.views[\'RetoldRemote-MediaViewer\'].toggleEbookTOC()">☰ TOC</button>'+'<button class="retold-remote-ebook-page-btn" onclick="pict.views[\'RetoldRemote-MediaViewer\'].ebookPrevPage()">← Prev</button>'+'<button class="retold-remote-ebook-page-btn" onclick="pict.views[\'RetoldRemote-MediaViewer\'].ebookNextPage()">Next →</button>'+'</div>'+'</div>'+'</div>';},/**
|
|
10898
|
+
*/_buildEbookHTML:function _buildEbookHTML(pURL,pFileName,pFilePath){return'<div class="retold-remote-ebook-wrap">'+'<div class="retold-remote-ebook-toc collapsed" id="RetoldRemote-EbookTOC">'+'<div class="retold-remote-ebook-toc-header">'+'<span>Contents</span>'+'<button class="retold-remote-ebook-toc-close" onclick="pict.views[\'RetoldRemote-MediaViewer\'].toggleEbookTOC()" title="Close">×</button>'+'</div>'+'<div class="retold-remote-ebook-toc-items" id="RetoldRemote-EbookTOCItems"></div>'+'</div>'+'<div class="retold-remote-ebook-reader">'+'<div class="retold-remote-ebook-content" id="RetoldRemote-EbookContent">'+'<div class="retold-remote-ebook-loading">Loading ebook...</div>'+'</div>'+'<div class="retold-remote-ebook-controls">'+'<button class="retold-remote-ebook-toc-btn" onclick="pict.views[\'RetoldRemote-MediaViewer\'].toggleEbookTOC()">☰ TOC</button>'+'<button class="retold-remote-ebook-page-btn" onclick="pict.views[\'RetoldRemote-MediaViewer\'].ebookPrevPage()">← Prev</button>'+'<button class="retold-remote-ebook-page-btn" onclick="pict.views[\'RetoldRemote-MediaViewer\'].ebookNextPage()">Next →</button>'+'<span style="flex:1;"></span>'+'<button class="retold-remote-ebook-page-btn" onclick="pict.views[\'RetoldRemote-MediaViewer\'].ebookSaveSelection()">💾 Save Selection</button>'+'<button class="retold-remote-ebook-page-btn" id="RetoldRemote-EbookRegionSelectBtn" onclick="pict.views[\'RetoldRemote-MediaViewer\'].ebookToggleRegionSelect()">✂ Select Region</button>'+'</div>'+'<div class="retold-remote-ebook-controls" id="RetoldRemote-EbookLabelInput" style="display:none;">'+'<input type="text" id="RetoldRemote-EbookLabelField" placeholder="Label..." '+'style="flex:1; padding:4px 8px; background:var(--retold-bg-secondary, #2d2d2d); color:var(--retold-text-primary, #d4d4d4); border:1px solid var(--retold-border, #444); border-radius:4px;" '+'onkeydown="if(event.key===\'Enter\'){pict.views[\'RetoldRemote-MediaViewer\'].ebookSaveLabel();}">'+'<button class="retold-remote-ebook-page-btn" onclick="pict.views[\'RetoldRemote-MediaViewer\'].ebookSaveLabel()">Save</button>'+'<button class="retold-remote-ebook-page-btn" onclick="pict.views[\'RetoldRemote-MediaViewer\'].ebookCancelSelection()">Cancel</button>'+'</div>'+'</div>'+'</div>';},/**
|
|
10874
10899
|
* Load and render an ebook using epub.js.
|
|
10875
10900
|
* For EPUB files, fetch directly. For MOBI files, convert server-side first.
|
|
10876
10901
|
*
|
|
@@ -10903,7 +10928,179 @@ tmpBook.loaded.navigation.then(pNav=>{tmpSelf._renderEbookTOC(pNav.toc);});}).ca
|
|
|
10903
10928
|
* Go to the next page in the ebook.
|
|
10904
10929
|
*/ebookNextPage:function ebookNextPage(){if(this._activeRendition){this._activeRendition.next();}},/**
|
|
10905
10930
|
* Toggle the table of contents sidebar.
|
|
10906
|
-
*/toggleEbookTOC:function toggleEbookTOC(){let tmpTocEl=document.getElementById('RetoldRemote-EbookTOC');if(tmpTocEl){tmpTocEl.classList.toggle('collapsed');}}
|
|
10931
|
+
*/toggleEbookTOC:function toggleEbookTOC(){let tmpTocEl=document.getElementById('RetoldRemote-EbookTOC');if(tmpTocEl){tmpTocEl.classList.toggle('collapsed');}},/**
|
|
10932
|
+
* Capture the current text selection from the epub.js rendition,
|
|
10933
|
+
* derive a CFI, and show the label input for saving.
|
|
10934
|
+
*/ebookSaveSelection:function ebookSaveSelection(){let tmpSelf=this;if(!this._activeRendition){this.pict.providers['RetoldRemote-ToastNotification'].showToast('No ebook loaded.');return;}let tmpContents=this._activeRendition.getContents();if(!tmpContents||tmpContents.length<1){this.pict.providers['RetoldRemote-ToastNotification'].showToast('Unable to access ebook contents.');return;}let tmpDoc=tmpContents[0].document;let tmpSelection=tmpDoc.getSelection();let tmpSelectedText=tmpSelection?tmpSelection.toString():'';if(!tmpSelectedText||tmpSelectedText.trim().length===0){this.pict.providers['RetoldRemote-ToastNotification'].showToast('Select text first.');return;}// Derive the CFI from the selection range
|
|
10935
|
+
let tmpCFI='';try{let tmpRange=tmpSelection.getRangeAt(0);tmpCFI=tmpContents[0].cfiFromRange(tmpRange);}catch(pError){this.pict.log.warn('Could not derive CFI from selection: '+pError.message);}// Get current location for spine index
|
|
10936
|
+
let tmpLocation=this._activeRendition.currentLocation();let tmpSpineIndex=tmpLocation&&tmpLocation.start?tmpLocation.start.index:-1;// Try to find the chapter title from the TOC
|
|
10937
|
+
let tmpChapterTitle='';try{let tmpTocItems=document.querySelectorAll('#RetoldRemote-EbookTOCItems .retold-remote-ebook-toc-item');if(tmpTocItems.length>0&&tmpSpineIndex>=0){// Best effort: use the TOC item closest to the spine index
|
|
10938
|
+
let tmpTocIndex=Math.min(tmpSpineIndex,tmpTocItems.length-1);tmpChapterTitle=tmpTocItems[tmpTocIndex].textContent.trim();}}catch(pError){// Chapter title is best-effort; ignore errors
|
|
10939
|
+
}// Store pending selection data on the view instance
|
|
10940
|
+
this._pendingEbookSelection={Type:'text-selection',CFI:tmpCFI,SpineIndex:tmpSpineIndex,ChapterTitle:tmpChapterTitle,SelectedText:tmpSelectedText};// Show the label input
|
|
10941
|
+
let tmpLabelInput=document.getElementById('RetoldRemote-EbookLabelInput');if(tmpLabelInput){tmpLabelInput.style.display='';}let tmpLabelField=document.getElementById('RetoldRemote-EbookLabelField');if(tmpLabelField){tmpLabelField.value='';tmpLabelField.focus();}},/**
|
|
10942
|
+
* Toggle visual rectangle selection mode over the ebook content area.
|
|
10943
|
+
* When enabled, an overlay captures mouse events to draw a rectangle.
|
|
10944
|
+
*/ebookToggleRegionSelect:function ebookToggleRegionSelect(){let tmpSelf=this;let tmpContentEl=document.getElementById('RetoldRemote-EbookContent');let tmpToggleBtn=document.getElementById('RetoldRemote-EbookRegionSelectBtn');if(!tmpContentEl){return;}// If overlay already exists, remove it (toggle off)
|
|
10945
|
+
let tmpExistingOverlay=document.getElementById('RetoldRemote-EbookRegionOverlay');if(tmpExistingOverlay){tmpExistingOverlay.remove();if(tmpToggleBtn){tmpToggleBtn.style.background='';}this._ebookRegionActive=false;return;}this._ebookRegionActive=true;if(tmpToggleBtn){tmpToggleBtn.style.background='var(--retold-accent, #569cd6)';}// Create a transparent overlay div
|
|
10946
|
+
let tmpOverlay=document.createElement('div');tmpOverlay.id='RetoldRemote-EbookRegionOverlay';tmpOverlay.style.cssText='position:absolute; top:0; left:0; width:100%; height:100%; '+'cursor:crosshair; z-index:100; user-select:none;';tmpContentEl.style.position='relative';tmpContentEl.appendChild(tmpOverlay);let tmpDrawing=false;let tmpStartX=0;let tmpStartY=0;let tmpRectEl=null;tmpOverlay.addEventListener('mousedown',function(pEvent){pEvent.preventDefault();pEvent.stopPropagation();// Remove any previous rectangle
|
|
10947
|
+
let tmpOldRect=document.getElementById('RetoldRemote-EbookRegionRect');if(tmpOldRect){tmpOldRect.remove();}let tmpBounds=tmpOverlay.getBoundingClientRect();tmpStartX=pEvent.clientX-tmpBounds.left;tmpStartY=pEvent.clientY-tmpBounds.top;tmpDrawing=true;tmpRectEl=document.createElement('div');tmpRectEl.id='RetoldRemote-EbookRegionRect';tmpRectEl.style.cssText='position:absolute; border:2px dashed var(--retold-accent, #569cd6); '+'background:rgba(86, 156, 214, 0.15); pointer-events:none;';tmpRectEl.style.left=tmpStartX+'px';tmpRectEl.style.top=tmpStartY+'px';tmpRectEl.style.width='0px';tmpRectEl.style.height='0px';tmpOverlay.appendChild(tmpRectEl);});tmpOverlay.addEventListener('mousemove',function(pEvent){if(!tmpDrawing||!tmpRectEl){return;}pEvent.preventDefault();let tmpBounds=tmpOverlay.getBoundingClientRect();let tmpCurrentX=pEvent.clientX-tmpBounds.left;let tmpCurrentY=pEvent.clientY-tmpBounds.top;let tmpLeft=Math.min(tmpStartX,tmpCurrentX);let tmpTop=Math.min(tmpStartY,tmpCurrentY);let tmpWidth=Math.abs(tmpCurrentX-tmpStartX);let tmpHeight=Math.abs(tmpCurrentY-tmpStartY);tmpRectEl.style.left=tmpLeft+'px';tmpRectEl.style.top=tmpTop+'px';tmpRectEl.style.width=tmpWidth+'px';tmpRectEl.style.height=tmpHeight+'px';});tmpOverlay.addEventListener('mouseup',function(pEvent){if(!tmpDrawing||!tmpRectEl){return;}pEvent.preventDefault();tmpDrawing=false;let tmpBounds=tmpOverlay.getBoundingClientRect();let tmpEndX=pEvent.clientX-tmpBounds.left;let tmpEndY=pEvent.clientY-tmpBounds.top;let tmpRegionLeft=Math.min(tmpStartX,tmpEndX);let tmpRegionTop=Math.min(tmpStartY,tmpEndY);let tmpRegionWidth=Math.abs(tmpEndX-tmpStartX);let tmpRegionHeight=Math.abs(tmpEndY-tmpStartY);// Ignore tiny accidental drags
|
|
10948
|
+
if(tmpRegionWidth<5||tmpRegionHeight<5){if(tmpRectEl){tmpRectEl.remove();tmpRectEl=null;}return;}let tmpViewportWidth=tmpOverlay.offsetWidth;let tmpViewportHeight=tmpOverlay.offsetHeight;// Best-effort text extraction from the rectangle area
|
|
10949
|
+
let tmpExtractedText='';try{let tmpContents=tmpSelf._activeRendition.getContents();if(tmpContents&&tmpContents.length>0){let tmpDoc=tmpContents[0].document;let tmpBody=tmpDoc.body;if(tmpBody){// Walk text nodes and check if any fall within the rectangle
|
|
10950
|
+
let tmpTreeWalker=tmpDoc.createTreeWalker(tmpBody,NodeFilter.SHOW_TEXT,null,false);let tmpTextParts=[];let tmpNode;while(tmpNode=tmpTreeWalker.nextNode()){if(!tmpNode.textContent||tmpNode.textContent.trim().length===0){continue;}let tmpRange=tmpDoc.createRange();tmpRange.selectNodeContents(tmpNode);let tmpRects=tmpRange.getClientRects();for(let i=0;i<tmpRects.length;i++){let tmpR=tmpRects[i];// Check overlap with the drawn rectangle
|
|
10951
|
+
if(tmpR.right>=tmpRegionLeft&&tmpR.left<=tmpRegionLeft+tmpRegionWidth&&tmpR.bottom>=tmpRegionTop&&tmpR.top<=tmpRegionTop+tmpRegionHeight){tmpTextParts.push(tmpNode.textContent.trim());break;}}}tmpExtractedText=tmpTextParts.join(' ');}}}catch(pError){// Text extraction from region is best-effort
|
|
10952
|
+
tmpSelf.pict.log.warn('Region text extraction failed: '+pError.message);}// Get current location for spine index
|
|
10953
|
+
let tmpLocation=tmpSelf._activeRendition.currentLocation();let tmpSpineIndex=tmpLocation&&tmpLocation.start?tmpLocation.start.index:-1;// Store pending selection data
|
|
10954
|
+
tmpSelf._pendingEbookSelection={Type:'visual-region',X:Math.round(tmpRegionLeft),Y:Math.round(tmpRegionTop),Width:Math.round(tmpRegionWidth),Height:Math.round(tmpRegionHeight),ViewportWidth:tmpViewportWidth,ViewportHeight:tmpViewportHeight,SpineIndex:tmpSpineIndex,SelectedText:tmpExtractedText};// Show the label input
|
|
10955
|
+
let tmpLabelInput=document.getElementById('RetoldRemote-EbookLabelInput');if(tmpLabelInput){tmpLabelInput.style.display='';}let tmpLabelField=document.getElementById('RetoldRemote-EbookLabelField');if(tmpLabelField){tmpLabelField.value='';tmpLabelField.focus();}});},/**
|
|
10956
|
+
* Cancel any in-progress selection or region, hide the label input,
|
|
10957
|
+
* and remove the region overlay if present.
|
|
10958
|
+
*/ebookCancelSelection:function ebookCancelSelection(){// Hide the label input
|
|
10959
|
+
let tmpLabelInput=document.getElementById('RetoldRemote-EbookLabelInput');if(tmpLabelInput){tmpLabelInput.style.display='none';}// Clear the label field
|
|
10960
|
+
let tmpLabelField=document.getElementById('RetoldRemote-EbookLabelField');if(tmpLabelField){tmpLabelField.value='';}// Remove region overlay and rectangle if present
|
|
10961
|
+
let tmpRect=document.getElementById('RetoldRemote-EbookRegionRect');if(tmpRect){tmpRect.remove();}let tmpOverlay=document.getElementById('RetoldRemote-EbookRegionOverlay');if(tmpOverlay){tmpOverlay.remove();}// Reset toggle button style
|
|
10962
|
+
let tmpToggleBtn=document.getElementById('RetoldRemote-EbookRegionSelectBtn');if(tmpToggleBtn){tmpToggleBtn.style.background='';}this._ebookRegionActive=false;this._pendingEbookSelection=null;},/**
|
|
10963
|
+
* Save the pending selection with the label from the input field.
|
|
10964
|
+
* POSTs to /api/media/subimage-regions and updates the sidebar.
|
|
10965
|
+
*/ebookSaveLabel:function ebookSaveLabel(){let tmpSelf=this;if(!this._pendingEbookSelection){this.pict.providers['RetoldRemote-ToastNotification'].showToast('No selection to save.');return;}let tmpLabelField=document.getElementById('RetoldRemote-EbookLabelField');let tmpLabelValue=tmpLabelField?tmpLabelField.value.trim():'';if(!tmpLabelValue){this.pict.providers['RetoldRemote-ToastNotification'].showToast('Enter a label for the selection.');return;}let tmpRegion=this._pendingEbookSelection;tmpRegion.Label=tmpLabelValue;let tmpPayload={Path:this.pict.AppData.RetoldRemote.CurrentViewerFile,Region:tmpRegion};fetch('/api/media/subimage-regions',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(tmpPayload)}).then(pResponse=>{if(!pResponse.ok){throw new Error('HTTP '+pResponse.status);}return pResponse.json();}).then(pData=>{tmpSelf.pict.providers['RetoldRemote-ToastNotification'].showToast('Selection saved: '+tmpLabelValue);// Clean up the selection state and UI
|
|
10966
|
+
tmpSelf.ebookCancelSelection();// Refresh the sidebar panel if a regions panel method exists
|
|
10967
|
+
if(typeof tmpSelf.refreshSubimageRegions==='function'){tmpSelf.refreshSubimageRegions();}}).catch(pError=>{tmpSelf.pict.providers['RetoldRemote-ToastNotification'].showToast('Failed to save selection: '+pError.message);tmpSelf.pict.log.error('Ebook selection save error: '+pError.message);});}};},{}],139:[function(_require,module,exports){/**
|
|
10968
|
+
* MediaViewer — PDF Viewer Mixin
|
|
10969
|
+
*
|
|
10970
|
+
* Full pdf.js canvas renderer with text layer, page navigation,
|
|
10971
|
+
* zoom controls, text selection saving, and visual region selection.
|
|
10972
|
+
*
|
|
10973
|
+
* Mixed into RetoldRemoteMediaViewerView.prototype via Object.assign().
|
|
10974
|
+
* All methods access state through `this` (the view instance).
|
|
10975
|
+
*
|
|
10976
|
+
* @license MIT
|
|
10977
|
+
*/const _PDF_JS_CDN_URL='https://cdnjs.cloudflare.com/ajax/libs/pdf.js/4.9.155/pdf.min.mjs';const _PDF_JS_WORKER_CDN_URL='https://cdnjs.cloudflare.com/ajax/libs/pdf.js/4.9.155/pdf.worker.min.mjs';module.exports={/**
|
|
10978
|
+
* Build the HTML shell for the PDF viewer.
|
|
10979
|
+
*
|
|
10980
|
+
* @param {string} pURL - Content URL for the file
|
|
10981
|
+
* @param {string} pFileName - Display file name
|
|
10982
|
+
* @param {string} pFilePath - Relative file path
|
|
10983
|
+
* @returns {string} HTML string
|
|
10984
|
+
*/_buildPdfHTML:function _buildPdfHTML(pURL,pFileName,pFilePath){let tmpViewRef="pict.views['RetoldRemote-MediaViewer']";let tmpHTML='<div class="retold-remote-pdf-viewer">';// Controls bar
|
|
10985
|
+
tmpHTML+='<div class="retold-remote-pdf-controls" id="RetoldRemote-PdfControls">';tmpHTML+='<button class="retold-remote-pdf-btn" onclick="'+tmpViewRef+'.pdfPrevPage()" title="Previous page">← Prev</button>';tmpHTML+='<span class="retold-remote-pdf-page-info">';tmpHTML+='Page <input type="number" id="RetoldRemote-PdfPageInput" class="retold-remote-pdf-page-input" value="1" min="1" '+'onchange="'+tmpViewRef+'.pdfGoToPage(parseInt(this.value,10))" '+'onkeydown="if(event.key===\'Enter\'){'+tmpViewRef+'.pdfGoToPage(parseInt(this.value,10));event.preventDefault();}">';tmpHTML+=' of <span id="RetoldRemote-PdfPageCount">0</span>';tmpHTML+='</span>';tmpHTML+='<button class="retold-remote-pdf-btn" onclick="'+tmpViewRef+'.pdfNextPage()" title="Next page">Next →</button>';tmpHTML+='<span class="retold-remote-pdf-separator"></span>';tmpHTML+='<button class="retold-remote-pdf-btn" onclick="'+tmpViewRef+'.pdfSaveSelection()" title="Save selected text">💾 Save Selection</button>';tmpHTML+='<button class="retold-remote-pdf-btn" id="RetoldRemote-PdfRegionBtn" onclick="'+tmpViewRef+'.pdfToggleRegionSelect()" title="Select a visual region">✂ Select Region</button>';tmpHTML+='<span class="retold-remote-pdf-separator"></span>';tmpHTML+='<button class="retold-remote-pdf-btn" onclick="'+tmpViewRef+'.pdfZoomIn()" title="Zoom in (+)">+ Zoom In</button>';tmpHTML+='<span class="retold-remote-pdf-zoom-label" id="RetoldRemote-PdfZoomLabel">150%</span>';tmpHTML+='<button class="retold-remote-pdf-btn" onclick="'+tmpViewRef+'.pdfZoomOut()" title="Zoom out (-)">- Zoom Out</button>';tmpHTML+='<button class="retold-remote-pdf-btn" onclick="'+tmpViewRef+'.pdfZoomFit()" title="Fit to width">Fit</button>';tmpHTML+='</div>';// Content area
|
|
10986
|
+
tmpHTML+='<div class="retold-remote-pdf-content" id="RetoldRemote-PdfContent">';tmpHTML+='<div class="retold-remote-pdf-wrap" id="RetoldRemote-PdfWrap">';tmpHTML+='<canvas id="RetoldRemote-PdfCanvas"></canvas>';tmpHTML+='<div id="RetoldRemote-PdfTextLayer" class="retold-remote-pdf-text-layer"></div>';tmpHTML+='<div id="RetoldRemote-PdfSelectionOverlay" class="retold-remote-pdf-selection-overlay" style="display:none;"></div>';tmpHTML+='<div id="RetoldRemote-PdfRegionOverlays" class="retold-remote-pdf-region-overlays"></div>';tmpHTML+='</div>';tmpHTML+='<div class="retold-remote-pdf-loading" id="RetoldRemote-PdfLoading">Loading PDF...</div>';tmpHTML+='</div>';// Inline label input (hidden until needed)
|
|
10987
|
+
tmpHTML+='<div class="retold-remote-pdf-label-bar" id="RetoldRemote-PdfLabelInput" style="display:none;">';tmpHTML+='<input type="text" id="RetoldRemote-PdfLabelField" class="retold-remote-pdf-label-field" placeholder="Label this selection\u2026" '+'onkeydown="if(event.key===\'Enter\'){'+tmpViewRef+'.pdfSaveLabel();event.preventDefault();event.stopPropagation();}'+'if(event.key===\'Escape\'){'+tmpViewRef+'.pdfCancelSelection();event.preventDefault();event.stopPropagation();}">';tmpHTML+='<button class="retold-remote-pdf-btn" onclick="'+tmpViewRef+'.pdfSaveLabel()">Save</button>';tmpHTML+='<button class="retold-remote-pdf-btn" onclick="'+tmpViewRef+'.pdfCancelSelection()">Cancel</button>';tmpHTML+='</div>';tmpHTML+='</div>';// Inline styles for the PDF viewer
|
|
10988
|
+
tmpHTML+='<style>';tmpHTML+='.retold-remote-pdf-viewer { display: flex; flex-direction: column; height: 100%; overflow: hidden; }';tmpHTML+='.retold-remote-pdf-controls { display: flex; align-items: center; gap: 6px; padding: 6px 12px; background: var(--retold-bg-secondary, #252526); border-bottom: 1px solid var(--retold-border, #3e4451); flex-shrink: 0; flex-wrap: wrap; }';tmpHTML+='.retold-remote-pdf-btn { background: var(--retold-bg-tertiary, #2d2d2d); color: var(--retold-text-primary, #abb2bf); border: 1px solid var(--retold-border, #3e4451); border-radius: 4px; padding: 4px 10px; font-size: 0.78rem; cursor: pointer; white-space: nowrap; }';tmpHTML+='.retold-remote-pdf-btn:hover { background: var(--retold-bg-hover, #3e4451); }';tmpHTML+='.retold-remote-pdf-btn.active { background: var(--retold-accent, #569cd6); color: #fff; }';tmpHTML+='.retold-remote-pdf-page-info { font-size: 0.78rem; color: var(--retold-text-secondary, #8b949e); display: flex; align-items: center; gap: 4px; }';tmpHTML+='.retold-remote-pdf-page-input { width: 48px; background: var(--retold-bg-input, #1e1e1e); color: var(--retold-text-primary, #abb2bf); border: 1px solid var(--retold-border, #3e4451); border-radius: 4px; padding: 2px 6px; font-size: 0.78rem; text-align: center; }';tmpHTML+='.retold-remote-pdf-separator { width: 1px; height: 20px; background: var(--retold-border, #3e4451); margin: 0 4px; }';tmpHTML+='.retold-remote-pdf-zoom-label { font-size: 0.78rem; color: var(--retold-text-secondary, #8b949e); min-width: 40px; text-align: center; }';tmpHTML+='.retold-remote-pdf-content { flex: 1; overflow: auto; position: relative; background: var(--retold-bg-primary, #1e1e1e); }';tmpHTML+='.retold-remote-pdf-wrap { position: relative; display: inline-block; margin: 16px auto; }';tmpHTML+='.retold-remote-pdf-content { text-align: center; }';tmpHTML+='.retold-remote-pdf-text-layer { position: absolute; top: 0; left: 0; overflow: hidden; opacity: 0.25; line-height: 1.0; }';tmpHTML+='.retold-remote-pdf-text-layer > span { position: absolute; white-space: pre; color: transparent; }';tmpHTML+='.retold-remote-pdf-text-layer ::selection { background: rgba(86, 156, 214, 0.4); }';tmpHTML+='.retold-remote-pdf-selection-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; cursor: crosshair; z-index: 5; }';tmpHTML+='.retold-remote-pdf-region-overlays { position: absolute; top: 0; left: 0; pointer-events: none; }';tmpHTML+='.retold-remote-pdf-region-rect { position: absolute; border: 2px solid rgba(86, 156, 214, 0.8); background: rgba(86, 156, 214, 0.12); pointer-events: none; }';tmpHTML+='.retold-remote-pdf-region-label { position: absolute; bottom: -18px; left: 0; font-size: 0.65rem; color: var(--retold-accent, #569cd6); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 160px; pointer-events: none; }';tmpHTML+='.retold-remote-pdf-active-rect { position: absolute; border: 2px dashed rgba(214, 156, 86, 0.9); background: rgba(214, 156, 86, 0.15); pointer-events: none; }';tmpHTML+='.retold-remote-pdf-loading { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 0.9rem; color: var(--retold-text-secondary, #8b949e); }';tmpHTML+='.retold-remote-pdf-label-bar { display: flex; align-items: center; gap: 6px; padding: 6px 12px; background: var(--retold-bg-secondary, #252526); border-top: 1px solid var(--retold-border, #3e4451); flex-shrink: 0; }';tmpHTML+='.retold-remote-pdf-label-field { flex: 1; background: var(--retold-bg-input, #1e1e1e); color: var(--retold-text-primary, #abb2bf); border: 1px solid var(--retold-border, #3e4451); border-radius: 4px; padding: 4px 10px; font-size: 0.78rem; }';tmpHTML+='</style>';return tmpHTML;},/**
|
|
10989
|
+
* Load the pdf.js library from CDN (if needed) and open a PDF document.
|
|
10990
|
+
*
|
|
10991
|
+
* @param {string} pContentURL - URL to fetch the PDF from
|
|
10992
|
+
* @param {string} pFilePath - Relative file path
|
|
10993
|
+
*/_loadPdfViewer:function _loadPdfViewer(pContentURL,pFilePath){let tmpSelf=this;// Initialize instance state
|
|
10994
|
+
this._pdfDocument=null;this._pdfCurrentPage=1;this._pdfPageCount=0;this._pdfScale=1.5;this._pdfSelectionMode=false;this._pdfSavedRegions=[];this._pdfPendingRegion=null;this._pdfPendingText=null;this._pdfLibLoaded=false;this._pdfFilePath=pFilePath;this._ensurePdfJsLoaded(function(){tmpSelf._pdfLibLoaded=true;tmpSelf._openPdfDocument(pContentURL);});},/**
|
|
10995
|
+
* Ensure pdf.js is loaded from CDN via dynamic import.
|
|
10996
|
+
*
|
|
10997
|
+
* @param {Function} fCallback - Called when pdf.js is ready
|
|
10998
|
+
*/_ensurePdfJsLoaded:function _ensurePdfJsLoaded(fCallback){if(typeof window!=='undefined'&&window.pdfjsLib){return fCallback();}let tmpSelf=this;let tmpLoadingEl=document.getElementById('RetoldRemote-PdfLoading');if(tmpLoadingEl){tmpLoadingEl.textContent='Loading PDF renderer...';}(specifier=>new Promise(r=>r(`${specifier}`)).then(s=>_interopRequireWildcard(require(s))))(_PDF_JS_CDN_URL).then(function(pModule){window.pdfjsLib=pModule;window.pdfjsLib.GlobalWorkerOptions.workerSrc=_PDF_JS_WORKER_CDN_URL;fCallback();}).catch(function(pError){let tmpEl=document.getElementById('RetoldRemote-PdfLoading');if(tmpEl){tmpEl.textContent='Failed to load PDF renderer: '+pError.message;}});},/**
|
|
10999
|
+
* Open a PDF document from a URL using pdf.js.
|
|
11000
|
+
*
|
|
11001
|
+
* @param {string} pContentURL - URL to fetch the PDF from
|
|
11002
|
+
*/_openPdfDocument:function _openPdfDocument(pContentURL){let tmpSelf=this;let tmpLoadingEl=document.getElementById('RetoldRemote-PdfLoading');if(tmpLoadingEl){tmpLoadingEl.textContent='Opening PDF...';}let tmpLoadingTask=window.pdfjsLib.getDocument(pContentURL);tmpLoadingTask.promise.then(function(pDocument){tmpSelf._pdfDocument=pDocument;tmpSelf._pdfPageCount=pDocument.numPages;tmpSelf._pdfCurrentPage=1;// Update the page count display
|
|
11003
|
+
let tmpCountEl=document.getElementById('RetoldRemote-PdfPageCount');if(tmpCountEl){tmpCountEl.textContent=pDocument.numPages;}let tmpPageInput=document.getElementById('RetoldRemote-PdfPageInput');if(tmpPageInput){tmpPageInput.max=pDocument.numPages;}// Hide loading indicator
|
|
11004
|
+
if(tmpLoadingEl){tmpLoadingEl.style.display='none';}// Render the first page
|
|
11005
|
+
tmpSelf._renderPdfPage(1);// Load saved regions
|
|
11006
|
+
tmpSelf._pdfLoadSavedRegions(tmpSelf._pdfFilePath);}).catch(function(pError){if(tmpLoadingEl){tmpLoadingEl.textContent='Failed to open PDF: '+pError.message;}});},/**
|
|
11007
|
+
* Render a specific page of the PDF onto the canvas.
|
|
11008
|
+
*
|
|
11009
|
+
* @param {number} pPageNumber - 1-based page number
|
|
11010
|
+
*/_renderPdfPage:function _renderPdfPage(pPageNumber){if(!this._pdfDocument){return;}if(pPageNumber<1||pPageNumber>this._pdfPageCount){return;}let tmpSelf=this;this._pdfCurrentPage=pPageNumber;this._pdfDocument.getPage(pPageNumber).then(function(pPage){let tmpViewport=pPage.getViewport({scale:tmpSelf._pdfScale});let tmpCanvas=document.getElementById('RetoldRemote-PdfCanvas');if(!tmpCanvas){return;}let tmpContext=tmpCanvas.getContext('2d');// Set canvas dimensions to match the viewport
|
|
11011
|
+
tmpCanvas.width=tmpViewport.width;tmpCanvas.height=tmpViewport.height;// Set the wrap container dimensions
|
|
11012
|
+
let tmpWrap=document.getElementById('RetoldRemote-PdfWrap');if(tmpWrap){tmpWrap.style.width=tmpViewport.width+'px';tmpWrap.style.height=tmpViewport.height+'px';}// Render the page onto the canvas
|
|
11013
|
+
let tmpRenderContext={canvasContext:tmpContext,viewport:tmpViewport};pPage.render(tmpRenderContext).promise.then(function(){// After canvas renders, build the text layer
|
|
11014
|
+
tmpSelf._renderPdfTextLayer(pPage,tmpViewport);// Render saved region overlays for this page
|
|
11015
|
+
tmpSelf._pdfRenderRegionOverlays();});// Update the page number input
|
|
11016
|
+
let tmpPageInput=document.getElementById('RetoldRemote-PdfPageInput');if(tmpPageInput){tmpPageInput.value=pPageNumber;}// Update the zoom label
|
|
11017
|
+
tmpSelf._pdfUpdateZoomLabel();}).catch(function(pError){let tmpLoadingEl=document.getElementById('RetoldRemote-PdfLoading');if(tmpLoadingEl){tmpLoadingEl.style.display='';tmpLoadingEl.textContent='Failed to render page: '+pError.message;}});},/**
|
|
11018
|
+
* Render the text layer on top of the canvas so text can be selected.
|
|
11019
|
+
*
|
|
11020
|
+
* @param {Object} pPage - pdf.js page object
|
|
11021
|
+
* @param {Object} pViewport - pdf.js viewport for the current scale
|
|
11022
|
+
*/_renderPdfTextLayer:function _renderPdfTextLayer(pPage,pViewport){let tmpTextLayerEl=document.getElementById('RetoldRemote-PdfTextLayer');if(!tmpTextLayerEl){return;}// Clear previous text layer content
|
|
11023
|
+
tmpTextLayerEl.innerHTML='';// Match text layer dimensions to the canvas
|
|
11024
|
+
tmpTextLayerEl.style.width=pViewport.width+'px';tmpTextLayerEl.style.height=pViewport.height+'px';pPage.getTextContent().then(function(pTextContent){// Use pdf.js built-in renderTextLayer if available
|
|
11025
|
+
if(window.pdfjsLib&&window.pdfjsLib.renderTextLayer){let tmpTask=window.pdfjsLib.renderTextLayer({textContentSource:pTextContent,container:tmpTextLayerEl,viewport:pViewport});tmpTask.promise.catch(function(){// Silently ignore text layer errors
|
|
11026
|
+
});}else{// Manual fallback: position spans from the text content items
|
|
11027
|
+
let tmpItems=pTextContent.items;for(let i=0;i<tmpItems.length;i++){let tmpItem=tmpItems[i];if(!tmpItem.str){continue;}let tmpSpan=document.createElement('span');tmpSpan.textContent=tmpItem.str;// Position from the transform matrix [scaleX, skewX, skewY, scaleY, translateX, translateY]
|
|
11028
|
+
let tmpTx=tmpItem.transform;let tmpFontSize=Math.sqrt(tmpTx[2]*tmpTx[2]+tmpTx[3]*tmpTx[3]);let tmpLeft=tmpTx[4]*(pViewport.width/(pViewport.viewBox[2]-pViewport.viewBox[0]));// PDF coordinates have origin at bottom-left; canvas at top-left
|
|
11029
|
+
let tmpTop=pViewport.height-tmpTx[5]*(pViewport.height/(pViewport.viewBox[3]-pViewport.viewBox[1]));tmpSpan.style.left=tmpLeft+'px';tmpSpan.style.top=tmpTop-tmpFontSize+'px';tmpSpan.style.fontSize=tmpFontSize+'px';tmpSpan.style.fontFamily=tmpItem.fontName||'sans-serif';tmpTextLayerEl.appendChild(tmpSpan);}}});},/**
|
|
11030
|
+
* Update the zoom percentage label.
|
|
11031
|
+
*/_pdfUpdateZoomLabel:function _pdfUpdateZoomLabel(){let tmpLabel=document.getElementById('RetoldRemote-PdfZoomLabel');if(tmpLabel){tmpLabel.textContent=Math.round(this._pdfScale*100)+'%';}},// -----------------------------------------------------------------
|
|
11032
|
+
// Page navigation
|
|
11033
|
+
// -----------------------------------------------------------------
|
|
11034
|
+
/**
|
|
11035
|
+
* Go to the next page.
|
|
11036
|
+
*/pdfNextPage:function pdfNextPage(){if(this._pdfCurrentPage<this._pdfPageCount){this._renderPdfPage(this._pdfCurrentPage+1);}},/**
|
|
11037
|
+
* Go to the previous page.
|
|
11038
|
+
*/pdfPrevPage:function pdfPrevPage(){if(this._pdfCurrentPage>1){this._renderPdfPage(this._pdfCurrentPage-1);}},/**
|
|
11039
|
+
* Jump to a specific page number.
|
|
11040
|
+
*
|
|
11041
|
+
* @param {number} pPageNumber - 1-based page number
|
|
11042
|
+
*/pdfGoToPage:function pdfGoToPage(pPageNumber){if(isNaN(pPageNumber)||pPageNumber<1){pPageNumber=1;}if(pPageNumber>this._pdfPageCount){pPageNumber=this._pdfPageCount;}this._renderPdfPage(pPageNumber);},// -----------------------------------------------------------------
|
|
11043
|
+
// Zoom
|
|
11044
|
+
// -----------------------------------------------------------------
|
|
11045
|
+
/**
|
|
11046
|
+
* Zoom in by 25%.
|
|
11047
|
+
*/pdfZoomIn:function pdfZoomIn(){this._pdfScale=Math.min(this._pdfScale+0.25,5.0);this._renderPdfPage(this._pdfCurrentPage);},/**
|
|
11048
|
+
* Zoom out by 25%.
|
|
11049
|
+
*/pdfZoomOut:function pdfZoomOut(){this._pdfScale=Math.max(this._pdfScale-0.25,0.25);this._renderPdfPage(this._pdfCurrentPage);},/**
|
|
11050
|
+
* Fit the PDF page width to the content area.
|
|
11051
|
+
*/pdfZoomFit:function pdfZoomFit(){if(!this._pdfDocument){return;}let tmpSelf=this;this._pdfDocument.getPage(this._pdfCurrentPage).then(function(pPage){let tmpContentEl=document.getElementById('RetoldRemote-PdfContent');if(!tmpContentEl){return;}// Get the page dimensions at scale 1.0
|
|
11052
|
+
let tmpBaseViewport=pPage.getViewport({scale:1.0});let tmpAvailableWidth=tmpContentEl.clientWidth-32;// Subtract padding
|
|
11053
|
+
let tmpFitScale=tmpAvailableWidth/tmpBaseViewport.width;tmpSelf._pdfScale=Math.max(0.25,Math.min(tmpFitScale,5.0));tmpSelf._renderPdfPage(tmpSelf._pdfCurrentPage);});},// -----------------------------------------------------------------
|
|
11054
|
+
// Text selection saving
|
|
11055
|
+
// -----------------------------------------------------------------
|
|
11056
|
+
/**
|
|
11057
|
+
* Save the currently selected text from the text layer.
|
|
11058
|
+
*/pdfSaveSelection:function pdfSaveSelection(){let tmpSelectedText='';if(typeof window!=='undefined'&&window.getSelection){tmpSelectedText=window.getSelection().toString().trim();}if(!tmpSelectedText){let tmpToast=this.pict.providers['RetoldRemote-ToastNotification'];if(tmpToast){tmpToast.showToast('Select some text in the PDF first.');}return;}this._pdfPendingText=tmpSelectedText;this._pdfPendingRegion=null;// Show the label input bar
|
|
11059
|
+
let tmpLabelBar=document.getElementById('RetoldRemote-PdfLabelInput');if(tmpLabelBar){tmpLabelBar.style.display='';}let tmpField=document.getElementById('RetoldRemote-PdfLabelField');if(tmpField){tmpField.value='';tmpField.placeholder='Label this text selection\u2026';tmpField.focus();}},// -----------------------------------------------------------------
|
|
11060
|
+
// Visual region selection
|
|
11061
|
+
// -----------------------------------------------------------------
|
|
11062
|
+
/**
|
|
11063
|
+
* Toggle the visual region selection mode.
|
|
11064
|
+
*/pdfToggleRegionSelect:function pdfToggleRegionSelect(){this._pdfSelectionMode=!this._pdfSelectionMode;let tmpOverlay=document.getElementById('RetoldRemote-PdfSelectionOverlay');let tmpBtn=document.getElementById('RetoldRemote-PdfRegionBtn');if(this._pdfSelectionMode){if(tmpOverlay){tmpOverlay.style.display='';}if(tmpBtn){tmpBtn.classList.add('active');}this._pdfSetupRegionDrag();}else{if(tmpOverlay){tmpOverlay.style.display='none';tmpOverlay.innerHTML='';}if(tmpBtn){tmpBtn.classList.remove('active');}this._pdfCleanupRegionDrag();}},/**
|
|
11065
|
+
* Set up mouse event handlers for dragging a selection rectangle.
|
|
11066
|
+
*/_pdfSetupRegionDrag:function _pdfSetupRegionDrag(){let tmpSelf=this;let tmpOverlay=document.getElementById('RetoldRemote-PdfSelectionOverlay');if(!tmpOverlay){return;}let tmpDragging=false;let tmpStartX=0;let tmpStartY=0;let tmpRectEl=null;this._pdfRegionMouseDown=function(pEvent){pEvent.preventDefault();tmpDragging=true;let tmpRect=tmpOverlay.getBoundingClientRect();tmpStartX=pEvent.clientX-tmpRect.left;tmpStartY=pEvent.clientY-tmpRect.top;// Create the selection rectangle element
|
|
11067
|
+
tmpRectEl=document.createElement('div');tmpRectEl.className='retold-remote-pdf-active-rect';tmpRectEl.style.left=tmpStartX+'px';tmpRectEl.style.top=tmpStartY+'px';tmpRectEl.style.width='0px';tmpRectEl.style.height='0px';tmpOverlay.appendChild(tmpRectEl);};this._pdfRegionMouseMove=function(pEvent){if(!tmpDragging||!tmpRectEl){return;}let tmpRect=tmpOverlay.getBoundingClientRect();let tmpCurrentX=pEvent.clientX-tmpRect.left;let tmpCurrentY=pEvent.clientY-tmpRect.top;let tmpLeft=Math.min(tmpStartX,tmpCurrentX);let tmpTop=Math.min(tmpStartY,tmpCurrentY);let tmpWidth=Math.abs(tmpCurrentX-tmpStartX);let tmpHeight=Math.abs(tmpCurrentY-tmpStartY);tmpRectEl.style.left=tmpLeft+'px';tmpRectEl.style.top=tmpTop+'px';tmpRectEl.style.width=tmpWidth+'px';tmpRectEl.style.height=tmpHeight+'px';};this._pdfRegionMouseUp=function(pEvent){if(!tmpDragging){return;}tmpDragging=false;let tmpRect=tmpOverlay.getBoundingClientRect();let tmpEndX=pEvent.clientX-tmpRect.left;let tmpEndY=pEvent.clientY-tmpRect.top;let tmpLeft=Math.min(tmpStartX,tmpEndX);let tmpTop=Math.min(tmpStartY,tmpEndY);let tmpWidth=Math.abs(tmpEndX-tmpStartX);let tmpHeight=Math.abs(tmpEndY-tmpStartY);// Ignore tiny drags (likely accidental clicks)
|
|
11068
|
+
if(tmpWidth<5||tmpHeight<5){if(tmpRectEl&&tmpRectEl.parentElement){tmpRectEl.parentElement.removeChild(tmpRectEl);}tmpRectEl=null;return;}// Convert screen pixels to PDF coordinate units
|
|
11069
|
+
let tmpCanvas=document.getElementById('RetoldRemote-PdfCanvas');if(!tmpCanvas){return;}let tmpCanvasWidth=tmpCanvas.width;let tmpCanvasHeight=tmpCanvas.height;let tmpDisplayWidth=tmpCanvas.offsetWidth;let tmpDisplayHeight=tmpCanvas.offsetHeight;// Scale from display pixels to canvas pixels, then to PDF units via scale
|
|
11070
|
+
let tmpScaleX=tmpCanvasWidth/tmpDisplayWidth;let tmpScaleY=tmpCanvasHeight/tmpDisplayHeight;let tmpPdfX=tmpLeft*tmpScaleX/tmpSelf._pdfScale;let tmpPdfY=tmpTop*tmpScaleY/tmpSelf._pdfScale;let tmpPdfWidth=tmpWidth*tmpScaleX/tmpSelf._pdfScale;let tmpPdfHeight=tmpHeight*tmpScaleY/tmpSelf._pdfScale;tmpSelf._pdfPendingRegion={X:Math.round(tmpPdfX*100)/100,Y:Math.round(tmpPdfY*100)/100,Width:Math.round(tmpPdfWidth*100)/100,Height:Math.round(tmpPdfHeight*100)/100};tmpSelf._pdfPendingText=null;// Show label input
|
|
11071
|
+
let tmpLabelBar=document.getElementById('RetoldRemote-PdfLabelInput');if(tmpLabelBar){tmpLabelBar.style.display='';}let tmpField=document.getElementById('RetoldRemote-PdfLabelField');if(tmpField){tmpField.value='';tmpField.placeholder='Label this region\u2026';tmpField.focus();}};tmpOverlay.addEventListener('mousedown',this._pdfRegionMouseDown);tmpOverlay.addEventListener('mousemove',this._pdfRegionMouseMove);tmpOverlay.addEventListener('mouseup',this._pdfRegionMouseUp);},/**
|
|
11072
|
+
* Remove mouse event handlers for region dragging.
|
|
11073
|
+
*/_pdfCleanupRegionDrag:function _pdfCleanupRegionDrag(){let tmpOverlay=document.getElementById('RetoldRemote-PdfSelectionOverlay');if(tmpOverlay){if(this._pdfRegionMouseDown){tmpOverlay.removeEventListener('mousedown',this._pdfRegionMouseDown);}if(this._pdfRegionMouseMove){tmpOverlay.removeEventListener('mousemove',this._pdfRegionMouseMove);}if(this._pdfRegionMouseUp){tmpOverlay.removeEventListener('mouseup',this._pdfRegionMouseUp);}}this._pdfRegionMouseDown=null;this._pdfRegionMouseMove=null;this._pdfRegionMouseUp=null;},// -----------------------------------------------------------------
|
|
11074
|
+
// Label save / cancel
|
|
11075
|
+
// -----------------------------------------------------------------
|
|
11076
|
+
/**
|
|
11077
|
+
* Save the labeled selection (text or visual region) to the server.
|
|
11078
|
+
*/pdfSaveLabel:function pdfSaveLabel(){let tmpField=document.getElementById('RetoldRemote-PdfLabelField');let tmpLabel=tmpField?tmpField.value.trim():'';let tmpSelf=this;let tmpProvider=this.pict.providers['RetoldRemote-Provider'];let tmpPathParam=tmpProvider?tmpProvider._getPathParam(this._pdfFilePath):encodeURIComponent(this._pdfFilePath);let tmpBody={Path:this._pdfFilePath,Region:{Label:tmpLabel,PageNumber:this._pdfCurrentPage}};if(this._pdfPendingText){tmpBody.Region.Type='text-selection';tmpBody.Region.SelectedText=this._pdfPendingText;}else if(this._pdfPendingRegion){tmpBody.Region.Type='visual-region';tmpBody.Region.X=this._pdfPendingRegion.X;tmpBody.Region.Y=this._pdfPendingRegion.Y;tmpBody.Region.Width=this._pdfPendingRegion.Width;tmpBody.Region.Height=this._pdfPendingRegion.Height;}else{// Nothing pending
|
|
11079
|
+
this.pdfCancelSelection();return;}fetch('/api/media/subimage-regions',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(tmpBody)}).then(function(pResponse){return pResponse.json();}).then(function(pResult){if(pResult&&pResult.Success){tmpSelf._pdfSavedRegions=pResult.Regions||[];tmpSelf._pdfRenderRegionOverlays();let tmpToast=tmpSelf.pict.providers['RetoldRemote-ToastNotification'];if(tmpToast){tmpToast.showToast('Selection saved'+(tmpLabel?': '+tmpLabel:''));}// Update the subimages panel if visible
|
|
11080
|
+
let tmpSubPanel=tmpSelf.pict.views['RetoldRemote-SubimagesPanel'];if(tmpSubPanel){tmpSubPanel.render();}}}).catch(function(pErr){let tmpToast=tmpSelf.pict.providers['RetoldRemote-ToastNotification'];if(tmpToast){tmpToast.showToast('Failed to save selection: '+pErr.message);}});// Clean up
|
|
11081
|
+
this._pdfPendingRegion=null;this._pdfPendingText=null;// Hide the label bar
|
|
11082
|
+
let tmpLabelBar=document.getElementById('RetoldRemote-PdfLabelInput');if(tmpLabelBar){tmpLabelBar.style.display='none';}// Remove the active drag rectangle if any
|
|
11083
|
+
let tmpOverlay=document.getElementById('RetoldRemote-PdfSelectionOverlay');if(tmpOverlay){tmpOverlay.innerHTML='';}},/**
|
|
11084
|
+
* Cancel the current selection without saving.
|
|
11085
|
+
*/pdfCancelSelection:function pdfCancelSelection(){this._pdfPendingRegion=null;this._pdfPendingText=null;// Hide the label bar
|
|
11086
|
+
let tmpLabelBar=document.getElementById('RetoldRemote-PdfLabelInput');if(tmpLabelBar){tmpLabelBar.style.display='none';}// Remove any active drag rectangle
|
|
11087
|
+
let tmpOverlay=document.getElementById('RetoldRemote-PdfSelectionOverlay');if(tmpOverlay){tmpOverlay.innerHTML='';}},// -----------------------------------------------------------------
|
|
11088
|
+
// Saved region management
|
|
11089
|
+
// -----------------------------------------------------------------
|
|
11090
|
+
/**
|
|
11091
|
+
* Load saved subimage regions from the server for this PDF.
|
|
11092
|
+
*
|
|
11093
|
+
* @param {string} pFilePath - Relative file path
|
|
11094
|
+
*/_pdfLoadSavedRegions:function _pdfLoadSavedRegions(pFilePath){let tmpSelf=this;let tmpProvider=this.pict.providers['RetoldRemote-Provider'];let tmpPathParam=tmpProvider?tmpProvider._getPathParam(pFilePath):encodeURIComponent(pFilePath);fetch('/api/media/subimage-regions?path='+tmpPathParam).then(function(pResponse){return pResponse.json();}).then(function(pResult){if(pResult&&pResult.Success&&Array.isArray(pResult.Regions)){tmpSelf._pdfSavedRegions=pResult.Regions;tmpSelf._pdfRenderRegionOverlays();}}).catch(function(){// Silently ignore — regions are optional
|
|
11095
|
+
});},/**
|
|
11096
|
+
* Render saved region overlays for the current page as colored rectangles
|
|
11097
|
+
* positioned over the canvas.
|
|
11098
|
+
*/_pdfRenderRegionOverlays:function _pdfRenderRegionOverlays(){let tmpOverlaysContainer=document.getElementById('RetoldRemote-PdfRegionOverlays');if(!tmpOverlaysContainer){return;}let tmpCanvas=document.getElementById('RetoldRemote-PdfCanvas');if(!tmpCanvas){return;}// Match container dimensions to the canvas
|
|
11099
|
+
tmpOverlaysContainer.style.width=tmpCanvas.offsetWidth+'px';tmpOverlaysContainer.style.height=tmpCanvas.offsetHeight+'px';// Clear existing overlays
|
|
11100
|
+
tmpOverlaysContainer.innerHTML='';let tmpCurrentPage=this._pdfCurrentPage;let tmpScale=this._pdfScale;let tmpDisplayWidth=tmpCanvas.offsetWidth;let tmpCanvasWidth=tmpCanvas.width;let tmpDisplayScale=tmpDisplayWidth/tmpCanvasWidth;for(let i=0;i<this._pdfSavedRegions.length;i++){let tmpRegion=this._pdfSavedRegions[i];// Only show regions for the current page (or regions without a page number)
|
|
11101
|
+
if(tmpRegion.PageNumber&&tmpRegion.PageNumber!==tmpCurrentPage){continue;}// Only render visual-region types as overlays
|
|
11102
|
+
if(tmpRegion.Type!=='visual-region'){continue;}// Convert PDF coordinates to display pixels
|
|
11103
|
+
let tmpLeft=tmpRegion.X*tmpScale*tmpDisplayScale;let tmpTop=tmpRegion.Y*tmpScale*tmpDisplayScale;let tmpWidth=tmpRegion.Width*tmpScale*tmpDisplayScale;let tmpHeight=tmpRegion.Height*tmpScale*tmpDisplayScale;let tmpRectEl=document.createElement('div');tmpRectEl.className='retold-remote-pdf-region-rect';tmpRectEl.style.left=tmpLeft+'px';tmpRectEl.style.top=tmpTop+'px';tmpRectEl.style.width=tmpWidth+'px';tmpRectEl.style.height=tmpHeight+'px';if(tmpRegion.Label){let tmpLabelEl=document.createElement('div');tmpLabelEl.className='retold-remote-pdf-region-label';tmpLabelEl.textContent=tmpRegion.Label;tmpRectEl.appendChild(tmpLabelEl);}tmpOverlaysContainer.appendChild(tmpRectEl);}}};},{}],140:[function(require,module,exports){const libPictView=require('pict-view');const _ViewConfiguration={ViewIdentifier:"RetoldRemote-AudioExplorer",DefaultRenderable:"RetoldRemote-AudioExplorer",DefaultDestinationAddress:"#RetoldRemote-Viewer-Container",AutoRender:false,CSS:``};class RetoldRemoteAudioExplorerView extends libPictView{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this._currentPath='';this._waveformData=null;this._peaks=[];// View state
|
|
10907
11104
|
this._viewStart=0;// Start of visible range (0..1)
|
|
10908
11105
|
this._viewEnd=1;// End of visible range (0..1)
|
|
10909
11106
|
this._minZoom=0.005;// Minimum visible range (0.5% of total)
|
|
@@ -11035,7 +11232,7 @@ tmpSelf._applyPendingSelection();tmpSelf._updateSelectionButtons();tmpSelf._draw
|
|
|
11035
11232
|
* Show an error message.
|
|
11036
11233
|
*
|
|
11037
11234
|
* @param {string} pMessage - Error message
|
|
11038
|
-
*/_showError(pMessage){let tmpBody=document.getElementById('RetoldRemote-AEX-Body');if(tmpBody){tmpBody.innerHTML='<div class="retold-remote-aex-error">'+'<div class="retold-remote-aex-error-message">'+this.pict.providers['RetoldRemote-FormattingUtilities'].escapeHTML(pMessage||'An error occurred.')+'</div>'+'<button class="retold-remote-aex-nav-btn" onclick="pict.views[\'RetoldRemote-AudioExplorer\'].goBack()">Back to Audio</button>'+'</div>';}}}RetoldRemoteAudioExplorerView.default_configuration=_ViewConfiguration;module.exports=RetoldRemoteAudioExplorerView;},{"pict-view":88}],
|
|
11235
|
+
*/_showError(pMessage){let tmpBody=document.getElementById('RetoldRemote-AEX-Body');if(tmpBody){tmpBody.innerHTML='<div class="retold-remote-aex-error">'+'<div class="retold-remote-aex-error-message">'+this.pict.providers['RetoldRemote-FormattingUtilities'].escapeHTML(pMessage||'An error occurred.')+'</div>'+'<button class="retold-remote-aex-nav-btn" onclick="pict.views[\'RetoldRemote-AudioExplorer\'].goBack()">Back to Audio</button>'+'</div>';}}}RetoldRemoteAudioExplorerView.default_configuration=_ViewConfiguration;module.exports=RetoldRemoteAudioExplorerView;},{"pict-view":88}],141:[function(require,module,exports){/**
|
|
11039
11236
|
* Retold Remote -- Collections Panel View
|
|
11040
11237
|
*
|
|
11041
11238
|
* Right-side flyout panel for managing user-defined collections.
|
|
@@ -11065,7 +11262,7 @@ let tmpHeader=document.createElement('div');tmpHeader.className='retold-remote-c
|
|
|
11065
11262
|
let tmpIsOperationPlan=tmpCollection.CollectionType==='operation-plan';if(tmpIsOperationPlan){// Operation plan controls: summary + execute/undo buttons
|
|
11066
11263
|
let tmpOpControls=document.createElement('div');tmpOpControls.className='retold-remote-collections-detail-controls retold-remote-collections-op-controls';// Count pending, completed, failed, skipped
|
|
11067
11264
|
let tmpItems=tmpCollection.Items||[];let tmpPending=0;let tmpCompleted=0;let tmpFailed=0;let tmpSkipped=0;for(let i=0;i<tmpItems.length;i++){let tmpStatus=tmpItems[i].OperationStatus;if(tmpStatus==='completed')tmpCompleted++;else if(tmpStatus==='failed')tmpFailed++;else if(tmpStatus==='skipped')tmpSkipped++;else if(tmpItems[i].Operation)tmpPending++;}let tmpSummary=document.createElement('div');tmpSummary.className='retold-remote-collections-op-summary';let tmpSummaryParts=[];if(tmpPending>0)tmpSummaryParts.push(tmpPending+' pending');if(tmpCompleted>0)tmpSummaryParts.push(tmpCompleted+' done');if(tmpFailed>0)tmpSummaryParts.push(tmpFailed+' failed');if(tmpSkipped>0)tmpSummaryParts.push(tmpSkipped+' skipped');tmpSummary.textContent=tmpSummaryParts.join(' \u00b7 ')||'No operations';tmpOpControls.appendChild(tmpSummary);let tmpBtnRow=document.createElement('div');tmpBtnRow.className='retold-remote-collections-op-buttons';if(tmpPending>0){let tmpExecBtn=document.createElement('button');tmpExecBtn.className='retold-remote-collections-op-execute-btn';tmpExecBtn.textContent='Execute '+tmpPending+' Move'+(tmpPending>1?'s':'');tmpExecBtn.onclick=()=>{tmpExecBtn.disabled=true;tmpExecBtn.textContent='Moving...';tmpManager.executeCollectionOperations(tmpCollection.GUID);};tmpBtnRow.appendChild(tmpExecBtn);}if(tmpCollection.OperationBatchGUID&&tmpCompleted>0){let tmpUndoBtn=document.createElement('button');tmpUndoBtn.className='retold-remote-collections-op-undo-btn';tmpUndoBtn.textContent='Undo';tmpUndoBtn.onclick=()=>{tmpUndoBtn.disabled=true;tmpUndoBtn.textContent='Undoing...';tmpManager.undoCollectionOperations(tmpCollection.GUID);};tmpBtnRow.appendChild(tmpUndoBtn);}tmpOpControls.appendChild(tmpBtnRow);pRoot.appendChild(tmpOpControls);}else{// Standard sort controls for bookmark collections
|
|
11068
|
-
let tmpControls=document.createElement('div');tmpControls.className='retold-remote-collections-detail-controls';let tmpSortSelect=document.createElement('select');tmpSortSelect.className='retold-remote-collections-sort-select';let tmpSortOptions=[{value:'manual',label:'Manual'},{value:'name',label:'Name'},{value:'modified',label:'Date Added'},{value:'type',label:'Type'}];for(let i=0;i<tmpSortOptions.length;i++){let tmpOpt=document.createElement('option');tmpOpt.value=tmpSortOptions[i].value;tmpOpt.textContent=tmpSortOptions[i].label;if(tmpCollection.SortMode===tmpSortOptions[i].value){tmpOpt.selected=true;}tmpSortSelect.appendChild(tmpOpt);}tmpSortSelect.onchange=pEvent=>{tmpManager.sortActiveCollection(pEvent.target.value,null);};let tmpDirBtn=document.createElement('button');tmpDirBtn.className='retold-remote-collections-sort-dir';tmpDirBtn.textContent=tmpCollection.SortDirection==='desc'?'\u2193':'\u2191';tmpDirBtn.title=tmpCollection.SortDirection==='desc'?'Descending':'Ascending';tmpDirBtn.onclick=()=>{let tmpNewDir=tmpRemote.ActiveCollection.SortDirection==='desc'?'asc':'desc';tmpManager.sortActiveCollection(null,tmpNewDir);};tmpControls.appendChild(tmpSortSelect);tmpControls.appendChild(tmpDirBtn);pRoot.appendChild(tmpControls);}// Item list
|
|
11265
|
+
let tmpControls=document.createElement('div');tmpControls.className='retold-remote-collections-detail-controls';let tmpSortSelect=document.createElement('select');tmpSortSelect.className='retold-remote-collections-sort-select';let tmpSortOptions=[{value:'manual',label:'Manual'},{value:'name',label:'Name'},{value:'modified',label:'Date Added'},{value:'type',label:'Type'}];for(let i=0;i<tmpSortOptions.length;i++){let tmpOpt=document.createElement('option');tmpOpt.value=tmpSortOptions[i].value;tmpOpt.textContent=tmpSortOptions[i].label;if(tmpCollection.SortMode===tmpSortOptions[i].value){tmpOpt.selected=true;}tmpSortSelect.appendChild(tmpOpt);}tmpSortSelect.onchange=pEvent=>{tmpManager.sortActiveCollection(pEvent.target.value,null);};let tmpDirBtn=document.createElement('button');tmpDirBtn.className='retold-remote-collections-sort-dir';tmpDirBtn.textContent=tmpCollection.SortDirection==='desc'?'\u2193':'\u2191';tmpDirBtn.title=tmpCollection.SortDirection==='desc'?'Descending':'Ascending';tmpDirBtn.onclick=()=>{let tmpNewDir=tmpRemote.ActiveCollection.SortDirection==='desc'?'asc':'desc';tmpManager.sortActiveCollection(null,tmpNewDir);};let tmpExportBtn=document.createElement('button');tmpExportBtn.className='retold-remote-collections-export-btn';tmpExportBtn.textContent='\u21e9 Export';tmpExportBtn.title='Export collection to a folder';tmpExportBtn.onclick=()=>{tmpSelf._showExportDialog(tmpCollection.GUID,tmpCollection.Name);};tmpControls.appendChild(tmpSortSelect);tmpControls.appendChild(tmpDirBtn);tmpControls.appendChild(tmpExportBtn);pRoot.appendChild(tmpControls);}// Item list
|
|
11069
11266
|
let tmpBody=document.createElement('div');tmpBody.className='retold-remote-collections-body';pRoot.appendChild(tmpBody);if(tmpIsOperationPlan){this._renderOperationItemList(tmpBody,tmpCollection);}else{this._renderItemList(tmpBody,tmpCollection);}}_renderItemList(pBody,pCollection){let tmpSelf=this;let tmpRemote=this.pict.AppData.RetoldRemote;let tmpManager=this.pict.providers['RetoldRemote-CollectionManager'];let tmpItems=pCollection.Items||[];pBody.innerHTML='';if(tmpItems.length===0){let tmpEmpty=document.createElement('div');tmpEmpty.className='retold-remote-collections-empty';tmpEmpty.textContent='No items yet. Browse files and add them to this collection.';pBody.appendChild(tmpEmpty);return;}for(let i=0;i<tmpItems.length;i++){let tmpItem=tmpItems[i];let tmpRow=document.createElement('div');tmpRow.className='retold-remote-collection-item';tmpRow.setAttribute('data-item-id',tmpItem.ID);// Drag handle (for manual sort)
|
|
11070
11267
|
if(pCollection.SortMode==='manual'){let tmpDrag=document.createElement('div');tmpDrag.className='retold-remote-collection-item-drag';tmpDrag.textContent='\u2630';tmpDrag.draggable=true;tmpDrag.ondragstart=pEvent=>{tmpSelf._draggedItemId=tmpItem.ID;tmpRow.classList.add('dragging');pEvent.dataTransfer.effectAllowed='move';};tmpDrag.ondragend=()=>{tmpRow.classList.remove('dragging');tmpSelf._draggedItemId=null;// Remove all drag-over classes
|
|
11071
11268
|
let tmpAllItems=pBody.querySelectorAll('.retold-remote-collection-item');for(let j=0;j<tmpAllItems.length;j++){tmpAllItems[j].classList.remove('drag-over');}};tmpRow.appendChild(tmpDrag);}// Drop target events
|
|
@@ -11104,7 +11301,22 @@ let tmpDeleteBtn=document.createElement('button');tmpDeleteBtn.className='retold
|
|
|
11104
11301
|
*/_createEditGroup(pLabel,pType,pValue,pId){let tmpGroup=document.createElement('div');tmpGroup.className='retold-remote-collections-edit-group';let tmpLabel=document.createElement('div');tmpLabel.className='retold-remote-collections-edit-label';tmpLabel.textContent=pLabel;let tmpInput;if(pType==='textarea'){tmpInput=document.createElement('textarea');tmpInput.className='retold-remote-collections-edit-textarea';}else{tmpInput=document.createElement('input');tmpInput.className='retold-remote-collections-edit-input';tmpInput.type='text';}tmpInput.value=pValue;tmpInput.id='retold-remote-'+pId;tmpGroup.appendChild(tmpLabel);tmpGroup.appendChild(tmpInput);return tmpGroup;}// -- Helpers ----------------------------------------------------------
|
|
11105
11302
|
/**
|
|
11106
11303
|
* Get a text icon character for an item type.
|
|
11107
|
-
*/_getTypeIcon(pType,pMediaType){switch(pType){case'folder':case'folder-contents':return'\uD83D\uDCC1';case'subfile':return'\uD83D\uDDC4';case'image-crop':return'\u2702';case'audio-clip':return'\uD83C\uDFB5';case'video-clip':case'video-frame':return'\uD83C\uDFAC';default:break;}switch(pMediaType){case'image':return'\uD83D\uDDBC';case'video':return'\uD83C\uDFAC';case'audio':return'\uD83C\uDFB5';case'document':return'\uD83D\uDCC4';default:return'\uD83D\uDCC4';}}
|
|
11304
|
+
*/_getTypeIcon(pType,pMediaType){switch(pType){case'folder':case'folder-contents':return'\uD83D\uDCC1';case'subfile':return'\uD83D\uDDC4';case'image-crop':return'\u2702';case'audio-clip':return'\uD83C\uDFB5';case'video-clip':case'video-frame':return'\uD83C\uDFAC';default:break;}switch(pMediaType){case'image':return'\uD83D\uDDBC';case'video':return'\uD83C\uDFAC';case'audio':return'\uD83C\uDFB5';case'document':return'\uD83D\uDCC4';default:return'\uD83D\uDCC4';}}// -- Export Dialog -------------------------------------------------------
|
|
11305
|
+
/**
|
|
11306
|
+
* Show the export dialog for a collection.
|
|
11307
|
+
*
|
|
11308
|
+
* @param {string} pGUID - Collection GUID
|
|
11309
|
+
* @param {string} pCollectionName - Collection name (for default folder)
|
|
11310
|
+
*/_showExportDialog(pGUID,pCollectionName){let tmpSelf=this;// Build a default folder name from the collection name
|
|
11311
|
+
let tmpDefaultFolder=(pCollectionName||'collection-export').replace(/[<>:"/\\|?*\x00-\x1F]/g,'_').replace(/\s+/g,'_').substring(0,80);// Use the current browsed folder as a prefix if available
|
|
11312
|
+
let tmpRemote=this.pict.AppData.RetoldRemote;let tmpCurrentFolder=tmpRemote.CurrentBrowsedFolder||'';let tmpDefaultPath=tmpCurrentFolder?tmpCurrentFolder.replace(/\/+$/,'')+'/'+tmpDefaultFolder:tmpDefaultFolder;// Create a simple inline prompt in the collections detail area
|
|
11313
|
+
let tmpRoot=document.getElementById('RetoldRemote-Collections-Detail');if(!tmpRoot){return;}// Find or create the export dialog container
|
|
11314
|
+
let tmpExistingDialog=document.getElementById('RetoldRemote-ExportDialog');if(tmpExistingDialog){tmpExistingDialog.parentElement.removeChild(tmpExistingDialog);}let tmpDialog=document.createElement('div');tmpDialog.id='RetoldRemote-ExportDialog';tmpDialog.style.cssText='padding:10px;border-top:1px solid var(--retold-border);background:var(--retold-bg-secondary,#21252b);';tmpDialog.innerHTML='<div style="font-size:0.78rem;color:var(--retold-text);margin-bottom:6px;">Export to folder (within content root):</div>'+'<input type="text" id="RetoldRemote-ExportPath" value="'+tmpDefaultPath.replace(/"/g,'"')+'" '+'style="width:100%;box-sizing:border-box;background:var(--retold-bg-input,#1e1e1e);color:var(--retold-text);border:1px solid var(--retold-border);border-radius:4px;padding:4px 8px;font-size:0.78rem;font-family:inherit;margin-bottom:6px;">'+'<div style="display:flex;gap:6px;">'+'<button id="RetoldRemote-ExportConfirmBtn" style="flex:1;padding:4px 8px;font-size:0.75rem;">Export</button>'+'<button id="RetoldRemote-ExportCancelBtn" style="padding:4px 8px;font-size:0.75rem;">Cancel</button>'+'</div>'+'<div id="RetoldRemote-ExportStatus" style="font-size:0.72rem;color:var(--retold-text-dim);margin-top:6px;display:none;"></div>';tmpRoot.appendChild(tmpDialog);// Focus the path input
|
|
11315
|
+
let tmpPathInput=document.getElementById('RetoldRemote-ExportPath');if(tmpPathInput){tmpPathInput.focus();tmpPathInput.select();}// Cancel handler
|
|
11316
|
+
document.getElementById('RetoldRemote-ExportCancelBtn').onclick=()=>{tmpDialog.parentElement.removeChild(tmpDialog);};// Export handler
|
|
11317
|
+
document.getElementById('RetoldRemote-ExportConfirmBtn').onclick=()=>{let tmpDestPath=tmpPathInput?tmpPathInput.value.trim():'';if(!tmpDestPath){return;}let tmpBtn=document.getElementById('RetoldRemote-ExportConfirmBtn');let tmpStatus=document.getElementById('RetoldRemote-ExportStatus');if(tmpBtn)tmpBtn.disabled=true;if(tmpBtn)tmpBtn.textContent='Exporting\u2026';if(tmpStatus)tmpStatus.style.display='';if(tmpStatus)tmpStatus.textContent='Exporting\u2026';fetch('/api/collections/'+encodeURIComponent(pGUID)+'/export',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({DestinationPath:tmpDestPath})}).then(pResponse=>pResponse.json()).then(pResult=>{if(pResult&&pResult.Success){let tmpMsg='Exported '+pResult.ExportedCount+' of '+pResult.TotalItems+' items';if(pResult.ErrorCount>0){tmpMsg+=' ('+pResult.ErrorCount+' errors)';}tmpMsg+=' to '+pResult.DestinationPath;if(tmpStatus)tmpStatus.textContent=tmpMsg;if(tmpBtn)tmpBtn.textContent='Done';let tmpToast=tmpSelf.pict.providers['RetoldRemote-ToastNotification'];if(tmpToast){tmpToast.showToast(tmpMsg);}// Auto-dismiss after a moment
|
|
11318
|
+
setTimeout(()=>{if(tmpDialog.parentElement){tmpDialog.parentElement.removeChild(tmpDialog);}},3000);}else{let tmpErrMsg=pResult&&pResult.Error||'Export failed';if(tmpStatus)tmpStatus.textContent=tmpErrMsg;if(tmpStatus)tmpStatus.style.color='#e06c75';if(tmpBtn)tmpBtn.textContent='Retry';if(tmpBtn)tmpBtn.disabled=false;}}).catch(pError=>{if(tmpStatus)tmpStatus.textContent='Request failed: '+pError.message;if(tmpStatus)tmpStatus.style.color='#e06c75';if(tmpBtn)tmpBtn.textContent='Retry';if(tmpBtn)tmpBtn.disabled=false;});};// Enter key in input triggers export
|
|
11319
|
+
if(tmpPathInput){tmpPathInput.onkeydown=pEvent=>{if(pEvent.key==='Enter'){document.getElementById('RetoldRemote-ExportConfirmBtn').click();}if(pEvent.key==='Escape'){tmpDialog.parentElement.removeChild(tmpDialog);}};}}}RetoldRemoteCollectionsPanelView.default_configuration=_ViewConfiguration;module.exports=RetoldRemoteCollectionsPanelView;},{"pict-view":88}],142:[function(require,module,exports){const libPictView=require('pict-view');const _ViewConfiguration={ViewIdentifier:"RetoldRemote-FileInfoPanel",DefaultRenderable:"RetoldRemote-FileInfoPanel",DefaultDestinationAddress:"#RetoldRemote-Info-Container",AutoRender:false,CSS:``,DefaultTemplateRecordAddress:false,Templates:[{Hash:"RetoldRemote-FileInfoPanel",Template:`<div class="retold-remote-info" id="RetoldRemote-Info-Body"></div>`}],Renderables:[{RenderableHash:"RetoldRemote-FileInfoPanel",TemplateHash:"RetoldRemote-FileInfoPanel",DestinationAddress:"#RetoldRemote-Info-Container"}]};class RetoldRemoteFileInfoPanel extends libPictView{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this._currentPath=null;this._currentMetadata=null;this._extracting=false;}onAfterRender(){this._refreshForCurrentFile();}/**
|
|
11108
11320
|
* Determine the currently selected file path and fetch metadata.
|
|
11109
11321
|
*/_refreshForCurrentFile(){let tmpRemote=this.pict.AppData.RetoldRemote;let tmpPath='';// Try content editor current file first
|
|
11110
11322
|
if(this.pict.AppData.ContentEditor&&this.pict.AppData.ContentEditor.CurrentFile){tmpPath=this.pict.AppData.ContentEditor.CurrentFile;}// Fall back to viewer state
|
|
@@ -11155,7 +11367,7 @@ tmpHTML+=`<button class="retold-remote-info-extract-btn" onclick="pict.views['Re
|
|
|
11155
11367
|
// Formatting utilities
|
|
11156
11368
|
// ---------------------------------------------------------------
|
|
11157
11369
|
_row(pLabel,pValue){return`<div class="retold-remote-info-row"><span class="retold-remote-info-label">${this._esc(String(pLabel))}</span><span class="retold-remote-info-value">${this._esc(String(pValue))}</span></div>`;}_esc(pStr){if(!pStr){return'';}return String(pStr).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');}_formatSize(pBytes){if(!pBytes&&pBytes!==0){return'unknown';}let tmpBytes=parseInt(pBytes,10);if(tmpBytes<1024){return tmpBytes+' B';}if(tmpBytes<1024*1024){return(tmpBytes/1024).toFixed(1)+' KB';}if(tmpBytes<1024*1024*1024){return(tmpBytes/(1024*1024)).toFixed(1)+' MB';}return(tmpBytes/(1024*1024*1024)).toFixed(2)+' GB';}_formatDuration(pSeconds){if(!pSeconds&&pSeconds!==0){return'unknown';}let tmpSec=Math.floor(pSeconds);let tmpHours=Math.floor(tmpSec/3600);let tmpMins=Math.floor(tmpSec%3600/60);let tmpRem=tmpSec%60;if(tmpHours>0){return`${tmpHours}:${String(tmpMins).padStart(2,'0')}:${String(tmpRem).padStart(2,'0')}`;}return`${tmpMins}:${String(tmpRem).padStart(2,'0')}`;}_formatBitrate(pBits){if(!pBits){return'unknown';}let tmpBits=parseInt(pBits,10);if(tmpBits<1000){return tmpBits+' bps';}if(tmpBits<1000000){return(tmpBits/1000).toFixed(0)+' kbps';}return(tmpBits/1000000).toFixed(1)+' Mbps';}_formatFrameRate(pRate){if(!pRate){return'unknown';}// ffprobe returns frame rate as "24000/1001" or "30/1"
|
|
11158
|
-
if(typeof pRate==='string'&&pRate.includes('/')){let tmpParts=pRate.split('/');let tmpNum=parseFloat(tmpParts[0]);let tmpDen=parseFloat(tmpParts[1]);if(tmpDen>0){return(tmpNum/tmpDen).toFixed(3).replace(/\.?0+$/,'')+' fps';}}return pRate+' fps';}_formatDate(pDateStr){if(!pDateStr){return'unknown';}try{let tmpDate=new Date(pDateStr);if(isNaN(tmpDate.getTime())){return String(pDateStr);}return tmpDate.toLocaleDateString()+' '+tmpDate.toLocaleTimeString([],{hour:'2-digit',minute:'2-digit'});}catch(pError){return String(pDateStr);}}}module.exports=RetoldRemoteFileInfoPanel;module.exports.default_configuration=_ViewConfiguration;},{"pict-view":88}],
|
|
11370
|
+
if(typeof pRate==='string'&&pRate.includes('/')){let tmpParts=pRate.split('/');let tmpNum=parseFloat(tmpParts[0]);let tmpDen=parseFloat(tmpParts[1]);if(tmpDen>0){return(tmpNum/tmpDen).toFixed(3).replace(/\.?0+$/,'')+' fps';}}return pRate+' fps';}_formatDate(pDateStr){if(!pDateStr){return'unknown';}try{let tmpDate=new Date(pDateStr);if(isNaN(tmpDate.getTime())){return String(pDateStr);}return tmpDate.toLocaleDateString()+' '+tmpDate.toLocaleTimeString([],{hour:'2-digit',minute:'2-digit'});}catch(pError){return String(pDateStr);}}}module.exports=RetoldRemoteFileInfoPanel;module.exports.default_configuration=_ViewConfiguration;},{"pict-view":88}],143:[function(require,module,exports){const libPictView=require('pict-view');const _ViewConfiguration={ViewIdentifier:"RetoldRemote-Gallery",DefaultRenderable:"RetoldRemote-Gallery-Grid",DefaultDestinationAddress:"#RetoldRemote-Gallery-Container",AutoRender:false,CSS:``,Templates:[],Renderables:[]};class RetoldRemoteGalleryView extends libPictView{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this._intersectionObserver=null;}// ──────────────────────────────────────────────
|
|
11159
11371
|
// Gallery rendering
|
|
11160
11372
|
// ──────────────────────────────────────────────
|
|
11161
11373
|
/**
|
|
@@ -11289,11 +11501,16 @@ pEvent.preventDefault();}_hideLongPressTooltip(){if(this._longPressTooltipEl){if
|
|
|
11289
11501
|
* Get the media category for a file.
|
|
11290
11502
|
*/_getCategory(pExtension,pType){if(pType==='folder')return'folder';if(pType==='archive')return'archive';// Delegate to the filter/sort provider if available
|
|
11291
11503
|
let tmpFilterSort=this.pict.providers['RetoldRemote-GalleryFilterSort'];if(tmpFilterSort){return tmpFilterSort.getCategory(pExtension);}// Fallback
|
|
11292
|
-
let tmpExt=(pExtension||'').replace(/^\./,'').toLowerCase();if(tmpExt==='png'||tmpExt==='jpg'||tmpExt==='jpeg'||tmpExt==='gif'||tmpExt==='webp')return'image';if(tmpExt==='mp4'||tmpExt==='webm'||tmpExt==='mov')return'video';if(tmpExt==='mp3'||tmpExt==='wav'||tmpExt==='ogg')return'audio';if(tmpExt==='pdf')return'document';return'other';}}RetoldRemoteGalleryView.default_configuration=_ViewConfiguration;module.exports=RetoldRemoteGalleryView;},{"pict-view":88}],
|
|
11504
|
+
let tmpExt=(pExtension||'').replace(/^\./,'').toLowerCase();if(tmpExt==='png'||tmpExt==='jpg'||tmpExt==='jpeg'||tmpExt==='gif'||tmpExt==='webp')return'image';if(tmpExt==='mp4'||tmpExt==='webm'||tmpExt==='mov')return'video';if(tmpExt==='mp3'||tmpExt==='wav'||tmpExt==='ogg')return'audio';if(tmpExt==='pdf')return'document';return'other';}}RetoldRemoteGalleryView.default_configuration=_ViewConfiguration;module.exports=RetoldRemoteGalleryView;},{"pict-view":88}],144:[function(require,module,exports){const libPictView=require('pict-view');const _OSD_CDN_URL='https://cdnjs.cloudflare.com/ajax/libs/openseadragon/4.1.1/openseadragon.min.js';const _ViewConfiguration={ViewIdentifier:"RetoldRemote-ImageExplorer",DefaultRenderable:"RetoldRemote-ImageExplorer",DefaultDestinationAddress:"#RetoldRemote-Viewer-Container",AutoRender:false,CSS:``};class RetoldRemoteImageExplorerView extends libPictView{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this._currentPath='';this._osdViewer=null;this._dziData=null;this._osdLoaded=false;this._loading=false;// Selection mode state
|
|
11505
|
+
this._selectionMode=false;this._selectionTracker=null;this._selectionOverlay=null;this._selectionRegion=null;// { X, Y, Width, Height } in image coords
|
|
11506
|
+
this._selectionStart=null;// viewport point where drag began
|
|
11507
|
+
this._savedRegions=[];// loaded from server
|
|
11508
|
+
}/**
|
|
11293
11509
|
* Show the image explorer for a given image file.
|
|
11294
11510
|
*
|
|
11295
11511
|
* @param {string} pFilePath - Relative file path
|
|
11296
|
-
*/showExplorer(pFilePath){let tmpRemote=this.pict.AppData.RetoldRemote;tmpRemote.ActiveMode='image-explorer';tmpRemote.CurrentViewerFile=pFilePath;tmpRemote.CurrentViewerMediaType='image';this._currentPath=pFilePath;this._dziData=null;this._loading=false;//
|
|
11512
|
+
*/showExplorer(pFilePath){let tmpRemote=this.pict.AppData.RetoldRemote;tmpRemote.ActiveMode='image-explorer';tmpRemote.CurrentViewerFile=pFilePath;tmpRemote.CurrentViewerMediaType='image';this._currentPath=pFilePath;this._dziData=null;this._loading=false;// Reset selection state
|
|
11513
|
+
this._selectionMode=false;this._selectionTracker=null;this._selectionOverlay=null;this._selectionRegion=null;this._selectionStart=null;this._savedRegions=[];// Clean up existing viewer
|
|
11297
11514
|
if(this._osdViewer){try{this._osdViewer.destroy();}catch(pErr){// ignore
|
|
11298
11515
|
}this._osdViewer=null;}// Update URL hash.
|
|
11299
11516
|
// When the current hash is #/view/ for the same file (i.e. the media
|
|
@@ -11302,12 +11519,12 @@ if(this._osdViewer){try{this._osdViewer.destroy();}catch(pErr){// ignore
|
|
|
11302
11519
|
let tmpFragProvider=this.pict.providers['RetoldRemote-Provider'];let tmpFragId=tmpFragProvider?tmpFragProvider.getFragmentIdentifier(pFilePath):pFilePath;let tmpNewHash='#/explore-image/'+tmpFragId;let tmpCurrentHash=window.location.hash||'';if(tmpCurrentHash.indexOf('#/view/')===0){history.replaceState(null,'',tmpNewHash);}else{window.location.hash=tmpNewHash;}// Show viewer, hide gallery
|
|
11303
11520
|
let tmpGalleryContainer=document.getElementById('RetoldRemote-Gallery-Container');let tmpViewerContainer=document.getElementById('RetoldRemote-Viewer-Container');if(tmpGalleryContainer)tmpGalleryContainer.style.display='none';if(tmpViewerContainer)tmpViewerContainer.style.display='block';let tmpFileName=pFilePath.replace(/^.*\//,'');let tmpFmt=this.pict.providers['RetoldRemote-FormattingUtilities'];// Build the explorer UI
|
|
11304
11521
|
let tmpHTML='<div class="retold-remote-iex">';// Header
|
|
11305
|
-
tmpHTML+='<div class="retold-remote-iex-header">';tmpHTML+='<button class="retold-remote-iex-nav-btn" onclick="pict.views[\'RetoldRemote-ImageExplorer\'].goBack()" title="Back (Esc)">← Back</button>';tmpHTML+='<div class="retold-remote-iex-title">Image Explorer — '+tmpFmt.escapeHTML(tmpFileName)+'</div>';tmpHTML+='<div class="retold-remote-iex-actions">';tmpHTML+='<button class="retold-remote-iex-action-btn" onclick="pict.views[\'RetoldRemote-ImageExplorer\'].viewInBrowser()" title="View in standard viewer">🖼 View</button>';tmpHTML+='</div>';tmpHTML+='</div>';// Info bar
|
|
11522
|
+
tmpHTML+='<div class="retold-remote-iex-header">';tmpHTML+='<button class="retold-remote-iex-nav-btn" onclick="pict.views[\'RetoldRemote-ImageExplorer\'].goBack()" title="Back (Esc)">← Back</button>';tmpHTML+='<div class="retold-remote-iex-title">Image Explorer — '+tmpFmt.escapeHTML(tmpFileName)+'</div>';tmpHTML+='<div class="retold-remote-iex-actions">';tmpHTML+='<button class="retold-remote-iex-action-btn" id="RetoldRemote-IEX-SelectBtn" onclick="pict.views[\'RetoldRemote-ImageExplorer\'].toggleSelectionMode()" title="Select a region (s)">✂ Select</button>';tmpHTML+='<button class="retold-remote-iex-action-btn" onclick="pict.views[\'RetoldRemote-ImageExplorer\'].viewInBrowser()" title="View in standard viewer">🖼 View</button>';tmpHTML+='</div>';tmpHTML+='</div>';// Info bar
|
|
11306
11523
|
tmpHTML+='<div class="retold-remote-iex-info" id="RetoldRemote-IEX-Info" style="display:none;"></div>';// Body
|
|
11307
11524
|
tmpHTML+='<div class="retold-remote-iex-body" id="RetoldRemote-IEX-Body">';tmpHTML+='<div class="retold-remote-iex-loading" id="RetoldRemote-IEX-Loading">';tmpHTML+='<div>Loading image\u2026</div>';tmpHTML+='</div>';tmpHTML+='<div id="RetoldRemote-IEX-Viewer" style="display:none;"></div>';tmpHTML+='</div>';// Controls bar
|
|
11308
|
-
tmpHTML+='<div class="retold-remote-iex-controls" id="RetoldRemote-IEX-Controls" style="display:none;">';tmpHTML+='<button onclick="pict.views[\'RetoldRemote-ImageExplorer\'].zoomIn()" title="Zoom In (+)">+ Zoom In</button>';tmpHTML+='<span class="retold-remote-iex-zoom-label" id="RetoldRemote-IEX-ZoomLabel">100%</span>';tmpHTML+='<button onclick="pict.views[\'RetoldRemote-ImageExplorer\'].zoomOut()" title="Zoom Out (-)">- Zoom Out</button>';tmpHTML+='<button onclick="pict.views[\'RetoldRemote-ImageExplorer\'].zoomHome()" title="Fit to view (0)">Fit</button>';tmpHTML+='<span style="flex:1;"></span>';tmpHTML+='<span id="RetoldRemote-IEX-Coords" style="color:var(--retold-text-dim);font-size:0.72rem;"></span>';tmpHTML+='</div>';tmpHTML+='</div>';if(tmpViewerContainer){tmpViewerContainer.innerHTML=tmpHTML;}// Update topbar
|
|
11525
|
+
tmpHTML+='<div class="retold-remote-iex-controls" id="RetoldRemote-IEX-Controls" style="display:none;">';tmpHTML+='<button onclick="pict.views[\'RetoldRemote-ImageExplorer\'].zoomIn()" title="Zoom In (+)">+ Zoom In</button>';tmpHTML+='<span class="retold-remote-iex-zoom-label" id="RetoldRemote-IEX-ZoomLabel">100%</span>';tmpHTML+='<button onclick="pict.views[\'RetoldRemote-ImageExplorer\'].zoomOut()" title="Zoom Out (-)">- Zoom Out</button>';tmpHTML+='<button onclick="pict.views[\'RetoldRemote-ImageExplorer\'].zoomHome()" title="Fit to view (0)">Fit</button>';tmpHTML+='<span style="flex:1;"></span>';tmpHTML+='<span id="RetoldRemote-IEX-LabelInput" style="display:none;">';tmpHTML+='<input type="text" id="RetoldRemote-IEX-LabelField" placeholder="Label this region\u2026" style="background:var(--retold-bg-input,#1e1e1e);color:var(--retold-text,#abb2bf);border:1px solid var(--retold-border,#3e4451);border-radius:4px;padding:2px 8px;font-size:0.78rem;width:180px;margin-right:4px;" onkeydown="if(event.key===\'Enter\'){pict.views[\'RetoldRemote-ImageExplorer\'].saveSelectionLabel();event.preventDefault();event.stopPropagation();}if(event.key===\'Escape\'){pict.views[\'RetoldRemote-ImageExplorer\'].cancelSelection();event.preventDefault();event.stopPropagation();}">';tmpHTML+='<button onclick="pict.views[\'RetoldRemote-ImageExplorer\'].saveSelectionLabel()" style="font-size:0.75rem;padding:2px 8px;">Save</button>';tmpHTML+='<button onclick="pict.views[\'RetoldRemote-ImageExplorer\'].cancelSelection()" style="font-size:0.75rem;padding:2px 8px;margin-left:2px;">Cancel</button>';tmpHTML+='</span>';tmpHTML+='<span id="RetoldRemote-IEX-Coords" style="color:var(--retold-text-dim);font-size:0.72rem;"></span>';tmpHTML+='</div>';tmpHTML+='</div>';if(tmpViewerContainer){tmpViewerContainer.innerHTML=tmpHTML;}// Update topbar
|
|
11309
11526
|
let tmpTopBar=this.pict.views['ContentEditor-TopBar'];if(tmpTopBar){tmpTopBar.updateInfo();}// Load OpenSeadragon, then decide whether to use simple image or DZI tiles
|
|
11310
|
-
this._ensureOSDLoaded(()=>{
|
|
11527
|
+
let tmpSelfShow=this;this._ensureOSDLoaded(()=>{tmpSelfShow._probeAndShow(pFilePath);tmpSelfShow._loadSavedRegions(pFilePath);});}/**
|
|
11311
11528
|
* Ensure OpenSeadragon library is loaded (from CDN on first use).
|
|
11312
11529
|
*
|
|
11313
11530
|
* @param {Function} fCallback - Called when OSD is ready
|
|
@@ -11401,9 +11618,88 @@ let tmpHomeZoom=this._osdViewer.viewport.getHomeZoom();let tmpPercent=Math.round
|
|
|
11401
11618
|
* Zoom out by a step.
|
|
11402
11619
|
*/zoomOut(){if(this._osdViewer){let tmpCurrentZoom=this._osdViewer.viewport.getZoom();this._osdViewer.viewport.zoomTo(tmpCurrentZoom/1.5);}}/**
|
|
11403
11620
|
* Reset to home (fit to view).
|
|
11404
|
-
*/zoomHome(){if(this._osdViewer){this._osdViewer.viewport.goHome();}}
|
|
11621
|
+
*/zoomHome(){if(this._osdViewer){this._osdViewer.viewport.goHome();}}// -----------------------------------------------------------------
|
|
11622
|
+
// Selection mode — draw rectangles to create labeled subimage regions
|
|
11623
|
+
// -----------------------------------------------------------------
|
|
11624
|
+
/**
|
|
11625
|
+
* Toggle selection mode on/off.
|
|
11626
|
+
*/toggleSelectionMode(){if(this._selectionMode){this._exitSelectionMode();}else{this._enterSelectionMode();}}/**
|
|
11627
|
+
* Enter selection mode: disable panning, install drag tracker.
|
|
11628
|
+
*/_enterSelectionMode(){if(!this._osdViewer){return;}this._selectionMode=true;// Highlight the Select button
|
|
11629
|
+
let tmpBtn=document.getElementById('RetoldRemote-IEX-SelectBtn');if(tmpBtn){tmpBtn.style.background='rgba(97, 175, 239, 0.4)';tmpBtn.style.color='#fff';}// Disable OSD panning so drag draws a selection instead
|
|
11630
|
+
this._osdViewer.setMouseNavEnabled(false);let tmpSelf=this;let tmpViewerDiv=document.getElementById('RetoldRemote-IEX-Viewer');if(!tmpViewerDiv){return;}tmpViewerDiv.style.cursor='crosshair';this._selectionTracker=new OpenSeadragon.MouseTracker({element:tmpViewerDiv,pressHandler:function(pEvent){tmpSelf._onSelectionPress(pEvent);},dragHandler:function(pEvent){tmpSelf._onSelectionDrag(pEvent);},releaseHandler:function(pEvent){tmpSelf._onSelectionRelease(pEvent);}});}/**
|
|
11631
|
+
* Exit selection mode: re-enable panning, remove drag tracker.
|
|
11632
|
+
*/_exitSelectionMode(){this._selectionMode=false;let tmpBtn=document.getElementById('RetoldRemote-IEX-SelectBtn');if(tmpBtn){tmpBtn.style.background='';tmpBtn.style.color='';}if(this._osdViewer){this._osdViewer.setMouseNavEnabled(true);}if(this._selectionTracker){this._selectionTracker.destroy();this._selectionTracker=null;}let tmpViewerDiv=document.getElementById('RetoldRemote-IEX-Viewer');if(tmpViewerDiv){tmpViewerDiv.style.cursor='';}// Remove in-progress selection overlay (keep saved ones)
|
|
11633
|
+
this._removeActiveSelectionOverlay();this._selectionRegion=null;this._selectionStart=null;// Hide label input
|
|
11634
|
+
let tmpLabelWrap=document.getElementById('RetoldRemote-IEX-LabelInput');if(tmpLabelWrap){tmpLabelWrap.style.display='none';}let tmpCoords=document.getElementById('RetoldRemote-IEX-Coords');if(tmpCoords){tmpCoords.style.display='';}}/**
|
|
11635
|
+
* Handle the start of a selection drag.
|
|
11636
|
+
*/_onSelectionPress(pEvent){if(!this._osdViewer){return;}// Remove any previous in-progress selection overlay
|
|
11637
|
+
this._removeActiveSelectionOverlay();this._selectionStart=this._osdViewer.viewport.pointFromPixel(pEvent.position);// Create the selection rectangle overlay element
|
|
11638
|
+
let tmpOverlay=document.createElement('div');tmpOverlay.id='RetoldRemote-IEX-ActiveSelection';tmpOverlay.style.cssText='border: 2px solid rgba(97, 175, 239, 0.9); background: rgba(97, 175, 239, 0.15); pointer-events: none;';this._selectionOverlay=tmpOverlay;// Add the overlay at zero size, will expand during drag
|
|
11639
|
+
this._osdViewer.addOverlay({element:tmpOverlay,location:new OpenSeadragon.Rect(this._selectionStart.x,this._selectionStart.y,0,0)});}/**
|
|
11640
|
+
* Handle selection dragging — update the rectangle size.
|
|
11641
|
+
*/_onSelectionDrag(pEvent){if(!this._osdViewer||!this._selectionStart||!this._selectionOverlay){return;}let tmpCurrent=this._osdViewer.viewport.pointFromPixel(pEvent.position);let tmpX=Math.min(this._selectionStart.x,tmpCurrent.x);let tmpY=Math.min(this._selectionStart.y,tmpCurrent.y);let tmpW=Math.abs(tmpCurrent.x-this._selectionStart.x);let tmpH=Math.abs(tmpCurrent.y-this._selectionStart.y);this._osdViewer.updateOverlay(this._selectionOverlay,new OpenSeadragon.Rect(tmpX,tmpY,tmpW,tmpH));}/**
|
|
11642
|
+
* Handle selection release — compute image-coordinate region and show label input.
|
|
11643
|
+
*/_onSelectionRelease(pEvent){if(!this._osdViewer||!this._selectionStart){return;}let tmpEnd=this._osdViewer.viewport.pointFromPixel(pEvent.position);// Convert viewport rectangle to image pixel coordinates
|
|
11644
|
+
let tmpVpX=Math.min(this._selectionStart.x,tmpEnd.x);let tmpVpY=Math.min(this._selectionStart.y,tmpEnd.y);let tmpVpW=Math.abs(tmpEnd.x-this._selectionStart.x);let tmpVpH=Math.abs(tmpEnd.y-this._selectionStart.y);let tmpTopLeft=this._osdViewer.viewport.viewportToImageCoordinates(new OpenSeadragon.Point(tmpVpX,tmpVpY));let tmpBottomRight=this._osdViewer.viewport.viewportToImageCoordinates(new OpenSeadragon.Point(tmpVpX+tmpVpW,tmpVpY+tmpVpH));let tmpRegion={X:Math.max(0,Math.round(tmpTopLeft.x)),Y:Math.max(0,Math.round(tmpTopLeft.y)),Width:Math.round(tmpBottomRight.x-tmpTopLeft.x),Height:Math.round(tmpBottomRight.y-tmpTopLeft.y)};// Clamp to image dimensions
|
|
11645
|
+
if(this._dziData){if(tmpRegion.X+tmpRegion.Width>this._dziData.Width){tmpRegion.Width=this._dziData.Width-tmpRegion.X;}if(tmpRegion.Y+tmpRegion.Height>this._dziData.Height){tmpRegion.Height=this._dziData.Height-tmpRegion.Y;}}// Ignore tiny selections (likely accidental clicks)
|
|
11646
|
+
if(tmpRegion.Width<5||tmpRegion.Height<5){this._removeActiveSelectionOverlay();return;}this._selectionRegion=tmpRegion;// Show the inline label input in the controls bar
|
|
11647
|
+
let tmpLabelWrap=document.getElementById('RetoldRemote-IEX-LabelInput');let tmpCoords=document.getElementById('RetoldRemote-IEX-Coords');if(tmpLabelWrap){tmpLabelWrap.style.display='';}if(tmpCoords){tmpCoords.style.display='none';}// Focus the label field
|
|
11648
|
+
let tmpField=document.getElementById('RetoldRemote-IEX-LabelField');if(tmpField){tmpField.value='';tmpField.focus();}}/**
|
|
11649
|
+
* Save the current selection with the entered label.
|
|
11650
|
+
*/saveSelectionLabel(){if(!this._selectionRegion){return;}let tmpField=document.getElementById('RetoldRemote-IEX-LabelField');let tmpLabel=tmpField?tmpField.value.trim():'';let tmpSelf=this;let tmpProvider=this.pict.providers['RetoldRemote-Provider'];let tmpPathParam=tmpProvider?tmpProvider._getPathParam(this._currentPath):encodeURIComponent(this._currentPath);fetch('/api/media/subimage-regions',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({Path:this._currentPath,Region:{Label:tmpLabel,X:this._selectionRegion.X,Y:this._selectionRegion.Y,Width:this._selectionRegion.Width,Height:this._selectionRegion.Height}})}).then(pResponse=>pResponse.json()).then(pResult=>{if(pResult&&pResult.Success){tmpSelf._savedRegions=pResult.Regions||[];// Remove the active selection overlay and render persistent ones
|
|
11651
|
+
tmpSelf._removeActiveSelectionOverlay();tmpSelf._renderSavedRegionOverlays();// Notify the user
|
|
11652
|
+
let tmpToast=tmpSelf.pict.providers['RetoldRemote-ToastNotification'];if(tmpToast){tmpToast.showToast('Subimage region saved'+(tmpLabel?': '+tmpLabel:''));}// Update the sidebar panel if visible
|
|
11653
|
+
let tmpSubPanel=tmpSelf.pict.views['RetoldRemote-SubimagesPanel'];if(tmpSubPanel){tmpSubPanel.render();}}}).catch(pErr=>{let tmpToast=tmpSelf.pict.providers['RetoldRemote-ToastNotification'];if(tmpToast){tmpToast.showToast('Failed to save region: '+pErr.message);}});// Hide label input, show coords
|
|
11654
|
+
this._selectionRegion=null;this._selectionStart=null;let tmpLabelWrap=document.getElementById('RetoldRemote-IEX-LabelInput');if(tmpLabelWrap){tmpLabelWrap.style.display='none';}let tmpCoords=document.getElementById('RetoldRemote-IEX-Coords');if(tmpCoords){tmpCoords.style.display='';}}/**
|
|
11655
|
+
* Cancel the current in-progress selection.
|
|
11656
|
+
*/cancelSelection(){this._removeActiveSelectionOverlay();this._selectionRegion=null;this._selectionStart=null;let tmpLabelWrap=document.getElementById('RetoldRemote-IEX-LabelInput');if(tmpLabelWrap){tmpLabelWrap.style.display='none';}let tmpCoords=document.getElementById('RetoldRemote-IEX-Coords');if(tmpCoords){tmpCoords.style.display='';}}/**
|
|
11657
|
+
* Remove the active (in-progress) selection overlay.
|
|
11658
|
+
*/_removeActiveSelectionOverlay(){let tmpActive=document.getElementById('RetoldRemote-IEX-ActiveSelection');if(tmpActive&&this._osdViewer){try{this._osdViewer.removeOverlay(tmpActive);}catch(pErr){// May not be an overlay; just remove from DOM
|
|
11659
|
+
if(tmpActive.parentElement){tmpActive.parentElement.removeChild(tmpActive);}}}this._selectionOverlay=null;}// -----------------------------------------------------------------
|
|
11660
|
+
// Saved region overlays
|
|
11661
|
+
// -----------------------------------------------------------------
|
|
11662
|
+
/**
|
|
11663
|
+
* Load saved subimage regions from the server.
|
|
11664
|
+
*
|
|
11665
|
+
* @param {string} pFilePath - Relative file path
|
|
11666
|
+
*/_loadSavedRegions(pFilePath){let tmpSelf=this;let tmpProvider=this.pict.providers['RetoldRemote-Provider'];let tmpPathParam=tmpProvider?tmpProvider._getPathParam(pFilePath):encodeURIComponent(pFilePath);fetch('/api/media/subimage-regions?path='+tmpPathParam).then(pResponse=>pResponse.json()).then(pResult=>{if(pResult&&pResult.Success&&Array.isArray(pResult.Regions)){tmpSelf._savedRegions=pResult.Regions;tmpSelf._renderSavedRegionOverlays();}}).catch(()=>{// Silently ignore — regions are optional
|
|
11667
|
+
});}/**
|
|
11668
|
+
* Render all saved regions as OSD overlays with colored borders and labels.
|
|
11669
|
+
*/_renderSavedRegionOverlays(){if(!this._osdViewer){return;}// Remove existing saved-region overlays
|
|
11670
|
+
let tmpExisting=document.querySelectorAll('.retold-remote-iex-region-overlay');for(let i=0;i<tmpExisting.length;i++){try{this._osdViewer.removeOverlay(tmpExisting[i]);}catch(pErr){if(tmpExisting[i].parentElement){tmpExisting[i].parentElement.removeChild(tmpExisting[i]);}}}// Render each saved region
|
|
11671
|
+
for(let i=0;i<this._savedRegions.length;i++){let tmpRegion=this._savedRegions[i];this._addRegionOverlay(tmpRegion);}}/**
|
|
11672
|
+
* Add a single region overlay to the OSD viewer.
|
|
11673
|
+
*
|
|
11674
|
+
* @param {object} pRegion - { ID, Label, X, Y, Width, Height }
|
|
11675
|
+
*/_addRegionOverlay(pRegion){if(!this._osdViewer||!this._dziData){return;}let tmpEl=document.createElement('div');tmpEl.className='retold-remote-iex-region-overlay';tmpEl.setAttribute('data-region-id',pRegion.ID);tmpEl.style.cssText='border: 2px solid rgba(229, 192, 123, 0.85); background: rgba(229, 192, 123, 0.08); pointer-events: none; position: relative;';// Label badge
|
|
11676
|
+
if(pRegion.Label){let tmpLabelEl=document.createElement('span');tmpLabelEl.style.cssText='position:absolute;top:-1px;left:-1px;background:rgba(229,192,123,0.9);color:#282c34;font-size:0.65rem;padding:1px 5px;border-radius:0 0 3px 0;white-space:nowrap;pointer-events:none;';tmpLabelEl.textContent=pRegion.Label;tmpEl.appendChild(tmpLabelEl);}// Convert image coordinates to viewport coordinates
|
|
11677
|
+
let tmpImageRect=new OpenSeadragon.Rect(pRegion.X,pRegion.Y,pRegion.Width,pRegion.Height);let tmpViewportRect=this._osdViewer.viewport.imageToViewportRectangle(tmpImageRect);this._osdViewer.addOverlay({element:tmpEl,location:tmpViewportRect});}/**
|
|
11678
|
+
* Navigate to (zoom into) a specific saved region by ID.
|
|
11679
|
+
*
|
|
11680
|
+
* @param {string} pRegionID - The region ID to navigate to
|
|
11681
|
+
*/zoomToRegion(pRegionID){if(!this._osdViewer||!this._dziData){return;}let tmpRegion=null;for(let i=0;i<this._savedRegions.length;i++){if(this._savedRegions[i].ID===pRegionID){tmpRegion=this._savedRegions[i];break;}}if(!tmpRegion){return;}// Convert image rect to viewport rect and fit to it
|
|
11682
|
+
let tmpImageRect=new OpenSeadragon.Rect(tmpRegion.X,tmpRegion.Y,tmpRegion.Width,tmpRegion.Height);let tmpViewportRect=this._osdViewer.viewport.imageToViewportRectangle(tmpImageRect);this._osdViewer.viewport.fitBounds(tmpViewportRect);}/**
|
|
11683
|
+
* Delete a saved region by ID.
|
|
11684
|
+
*
|
|
11685
|
+
* @param {string} pRegionID - The region ID to delete
|
|
11686
|
+
*/deleteRegion(pRegionID){let tmpSelf=this;let tmpProvider=this.pict.providers['RetoldRemote-Provider'];let tmpPathParam=tmpProvider?tmpProvider._getPathParam(this._currentPath):encodeURIComponent(this._currentPath);fetch('/api/media/subimage-regions/'+encodeURIComponent(pRegionID)+'?path='+tmpPathParam,{method:'DELETE'}).then(pResponse=>pResponse.json()).then(pResult=>{if(pResult&&pResult.Success){tmpSelf._savedRegions=pResult.Regions||[];tmpSelf._renderSavedRegionOverlays();let tmpToast=tmpSelf.pict.providers['RetoldRemote-ToastNotification'];if(tmpToast){tmpToast.showToast('Region deleted');}// Update sidebar
|
|
11687
|
+
let tmpSubPanel=tmpSelf.pict.views['RetoldRemote-SubimagesPanel'];if(tmpSubPanel){tmpSubPanel.render();}}}).catch(()=>{// ignore
|
|
11688
|
+
});}/**
|
|
11689
|
+
* Get the current selection region (for use by collection add).
|
|
11690
|
+
*
|
|
11691
|
+
* @returns {object|null} The current selection or null
|
|
11692
|
+
*/getActiveSelection(){return this._selectionRegion;}/**
|
|
11693
|
+
* Get the saved regions array.
|
|
11694
|
+
*
|
|
11695
|
+
* @returns {Array}
|
|
11696
|
+
*/getSavedRegions(){return this._savedRegions;}// -----------------------------------------------------------------
|
|
11697
|
+
// Navigation
|
|
11698
|
+
// -----------------------------------------------------------------
|
|
11699
|
+
/**
|
|
11405
11700
|
* Navigate back to the gallery / file listing.
|
|
11406
|
-
*/goBack(){//
|
|
11701
|
+
*/goBack(){// Clean up selection mode
|
|
11702
|
+
if(this._selectionMode){this._exitSelectionMode();}// Destroy the OSD viewer
|
|
11407
11703
|
if(this._osdViewer){try{this._osdViewer.destroy();}catch(pErr){// ignore
|
|
11408
11704
|
}this._osdViewer=null;}let tmpNav=this.pict.providers['RetoldRemote-GalleryNavigation'];if(tmpNav){tmpNav.closeViewer();}}/**
|
|
11409
11705
|
* Leave the image explorer and view the image in the standard viewer.
|
|
@@ -11413,7 +11709,7 @@ if(this._osdViewer){try{this._osdViewer.destroy();}catch(pErr){// ignore
|
|
|
11413
11709
|
* Show an error message.
|
|
11414
11710
|
*
|
|
11415
11711
|
* @param {string} pMessage - Error message
|
|
11416
|
-
*/_showError(pMessage){let tmpLoading=document.getElementById('RetoldRemote-IEX-Loading');if(tmpLoading){tmpLoading.style.display='none';}let tmpBody=document.getElementById('RetoldRemote-IEX-Body');if(tmpBody){let tmpFmt=this.pict.providers['RetoldRemote-FormattingUtilities'];tmpBody.innerHTML='<div class="retold-remote-iex-error">'+'<div class="retold-remote-iex-error-message">'+tmpFmt.escapeHTML(pMessage||'An error occurred.')+'</div>'+'<button class="retold-remote-iex-nav-btn" onclick="pict.views[\'RetoldRemote-ImageExplorer\'].goBack()">Back to Image</button>'+'</div>';}}}RetoldRemoteImageExplorerView.default_configuration=_ViewConfiguration;module.exports=RetoldRemoteImageExplorerView;},{"pict-view":88}],
|
|
11712
|
+
*/_showError(pMessage){let tmpLoading=document.getElementById('RetoldRemote-IEX-Loading');if(tmpLoading){tmpLoading.style.display='none';}let tmpBody=document.getElementById('RetoldRemote-IEX-Body');if(tmpBody){let tmpFmt=this.pict.providers['RetoldRemote-FormattingUtilities'];tmpBody.innerHTML='<div class="retold-remote-iex-error">'+'<div class="retold-remote-iex-error-message">'+tmpFmt.escapeHTML(pMessage||'An error occurred.')+'</div>'+'<button class="retold-remote-iex-nav-btn" onclick="pict.views[\'RetoldRemote-ImageExplorer\'].goBack()">Back to Image</button>'+'</div>';}}}RetoldRemoteImageExplorerView.default_configuration=_ViewConfiguration;module.exports=RetoldRemoteImageExplorerView;},{"pict-view":88}],145:[function(require,module,exports){const libPictView=require('pict-view');const _ViewConfiguration={ViewIdentifier:"RetoldRemote-ImageViewer",DefaultRenderable:"RetoldRemote-ImageViewer",DefaultDestinationAddress:"#RetoldRemote-Viewer-Container",AutoRender:false,CSS:``};class RetoldRemoteImageViewerView extends libPictView{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this._zoomLevel=1;this._naturalWidth=0;this._naturalHeight=0;this._resizeHandler=null;}/**
|
|
11417
11713
|
* Called when the image finishes loading. Captures the natural
|
|
11418
11714
|
* dimensions and applies the current fit mode.
|
|
11419
11715
|
*
|
|
@@ -11424,8 +11720,8 @@ if(this._osdViewer){try{this._osdViewer.destroy();}catch(pErr){// ignore
|
|
|
11424
11720
|
*/initImage(){let tmpImg=document.getElementById('RetoldRemote-ImageViewer-Img');if(!tmpImg){return;}this._naturalWidth=tmpImg.naturalWidth;this._naturalHeight=tmpImg.naturalHeight;this._zoomLevel=1;this._applyDisplay();// Recalculate on window resize
|
|
11425
11721
|
if(this._resizeHandler){window.removeEventListener('resize',this._resizeHandler);}let tmpSelf=this;let tmpResizeTimer=null;this._resizeHandler=function(){clearTimeout(tmpResizeTimer);tmpResizeTimer=setTimeout(function(){tmpSelf._applyDisplay();},100);};window.addEventListener('resize',this._resizeHandler);// Always show the Explore button so `e` works on any image
|
|
11426
11722
|
this._showExploreButton();}/**
|
|
11427
|
-
* Show the explore button
|
|
11428
|
-
*/_showExploreButton(){let tmpBtn=document.getElementById('RetoldRemote-
|
|
11723
|
+
* Show the explore button in the header nav bar.
|
|
11724
|
+
*/_showExploreButton(){let tmpBtn=document.getElementById('RetoldRemote-HeaderExploreBtn');if(tmpBtn){tmpBtn.style.display='';}}/**
|
|
11429
11725
|
* Get the current fit mode from AppData.
|
|
11430
11726
|
*
|
|
11431
11727
|
* @returns {string} 'fit' | 'auto' | 'original'
|
|
@@ -11459,7 +11755,7 @@ return{width:tmpNW,height:tmpNH};}}}/**
|
|
|
11459
11755
|
* @param {string} pMode - The mode identifier
|
|
11460
11756
|
*/_showFitModeIndicator(pMode){let tmpLabels={'fit':'Fit to Window','auto':'Original if Smaller','original':'Original Size'};let tmpLabel=tmpLabels[pMode]||pMode;this.pict.providers['RetoldRemote-ToastNotification'].showOverlayIndicator(tmpLabel,1200);}/**
|
|
11461
11757
|
* Clean up resize handler when navigating away.
|
|
11462
|
-
*/cleanup(){if(this._resizeHandler){window.removeEventListener('resize',this._resizeHandler);this._resizeHandler=null;}}}RetoldRemoteImageViewerView.default_configuration=_ViewConfiguration;module.exports=RetoldRemoteImageViewerView;},{"pict-view":88}],
|
|
11758
|
+
*/cleanup(){if(this._resizeHandler){window.removeEventListener('resize',this._resizeHandler);this._resizeHandler=null;}}}RetoldRemoteImageViewerView.default_configuration=_ViewConfiguration;module.exports=RetoldRemoteImageViewerView;},{"pict-view":88}],146:[function(require,module,exports){const libPictView=require('pict-view');const _ViewConfiguration={ViewIdentifier:"ContentEditor-Layout",DefaultRenderable:"RetoldRemote-Layout-Shell",DefaultDestinationAddress:"#ContentEditor-Application-Container",AutoRender:false,CSS:``,Templates:[{Hash:"RetoldRemote-Layout-Shell",Template:/*html*/`
|
|
11463
11759
|
<div id="ContentEditor-TopBar-Container"></div>
|
|
11464
11760
|
<div class="content-editor-body">
|
|
11465
11761
|
<div class="content-editor-sidebar-wrap" style="width: 250px;">
|
|
@@ -11468,6 +11764,7 @@ return{width:tmpNW,height:tmpNH};}}}/**
|
|
|
11468
11764
|
<button class="content-editor-sidebar-tab active" data-tab="files" onclick="pict.views['ContentEditor-Layout'].switchSidebarTab('files')">Files</button>
|
|
11469
11765
|
<button class="content-editor-sidebar-tab" data-tab="favorites" onclick="pict.views['ContentEditor-Layout'].switchSidebarTab('favorites')">Favorites</button>
|
|
11470
11766
|
<button class="content-editor-sidebar-tab" data-tab="info" onclick="pict.views['ContentEditor-Layout'].switchSidebarTab('info')">Info</button>
|
|
11767
|
+
<button class="content-editor-sidebar-tab" data-tab="subimages" onclick="pict.views['ContentEditor-Layout'].switchSidebarTab('subimages')">Regions</button>
|
|
11471
11768
|
<button class="content-editor-sidebar-tab" data-tab="settings" onclick="pict.views['ContentEditor-Layout'].switchSidebarTab('settings')">Settings</button>
|
|
11472
11769
|
<button class="content-editor-sidebar-tab content-editor-sidebar-tab-collections" data-tab="collections" onclick="pict.views['ContentEditor-Layout'].switchSidebarTab('collections')" style="display:none;">Collections</button>
|
|
11473
11770
|
</div>
|
|
@@ -11476,6 +11773,7 @@ return{width:tmpNW,height:tmpNH};}}}/**
|
|
|
11476
11773
|
<div id="RetoldRemote-Favorites-Body"></div>
|
|
11477
11774
|
</div>
|
|
11478
11775
|
<div class="content-editor-sidebar-pane" data-pane="info" id="RetoldRemote-Info-Container" style="display:none"></div>
|
|
11776
|
+
<div class="content-editor-sidebar-pane" data-pane="subimages" id="RetoldRemote-Subimages-Container" style="display:none"></div>
|
|
11479
11777
|
<div class="content-editor-sidebar-pane" data-pane="settings" id="RetoldRemote-Settings-Container" style="display:none"></div>
|
|
11480
11778
|
<div class="content-editor-sidebar-pane" data-pane="collections" id="RetoldRemote-Collections-MobilePane" style="display:none"></div>
|
|
11481
11779
|
</div>
|
|
@@ -11504,7 +11802,8 @@ let tmpSelf=this;window.addEventListener('hashchange',()=>{tmpSelf.pict.PictAppl
|
|
|
11504
11802
|
if(!tmpIsCollapsed){if(this.isMobileDrawer()){let tmpHeight=tmpRemote.SidebarDrawerHeight||Math.round(window.innerHeight*0.33);tmpWrap.style.height=tmpHeight+'px';}else if(tmpRemote.SidebarWidth){tmpWrap.style.width=tmpRemote.SidebarWidth+'px';}}this.pict.PictApplication.saveSettings();// Recalculate gallery columns after sidebar resize
|
|
11505
11803
|
let tmpNavProvider=this.pict.providers['RetoldRemote-GalleryNavigation'];if(tmpNavProvider){setTimeout(()=>tmpNavProvider.recalculateColumns(),250);}}switchSidebarTab(pTab){// Update tab buttons
|
|
11506
11804
|
let tmpTabs=document.querySelectorAll('.content-editor-sidebar-tab');tmpTabs.forEach(pEl=>{pEl.classList.toggle('active',pEl.getAttribute('data-tab')===pTab);});// Update panes
|
|
11507
|
-
let tmpPanes=document.querySelectorAll('.content-editor-sidebar-pane');tmpPanes.forEach(pEl=>{pEl.style.display=pEl.getAttribute('data-pane')===pTab?'':'none';});//
|
|
11805
|
+
let tmpPanes=document.querySelectorAll('.content-editor-sidebar-pane');tmpPanes.forEach(pEl=>{pEl.style.display=pEl.getAttribute('data-pane')===pTab?'':'none';});// Subimages tab: render the subimages panel
|
|
11806
|
+
if(pTab==='subimages'){let tmpSubimagesView=this.pict.views['RetoldRemote-SubimagesPanel'];if(tmpSubimagesView){tmpSubimagesView.render();}}// Render settings panel on demand
|
|
11508
11807
|
if(pTab==='settings'){let tmpSettingsView=this.pict.views['RetoldRemote-SettingsPanel'];if(tmpSettingsView){tmpSettingsView.render();}}// Favorites tab: render the favorites list
|
|
11509
11808
|
if(pTab==='favorites'){this.renderFavoritesList();}// Info tab: render the file info panel
|
|
11510
11809
|
if(pTab==='info'){let tmpInfoView=this.pict.views['RetoldRemote-FileInfoPanel'];if(tmpInfoView){tmpInfoView.render();}}// Collections tab: move the collections container into the mobile pane
|
|
@@ -11527,7 +11826,7 @@ let tmpEscapedPath=tmpPath.replace(/'/g,"\\'");tmpHTML+='<div class="retold-remo
|
|
|
11527
11826
|
*/_setupCollectionsResizeHandle(){let tmpHandle=document.querySelector('.retold-remote-collections-resize-handle');let tmpWrap=document.getElementById('RetoldRemote-Collections-Wrap');if(!tmpHandle||!tmpWrap){return;}let tmpSelf=this;let tmpStartX=0;let tmpStartWidth=0;function onDragStart(pEvent){if(tmpWrap.classList.contains('collapsed')){return;}pEvent.preventDefault();tmpSelf._collectionsDragging=true;tmpHandle.classList.add('dragging');let tmpClientX=pEvent.touches?pEvent.touches[0].clientX:pEvent.clientX;tmpStartX=tmpClientX;tmpStartWidth=tmpWrap.getBoundingClientRect().width;document.addEventListener('mousemove',onDragMove);document.addEventListener('mouseup',onDragEnd);document.addEventListener('touchmove',onDragMove,{passive:false});document.addEventListener('touchend',onDragEnd);}function onDragMove(pEvent){if(!tmpSelf._collectionsDragging){return;}pEvent.preventDefault();let tmpClientX=pEvent.touches?pEvent.touches[0].clientX:pEvent.clientX;// Dragging left (negative deltaX) increases width
|
|
11528
11827
|
let tmpDelta=tmpStartX-tmpClientX;let tmpNewWidth=Math.max(150,Math.min(600,tmpStartWidth+tmpDelta));tmpWrap.style.width=tmpNewWidth+'px';}function onDragEnd(){if(!tmpSelf._collectionsDragging){return;}tmpSelf._collectionsDragging=false;tmpHandle.classList.remove('dragging');let tmpRemote=tmpSelf.pict.AppData.RetoldRemote;tmpRemote.CollectionsPanelWidth=tmpWrap.getBoundingClientRect().width;tmpSelf.pict.PictApplication.saveSettings();document.removeEventListener('mousemove',onDragMove);document.removeEventListener('mouseup',onDragEnd);document.removeEventListener('touchmove',onDragMove);document.removeEventListener('touchend',onDragEnd);// Recalculate gallery columns
|
|
11529
11828
|
let tmpGalleryNav=tmpSelf.pict.providers['RetoldRemote-GalleryNavigation'];if(tmpGalleryNav&&typeof tmpGalleryNav.recalculateColumns==='function'){tmpGalleryNav.recalculateColumns();}}tmpHandle.addEventListener('mousedown',onDragStart);tmpHandle.addEventListener('touchstart',onDragStart,{passive:false});// Double-click collapses the collections panel
|
|
11530
|
-
tmpHandle.addEventListener('dblclick',function(pEvent){pEvent.preventDefault();tmpSelf.toggleCollectionsPanel();});}}RetoldRemoteLayoutView.default_configuration=_ViewConfiguration;module.exports=RetoldRemoteLayoutView;},{"pict-view":88}],
|
|
11829
|
+
tmpHandle.addEventListener('dblclick',function(pEvent){pEvent.preventDefault();tmpSelf.toggleCollectionsPanel();});}}RetoldRemoteLayoutView.default_configuration=_ViewConfiguration;module.exports=RetoldRemoteLayoutView;},{"pict-view":88}],147:[function(require,module,exports){const libPictView=require('pict-view');const _MediaViewerEbookViewer=require('./MediaViewer-EbookViewer');const _MediaViewerCodeViewer=require('./MediaViewer-CodeViewer');const _MediaViewerPdfViewer=require('./MediaViewer-PdfViewer');const _ViewConfiguration={ViewIdentifier:"RetoldRemote-MediaViewer",DefaultRenderable:"RetoldRemote-MediaViewer",DefaultDestinationAddress:"#RetoldRemote-Viewer-Container",AutoRender:false,CSS:``};class RetoldRemoteMediaViewerView extends libPictView{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this._swipeStartX=0;this._swipeStartY=0;this._swipeTouchCount=0;this._swipeHandlers=null;this._dfExitHandlers=null;}/**
|
|
11531
11830
|
* Show the media viewer for a given file.
|
|
11532
11831
|
*
|
|
11533
11832
|
* @param {string} pFilePath - Relative file path
|
|
@@ -11535,7 +11834,7 @@ tmpHandle.addEventListener('dblclick',function(pEvent){pEvent.preventDefault();t
|
|
|
11535
11834
|
*/showMedia(pFilePath,pMediaType){let tmpRemote=this.pict.AppData.RetoldRemote;tmpRemote.ActiveMode='viewer';tmpRemote.CurrentViewerFile=pFilePath;tmpRemote.CurrentViewerMediaType=pMediaType;tmpRemote.VideoMenuActive=pMediaType==='video';// Show viewer, hide gallery
|
|
11536
11835
|
let tmpGalleryContainer=document.getElementById('RetoldRemote-Gallery-Container');let tmpViewerContainer=document.getElementById('RetoldRemote-Viewer-Container');if(tmpGalleryContainer)tmpGalleryContainer.style.display='none';if(tmpViewerContainer)tmpViewerContainer.style.display='block';let tmpFileName=pFilePath.replace(/^.*\//,'');let tmpProvider=this.pict.providers['RetoldRemote-Provider'];let tmpContentURL=tmpProvider?tmpProvider.getContentURL(pFilePath):'/content/'+encodeURIComponent(pFilePath);// Build the viewer HTML
|
|
11537
11836
|
let tmpHTML='<div class="retold-remote-viewer">';// Header with nav
|
|
11538
|
-
tmpHTML+='<div class="retold-remote-viewer-header">';tmpHTML+='<button class="retold-remote-viewer-nav-btn" onclick="pict.providers[\'RetoldRemote-GalleryNavigation\'].closeViewer()" title="Back (Esc)">← Back</button>';tmpHTML+='<button class="retold-remote-viewer-nav-btn" onclick="pict.providers[\'RetoldRemote-GalleryNavigation\'].prevFile()" title="Previous (k)">‹ Prev</button>';tmpHTML+='<div class="retold-remote-viewer-title">'+this.pict.providers['RetoldRemote-FormattingUtilities'].escapeHTML(tmpFileName)+'</div>';tmpHTML+='<button class="retold-remote-viewer-nav-btn" onclick="pict.providers[\'RetoldRemote-GalleryNavigation\'].nextFile()" title="Next (j)">Next ›</button>';tmpHTML+='<button class="retold-remote-viewer-nav-btn" onclick="pict.providers[\'RetoldRemote-GalleryNavigation\']._toggleFileInfo()" title="Info (i)">ⓘ</button>';tmpHTML+='<button class="retold-remote-viewer-nav-btn" onclick="pict.views[\'RetoldRemote-MediaViewer\'].toggleDistractionFree()" title="Distraction-Free (d)">▢</button>';tmpHTML+='</div>';// Body with media content
|
|
11837
|
+
tmpHTML+='<div class="retold-remote-viewer-header">';tmpHTML+='<button class="retold-remote-viewer-nav-btn" onclick="pict.providers[\'RetoldRemote-GalleryNavigation\'].closeViewer()" title="Back (Esc)">← Back</button>';tmpHTML+='<button class="retold-remote-viewer-nav-btn" onclick="pict.providers[\'RetoldRemote-GalleryNavigation\'].prevFile()" title="Previous (k)">‹ Prev</button>';tmpHTML+='<div class="retold-remote-viewer-title">'+this.pict.providers['RetoldRemote-FormattingUtilities'].escapeHTML(tmpFileName)+'</div>';tmpHTML+='<button class="retold-remote-viewer-nav-btn" id="RetoldRemote-HeaderExploreBtn" onclick="pict.views[\'RetoldRemote-ImageExplorer\'].showExplorer(pict.AppData.RetoldRemote.CurrentViewerFile)" title="Explore image (e)" style="display:none;">🔍 Explore</button>';tmpHTML+='<button class="retold-remote-viewer-nav-btn" onclick="pict.providers[\'RetoldRemote-GalleryNavigation\'].nextFile()" title="Next (j)">Next ›</button>';tmpHTML+='<button class="retold-remote-viewer-nav-btn" onclick="pict.providers[\'RetoldRemote-GalleryNavigation\']._toggleFileInfo()" title="Info (i)">ⓘ</button>';tmpHTML+='<button class="retold-remote-viewer-nav-btn" onclick="pict.views[\'RetoldRemote-MediaViewer\'].toggleDistractionFree()" title="Distraction-Free (d)">▢</button>';tmpHTML+='</div>';// Body with media content
|
|
11539
11838
|
tmpHTML+='<div class="retold-remote-viewer-body">';// Exit hotspot for distraction-free mode (double-click/tap top-left to exit)
|
|
11540
11839
|
let tmpDFHotspotDisplay=tmpRemote._distractionFreeMode?'':' style="display:none"';tmpHTML+='<div class="retold-remote-df-exit-hotspot" id="RetoldRemote-DF-ExitHotspot"'+tmpDFHotspotDisplay+'></div>';// For images, probe size first to decide what URL to use
|
|
11541
11840
|
if(pMediaType==='image'){// Show a placeholder while we probe
|
|
@@ -11545,8 +11844,9 @@ tmpHTML+='</div>';// end viewer
|
|
|
11545
11844
|
if(tmpViewerContainer){tmpViewerContainer.innerHTML=tmpHTML;}// For images, probe dimensions and decide how to display
|
|
11546
11845
|
if(pMediaType==='image'){this._probeAndShowImage(pFilePath,tmpContentURL,tmpFileName);}// Fetch and populate file info
|
|
11547
11846
|
this._loadFileInfo(pFilePath);// Fetch text content and initialize code viewer
|
|
11548
|
-
if(pMediaType==='text'){this._loadCodeViewer(tmpContentURL,pFilePath);}// Load ebook
|
|
11549
|
-
if(pMediaType==='document'){let tmpExt=pFilePath.replace(/^.*\./,'').toLowerCase();if(tmpExt==='epub'||tmpExt==='mobi'){this._loadEbookViewer(tmpContentURL,pFilePath);}}//
|
|
11847
|
+
if(pMediaType==='text'){this._loadCodeViewer(tmpContentURL,pFilePath);}// Load document viewers: ebook for epub/mobi, PDF for pdf, convert-then-PDF for others
|
|
11848
|
+
if(pMediaType==='document'){let tmpExt=pFilePath.replace(/^.*\./,'').toLowerCase();if(tmpExt==='epub'||tmpExt==='mobi'){this._loadEbookViewer(tmpContentURL,pFilePath);}else if(tmpExt==='pdf'){this._loadPdfViewer(tmpContentURL,pFilePath);}else{// Convertible document types — convert to PDF first, then load PDF viewer
|
|
11849
|
+
this._loadConvertedDocumentViewer(pFilePath);}}// Set up swipe navigation for touch devices
|
|
11550
11850
|
this._setupSwipeNavigation();// Set up distraction-free exit hotspot (double-click/tap top-left)
|
|
11551
11851
|
this._setupDFExitHotspot();// Update topbar
|
|
11552
11852
|
let tmpTopBar=this.pict.views['ContentEditor-TopBar'];if(tmpTopBar){tmpTopBar.updateInfo();}}/**
|
|
@@ -11622,10 +11922,9 @@ tmpSelf._insertImageTag(pContentURL,pFileName,false);});}/**
|
|
|
11622
11922
|
* @param {number} [pOrigWidth] - Original image width (for the badge)
|
|
11623
11923
|
* @param {number} [pOrigHeight]- Original image height (for the badge)
|
|
11624
11924
|
*/_insertImageTag(pURL,pFileName,pShowExplore,pOrigWidth,pOrigHeight){let tmpPlaceholder=document.getElementById('RetoldRemote-ImagePlaceholder');if(!tmpPlaceholder||!tmpPlaceholder.parentElement){return;}let tmpEscapedName=this.pict.providers['RetoldRemote-FormattingUtilities'].escapeHTML(pFileName);let tmpFragment=document.createDocumentFragment();// The image element
|
|
11625
|
-
let tmpImg=document.createElement('img');tmpImg.src=pURL;tmpImg.alt=tmpEscapedName;tmpImg.id='RetoldRemote-ImageViewer-Img';tmpImg.style.cssText='max-width: 100%; max-height: 100%; object-fit: contain; cursor: zoom-in;';tmpImg.onload=function(){pict.views['RetoldRemote-ImageViewer'].initImage();};tmpImg.onclick=function(){pict.views['RetoldRemote-ImageViewer'].toggleZoom();};tmpFragment.appendChild(tmpImg);// Explore button
|
|
11626
|
-
let
|
|
11627
|
-
if(pShowExplore&&pOrigWidth&&pOrigHeight){let tmpBadge=document.createElement('div');tmpBadge.id='RetoldRemote-LargeImageBadge';tmpBadge.className='retold-remote-image-large-badge';tmpBadge.textContent=pOrigWidth+' \u00d7 '+pOrigHeight+' px (preview)';tmpFragment.appendChild(tmpBadge);}tmpPlaceholder.parentElement.replaceChild(tmpFragment,tmpPlaceholder);}_buildImageHTML(pURL,pFileName){let tmpEscapedName=this.pict.providers['RetoldRemote-FormattingUtilities'].escapeHTML(pFileName);let tmpHTML='<img src="'+pURL+'" alt="'+tmpEscapedName+'" '+'style="max-width: 100%; max-height: 100%; object-fit: contain; cursor: zoom-in;" '+'id="RetoldRemote-ImageViewer-Img" '+'onload="pict.views[\'RetoldRemote-ImageViewer\'].initImage()" '+'onclick="pict.views[\'RetoldRemote-ImageViewer\'].toggleZoom()">';//
|
|
11628
|
-
tmpHTML+='<button class="retold-remote-image-explore-btn" id="RetoldRemote-ImageExploreBtn" '+'style="display:none" '+'onclick="pict.views[\'RetoldRemote-ImageExplorer\'].showExplorer(pict.AppData.RetoldRemote.CurrentViewerFile)" '+'title="Open in deep-zoom explorer (e)">'+'🔍 Explore</button>';return tmpHTML;}_buildVideoHTML(pURL,pFileName){let tmpCapabilities=this.pict.AppData.RetoldRemote.ServerCapabilities||{};let tmpRemote=this.pict.AppData.RetoldRemote;let tmpFilePath=tmpRemote.CurrentViewerFile;// Build the action menu (shown by default instead of the player)
|
|
11925
|
+
let tmpImg=document.createElement('img');tmpImg.src=pURL;tmpImg.alt=tmpEscapedName;tmpImg.id='RetoldRemote-ImageViewer-Img';tmpImg.style.cssText='max-width: 100%; max-height: 100%; object-fit: contain; cursor: zoom-in;';tmpImg.onload=function(){pict.views['RetoldRemote-ImageViewer'].initImage();};tmpImg.onclick=function(){pict.views['RetoldRemote-ImageViewer'].toggleZoom();};tmpFragment.appendChild(tmpImg);// Always show the Explore button in the header nav bar for images
|
|
11926
|
+
let tmpHeaderExploreBtn=document.getElementById('RetoldRemote-HeaderExploreBtn');if(tmpHeaderExploreBtn){tmpHeaderExploreBtn.style.display='';}// Dimension badge for large images
|
|
11927
|
+
if(pShowExplore&&pOrigWidth&&pOrigHeight){let tmpBadge=document.createElement('div');tmpBadge.id='RetoldRemote-LargeImageBadge';tmpBadge.className='retold-remote-image-large-badge';tmpBadge.textContent=pOrigWidth+' \u00d7 '+pOrigHeight+' px (preview)';tmpFragment.appendChild(tmpBadge);}tmpPlaceholder.parentElement.replaceChild(tmpFragment,tmpPlaceholder);}_buildImageHTML(pURL,pFileName){let tmpEscapedName=this.pict.providers['RetoldRemote-FormattingUtilities'].escapeHTML(pFileName);let tmpHTML='<img src="'+pURL+'" alt="'+tmpEscapedName+'" '+'style="max-width: 100%; max-height: 100%; object-fit: contain; cursor: zoom-in;" '+'id="RetoldRemote-ImageViewer-Img" '+'onload="pict.views[\'RetoldRemote-ImageViewer\'].initImage()" '+'onclick="pict.views[\'RetoldRemote-ImageViewer\'].toggleZoom()">';return tmpHTML;}_buildVideoHTML(pURL,pFileName){let tmpCapabilities=this.pict.AppData.RetoldRemote.ServerCapabilities||{};let tmpRemote=this.pict.AppData.RetoldRemote;let tmpFilePath=tmpRemote.CurrentViewerFile;// Build the action menu (shown by default instead of the player)
|
|
11629
11928
|
let tmpHTML='<div class="retold-remote-video-action-menu" id="RetoldRemote-VideoActionMenu">';tmpHTML+='<div class="retold-remote-video-action-menu-title">'+this.pict.providers['RetoldRemote-FormattingUtilities'].escapeHTML(pFileName)+'</div>';// Frame preview container (loaded on demand via t key or automatically)
|
|
11630
11929
|
if(tmpCapabilities.ffmpeg){tmpHTML+='<div id="RetoldRemote-VideoActionThumb" class="retold-remote-video-action-thumb-wrap"></div>';// Kick off frame extraction automatically
|
|
11631
11930
|
setTimeout(()=>{this.loadVideoMenuFrame();},0);}// Explore option (e)
|
|
@@ -11645,18 +11944,28 @@ tmpRemote.VideoMenuActive=false;}/**
|
|
|
11645
11944
|
if(tmpRemote.CurrentViewerFile!==tmpFilePath)return;let tmpWrap=document.getElementById('RetoldRemote-VideoActionThumb');if(!tmpWrap)return;if(pData&&pData.Frames&&pData.Frames.length>0){let tmpFrame=pData.Frames[0];let tmpFrameURL='/api/media/video-frame/'+pData.CacheKey+'/'+tmpFrame.Filename;tmpWrap.innerHTML='<img src="'+tmpFrameURL+'" '+'alt="'+this.pict.providers['RetoldRemote-FormattingUtilities'].escapeHTML(tmpFilePath.replace(/^.*\//,''))+'" '+'onerror="this.parentNode.innerHTML=\'\'">';}else{tmpWrap.innerHTML='';}}).catch(()=>{let tmpWrap=document.getElementById('RetoldRemote-VideoActionThumb');if(tmpWrap)tmpWrap.innerHTML='';});}_buildAudioHTML(pURL,pFileName){let tmpIconProvider=this.pict.providers['RetoldRemote-Icons'];let tmpIconHTML=tmpIconProvider?'<span class="retold-remote-icon retold-remote-icon-lg">'+tmpIconProvider.getIcon('music-note',64)+'</span>':'🎵';let tmpHTML='<div style="text-align: center; padding: 40px;">'+'<div style="margin-bottom: 24px;">'+tmpIconHTML+'</div>'+'<div style="font-size: 1.1rem; color: var(--retold-text-secondary); margin-bottom: 24px;">'+this.pict.providers['RetoldRemote-FormattingUtilities'].escapeHTML(pFileName)+'</div>'+'<audio controls'+(this.pict.AppData.RetoldRemote.AutoplayAudio?' autoplay':'')+' preload="metadata" id="RetoldRemote-AudioPlayer" style="width: 100%; max-width: 500px;">'+'<source src="'+pURL+'">'+'Your browser does not support the audio tag.'+'</audio>';// Action buttons below the player
|
|
11646
11945
|
tmpHTML+='<div style="margin-top: 20px; display: flex; gap: 12px; justify-content: center; flex-wrap: wrap;">';// Explore Audio button (available when ffprobe is present)
|
|
11647
11946
|
let tmpCapabilities=this.pict.AppData.RetoldRemote.ServerCapabilities||{};if(tmpCapabilities.ffprobe||tmpCapabilities.ffmpeg){tmpHTML+='<button class="retold-remote-explore-btn" '+'onclick="pict.views[\'RetoldRemote-AudioExplorer\'].showExplorer(pict.AppData.RetoldRemote.CurrentViewerFile)" '+'title="Explore waveform and extract segments from this audio">'+'Explore Audio'+'</button>';}// Stream with VLC
|
|
11648
|
-
tmpHTML+='<button class="retold-remote-vlc-btn" '+'onclick="pict.providers[\'RetoldRemote-GalleryNavigation\']._streamWithVLC()" '+'title="Stream to VLC on this device (v)">'+'Stream with VLC'+'</button>';tmpHTML+='</div>';tmpHTML+='</div>';return tmpHTML;}_buildDocumentHTML(pURL,pFileName,pFilePath){let tmpExtension=pFilePath.replace(/^.*\./,'').toLowerCase();if(tmpExtension==='pdf'){return
|
|
11947
|
+
tmpHTML+='<button class="retold-remote-vlc-btn" '+'onclick="pict.providers[\'RetoldRemote-GalleryNavigation\']._streamWithVLC()" '+'title="Stream to VLC on this device (v)">'+'Stream with VLC'+'</button>';tmpHTML+='</div>';tmpHTML+='</div>';return tmpHTML;}_buildDocumentHTML(pURL,pFileName,pFilePath){let tmpExtension=pFilePath.replace(/^.*\./,'').toLowerCase();if(tmpExtension==='pdf'){return this._buildPdfHTML(pURL,pFileName,pFilePath);}if(tmpExtension==='epub'||tmpExtension==='mobi'){return this._buildEbookHTML(pURL,pFileName,pFilePath);}// For convertible document types (doc, docx, rtf, odt, wpd, etc.),
|
|
11948
|
+
// show the PDF viewer shell — conversion happens async in _loadDocumentViewer
|
|
11949
|
+
let tmpConvertibleExts={'doc':true,'docx':true,'rtf':true,'odt':true,'wpd':true,'wps':true,'pages':true,'odp':true,'ppt':true,'pptx':true,'ods':true,'xls':true,'xlsx':true};if(tmpConvertibleExts[tmpExtension]){return this._buildPdfHTML(pURL,pFileName,pFilePath);}// Unknown document types: show a download link
|
|
11649
11950
|
let tmpIconProvider=this.pict.providers['RetoldRemote-Icons'];let tmpDocIconHTML=tmpIconProvider?'<span class="retold-remote-icon retold-remote-icon-lg">'+tmpIconProvider.getIcon('document-large',64)+'</span>':'📄';return'<div style="text-align: center; padding: 40px;">'+'<div style="margin-bottom: 24px;">'+tmpDocIconHTML+'</div>'+'<div style="font-size: 1.1rem; color: var(--retold-text-secondary); margin-bottom: 24px;">'+this.pict.providers['RetoldRemote-FormattingUtilities'].escapeHTML(pFileName)+'</div>'+'<a href="'+pURL+'" target="_blank" style="color: var(--retold-accent); font-size: 0.9rem;">Open in new tab</a>'+'</div>';}// Note: _buildTextHTML, _getHighlightLanguage, _loadCodeViewer
|
|
11650
11951
|
// are in MediaViewer-CodeViewer.js (mixed in below).
|
|
11651
11952
|
// Note: _buildEbookHTML, _loadEbookViewer, _renderEpub, _renderEbookTOC,
|
|
11652
11953
|
// ebookGoToChapter, ebookPrevPage, ebookNextPage, toggleEbookTOC
|
|
11653
11954
|
// are in MediaViewer-EbookViewer.js (mixed in below).
|
|
11654
|
-
|
|
11955
|
+
/**
|
|
11956
|
+
* Convert a document (doc, docx, rtf, odt, wpd, etc.) to PDF and load in the PDF viewer.
|
|
11957
|
+
* Shows a converting message in the PDF content area while waiting.
|
|
11958
|
+
*
|
|
11959
|
+
* @param {string} pFilePath - Relative file path
|
|
11960
|
+
*/_loadConvertedDocumentViewer(pFilePath){let tmpSelf=this;let tmpProvider=this.pict.providers['RetoldRemote-Provider'];let tmpPathParam=tmpProvider?tmpProvider._getPathParam(pFilePath):encodeURIComponent(pFilePath);// Show converting message in the PDF content area
|
|
11961
|
+
let tmpContent=document.getElementById('RetoldRemote-PdfContent');if(tmpContent){tmpContent.innerHTML='<div style="text-align:center;padding:40px;color:var(--retold-text-dim);">'+'<div style="font-size:1.5rem;margin-bottom:12px;">⚙</div>'+'Converting document to PDF\u2026'+'</div>';}fetch('/api/media/doc-convert?path='+tmpPathParam).then(pResponse=>pResponse.json()).then(pData=>{if(!pData||!pData.Success){throw new Error(pData?pData.Error:'Conversion failed.');}// Build the PDF URL from the ebook cache (same serving endpoint)
|
|
11962
|
+
let tmpPdfURL='/api/media/ebook/'+pData.CacheKey+'/'+pData.OutputFilename;// Load the PDF viewer with the converted file
|
|
11963
|
+
tmpSelf._loadPdfViewer(tmpPdfURL,pFilePath);}).catch(pError=>{if(tmpContent){let tmpFmt=tmpSelf.pict.providers['RetoldRemote-FormattingUtilities'];tmpContent.innerHTML='<div style="text-align:center;padding:40px;color:var(--retold-text-dim);">'+'<div style="margin-bottom:12px;color:#e06c75;">Conversion failed</div>'+'<div style="font-size:0.85rem;">'+tmpFmt.escapeHTML(pError.message)+'</div>'+'<div style="margin-top:16px;">'+'<a href="'+(tmpProvider?tmpProvider.getContentURL(pFilePath):'/content/'+encodeURIComponent(pFilePath))+'" target="_blank" style="color:var(--retold-accent);font-size:0.85rem;">Download original file</a>'+'</div>'+'</div>';}});}_buildFallbackHTML(pURL,pFileName){let tmpIconProvider=this.pict.providers['RetoldRemote-Icons'];let tmpFallbackIconHTML=tmpIconProvider?'<span class="retold-remote-icon retold-remote-icon-lg">'+tmpIconProvider.getIcon('document-large',64)+'</span>':'📄';return'<div style="text-align: center; padding: 40px;">'+'<div style="margin-bottom: 24px;">'+tmpFallbackIconHTML+'</div>'+'<div style="font-size: 1.1rem; color: var(--retold-text-secondary); margin-bottom: 24px;">'+this.pict.providers['RetoldRemote-FormattingUtilities'].escapeHTML(pFileName)+'</div>'+'<a href="'+pURL+'" target="_blank" style="color: var(--retold-accent); font-size: 0.9rem;">Download / Open in new tab</a>'+'</div>';}/**
|
|
11655
11964
|
* Fetch file info and populate the overlay and video stats bar.
|
|
11656
11965
|
*/_loadFileInfo(pFilePath){let tmpSelf=this;let tmpProvider=this.pict.providers['RetoldRemote-Provider'];if(!tmpProvider){return;}tmpProvider.fetchMediaProbe(pFilePath,(pError,pData)=>{if(!pData){return;}// Populate the info overlay
|
|
11657
11966
|
let tmpOverlay=document.getElementById('RetoldRemote-FileInfo-Overlay');if(tmpOverlay){let tmpHTML='';if(pData.Size!==undefined){tmpHTML+='<div class="retold-remote-fileinfo-row"><span class="retold-remote-fileinfo-label">Size</span><span class="retold-remote-fileinfo-value">'+tmpSelf.pict.providers['RetoldRemote-FormattingUtilities'].formatFileSize(pData.Size)+'</span></div>';}if(pData.Width&&pData.Height){tmpHTML+='<div class="retold-remote-fileinfo-row"><span class="retold-remote-fileinfo-label">Dimensions</span><span class="retold-remote-fileinfo-value">'+pData.Width+' x '+pData.Height+'</span></div>';}if(pData.Duration){let tmpMin=Math.floor(pData.Duration/60);let tmpSec=Math.floor(pData.Duration%60);tmpHTML+='<div class="retold-remote-fileinfo-row"><span class="retold-remote-fileinfo-label">Duration</span><span class="retold-remote-fileinfo-value">'+tmpMin+':'+(tmpSec<10?'0':'')+tmpSec+'</span></div>';}if(pData.Codec){tmpHTML+='<div class="retold-remote-fileinfo-row"><span class="retold-remote-fileinfo-label">Codec</span><span class="retold-remote-fileinfo-value">'+pData.Codec+'</span></div>';}if(pData.Format){tmpHTML+='<div class="retold-remote-fileinfo-row"><span class="retold-remote-fileinfo-label">Format</span><span class="retold-remote-fileinfo-value">'+pData.Format+'</span></div>';}if(pData.Modified){tmpHTML+='<div class="retold-remote-fileinfo-row"><span class="retold-remote-fileinfo-label">Modified</span><span class="retold-remote-fileinfo-value">'+new Date(pData.Modified).toLocaleString()+'</span></div>';}if(pData.Path){tmpHTML+='<div class="retold-remote-fileinfo-row"><span class="retold-remote-fileinfo-label">Path</span><span class="retold-remote-fileinfo-value">'+pData.Path+'</span></div>';}tmpOverlay.innerHTML=tmpHTML;}// Populate the video stats bar (if viewing a video)
|
|
11658
11967
|
let tmpStatsBar=document.getElementById('RetoldRemote-VideoStats');if(tmpStatsBar){let tmpStatsHTML='';if(pData.Duration){let tmpMin=Math.floor(pData.Duration/60);let tmpSec=Math.floor(pData.Duration%60);tmpStatsHTML+='<span><span class="retold-remote-video-stat-label">Duration</span> <span class="retold-remote-video-stat-value">'+tmpMin+':'+(tmpSec<10?'0':'')+tmpSec+'</span></span>';}if(pData.Width&&pData.Height){tmpStatsHTML+='<span><span class="retold-remote-video-stat-label">Resolution</span> <span class="retold-remote-video-stat-value">'+pData.Width+'×'+pData.Height+'</span></span>';}if(pData.Codec){tmpStatsHTML+='<span><span class="retold-remote-video-stat-label">Codec</span> <span class="retold-remote-video-stat-value">'+pData.Codec+'</span></span>';}if(pData.Bitrate){let tmpBitrate=pData.Bitrate;let tmpBitrateStr;if(tmpBitrate>=1000000){tmpBitrateStr=(tmpBitrate/1000000).toFixed(1)+' Mbps';}else if(tmpBitrate>=1000){tmpBitrateStr=Math.round(tmpBitrate/1000)+' kbps';}else{tmpBitrateStr=tmpBitrate+' bps';}tmpStatsHTML+='<span><span class="retold-remote-video-stat-label">Bitrate</span> <span class="retold-remote-video-stat-value">'+tmpBitrateStr+'</span></span>';}if(pData.Size!==undefined){tmpStatsHTML+='<span><span class="retold-remote-video-stat-label">Size</span> <span class="retold-remote-video-stat-value">'+tmpSelf.pict.providers['RetoldRemote-FormattingUtilities'].formatFileSize(pData.Size)+'</span></span>';}// Preserve the Explore and VLC buttons if they exist
|
|
11659
|
-
let tmpExploreBtn=tmpStatsBar.querySelector('.retold-remote-explore-btn');let tmpExploreHTML=tmpExploreBtn?tmpExploreBtn.outerHTML:'';let tmpVLCBtn=tmpStatsBar.querySelector('.retold-remote-vlc-btn');let tmpVLCHTML=tmpVLCBtn?tmpVLCBtn.outerHTML:'';tmpStatsBar.innerHTML=tmpStatsHTML+tmpExploreHTML+tmpVLCHTML;}});}}Object.assign(RetoldRemoteMediaViewerView.prototype,_MediaViewerEbookViewer);Object.assign(RetoldRemoteMediaViewerView.prototype,_MediaViewerCodeViewer);RetoldRemoteMediaViewerView.default_configuration=_ViewConfiguration;module.exports=RetoldRemoteMediaViewerView;},{"./MediaViewer-CodeViewer":137,"./MediaViewer-EbookViewer":138,"pict-view":88}],
|
|
11968
|
+
let tmpExploreBtn=tmpStatsBar.querySelector('.retold-remote-explore-btn');let tmpExploreHTML=tmpExploreBtn?tmpExploreBtn.outerHTML:'';let tmpVLCBtn=tmpStatsBar.querySelector('.retold-remote-vlc-btn');let tmpVLCHTML=tmpVLCBtn?tmpVLCBtn.outerHTML:'';tmpStatsBar.innerHTML=tmpStatsHTML+tmpExploreHTML+tmpVLCHTML;}});}}Object.assign(RetoldRemoteMediaViewerView.prototype,_MediaViewerEbookViewer);Object.assign(RetoldRemoteMediaViewerView.prototype,_MediaViewerCodeViewer);Object.assign(RetoldRemoteMediaViewerView.prototype,_MediaViewerPdfViewer);RetoldRemoteMediaViewerView.default_configuration=_ViewConfiguration;module.exports=RetoldRemoteMediaViewerView;},{"./MediaViewer-CodeViewer":137,"./MediaViewer-EbookViewer":138,"./MediaViewer-PdfViewer":139,"pict-view":88}],148:[function(require,module,exports){const libPictView=require('pict-view');const _ViewConfiguration={ViewIdentifier:"RetoldRemote-SettingsPanel",DefaultRenderable:"RetoldRemote-SettingsPanel",DefaultDestinationAddress:"#RetoldRemote-Settings-Container",AutoRender:false,CSS:``};class RetoldRemoteSettingsPanelView extends libPictView{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);}onAfterRender(){super.onAfterRender();this._renderSettingsContent();}_renderSettingsContent(){let tmpContainer=document.getElementById('RetoldRemote-Settings-Container');if(!tmpContainer){return;}let tmpRemote=this.pict.AppData.RetoldRemote;let tmpCapabilities=tmpRemote.ServerCapabilities||{};let tmpHTML='<div class="retold-remote-settings">';// Appearance section (theme dropdown)
|
|
11660
11969
|
tmpHTML+='<div class="retold-remote-settings-section">';tmpHTML+='<div class="retold-remote-settings-section-title">Appearance</div>';tmpHTML+='<div class="retold-remote-settings-row">';tmpHTML+='<span class="retold-remote-settings-label">Theme</span>';tmpHTML+='<select class="retold-remote-settings-select" onchange="pict.views[\'RetoldRemote-SettingsPanel\'].changeTheme(this.value)">';let tmpThemeProvider=this.pict.providers['RetoldRemote-Theme'];if(tmpThemeProvider){let tmpThemes=tmpThemeProvider.getThemeList();let tmpCurrentTheme=tmpThemeProvider.getCurrentTheme();let tmpCurrentCategory='';for(let i=0;i<tmpThemes.length;i++){let tmpTheme=tmpThemes[i];if(tmpTheme.category!==tmpCurrentCategory){if(tmpCurrentCategory){tmpHTML+='</optgroup>';}tmpHTML+='<optgroup label="'+tmpTheme.category+'">';tmpCurrentCategory=tmpTheme.category;}tmpHTML+='<option value="'+tmpTheme.key+'"'+(tmpTheme.key===tmpCurrentTheme?' selected':'')+'>'+tmpTheme.name+'</option>';}if(tmpCurrentCategory){tmpHTML+='</optgroup>';}}tmpHTML+='</select>';tmpHTML+='</div>';tmpHTML+='</div>';// end appearance section
|
|
11661
11970
|
// Gallery section
|
|
11662
11971
|
tmpHTML+='<div class="retold-remote-settings-section">';tmpHTML+='<div class="retold-remote-settings-section-title">Gallery</div>';// View mode
|
|
@@ -11709,7 +12018,52 @@ if(pKey==='NamingTemplate'){this._renderSettingsContent();}}/**
|
|
|
11709
12018
|
* @returns {string}
|
|
11710
12019
|
*/_escapeHTML(pStr){if(!pStr)return'';return String(pStr).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');}/**
|
|
11711
12020
|
* Re-run the filter/sort pipeline and refresh the gallery.
|
|
11712
|
-
*/_refilterGallery(){let tmpRemote=this.pict.AppData.RetoldRemote;let tmpFilterSort=this.pict.providers['RetoldRemote-GalleryFilterSort'];if(tmpFilterSort){tmpFilterSort.runFilterPipeline();}if(tmpRemote.ActiveMode==='gallery'){let tmpGalleryView=this.pict.views['RetoldRemote-Gallery'];if(tmpGalleryView){tmpGalleryView.renderGallery();}}}}RetoldRemoteSettingsPanelView.default_configuration=_ViewConfiguration;module.exports=RetoldRemoteSettingsPanelView;},{"pict-view":88}],
|
|
12021
|
+
*/_refilterGallery(){let tmpRemote=this.pict.AppData.RetoldRemote;let tmpFilterSort=this.pict.providers['RetoldRemote-GalleryFilterSort'];if(tmpFilterSort){tmpFilterSort.runFilterPipeline();}if(tmpRemote.ActiveMode==='gallery'){let tmpGalleryView=this.pict.views['RetoldRemote-Gallery'];if(tmpGalleryView){tmpGalleryView.renderGallery();}}}}RetoldRemoteSettingsPanelView.default_configuration=_ViewConfiguration;module.exports=RetoldRemoteSettingsPanelView;},{"pict-view":88}],149:[function(require,module,exports){const libPictView=require('pict-view');const _ViewConfiguration={ViewIdentifier:"RetoldRemote-SubimagesPanel",DefaultRenderable:"RetoldRemote-SubimagesPanel",DefaultDestinationAddress:"#RetoldRemote-Subimages-Container",AutoRender:false,CSS:``};/**
|
|
12022
|
+
* Subimages Panel — sidebar tab showing labeled subimage regions
|
|
12023
|
+
* for the currently viewed image file.
|
|
12024
|
+
*
|
|
12025
|
+
* Regions are fetched from the SubimageService API and displayed
|
|
12026
|
+
* as a list with label, dimensions, and action buttons.
|
|
12027
|
+
*/class RetoldRemoteSubimagesPanelView extends libPictView{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this._regions=[];this._currentPath='';}/**
|
|
12028
|
+
* Render the subimages panel for the current file.
|
|
12029
|
+
*/render(){let tmpContainer=document.getElementById('RetoldRemote-Subimages-Container');if(!tmpContainer){return;}let tmpRemote=this.pict.AppData.RetoldRemote;let tmpFilePath=tmpRemote.CurrentViewerFile;let tmpMediaType=tmpRemote.CurrentViewerMediaType;// Show for images and documents (EPUB, PDF, CBZ pages)
|
|
12030
|
+
if(!tmpFilePath){tmpContainer.innerHTML='<div style="padding:12px;color:var(--retold-text-dim);font-size:0.82rem;">View a file to see its regions.</div>';this._regions=[];this._currentPath='';return;}// If the file changed, fetch regions
|
|
12031
|
+
if(tmpFilePath!==this._currentPath){this._currentPath=tmpFilePath;this._fetchAndRender(tmpFilePath,tmpContainer);return;}// Re-render with cached regions (e.g. after add/delete)
|
|
12032
|
+
this._renderRegionList(tmpContainer);}/**
|
|
12033
|
+
* Force a refresh from the server for the current file.
|
|
12034
|
+
*/refresh(){this._currentPath='';this.render();}/**
|
|
12035
|
+
* Fetch regions from the server and render.
|
|
12036
|
+
*
|
|
12037
|
+
* @param {string} pFilePath - Relative file path
|
|
12038
|
+
* @param {HTMLElement} pContainer - The container to render into
|
|
12039
|
+
*/_fetchAndRender(pFilePath,pContainer){let tmpSelf=this;let tmpProvider=this.pict.providers['RetoldRemote-Provider'];let tmpPathParam=tmpProvider?tmpProvider._getPathParam(pFilePath):encodeURIComponent(pFilePath);pContainer.innerHTML='<div style="padding:12px;color:var(--retold-text-dim);font-size:0.82rem;">Loading\u2026</div>';fetch('/api/media/subimage-regions?path='+tmpPathParam).then(pResponse=>pResponse.json()).then(pResult=>{if(pResult&&pResult.Success){tmpSelf._regions=pResult.Regions||[];}else{tmpSelf._regions=[];}tmpSelf._renderRegionList(pContainer);}).catch(()=>{tmpSelf._regions=[];tmpSelf._renderRegionList(pContainer);});}/**
|
|
12040
|
+
* Render the region list into the container.
|
|
12041
|
+
*
|
|
12042
|
+
* @param {HTMLElement} pContainer - The container element
|
|
12043
|
+
*/_renderRegionList(pContainer){if(!pContainer){pContainer=document.getElementById('RetoldRemote-Subimages-Container');}if(!pContainer){return;}// Also sync the regions to the image explorer if it's open
|
|
12044
|
+
let tmpIEX=this.pict.views['RetoldRemote-ImageExplorer'];if(tmpIEX&&tmpIEX._currentPath===this._currentPath){tmpIEX._savedRegions=this._regions;}let tmpFmt=this.pict.providers['RetoldRemote-FormattingUtilities'];let tmpFileName=(this._currentPath||'').replace(/^.*\//,'');let tmpHTML='<div class="retold-remote-subimages-panel">';// Header
|
|
12045
|
+
tmpHTML+='<div style="padding:8px 10px;font-size:0.78rem;color:var(--retold-text-dim);border-bottom:1px solid var(--retold-border);">';tmpHTML+=tmpFmt.escapeHTML(tmpFileName);tmpHTML+=' — '+this._regions.length+' region'+(this._regions.length!==1?'s':'');tmpHTML+='</div>';if(this._regions.length===0){tmpHTML+='<div style="padding:16px 12px;color:var(--retold-text-dim);font-size:0.8rem;text-align:center;">';tmpHTML+='No regions yet.<br>Use selection tools in the viewer to create regions.';tmpHTML+='</div>';}else{for(let i=0;i<this._regions.length;i++){let tmpRegion=this._regions[i];let tmpLabel=tmpRegion.Label||'(unlabeled)';let tmpIsText=tmpRegion.Type==='text-selection';// Build description based on region type
|
|
12046
|
+
let tmpDesc='';if(tmpIsText){let tmpPreview=(tmpRegion.SelectedText||'').substring(0,60);if((tmpRegion.SelectedText||'').length>60)tmpPreview+='\u2026';tmpDesc=tmpPreview||'(no text)';if(tmpRegion.PageNumber){tmpDesc='p.'+tmpRegion.PageNumber+' \u2014 '+tmpDesc;}else if(tmpRegion.ChapterTitle){tmpDesc=tmpRegion.ChapterTitle;}}else{tmpDesc=(tmpRegion.Width||0)+' \u00d7 '+(tmpRegion.Height||0)+' px';if(tmpRegion.PageNumber){tmpDesc='p.'+tmpRegion.PageNumber+' \u2014 '+tmpDesc;}else if(tmpRegion.X!==null&&tmpRegion.Y!==null){tmpDesc+=' at '+tmpRegion.X+', '+tmpRegion.Y;}}// Type icon
|
|
12047
|
+
let tmpTypeIcon=tmpIsText?'\uD83D\uDCDD':'\uD83D\uDD32';tmpHTML+='<div class="retold-remote-subimages-item" data-region-id="'+tmpRegion.ID+'">';// Region info
|
|
12048
|
+
tmpHTML+='<div class="retold-remote-subimages-item-info">';tmpHTML+='<div class="retold-remote-subimages-item-label">'+tmpTypeIcon+' '+tmpFmt.escapeHTML(tmpLabel)+'</div>';tmpHTML+='<div class="retold-remote-subimages-item-dims">'+tmpFmt.escapeHTML(tmpDesc)+'</div>';tmpHTML+='</div>';// Actions
|
|
12049
|
+
tmpHTML+='<div class="retold-remote-subimages-item-actions">';tmpHTML+='<button onclick="pict.views[\'RetoldRemote-SubimagesPanel\'].navigateToRegion(\''+tmpRegion.ID+'\')" title="Navigate to region" style="font-size:0.7rem;padding:2px 6px;">🔎</button>';tmpHTML+='<button onclick="pict.views[\'RetoldRemote-SubimagesPanel\'].addRegionToCollection(\''+tmpRegion.ID+'\')" title="Add to collection" style="font-size:0.7rem;padding:2px 6px;">✚</button>';tmpHTML+='<button onclick="pict.views[\'RetoldRemote-SubimagesPanel\'].deleteRegion(\''+tmpRegion.ID+'\')" title="Delete region" style="font-size:0.7rem;padding:2px 6px;">🗑</button>';tmpHTML+='</div>';tmpHTML+='</div>';}}tmpHTML+='</div>';pContainer.innerHTML=tmpHTML;}/**
|
|
12050
|
+
* Navigate to a specific region — handles images, EPUB, and PDF.
|
|
12051
|
+
*
|
|
12052
|
+
* @param {string} pRegionID - The region ID
|
|
12053
|
+
*/navigateToRegion(pRegionID){let tmpRegion=null;for(let i=0;i<this._regions.length;i++){if(this._regions[i].ID===pRegionID){tmpRegion=this._regions[i];break;}}if(!tmpRegion){return;}let tmpRemote=this.pict.AppData.RetoldRemote;let tmpMediaViewer=this.pict.views['RetoldRemote-MediaViewer'];// EPUB: navigate to CFI location
|
|
12054
|
+
if(tmpRegion.CFI&&tmpMediaViewer&&tmpMediaViewer._activeRendition){tmpMediaViewer._activeRendition.display(tmpRegion.CFI);return;}// PDF: navigate to page
|
|
12055
|
+
if(tmpRegion.PageNumber&&tmpMediaViewer&&typeof tmpMediaViewer._renderPdfPage==='function'){tmpMediaViewer._renderPdfPage(tmpRegion.PageNumber);return;}// Image: use image explorer
|
|
12056
|
+
let tmpIEX=this.pict.views['RetoldRemote-ImageExplorer'];if(tmpRemote.ActiveMode==='image-explorer'&&tmpIEX){tmpIEX.zoomToRegion(pRegionID);}else if(tmpIEX&&this._currentPath){tmpIEX.showExplorer(this._currentPath);setTimeout(()=>{tmpIEX.zoomToRegion(pRegionID);},800);}}/**
|
|
12057
|
+
* Add a subimage region to the active collection.
|
|
12058
|
+
*
|
|
12059
|
+
* @param {string} pRegionID - The region ID to add
|
|
12060
|
+
*/addRegionToCollection(pRegionID){let tmpRegion=null;for(let i=0;i<this._regions.length;i++){if(this._regions[i].ID===pRegionID){tmpRegion=this._regions[i];break;}}if(!tmpRegion){return;}let tmpCollMgr=this.pict.providers['RetoldRemote-CollectionManager'];if(tmpCollMgr){let tmpGUID=tmpCollMgr.getQuickAddTargetGUID();if(tmpGUID){tmpCollMgr.addSubimageToCollection(tmpGUID,tmpRegion,this._currentPath);}else{let tmpTopBar=this.pict.views['ContentEditor-TopBar'];if(tmpTopBar&&typeof tmpTopBar.showAddToCollectionDropdown==='function'){tmpTopBar.showAddToCollectionDropdown();}}}}/**
|
|
12061
|
+
* Delete a subimage region.
|
|
12062
|
+
*
|
|
12063
|
+
* @param {string} pRegionID - The region ID to delete
|
|
12064
|
+
*/deleteRegion(pRegionID){let tmpIEX=this.pict.views['RetoldRemote-ImageExplorer'];if(tmpIEX&&tmpIEX._currentPath===this._currentPath){// Delegate to the explorer which handles the API call and overlay removal
|
|
12065
|
+
tmpIEX.deleteRegion(pRegionID);}else{// Delete directly via API
|
|
12066
|
+
let tmpSelf=this;let tmpProvider=this.pict.providers['RetoldRemote-Provider'];let tmpPathParam=tmpProvider?tmpProvider._getPathParam(this._currentPath):encodeURIComponent(this._currentPath);fetch('/api/media/subimage-regions/'+encodeURIComponent(pRegionID)+'?path='+tmpPathParam,{method:'DELETE'}).then(pResponse=>pResponse.json()).then(pResult=>{if(pResult&&pResult.Success){tmpSelf._regions=pResult.Regions||[];tmpSelf._renderRegionList();let tmpToast=tmpSelf.pict.providers['RetoldRemote-ToastNotification'];if(tmpToast){tmpToast.showToast('Region deleted');}}}).catch(()=>{});}}}RetoldRemoteSubimagesPanelView.default_configuration=_ViewConfiguration;module.exports=RetoldRemoteSubimagesPanelView;},{"pict-view":88}],150:[function(require,module,exports){const libPictView=require('pict-view');const _ViewConfiguration={ViewIdentifier:"ContentEditor-TopBar",DefaultRenderable:"RetoldRemote-TopBar",DefaultDestinationAddress:"#ContentEditor-TopBar-Container",AutoRender:false,CSS:``,Templates:[{Hash:"RetoldRemote-TopBar",Template:/*html*/`
|
|
11713
12067
|
<div class="retold-remote-topbar">
|
|
11714
12068
|
<button class="retold-remote-topbar-sidebar-toggle" id="RetoldRemote-TopBar-SidebarToggle" onclick="pict.views['ContentEditor-Layout'].toggleSidebar()" title="Toggle Sidebar"></button>
|
|
11715
12069
|
<button class="retold-remote-topbar-df-toggle" id="RetoldRemote-TopBar-DFToggle" onclick="pict.views['ContentEditor-TopBar'].toggleDistractionFree()" title="Distraction-free mode (d)"></button>
|
|
@@ -11820,7 +12174,7 @@ tmpBtn.style.position='relative';tmpBtn.appendChild(tmpDropdown);// Close on out
|
|
|
11820
12174
|
setTimeout(()=>{document.addEventListener('click',tmpSelf._boundCloseDropdown=pClickEvent=>{if(!tmpDropdown.contains(pClickEvent.target)&&pClickEvent.target!==tmpBtn){tmpSelf._closeAddToCollectionDropdown();}});},10);});}/**
|
|
11821
12175
|
* Close the add-to-collection dropdown.
|
|
11822
12176
|
*/_closeAddToCollectionDropdown(){let tmpDropdown=document.getElementById('RetoldRemote-AddToCollection-Dropdown');if(tmpDropdown){tmpDropdown.remove();}if(this._boundCloseDropdown){document.removeEventListener('click',this._boundCloseDropdown);this._boundCloseDropdown=null;}// Clear any pending clip context that was never consumed
|
|
11823
|
-
let tmpManager=this.pict.providers['RetoldRemote-CollectionManager'];if(tmpManager){tmpManager.clearPendingClipContext();}}}RetoldRemoteTopBarView.default_configuration=_ViewConfiguration;module.exports=RetoldRemoteTopBarView;},{"pict-view":88}],
|
|
12177
|
+
let tmpManager=this.pict.providers['RetoldRemote-CollectionManager'];if(tmpManager){tmpManager.clearPendingClipContext();}}}RetoldRemoteTopBarView.default_configuration=_ViewConfiguration;module.exports=RetoldRemoteTopBarView;},{"pict-view":88}],151:[function(require,module,exports){const libPictView=require('pict-view');const _ViewConfiguration={ViewIdentifier:"RetoldRemote-VLCSetup",DefaultRenderable:"RetoldRemote-VLCSetup",DefaultDestinationAddress:"#ContentEditor-Application-Container",AutoRender:false,CSS:``};class RetoldRemoteVLCSetupView extends libPictView{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this._activePlatformTab=this._detectPlatform();this._modalVisible=false;this._boundKeyHandler=null;}_detectPlatform(){let tmpUA=typeof navigator!=='undefined'?navigator.userAgent:'';if(/iPhone|iPad|iPod/i.test(tmpUA)){return'ios';}// iPadOS 13+ sends a macOS user agent — detect via maxTouchPoints
|
|
11824
12178
|
if(/Macintosh/i.test(tmpUA)&&typeof navigator!=='undefined'&&navigator.maxTouchPoints>1){return'ios';}if(/Android/i.test(tmpUA)){return'android';}if(/Macintosh|Mac OS X/.test(tmpUA)){return'macos';}if(/Windows/.test(tmpUA)){return'windows';}return'linux';}openModal(){if(this._modalVisible){return;}this._modalVisible=true;// Create the backdrop
|
|
11825
12179
|
let tmpBackdrop=document.createElement('div');tmpBackdrop.className='retold-remote-vlc-modal-backdrop';tmpBackdrop.id='RetoldRemote-VLCSetup-Backdrop';tmpBackdrop.onclick=pEvent=>{if(pEvent.target===tmpBackdrop){this.closeModal();}};// Create the modal
|
|
11826
12180
|
let tmpModal=document.createElement('div');tmpModal.className='retold-remote-vlc-modal';// Header
|
|
@@ -11840,7 +12194,7 @@ return["Windows Registry Editor Version 5.00","","[HKEY_CLASSES_ROOT\\vlc]","@=\
|
|
|
11840
12194
|
// protocol to use it. The handler URL-decodes the argument because
|
|
11841
12195
|
// the client percent-encodes the URL to prevent Windows from
|
|
11842
12196
|
// stripping colons in nested http:// URLs.
|
|
11843
|
-
return["@echo off","REM VLC Protocol Handler Setup for Windows","REM Run this as Administrator","","REM Create the handler directory","mkdir \"%APPDATA%\\VLCProtocol\" 2>nul","","REM Write the PowerShell handler script","(","echo $url = $args[0]","echo if ^($url -and $url.StartsWith^('vlc://'^)^) { $url = $url.Substring^(6^) }","echo $url = [System.Uri]::UnescapeDataString^($url^)","echo $url = $url.TrimEnd^('/'^)","echo if ^($url^) { Start-Process 'C:\\Program Files\\VideoLAN\\VLC\\vlc.exe' -ArgumentList $url }",") > \"%APPDATA%\\VLCProtocol\\handler.ps1\"","","REM Register the protocol in the registry","reg add \"HKCU\\Software\\Classes\\vlc\" /ve /d \"URL:VLC Protocol\" /f","reg add \"HKCU\\Software\\Classes\\vlc\" /v \"URL Protocol\" /d \"\" /f","reg add \"HKCU\\Software\\Classes\\vlc\\shell\\open\\command\" /ve /d \"powershell.exe -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File \\\"%APPDATA%\\VLCProtocol\\handler.ps1\\\" \\\"%%1\\\"\" /f","","echo VLC protocol handler installed successfully.","pause"].join('\n');}_getLinuxSetupScript(){return["# Create handler script","mkdir -p ~/.local/bin","cat > ~/.local/bin/vlc-protocol << 'EOF'","#!/bin/bash","URL=\"$1\"","URL=\"${URL#vlc://}\"","URL=$(python3 -c \"import sys, urllib.parse; print(urllib.parse.unquote(sys.argv[1]))\" \"$URL\")","exec vlc \"$URL\" &","EOF","chmod +x ~/.local/bin/vlc-protocol","","# Create .desktop file","cat > ~/.local/share/applications/vlc-protocol.desktop << 'EOF'","[Desktop Entry]","Name=VLC Protocol Handler","Exec=bash -c '~/.local/bin/vlc-protocol %u'","Type=Application","NoDisplay=true","MimeType=x-scheme-handler/vlc;","EOF","","# Register the handler","xdg-mime default vlc-protocol.desktop x-scheme-handler/vlc","update-desktop-database ~/.local/share/applications/","","echo \"VLC protocol handler installed successfully.\""].join('\n');}_copyToClipboard(pText,pLabel){if(navigator.clipboard&&navigator.clipboard.writeText){navigator.clipboard.writeText(pText).then(()=>{this.pict.providers['RetoldRemote-ToastNotification'].showToast(pLabel+' copied to clipboard');}).catch(()=>{this._fallbackCopy(pText,pLabel);});}else{this._fallbackCopy(pText,pLabel);}}_fallbackCopy(pText,pLabel){let tmpTextarea=document.createElement('textarea');tmpTextarea.value=pText;tmpTextarea.style.position='fixed';tmpTextarea.style.left='-9999px';document.body.appendChild(tmpTextarea);tmpTextarea.select();try{document.execCommand('copy');this.pict.providers['RetoldRemote-ToastNotification'].showToast(pLabel+' copied to clipboard');}catch(pErr){this.pict.providers['RetoldRemote-ToastNotification'].showToast('Failed to copy - please select and copy manually');}document.body.removeChild(tmpTextarea);}copyMacSetup(){this._copyToClipboard(this._getMacSetupScript(),'macOS setup script');}copyWindowsReg(){this._copyToClipboard(this._getWindowsRegFile(),'Registry file');}copyWindowsBatch(){this._copyToClipboard(this._getWindowsBatchScript(),'Batch script');}copyLinuxSetup(){this._copyToClipboard(this._getLinuxSetupScript(),'Linux setup script');}testProtocol(){let tmpIsWindows=/Windows/.test(navigator.userAgent);let tmpIsMobile=/iPhone|iPad|iPod|Android/i.test(navigator.userAgent);let tmpSampleURL='https://www.sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4';let tmpTestURL=tmpIsWindows||tmpIsMobile?'vlc://'+tmpSampleURL:'vlc://'+encodeURIComponent(tmpSampleURL);let tmpLink=document.createElement('a');tmpLink.href=tmpTestURL;tmpLink.style.display='none';document.body.appendChild(tmpLink);tmpLink.click();document.body.removeChild(tmpLink);}}RetoldRemoteVLCSetupView.default_configuration=_ViewConfiguration;module.exports=RetoldRemoteVLCSetupView;},{"pict-view":88}],
|
|
12197
|
+
return["@echo off","REM VLC Protocol Handler Setup for Windows","REM Run this as Administrator","","REM Create the handler directory","mkdir \"%APPDATA%\\VLCProtocol\" 2>nul","","REM Write the PowerShell handler script","(","echo $url = $args[0]","echo if ^($url -and $url.StartsWith^('vlc://'^)^) { $url = $url.Substring^(6^) }","echo $url = [System.Uri]::UnescapeDataString^($url^)","echo $url = $url.TrimEnd^('/'^)","echo if ^($url^) { Start-Process 'C:\\Program Files\\VideoLAN\\VLC\\vlc.exe' -ArgumentList $url }",") > \"%APPDATA%\\VLCProtocol\\handler.ps1\"","","REM Register the protocol in the registry","reg add \"HKCU\\Software\\Classes\\vlc\" /ve /d \"URL:VLC Protocol\" /f","reg add \"HKCU\\Software\\Classes\\vlc\" /v \"URL Protocol\" /d \"\" /f","reg add \"HKCU\\Software\\Classes\\vlc\\shell\\open\\command\" /ve /d \"powershell.exe -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File \\\"%APPDATA%\\VLCProtocol\\handler.ps1\\\" \\\"%%1\\\"\" /f","","echo VLC protocol handler installed successfully.","pause"].join('\n');}_getLinuxSetupScript(){return["# Create handler script","mkdir -p ~/.local/bin","cat > ~/.local/bin/vlc-protocol << 'EOF'","#!/bin/bash","URL=\"$1\"","URL=\"${URL#vlc://}\"","URL=$(python3 -c \"import sys, urllib.parse; print(urllib.parse.unquote(sys.argv[1]))\" \"$URL\")","exec vlc \"$URL\" &","EOF","chmod +x ~/.local/bin/vlc-protocol","","# Create .desktop file","cat > ~/.local/share/applications/vlc-protocol.desktop << 'EOF'","[Desktop Entry]","Name=VLC Protocol Handler","Exec=bash -c '~/.local/bin/vlc-protocol %u'","Type=Application","NoDisplay=true","MimeType=x-scheme-handler/vlc;","EOF","","# Register the handler","xdg-mime default vlc-protocol.desktop x-scheme-handler/vlc","update-desktop-database ~/.local/share/applications/","","echo \"VLC protocol handler installed successfully.\""].join('\n');}_copyToClipboard(pText,pLabel){if(navigator.clipboard&&navigator.clipboard.writeText){navigator.clipboard.writeText(pText).then(()=>{this.pict.providers['RetoldRemote-ToastNotification'].showToast(pLabel+' copied to clipboard');}).catch(()=>{this._fallbackCopy(pText,pLabel);});}else{this._fallbackCopy(pText,pLabel);}}_fallbackCopy(pText,pLabel){let tmpTextarea=document.createElement('textarea');tmpTextarea.value=pText;tmpTextarea.style.position='fixed';tmpTextarea.style.left='-9999px';document.body.appendChild(tmpTextarea);tmpTextarea.select();try{document.execCommand('copy');this.pict.providers['RetoldRemote-ToastNotification'].showToast(pLabel+' copied to clipboard');}catch(pErr){this.pict.providers['RetoldRemote-ToastNotification'].showToast('Failed to copy - please select and copy manually');}document.body.removeChild(tmpTextarea);}copyMacSetup(){this._copyToClipboard(this._getMacSetupScript(),'macOS setup script');}copyWindowsReg(){this._copyToClipboard(this._getWindowsRegFile(),'Registry file');}copyWindowsBatch(){this._copyToClipboard(this._getWindowsBatchScript(),'Batch script');}copyLinuxSetup(){this._copyToClipboard(this._getLinuxSetupScript(),'Linux setup script');}testProtocol(){let tmpIsWindows=/Windows/.test(navigator.userAgent);let tmpIsMobile=/iPhone|iPad|iPod|Android/i.test(navigator.userAgent);let tmpSampleURL='https://www.sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4';let tmpTestURL=tmpIsWindows||tmpIsMobile?'vlc://'+tmpSampleURL:'vlc://'+encodeURIComponent(tmpSampleURL);let tmpLink=document.createElement('a');tmpLink.href=tmpTestURL;tmpLink.style.display='none';document.body.appendChild(tmpLink);tmpLink.click();document.body.removeChild(tmpLink);}}RetoldRemoteVLCSetupView.default_configuration=_ViewConfiguration;module.exports=RetoldRemoteVLCSetupView;},{"pict-view":88}],152:[function(require,module,exports){const libPictView=require('pict-view');const _VideoExplorerSelection=require('./VideoExplorer-Selection');const _VideoExplorerCustomFrames=require('./VideoExplorer-CustomFrames');const _VideoExplorerPreview=require('./VideoExplorer-Preview');const _ViewConfiguration={ViewIdentifier:"RetoldRemote-VideoExplorer",DefaultRenderable:"RetoldRemote-VideoExplorer",DefaultDestinationAddress:"#RetoldRemote-Viewer-Container",AutoRender:false,CSS:``};class RetoldRemoteVideoExplorerView extends libPictView{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this._currentPath='';this._frameData=null;this._selectedFrameIndex=-1;this._frameCount=20;this._fullResFrames=true;this._customFrames=[];// Selection mode and state for timeline range selection
|
|
11844
12198
|
this._selectionModeActive=false;this._selectionStartTime=-1;this._selectionEndTime=-1;this._isSelectingRange=false;this._isDraggingTimeline=false;this._draggingHandle=null;// 'start', 'end', or null
|
|
11845
12199
|
// Cached provider references (resolved lazily)
|
|
11846
12200
|
this._fmt=null;this._provider=null;}// -----------------------------------------------------------------
|
|
@@ -11975,7 +12329,7 @@ let tmpTimeline=document.getElementById('RetoldRemote-VEX-Timeline');if(tmpTimel
|
|
|
11975
12329
|
*
|
|
11976
12330
|
* @param {string} pMessage - Error message
|
|
11977
12331
|
*/_showError(pMessage){let tmpBody=document.getElementById('RetoldRemote-VEX-Body');if(tmpBody){tmpBody.innerHTML='<div class="retold-remote-vex-error">'+'<div class="retold-remote-vex-error-message">'+this._getFmt().escapeHTML(pMessage||'An error occurred.')+'</div>'+'<button class="retold-remote-vex-nav-btn" onclick="pict.views[\'RetoldRemote-VideoExplorer\'].goBack()">Back to Video</button>'+'</div>';}}}// -- Mix in method groups from sub-modules --------------------------------
|
|
11978
|
-
Object.assign(RetoldRemoteVideoExplorerView.prototype,_VideoExplorerSelection);Object.assign(RetoldRemoteVideoExplorerView.prototype,_VideoExplorerCustomFrames);Object.assign(RetoldRemoteVideoExplorerView.prototype,_VideoExplorerPreview);RetoldRemoteVideoExplorerView.default_configuration=_ViewConfiguration;module.exports=RetoldRemoteVideoExplorerView;},{"./VideoExplorer-CustomFrames":
|
|
12332
|
+
Object.assign(RetoldRemoteVideoExplorerView.prototype,_VideoExplorerSelection);Object.assign(RetoldRemoteVideoExplorerView.prototype,_VideoExplorerCustomFrames);Object.assign(RetoldRemoteVideoExplorerView.prototype,_VideoExplorerPreview);RetoldRemoteVideoExplorerView.default_configuration=_ViewConfiguration;module.exports=RetoldRemoteVideoExplorerView;},{"./VideoExplorer-CustomFrames":153,"./VideoExplorer-Preview":154,"./VideoExplorer-Selection":155,"pict-view":88}],153:[function(require,module,exports){/**
|
|
11979
12333
|
* VideoExplorer — Custom Frames Mixin
|
|
11980
12334
|
*
|
|
11981
12335
|
* Methods for extracting individual frames at arbitrary timestamps,
|
|
@@ -12057,7 +12411,7 @@ tmpEl.scrollIntoView({behavior:'smooth',block:'nearest'});},/**
|
|
|
12057
12411
|
*
|
|
12058
12412
|
* @param {string} pText - Formatted timestamp like "1:23" or "1:02:34"
|
|
12059
12413
|
* @returns {number} Seconds
|
|
12060
|
-
*/_parseTimestamp:function _parseTimestamp(pText){if(!pText)return 0;let tmpParts=pText.trim().split(':');if(tmpParts.length===3){return parseInt(tmpParts[0],10)*3600+parseInt(tmpParts[1],10)*60+parseInt(tmpParts[2],10);}if(tmpParts.length===2){return parseInt(tmpParts[0],10)*60+parseInt(tmpParts[1],10);}return parseFloat(pText)||0;}};},{}],
|
|
12414
|
+
*/_parseTimestamp:function _parseTimestamp(pText){if(!pText)return 0;let tmpParts=pText.trim().split(':');if(tmpParts.length===3){return parseInt(tmpParts[0],10)*3600+parseInt(tmpParts[1],10)*60+parseInt(tmpParts[2],10);}if(tmpParts.length===2){return parseInt(tmpParts[0],10)*60+parseInt(tmpParts[1],10);}return parseFloat(pText)||0;}};},{}],154:[function(require,module,exports){/**
|
|
12061
12415
|
* VideoExplorer — Frame Preview Mixin
|
|
12062
12416
|
*
|
|
12063
12417
|
* Full-screen frame preview overlay with keyboard navigation
|
|
@@ -12110,7 +12464,7 @@ this._previewKeyHandler=e=>{switch(e.key){case'Escape':e.preventDefault();e.stop
|
|
|
12110
12464
|
* Update the preview to show the frame at the current position.
|
|
12111
12465
|
*/_updatePreviewFrame:function _updatePreviewFrame(){let tmpFrame=this._previewAllFrames[this._previewPosition];if(!tmpFrame||!this._frameData){return;}// For custom frames, use the frame's own CacheKey (may differ from current batch)
|
|
12112
12466
|
let tmpCacheKey=this._frameData.CacheKey;if(tmpFrame.Type==='custom'&&tmpFrame.CacheKey){tmpCacheKey=tmpFrame.CacheKey;}let tmpURL=this._buildFrameURL(tmpCacheKey,tmpFrame.Filename);let tmpBody=document.getElementById('RetoldRemote-VEX-PreviewBody');if(tmpBody){tmpBody.innerHTML='<img src="'+tmpURL+'" alt="'+this._getFmt().escapeHTML(tmpFrame.Label)+'">';}let tmpTitle=document.getElementById('RetoldRemote-VEX-PreviewTitle');if(tmpTitle){tmpTitle.textContent=tmpFrame.Label;}// Also select the corresponding frame in the grid behind the overlay
|
|
12113
|
-
this._previewType=tmpFrame.Type;this._previewIndex=tmpFrame.Index;if(tmpFrame.Type==='regular'){this.selectFrame(tmpFrame.Index);}}};},{}],
|
|
12467
|
+
this._previewType=tmpFrame.Type;this._previewIndex=tmpFrame.Index;if(tmpFrame.Type==='regular'){this.selectFrame(tmpFrame.Index);}}};},{}],155:[function(require,module,exports){/**
|
|
12114
12468
|
* VideoExplorer — Selection Mixin
|
|
12115
12469
|
*
|
|
12116
12470
|
* Methods for timeline range selection: toggling selection mode,
|