retold-remote 0.0.5 → 0.0.7
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 +3 -0
- package/docs/README.md +181 -0
- package/docs/_cover.md +14 -0
- package/docs/_sidebar.md +10 -0
- package/docs/_topbar.md +3 -0
- package/docs/audio-viewer.md +133 -0
- package/docs/ebook-reader.md +90 -0
- package/docs/image-viewer.md +90 -0
- package/docs/server-setup.md +262 -0
- package/docs/video-viewer.md +134 -0
- package/html/docs.html +59 -0
- package/html/index.html +1 -1
- package/package.json +20 -6
- package/source/Pict-Application-RetoldRemote.js +122 -2
- package/source/RetoldRemote-ExtensionMaps.js +33 -0
- package/source/cli/RetoldRemote-Server-Setup.js +211 -67
- package/source/cli/commands/RetoldRemote-Command-Serve.js +5 -26
- package/source/providers/Pict-Provider-AISortManager.js +456 -0
- package/source/providers/Pict-Provider-CollectionManager.js +1200 -0
- package/source/providers/Pict-Provider-FormattingUtilities.js +109 -0
- package/source/providers/Pict-Provider-GalleryFilterSort.js +2 -11
- package/source/providers/Pict-Provider-GalleryNavigation.js +187 -409
- package/source/providers/Pict-Provider-RetoldRemoteIcons.js +52 -0
- package/source/providers/Pict-Provider-ToastNotification.js +96 -0
- package/source/providers/keyboard-handlers/KeyHandler-AudioExplorer.js +88 -0
- package/source/providers/keyboard-handlers/KeyHandler-Gallery.js +190 -0
- package/source/providers/keyboard-handlers/KeyHandler-Sidebar.js +65 -0
- package/source/providers/keyboard-handlers/KeyHandler-VideoExplorer.js +57 -0
- package/source/providers/keyboard-handlers/KeyHandler-Viewer.js +197 -0
- package/source/server/RetoldRemote-AISortService.js +879 -0
- package/source/server/RetoldRemote-ArchiveService.js +2 -12
- package/source/server/RetoldRemote-AudioWaveformService.js +7 -16
- package/source/server/RetoldRemote-CollectionService.js +843 -0
- package/source/server/RetoldRemote-EbookService.js +7 -16
- package/source/server/RetoldRemote-FileOperationService.js +560 -0
- package/source/server/RetoldRemote-MediaService.js +15 -14
- package/source/server/RetoldRemote-MetadataCache.js +411 -0
- package/source/server/RetoldRemote-ParimeCache.js +349 -0
- package/source/server/RetoldRemote-ThumbnailCache.js +52 -20
- package/source/server/RetoldRemote-VideoFrameService.js +7 -15
- package/source/views/PictView-Remote-AudioExplorer.js +10 -43
- package/source/views/PictView-Remote-CollectionsPanel.js +1486 -0
- package/source/views/PictView-Remote-Gallery.js +237 -44
- package/source/views/PictView-Remote-ImageViewer.js +1 -34
- package/source/views/PictView-Remote-Layout.js +411 -20
- package/source/views/PictView-Remote-MediaViewer.js +311 -28
- package/source/views/PictView-Remote-SettingsPanel.js +275 -133
- package/source/views/PictView-Remote-TopBar.js +701 -14
- package/source/views/PictView-Remote-VLCSetup.js +8 -39
- package/source/views/PictView-Remote-VideoExplorer.js +20 -54
- package/web-application/css/docuserve.css +73 -0
- package/web-application/css/retold-remote.css +3 -0
- package/web-application/docs/README.md +181 -0
- package/web-application/docs/_cover.md +14 -0
- package/web-application/docs/_sidebar.md +10 -0
- package/web-application/docs/_topbar.md +3 -0
- package/web-application/docs/audio-viewer.md +133 -0
- package/web-application/docs/ebook-reader.md +90 -0
- package/web-application/docs/image-viewer.md +90 -0
- package/web-application/docs/server-setup.md +262 -0
- package/web-application/docs/video-viewer.md +134 -0
- package/web-application/docs.html +59 -0
- package/web-application/index.html +1 -1
- package/web-application/js/pict-docuserve.min.js +58 -0
- package/web-application/js/pict.min.js +2 -2
- package/web-application/js/pict.min.js.map +1 -1
- package/web-application/retold-remote.js +2652 -970
- package/web-application/retold-remote.js.map +1 -1
- package/web-application/retold-remote.min.js +60 -13
- package/web-application/retold-remote.min.js.map +1 -1
- package/server.js +0 -43
|
@@ -433,6 +433,69 @@ const _ViewConfiguration =
|
|
|
433
433
|
color: var(--retold-text-dim);
|
|
434
434
|
font-size: 0.85rem;
|
|
435
435
|
}
|
|
436
|
+
/* Distraction-free toggle */
|
|
437
|
+
.retold-remote-df-toggle
|
|
438
|
+
{
|
|
439
|
+
position: absolute;
|
|
440
|
+
top: 8px;
|
|
441
|
+
left: 8px;
|
|
442
|
+
z-index: 15;
|
|
443
|
+
padding: 4px 8px;
|
|
444
|
+
border: 1px solid var(--retold-border);
|
|
445
|
+
border-radius: 3px;
|
|
446
|
+
background: rgba(0, 0, 0, 0.5);
|
|
447
|
+
color: var(--retold-text-muted);
|
|
448
|
+
font-size: 0.72rem;
|
|
449
|
+
cursor: pointer;
|
|
450
|
+
opacity: 0;
|
|
451
|
+
transition: opacity 0.2s ease, color 0.15s, border-color 0.15s;
|
|
452
|
+
font-family: inherit;
|
|
453
|
+
white-space: nowrap;
|
|
454
|
+
}
|
|
455
|
+
.retold-remote-viewer-body:hover .retold-remote-df-toggle,
|
|
456
|
+
.retold-remote-df-toggle:focus
|
|
457
|
+
{
|
|
458
|
+
opacity: 1;
|
|
459
|
+
}
|
|
460
|
+
.retold-remote-df-toggle:hover
|
|
461
|
+
{
|
|
462
|
+
color: var(--retold-text-primary);
|
|
463
|
+
border-color: var(--retold-accent);
|
|
464
|
+
}
|
|
465
|
+
.retold-remote-df-toggle.active
|
|
466
|
+
{
|
|
467
|
+
color: var(--retold-accent);
|
|
468
|
+
border-color: var(--retold-accent);
|
|
469
|
+
}
|
|
470
|
+
/* Distraction-free exit hotspot (top-left corner) */
|
|
471
|
+
.retold-remote-df-exit-hotspot
|
|
472
|
+
{
|
|
473
|
+
position: absolute;
|
|
474
|
+
top: 0;
|
|
475
|
+
left: 0;
|
|
476
|
+
width: 80px;
|
|
477
|
+
height: 80px;
|
|
478
|
+
z-index: 16;
|
|
479
|
+
cursor: pointer;
|
|
480
|
+
display: none;
|
|
481
|
+
}
|
|
482
|
+
.retold-remote-df-exit-hotspot::after
|
|
483
|
+
{
|
|
484
|
+
content: '';
|
|
485
|
+
position: absolute;
|
|
486
|
+
top: 12px;
|
|
487
|
+
left: 12px;
|
|
488
|
+
width: 8px;
|
|
489
|
+
height: 8px;
|
|
490
|
+
border-radius: 50%;
|
|
491
|
+
background: var(--retold-accent);
|
|
492
|
+
opacity: 0;
|
|
493
|
+
transition: opacity 0.3s ease;
|
|
494
|
+
}
|
|
495
|
+
.retold-remote-df-exit-hotspot:hover::after
|
|
496
|
+
{
|
|
497
|
+
opacity: 0.6;
|
|
498
|
+
}
|
|
436
499
|
`
|
|
437
500
|
};
|
|
438
501
|
|
|
@@ -441,6 +504,12 @@ class RetoldRemoteMediaViewerView extends libPictView
|
|
|
441
504
|
constructor(pFable, pOptions, pServiceHash)
|
|
442
505
|
{
|
|
443
506
|
super(pFable, pOptions, pServiceHash);
|
|
507
|
+
|
|
508
|
+
this._swipeStartX = 0;
|
|
509
|
+
this._swipeStartY = 0;
|
|
510
|
+
this._swipeTouchCount = 0;
|
|
511
|
+
this._swipeHandlers = null;
|
|
512
|
+
this._dfExitHandlers = null;
|
|
444
513
|
}
|
|
445
514
|
|
|
446
515
|
/**
|
|
@@ -475,7 +544,7 @@ class RetoldRemoteMediaViewerView extends libPictView
|
|
|
475
544
|
tmpHTML += '<div class="retold-remote-viewer-header">';
|
|
476
545
|
tmpHTML += '<button class="retold-remote-viewer-nav-btn" onclick="pict.providers[\'RetoldRemote-GalleryNavigation\'].closeViewer()" title="Back (Esc)">← Back</button>';
|
|
477
546
|
tmpHTML += '<button class="retold-remote-viewer-nav-btn" onclick="pict.providers[\'RetoldRemote-GalleryNavigation\'].prevFile()" title="Previous (k)">‹ Prev</button>';
|
|
478
|
-
tmpHTML += '<div class="retold-remote-viewer-title">' + this.
|
|
547
|
+
tmpHTML += '<div class="retold-remote-viewer-title">' + this.pict.providers['RetoldRemote-FormattingUtilities'].escapeHTML(tmpFileName) + '</div>';
|
|
479
548
|
tmpHTML += '<button class="retold-remote-viewer-nav-btn" onclick="pict.providers[\'RetoldRemote-GalleryNavigation\'].nextFile()" title="Next (j)">Next ›</button>';
|
|
480
549
|
tmpHTML += '<button class="retold-remote-viewer-nav-btn" onclick="pict.providers[\'RetoldRemote-GalleryNavigation\']._toggleFileInfo()" title="Info (i)">ⓘ</button>';
|
|
481
550
|
tmpHTML += '<button class="retold-remote-viewer-nav-btn" onclick="pict.providers[\'RetoldRemote-GalleryNavigation\']._toggleFullscreen()" title="Fullscreen (f)">▢</button>';
|
|
@@ -484,6 +553,14 @@ class RetoldRemoteMediaViewerView extends libPictView
|
|
|
484
553
|
// Body with media content
|
|
485
554
|
tmpHTML += '<div class="retold-remote-viewer-body">';
|
|
486
555
|
|
|
556
|
+
// Distraction-free toggle (top-left corner)
|
|
557
|
+
let tmpDFActive = tmpRemote._distractionFreeMode ? ' active' : '';
|
|
558
|
+
tmpHTML += '<button class="retold-remote-df-toggle' + tmpDFActive + '" id="RetoldRemote-DF-Toggle" onclick="pict.views[\'RetoldRemote-MediaViewer\'].toggleDistractionFree()" title="Distraction-Free (d)">◉ DF</button>';
|
|
559
|
+
|
|
560
|
+
// Exit hotspot for distraction-free mode (double-click/tap top-left to exit)
|
|
561
|
+
let tmpDFHotspotDisplay = tmpRemote._distractionFreeMode ? '' : ' style="display:none"';
|
|
562
|
+
tmpHTML += '<div class="retold-remote-df-exit-hotspot" id="RetoldRemote-DF-ExitHotspot"' + tmpDFHotspotDisplay + '></div>';
|
|
563
|
+
|
|
487
564
|
switch (pMediaType)
|
|
488
565
|
{
|
|
489
566
|
case 'image':
|
|
@@ -538,6 +615,12 @@ class RetoldRemoteMediaViewerView extends libPictView
|
|
|
538
615
|
}
|
|
539
616
|
}
|
|
540
617
|
|
|
618
|
+
// Set up swipe navigation for touch devices
|
|
619
|
+
this._setupSwipeNavigation();
|
|
620
|
+
|
|
621
|
+
// Set up distraction-free exit hotspot (double-click/tap top-left)
|
|
622
|
+
this._setupDFExitHotspot();
|
|
623
|
+
|
|
541
624
|
// Update topbar
|
|
542
625
|
let tmpTopBar = this.pict.views['ContentEditor-TopBar'];
|
|
543
626
|
if (tmpTopBar)
|
|
@@ -546,9 +629,224 @@ class RetoldRemoteMediaViewerView extends libPictView
|
|
|
546
629
|
}
|
|
547
630
|
}
|
|
548
631
|
|
|
632
|
+
/**
|
|
633
|
+
* Attach touch event listeners to the viewer body for swipe-based
|
|
634
|
+
* prev/next navigation. Only single-finger horizontal swipes are
|
|
635
|
+
* recognised; pinch gestures and vertical scrolling are ignored.
|
|
636
|
+
* Swipes are also suppressed when the image is zoomed and the
|
|
637
|
+
* container is scrollable, so the user can pan freely.
|
|
638
|
+
*/
|
|
639
|
+
_setupSwipeNavigation()
|
|
640
|
+
{
|
|
641
|
+
// Clean up any previous listeners
|
|
642
|
+
this._cleanupSwipe();
|
|
643
|
+
|
|
644
|
+
let tmpBody = document.querySelector('.retold-remote-viewer-body');
|
|
645
|
+
if (!tmpBody)
|
|
646
|
+
{
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
let tmpSelf = this;
|
|
651
|
+
let tmpSwipeThreshold = 50; // minimum px to count as a swipe
|
|
652
|
+
|
|
653
|
+
let tmpOnTouchStart = function (pEvent)
|
|
654
|
+
{
|
|
655
|
+
tmpSelf._swipeTouchCount = pEvent.touches.length;
|
|
656
|
+
if (pEvent.touches.length !== 1)
|
|
657
|
+
{
|
|
658
|
+
return;
|
|
659
|
+
}
|
|
660
|
+
tmpSelf._swipeStartX = pEvent.touches[0].clientX;
|
|
661
|
+
tmpSelf._swipeStartY = pEvent.touches[0].clientY;
|
|
662
|
+
};
|
|
663
|
+
|
|
664
|
+
let tmpOnTouchEnd = function (pEvent)
|
|
665
|
+
{
|
|
666
|
+
// Ignore multi-touch (pinch zoom, etc.)
|
|
667
|
+
if (tmpSelf._swipeTouchCount !== 1)
|
|
668
|
+
{
|
|
669
|
+
return;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
let tmpEndX = pEvent.changedTouches[0].clientX;
|
|
673
|
+
let tmpEndY = pEvent.changedTouches[0].clientY;
|
|
674
|
+
let tmpDeltaX = tmpEndX - tmpSelf._swipeStartX;
|
|
675
|
+
let tmpDeltaY = tmpEndY - tmpSelf._swipeStartY;
|
|
676
|
+
|
|
677
|
+
// Must be primarily horizontal
|
|
678
|
+
if (Math.abs(tmpDeltaX) < tmpSwipeThreshold || Math.abs(tmpDeltaY) > Math.abs(tmpDeltaX))
|
|
679
|
+
{
|
|
680
|
+
return;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
// If the viewer body is scrollable (zoomed image), don't
|
|
684
|
+
// swipe — let the user pan instead.
|
|
685
|
+
let tmpContainer = document.querySelector('.retold-remote-viewer-body');
|
|
686
|
+
if (tmpContainer && (tmpContainer.scrollWidth > tmpContainer.clientWidth + 2))
|
|
687
|
+
{
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
let tmpNav = tmpSelf.pict.providers['RetoldRemote-GalleryNavigation'];
|
|
692
|
+
if (!tmpNav)
|
|
693
|
+
{
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
if (tmpDeltaX < 0)
|
|
698
|
+
{
|
|
699
|
+
tmpNav.nextFile();
|
|
700
|
+
}
|
|
701
|
+
else
|
|
702
|
+
{
|
|
703
|
+
tmpNav.prevFile();
|
|
704
|
+
}
|
|
705
|
+
};
|
|
706
|
+
|
|
707
|
+
tmpBody.addEventListener('touchstart', tmpOnTouchStart, { passive: true });
|
|
708
|
+
tmpBody.addEventListener('touchend', tmpOnTouchEnd, { passive: true });
|
|
709
|
+
|
|
710
|
+
this._swipeHandlers =
|
|
711
|
+
{
|
|
712
|
+
element: tmpBody,
|
|
713
|
+
touchstart: tmpOnTouchStart,
|
|
714
|
+
touchend: tmpOnTouchEnd
|
|
715
|
+
};
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
/**
|
|
719
|
+
* Remove swipe touch listeners from the viewer body.
|
|
720
|
+
*/
|
|
721
|
+
_cleanupSwipe()
|
|
722
|
+
{
|
|
723
|
+
if (this._swipeHandlers)
|
|
724
|
+
{
|
|
725
|
+
this._swipeHandlers.element.removeEventListener('touchstart', this._swipeHandlers.touchstart);
|
|
726
|
+
this._swipeHandlers.element.removeEventListener('touchend', this._swipeHandlers.touchend);
|
|
727
|
+
this._swipeHandlers = null;
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
/**
|
|
732
|
+
* Toggle distraction-free mode from the viewer overlay button.
|
|
733
|
+
* Delegates to the gallery navigation provider, then updates
|
|
734
|
+
* the toggle button and exit hotspot state.
|
|
735
|
+
*/
|
|
736
|
+
toggleDistractionFree()
|
|
737
|
+
{
|
|
738
|
+
let tmpNav = this.pict.providers['RetoldRemote-GalleryNavigation'];
|
|
739
|
+
if (tmpNav)
|
|
740
|
+
{
|
|
741
|
+
tmpNav._toggleDistractionFree();
|
|
742
|
+
}
|
|
743
|
+
this._updateDFControls();
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
/**
|
|
747
|
+
* Sync the distraction-free toggle button and exit hotspot
|
|
748
|
+
* with the current mode state.
|
|
749
|
+
*/
|
|
750
|
+
_updateDFControls()
|
|
751
|
+
{
|
|
752
|
+
let tmpRemote = this.pict.AppData.RetoldRemote;
|
|
753
|
+
let tmpActive = tmpRemote._distractionFreeMode || false;
|
|
754
|
+
|
|
755
|
+
let tmpToggle = document.getElementById('RetoldRemote-DF-Toggle');
|
|
756
|
+
if (tmpToggle)
|
|
757
|
+
{
|
|
758
|
+
if (tmpActive)
|
|
759
|
+
{
|
|
760
|
+
tmpToggle.classList.add('active');
|
|
761
|
+
}
|
|
762
|
+
else
|
|
763
|
+
{
|
|
764
|
+
tmpToggle.classList.remove('active');
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
let tmpHotspot = document.getElementById('RetoldRemote-DF-ExitHotspot');
|
|
769
|
+
if (tmpHotspot)
|
|
770
|
+
{
|
|
771
|
+
tmpHotspot.style.display = tmpActive ? '' : 'none';
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
/**
|
|
776
|
+
* Set up the double-click / double-tap handler on the
|
|
777
|
+
* exit hotspot so the user can leave distraction-free mode
|
|
778
|
+
* from the top-left corner of the viewer.
|
|
779
|
+
*/
|
|
780
|
+
_setupDFExitHotspot()
|
|
781
|
+
{
|
|
782
|
+
this._cleanupDFExitHotspot();
|
|
783
|
+
|
|
784
|
+
let tmpHotspot = document.getElementById('RetoldRemote-DF-ExitHotspot');
|
|
785
|
+
if (!tmpHotspot)
|
|
786
|
+
{
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
let tmpSelf = this;
|
|
791
|
+
|
|
792
|
+
// Double-click for mouse
|
|
793
|
+
let tmpOnDblClick = function ()
|
|
794
|
+
{
|
|
795
|
+
let tmpRemote = tmpSelf.pict.AppData.RetoldRemote;
|
|
796
|
+
if (tmpRemote._distractionFreeMode)
|
|
797
|
+
{
|
|
798
|
+
tmpSelf.toggleDistractionFree();
|
|
799
|
+
}
|
|
800
|
+
};
|
|
801
|
+
|
|
802
|
+
// Double-tap for touch: detect two taps within 300ms
|
|
803
|
+
let tmpLastTap = 0;
|
|
804
|
+
let tmpOnTouchEnd = function (pEvent)
|
|
805
|
+
{
|
|
806
|
+
let tmpNow = Date.now();
|
|
807
|
+
if (tmpNow - tmpLastTap < 300)
|
|
808
|
+
{
|
|
809
|
+
pEvent.preventDefault();
|
|
810
|
+
let tmpRemote = tmpSelf.pict.AppData.RetoldRemote;
|
|
811
|
+
if (tmpRemote._distractionFreeMode)
|
|
812
|
+
{
|
|
813
|
+
tmpSelf.toggleDistractionFree();
|
|
814
|
+
}
|
|
815
|
+
tmpLastTap = 0;
|
|
816
|
+
}
|
|
817
|
+
else
|
|
818
|
+
{
|
|
819
|
+
tmpLastTap = tmpNow;
|
|
820
|
+
}
|
|
821
|
+
};
|
|
822
|
+
|
|
823
|
+
tmpHotspot.addEventListener('dblclick', tmpOnDblClick);
|
|
824
|
+
tmpHotspot.addEventListener('touchend', tmpOnTouchEnd);
|
|
825
|
+
|
|
826
|
+
this._dfExitHandlers =
|
|
827
|
+
{
|
|
828
|
+
element: tmpHotspot,
|
|
829
|
+
dblclick: tmpOnDblClick,
|
|
830
|
+
touchend: tmpOnTouchEnd
|
|
831
|
+
};
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
/**
|
|
835
|
+
* Remove exit hotspot event listeners.
|
|
836
|
+
*/
|
|
837
|
+
_cleanupDFExitHotspot()
|
|
838
|
+
{
|
|
839
|
+
if (this._dfExitHandlers)
|
|
840
|
+
{
|
|
841
|
+
this._dfExitHandlers.element.removeEventListener('dblclick', this._dfExitHandlers.dblclick);
|
|
842
|
+
this._dfExitHandlers.element.removeEventListener('touchend', this._dfExitHandlers.touchend);
|
|
843
|
+
this._dfExitHandlers = null;
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
|
|
549
847
|
_buildImageHTML(pURL, pFileName)
|
|
550
848
|
{
|
|
551
|
-
return '<img src="' + pURL + '" alt="' + this.
|
|
849
|
+
return '<img src="' + pURL + '" alt="' + this.pict.providers['RetoldRemote-FormattingUtilities'].escapeHTML(pFileName) + '" '
|
|
552
850
|
+ 'style="max-width: 100%; max-height: 100%; object-fit: contain; cursor: zoom-in;" '
|
|
553
851
|
+ 'id="RetoldRemote-ImageViewer-Img" '
|
|
554
852
|
+ 'onload="pict.views[\'RetoldRemote-ImageViewer\'].initImage()" '
|
|
@@ -563,7 +861,7 @@ class RetoldRemoteMediaViewerView extends libPictView
|
|
|
563
861
|
|
|
564
862
|
// Build the action menu (shown by default instead of the player)
|
|
565
863
|
let tmpHTML = '<div class="retold-remote-video-action-menu" id="RetoldRemote-VideoActionMenu">';
|
|
566
|
-
tmpHTML += '<div class="retold-remote-video-action-menu-title">' + this.
|
|
864
|
+
tmpHTML += '<div class="retold-remote-video-action-menu-title">' + this.pict.providers['RetoldRemote-FormattingUtilities'].escapeHTML(pFileName) + '</div>';
|
|
567
865
|
|
|
568
866
|
// Frame preview container (loaded on demand via t key or automatically)
|
|
569
867
|
if (tmpCapabilities.ffmpeg)
|
|
@@ -703,7 +1001,7 @@ class RetoldRemoteMediaViewerView extends libPictView
|
|
|
703
1001
|
let tmpFrame = pData.Frames[0];
|
|
704
1002
|
let tmpFrameURL = '/api/media/video-frame/' + pData.CacheKey + '/' + tmpFrame.Filename;
|
|
705
1003
|
tmpWrap.innerHTML = '<img src="' + tmpFrameURL + '" '
|
|
706
|
-
+ 'alt="' + this.
|
|
1004
|
+
+ 'alt="' + this.pict.providers['RetoldRemote-FormattingUtilities'].escapeHTML(tmpFilePath.replace(/^.*\//, '')) + '" '
|
|
707
1005
|
+ 'onerror="this.parentNode.innerHTML=\'\'">';
|
|
708
1006
|
}
|
|
709
1007
|
else
|
|
@@ -725,7 +1023,7 @@ class RetoldRemoteMediaViewerView extends libPictView
|
|
|
725
1023
|
|
|
726
1024
|
let tmpHTML = '<div style="text-align: center; padding: 40px;">'
|
|
727
1025
|
+ '<div style="margin-bottom: 24px;">' + tmpIconHTML + '</div>'
|
|
728
|
-
+ '<div style="font-size: 1.1rem; color: var(--retold-text-secondary); margin-bottom: 24px;">' + this.
|
|
1026
|
+
+ '<div style="font-size: 1.1rem; color: var(--retold-text-secondary); margin-bottom: 24px;">' + this.pict.providers['RetoldRemote-FormattingUtilities'].escapeHTML(pFileName) + '</div>'
|
|
729
1027
|
+ '<audio controls' + (this.pict.AppData.RetoldRemote.AutoplayAudio ? ' autoplay' : '') + ' preload="metadata" id="RetoldRemote-AudioPlayer" style="width: 100%; max-width: 500px;">'
|
|
730
1028
|
+ '<source src="' + pURL + '">'
|
|
731
1029
|
+ 'Your browser does not support the audio tag.'
|
|
@@ -779,7 +1077,7 @@ class RetoldRemoteMediaViewerView extends libPictView
|
|
|
779
1077
|
let tmpDocIconHTML = tmpIconProvider ? '<span class="retold-remote-icon retold-remote-icon-lg">' + tmpIconProvider.getIcon('document-large', 64) + '</span>' : '📄';
|
|
780
1078
|
return '<div style="text-align: center; padding: 40px;">'
|
|
781
1079
|
+ '<div style="margin-bottom: 24px;">' + tmpDocIconHTML + '</div>'
|
|
782
|
-
+ '<div style="font-size: 1.1rem; color: var(--retold-text-secondary); margin-bottom: 24px;">' + this.
|
|
1080
|
+
+ '<div style="font-size: 1.1rem; color: var(--retold-text-secondary); margin-bottom: 24px;">' + this.pict.providers['RetoldRemote-FormattingUtilities'].escapeHTML(pFileName) + '</div>'
|
|
783
1081
|
+ '<a href="' + pURL + '" target="_blank" style="color: var(--retold-accent); font-size: 0.9rem;">Open in new tab</a>'
|
|
784
1082
|
+ '</div>';
|
|
785
1083
|
}
|
|
@@ -998,7 +1296,7 @@ class RetoldRemoteMediaViewerView extends libPictView
|
|
|
998
1296
|
if (tmpEl)
|
|
999
1297
|
{
|
|
1000
1298
|
tmpEl.innerHTML = '<div class="retold-remote-ebook-loading">Failed to convert: '
|
|
1001
|
-
+ tmpSelf.
|
|
1299
|
+
+ tmpSelf.pict.providers['RetoldRemote-FormattingUtilities'].escapeHTML(pError.message)
|
|
1002
1300
|
+ '<br><a href="' + pContentURL + '" target="_blank" style="color: var(--retold-accent); margin-top: 12px; display: inline-block;">Download file</a>'
|
|
1003
1301
|
+ '</div>';
|
|
1004
1302
|
}
|
|
@@ -1102,7 +1400,7 @@ class RetoldRemoteMediaViewerView extends libPictView
|
|
|
1102
1400
|
if (tmpContentEl)
|
|
1103
1401
|
{
|
|
1104
1402
|
tmpContentEl.innerHTML = '<div class="retold-remote-ebook-loading">Failed to load ebook: '
|
|
1105
|
-
+ tmpSelf.
|
|
1403
|
+
+ tmpSelf.pict.providers['RetoldRemote-FormattingUtilities'].escapeHTML(pError.message) + '</div>';
|
|
1106
1404
|
}
|
|
1107
1405
|
});
|
|
1108
1406
|
}
|
|
@@ -1130,9 +1428,9 @@ class RetoldRemoteMediaViewerView extends libPictView
|
|
|
1130
1428
|
let tmpItem = pItems[i];
|
|
1131
1429
|
let tmpIndentClass = pDepth > 0 ? ' indent-' + Math.min(pDepth, 2) : '';
|
|
1132
1430
|
tmpHTML += '<button class="retold-remote-ebook-toc-item' + tmpIndentClass + '" '
|
|
1133
|
-
+ 'data-href="' + tmpSelf.
|
|
1431
|
+
+ 'data-href="' + tmpSelf.pict.providers['RetoldRemote-FormattingUtilities'].escapeHTML(tmpItem.href) + '" '
|
|
1134
1432
|
+ 'onclick="pict.views[\'RetoldRemote-MediaViewer\'].ebookGoToChapter(this.getAttribute(\'data-href\'))">'
|
|
1135
|
-
+ tmpSelf.
|
|
1433
|
+
+ tmpSelf.pict.providers['RetoldRemote-FormattingUtilities'].escapeHTML(tmpItem.label.trim())
|
|
1136
1434
|
+ '</button>';
|
|
1137
1435
|
|
|
1138
1436
|
if (tmpItem.subitems && tmpItem.subitems.length > 0)
|
|
@@ -1199,7 +1497,7 @@ class RetoldRemoteMediaViewerView extends libPictView
|
|
|
1199
1497
|
let tmpFallbackIconHTML = tmpIconProvider ? '<span class="retold-remote-icon retold-remote-icon-lg">' + tmpIconProvider.getIcon('document-large', 64) + '</span>' : '📄';
|
|
1200
1498
|
return '<div style="text-align: center; padding: 40px;">'
|
|
1201
1499
|
+ '<div style="margin-bottom: 24px;">' + tmpFallbackIconHTML + '</div>'
|
|
1202
|
-
+ '<div style="font-size: 1.1rem; color: var(--retold-text-secondary); margin-bottom: 24px;">' + this.
|
|
1500
|
+
+ '<div style="font-size: 1.1rem; color: var(--retold-text-secondary); margin-bottom: 24px;">' + this.pict.providers['RetoldRemote-FormattingUtilities'].escapeHTML(pFileName) + '</div>'
|
|
1203
1501
|
+ '<a href="' + pURL + '" target="_blank" style="color: var(--retold-accent); font-size: 0.9rem;">Download / Open in new tab</a>'
|
|
1204
1502
|
+ '</div>';
|
|
1205
1503
|
}
|
|
@@ -1232,7 +1530,7 @@ class RetoldRemoteMediaViewerView extends libPictView
|
|
|
1232
1530
|
|
|
1233
1531
|
if (pData.Size !== undefined)
|
|
1234
1532
|
{
|
|
1235
|
-
tmpHTML += '<div class="retold-remote-fileinfo-row"><span class="retold-remote-fileinfo-label">Size</span><span class="retold-remote-fileinfo-value">' + tmpSelf.
|
|
1533
|
+
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>';
|
|
1236
1534
|
}
|
|
1237
1535
|
if (pData.Width && pData.Height)
|
|
1238
1536
|
{
|
|
@@ -1304,7 +1602,7 @@ class RetoldRemoteMediaViewerView extends libPictView
|
|
|
1304
1602
|
}
|
|
1305
1603
|
if (pData.Size !== undefined)
|
|
1306
1604
|
{
|
|
1307
|
-
tmpStatsHTML += '<span><span class="retold-remote-video-stat-label">Size</span> <span class="retold-remote-video-stat-value">' + tmpSelf.
|
|
1605
|
+
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>';
|
|
1308
1606
|
}
|
|
1309
1607
|
|
|
1310
1608
|
// Preserve the Explore and VLC buttons if they exist
|
|
@@ -1318,21 +1616,6 @@ class RetoldRemoteMediaViewerView extends libPictView
|
|
|
1318
1616
|
});
|
|
1319
1617
|
}
|
|
1320
1618
|
|
|
1321
|
-
_formatFileSize(pBytes)
|
|
1322
|
-
{
|
|
1323
|
-
if (!pBytes || pBytes === 0) return '0 B';
|
|
1324
|
-
let tmpUnits = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
1325
|
-
let tmpIndex = Math.floor(Math.log(pBytes) / Math.log(1024));
|
|
1326
|
-
if (tmpIndex >= tmpUnits.length) tmpIndex = tmpUnits.length - 1;
|
|
1327
|
-
let tmpSize = pBytes / Math.pow(1024, tmpIndex);
|
|
1328
|
-
return tmpSize.toFixed(tmpIndex === 0 ? 0 : 1) + ' ' + tmpUnits[tmpIndex];
|
|
1329
|
-
}
|
|
1330
|
-
|
|
1331
|
-
_escapeHTML(pText)
|
|
1332
|
-
{
|
|
1333
|
-
if (!pText) return '';
|
|
1334
|
-
return pText.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
1335
|
-
}
|
|
1336
1619
|
}
|
|
1337
1620
|
|
|
1338
1621
|
RetoldRemoteMediaViewerView.default_configuration = _ViewConfiguration;
|