Skip to content

Commit 96877a2

Browse files
committed
Version 312:
* Added a new hotkey "Open Selected Clip", bound to "Enter" by default. This is mainly useful if navigating through the clip list using the recently-added "Clip Preview Animation" navigation buttons or hotkeys. * Fixed bugs related to the clip list thumbnail tooltip/popup and preview animation getting closed when it was intended to remain open.
1 parent d0ae2d8 commit 96877a2

2 files changed

Lines changed: 129 additions & 58 deletions

File tree

ui3.htm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@
128128
function isUrlPathBad(b) { const c = /^[A-Za-z0-9=_-]+$/; try { const a = (new URL(b)).pathname.slice(1); return 20 < a.length && c.test(a) } catch (a) { return !1 } };
129129
</script>
130130
<script type="text/javascript">
131-
var ui_version = "311";
131+
var ui_version = "312";
132132
var bi_version = "%%VERSION%%";
133133
var appPath_raw = "%%VIRTDIR%%";
134134
var local_bi_session = "%%SESSION%%";

ui3/ui3.js

Lines changed: 128 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -2854,6 +2854,24 @@ var defaultSettings =
28542854
, actionDown: BI_Hotkey_PlaybackSlower
28552855
, category: "Hotkeys"
28562856
}
2857+
, {
2858+
key: "ui3_hotkey_open_selected_clip"
2859+
, value: "0|0|0|13" // 13: enter
2860+
, hotkey: true
2861+
, label: "Open Selected Clip"
2862+
, hint: "Opens the first clip currently selected in the clip list."
2863+
, actionDown: BI_Hotkey_OpenSelectedClip
2864+
, category: "Hotkeys"
2865+
}
2866+
, { // The order of "close" hotkeys is important, because they suppress each other when one has an effect.
2867+
key: "ui3_hotkey_close_preview_animation"
2868+
, value: "0|0|0|27" // 27: escape
2869+
, hotkey: true
2870+
, label: "Close Clip Preview Animation"
2871+
, hint: "Closes the current clip preview animation"
2872+
, actionDown: BI_Hotkey_CloseClipPreviewAnimation
2873+
, category: "Hotkeys"
2874+
}
28572875
, {
28582876
key: "ui3_hotkey_close_clip"
28592877
, value: "0|0|0|27" // 27: escape
@@ -2872,15 +2890,6 @@ var defaultSettings =
28722890
, actionDown: BI_Hotkey_CloseCamera
28732891
, category: "Hotkeys"
28742892
}
2875-
, {
2876-
key: "ui3_hotkey_close_preview_animation"
2877-
, value: "0|0|0|27" // 27: escape
2878-
, hotkey: true
2879-
, label: "Close Clip Preview Animation"
2880-
, hint: "Closes the current clip preview animation"
2881-
, actionDown: BI_Hotkey_CloseClipPreviewAnimation
2882-
, category: "Hotkeys"
2883-
}
28842893
, {
28852894
key: "ui3_hotkey_preview_animation_up"
28862895
, value: "" // unset
@@ -7022,7 +7031,7 @@ function PtzButtons()
70227031
imgW = imgData.w;
70237032
imgH = imgData.h;
70247033
}
7025-
bigThumbHelper.Show($ele, $ele.parent(), self.GetPresetDescription(ele.presetnum), imgUrl, imgW, imgH);
7034+
bigThumbHelper.Show($ele, $ele.parent(), self.GetPresetDescription(ele.presetnum), imgUrl, imgW, imgH, undefined, undefined, undefined, undefined);
70267035
});
70277036
$ele.on("mouseleave touchend touchcancel", function (e)
70287037
{
@@ -12290,9 +12299,11 @@ function BigThumbHelper()
1229012299
var self = this;
1229112300
var $thumb, $desc, $img, img, $canvas, canvas;
1229212301
var isShowing = false;
12302+
var isShowingForRecId = undefined;
1229312303
var initialized = false;
1229412304
var imgCompleteCallback;
1229512305
var imgCompleteUserContext;
12306+
var showTickFlag = null;
1229612307
var Initialize = function ()
1229712308
{
1229812309
if (initialized)
@@ -12332,11 +12343,12 @@ function BigThumbHelper()
1233212343
imgCompleteCallback($img, imgCompleteUserContext, false);
1233312344
}
1233412345
}
12335-
this.Show = function ($vAlign, $hAlign, descriptionText, imgSrc, imgW, imgH, imgComplete, userContext, noClear)
12346+
this.Show = function ($vAlign, $hAlign, descriptionText, imgSrc, imgW, imgH, imgComplete, userContext, noClear, recId)
1233612347
{
1233712348
Initialize();
1233812349

1233912350
isShowing = true;
12351+
isShowingForRecId = recId;
1234012352

1234112353
// These callbacks are handled really clumsily such that they won't be called correctly if Show() is called again before the callback from the previous Show().
1234212354
imgCompleteCallback = null;
@@ -12425,19 +12437,37 @@ function BigThumbHelper()
1242512437
else
1242612438
$thumb.css("width", "");
1242712439
$thumb.show();
12440+
12441+
clearTimeout(showTickFlag);
12442+
showTickFlag = setTimeout(function () { showTickFlag = null; }, 0);
1242812443
}
12429-
this.Hide = function ()
12444+
/**
12445+
* Hides the big thumbnail tooltip if it is currently showing.
12446+
* @param {String} recId Optional recId of a recording. If provided, the thumbnail will only be hidden if it matches this recording ID.
12447+
*/
12448+
this.Hide = function (recId)
1243012449
{
1243112450
if (isShowing)
1243212451
{
12433-
isShowing = false;
12434-
$thumb.hide();
12452+
if (!recId || recId === isShowingForRecId)
12453+
{
12454+
isShowingForRecId = undefined;
12455+
isShowing = false;
12456+
clearTimeout(showTickFlag);
12457+
$thumb.hide();
12458+
return true;
12459+
}
1243512460
}
12461+
return false;
1243612462
}
1243712463
this.IsShowing = function ()
1243812464
{
1243912465
return isShowing;
1244012466
}
12467+
this.DidShowDuringThisTick = function ()
12468+
{
12469+
return !!showTickFlag;
12470+
}
1244112471
}
1244212472
///////////////////////////////////////////////////////////////
1244312473
// Touch Event Helper /////////////////////////////////////////
@@ -13269,9 +13299,9 @@ function ClipLoader(clipsBodySelector)
1326913299
clipVisibilityMap[clipData.recId] = false;
1327013300
if (!selectedClipsMap[clipData.recId]) // We need clip elements to stick around if they're selected, for the sake of multi-select.
1327113301
$("#c" + clipData.recId).remove();
13272-
self.HideBigClipThumb();
13302+
self.HideBigClipThumb(clipData.recId);
1327313303
}
13274-
var ClipTileCreateFromId = function (recId)
13304+
this.ClipTileCreateFromId = function (recId)
1327513305
{
1327613306
var $clip = $("#c" + recId);
1327713307
if ($clip.length == 0)
@@ -13334,7 +13364,8 @@ function ClipLoader(clipsBodySelector)
1333413364
$clip.on("mouseleave touchend touchcancel", function (e)
1333513365
{
1333613366
touchEvents.Gate(e);
13337-
self.HideBigClipThumb();
13367+
var recId = GetClipIdFromClip($(e.currentTarget));
13368+
self.HideBigClipThumb(recId);
1333813369
});
1333913370

1334013371
clipListContextMenu.AttachContextMenu($clip);
@@ -13384,16 +13415,26 @@ function ClipLoader(clipsBodySelector)
1338413415
}
1338513416
}
1338613417
var timeStr = GetTimeStr(clipData.displayDate);
13387-
bigThumbHelper.Show($clip, $clip, camName + " " + timeStr, thumbPath, renderW, renderH);
13418+
bigThumbHelper.Show($clip, $clip, camName + " " + timeStr, thumbPath, renderW, renderH, undefined, undefined, undefined, clipData.recId);
1338813419
if (!clipData.isSnapshot)
1338913420
clipThumbnailVideoPreview.Start($clip, clipData, camName);
1339013421
}
13391-
this.HideBigClipThumb = function ()
13422+
/**
13423+
* Hides the big thumbnail tooltip and stops the current clip preview animation.
13424+
* @param {String} recId If provided, the tooltip must match this recId in order to be closed.
13425+
* @returns {Boolean} true if the thumbnail tooltip was closed, false if it was not closed by this function call (it may have already been closed before calling).
13426+
*/
13427+
this.HideBigClipThumb = function (recId)
1339213428
{
13393-
bigThumbHelper.Hide();
13394-
clipThumbnailVideoPreview.Stop();
13429+
var didClose = bigThumbHelper.Hide(recId);
13430+
clipThumbnailVideoPreview.Stop(recId);
13431+
return didClose;
1339513432
}
13396-
BindEventsPassive(document, "click", self.HideBigClipThumb);
13433+
BindEventsPassive(document, "click", function ()
13434+
{
13435+
if (!bigThumbHelper.DidShowDuringThisTick()) // I'm unsure if this is check is necessary.
13436+
self.HideBigClipThumb(undefined);
13437+
});
1339713438
this.ScrollToClipObj = function ($clip)
1339813439
{
1339913440
var offset = ($clipsbody.height() / 2) - ($clip.height() / 2);
@@ -13406,7 +13447,7 @@ function ClipLoader(clipsBodySelector)
1340613447
}
1340713448
this.ClipPreviewNavigate = function (offset)
1340813449
{
13409-
self.HideBigClipThumb();
13450+
self.HideBigClipThumb(undefined);
1341013451
var lastStartedClipId = clipThumbnailVideoPreview.GetLastStartedClipId();
1341113452
var $clip = null;
1341213453
if (lastStartedClipId)
@@ -13479,7 +13520,7 @@ function ClipLoader(clipsBodySelector)
1347913520
{
1348013521
if (CheckSelectionLimit())
1348113522
return;
13482-
ClipTileCreateFromId(range[i]);
13523+
self.ClipTileCreateFromId(range[i]);
1348313524
$("#c" + range[i]).addClass("selected");
1348413525
selectedClips.push(range[i]);
1348513526
selectedClipsMap[range[i]] = true;
@@ -13517,7 +13558,7 @@ function ClipLoader(clipsBodySelector)
1351713558
}
1351813559
else
1351913560
{
13520-
self.HideBigClipThumb();
13561+
self.HideBigClipThumb(undefined);
1352113562
self.OpenClip(this, recId, true);
1352213563
}
1352313564
}
@@ -14261,14 +14302,14 @@ function ClipLoader(clipsBodySelector)
1426114302
{
1426214303
var clipIdx = GetClipIndexFromClipId(GetClipIdFromClip($clip));
1426314304
if (clipIdx != -1 && clipIdx + 1 < loadedClipIds.length)
14264-
return ClipTileCreateFromId(loadedClipIds[clipIdx + 1]);
14305+
return self.ClipTileCreateFromId(loadedClipIds[clipIdx + 1]);
1426514306
return null;
1426614307
}
1426714308
this.GetClipAboveClip = function ($clip)
1426814309
{
1426914310
var clipIdx = GetClipIndexFromClipId(GetClipIdFromClip($clip));
1427014311
if (clipIdx > 0 && clipIdx - 1 < loadedClipIds.length)
14271-
return ClipTileCreateFromId(loadedClipIds[clipIdx - 1]);
14312+
return self.ClipTileCreateFromId(loadedClipIds[clipIdx - 1]);
1427214313
return null;
1427314314
}
1427414315
var GetClipIndexFromClipId = function (recId)
@@ -14502,12 +14543,12 @@ function ClipThumbnailVideoPreview_BruteForce()
1450214543
var clipPreviewStartTimeout = null;
1450314544
var queuedPreview = null;
1450414545
var lastItemId = null;
14505-
var lastStartCalledItemId = null;
14546+
var lastStartCalledRecId = null;
1450614547
var averageFrameLoadTime = null;
1450714548

1450814549
this.Start = function ($clip, clipData, camName, frameNum, loopNum)
1450914550
{
14510-
lastStartCalledItemId = clipData.recId;
14551+
lastStartCalledRecId = clipData.recId;
1451114552
var duration = clipData.isClip ? clipData.msec : clipData.roughLengthMs;
1451214553
if (settings.ui3_clipPreviewEnabled !== "1" || duration < 500)
1451314554
return;
@@ -14596,14 +14637,17 @@ function ClipThumbnailVideoPreview_BruteForce()
1459614637

1459714638
self.Start($clip, clipData, camName, frameNum, loopNum);
1459814639
}
14599-
}, null, true);
14640+
}, null, true, clipData.recId);
1460014641
}
14601-
this.Stop = function ()
14642+
this.Stop = function (recId)
1460214643
{
14603-
ClearTimeouts();
14604-
clipThumbPlaybackActive = false;
14605-
bigThumbHelper.Hide();
14606-
averageFrameLoadTime = new RollingAverage(self.GetClipPreviewNumFrames());
14644+
if (!recId || lastStartCalledRecId === recId)
14645+
{
14646+
ClearTimeouts();
14647+
clipThumbPlaybackActive = false;
14648+
bigThumbHelper.Hide(lastStartCalledRecId);
14649+
averageFrameLoadTime = new RollingAverage(self.GetClipPreviewNumFrames());
14650+
}
1460714651
}
1460814652
this.GetClipPreviewNumFrames = function ()
1460914653
{
@@ -14615,20 +14659,14 @@ function ClipThumbnailVideoPreview_BruteForce()
1461514659
}
1461614660
this.GetLastStartedClipId = function ()
1461714661
{
14618-
return lastStartCalledItemId;
14662+
return lastStartCalledRecId;
1461914663
}
1462014664
var ClearTimeouts = function ()
1462114665
{
14622-
if (thumbVideoTimeout != null)
14623-
{
14624-
clearTimeout(thumbVideoTimeout);
14625-
thumbVideoTimeout = null;
14626-
}
14627-
if (clipPreviewStartTimeout != null)
14628-
{
14629-
clearTimeout(clipPreviewStartTimeout);
14630-
clipPreviewStartTimeout = null;
14631-
}
14666+
clearTimeout(thumbVideoTimeout);
14667+
thumbVideoTimeout = null;
14668+
clearTimeout(clipPreviewStartTimeout);
14669+
clipPreviewStartTimeout = null;
1463214670
queuedPreview = null;
1463314671
}
1463414672
}
@@ -17860,6 +17898,32 @@ function VideoPlayerController()
1786017898
self.Playback_Pause();
1786117899
}
1786217900
}
17901+
this.Playback_FirstSelectedClip = function ()
17902+
{
17903+
if (currentPrimaryTab === "clips")
17904+
{
17905+
var selectedClips = clipLoader.GetAllSelected();
17906+
if (selectedClips.length > 0)
17907+
{
17908+
var recId = selectedClips[0];
17909+
var img = videoPlayer.Loading().image;
17910+
if (!img.isLive && !img.isTimeline() && img.uniqueId === recId)
17911+
{
17912+
if (videoPlayer.Playback_IsPaused())
17913+
videoPlayer.Playback_Play();
17914+
else
17915+
console.log("Playback_FirstSelectedClip had no effect because the selected clip is already playing.");
17916+
return;
17917+
}
17918+
var $clip = clipLoader.ClipTileCreateFromId(recId);
17919+
Playback_ClipObj($clip);
17920+
}
17921+
else
17922+
console.log("Playback_FirstSelectedClip has no effect when a clip is not selected.");
17923+
}
17924+
else
17925+
console.log("Playback_FirstSelectedClip has no effect while not on the Clips tab.");
17926+
}
1786317927
var Playback_ClipObj = function ($clip)
1786417928
{
1786517929
if ($clip != null && $clip.length > 0)
@@ -31930,9 +31994,13 @@ function BI_Hotkey_PlaybackSlower()
3193031994
if (!videoPlayer.Loading().image.isLive)
3193131995
playbackControls.ChangePlaySpeed(-1);
3193231996
}
31997+
function BI_Hotkey_OpenSelectedClip()
31998+
{
31999+
videoPlayer.Playback_FirstSelectedClip();
32000+
}
3193332001
function BI_Hotkey_CloseClip()
3193432002
{
31935-
if (suppress_Hotkey_CloseClip)
32003+
if (suppress_Hotkey_CloseThings)
3193632004
return;
3193732005
if (videoPlayer.Loading().image.isTimeline())
3193832006
{
@@ -31943,30 +32011,33 @@ function BI_Hotkey_CloseClip()
3194332011
{
3194432012
clipLoader.CloseCurrentClip();
3194532013
// Prevent this same hotkey event from closing the current camera, too.
31946-
clearTimeout(suppress_Hotkey_CloseCamera);
31947-
suppress_Hotkey_CloseCamera = setTimeout(function () { suppress_Hotkey_CloseCamera = null; }, 0);
32014+
BI_Suppress_Close_Hotkeys_For_Next_Tick();
3194832015
}
3194932016
}
31950-
var suppress_Hotkey_CloseClip = null;
31951-
var suppress_Hotkey_CloseCamera = null;
32017+
var suppress_Hotkey_CloseThings = null;
32018+
function BI_Suppress_Close_Hotkeys_For_Next_Tick()
32019+
{
32020+
clearTimeout(suppress_Hotkey_CloseThings);
32021+
suppress_Hotkey_CloseThings = setTimeout(function () { suppress_Hotkey_CloseThings = null; }, 0);
32022+
}
3195232023
function BI_Hotkey_CloseCamera()
3195332024
{
31954-
if (suppress_Hotkey_CloseCamera)
32025+
if (suppress_Hotkey_CloseThings)
3195532026
return;
3195632027
var loading = videoPlayer.Loading();
3195732028
if ((loading.image.isLive || videoPlayer.Loading().image.isTimeline()) && !cameraListLoader.CameraIsGroupOrCycle(videoPlayer.Loading().cam))
3195832029
{
3195932030
videoPlayer.ImgClick_Camera(loading.cam);
3196032031
if (videoPlayer.Loading().image.isTimeline())
31961-
{
31962-
clearTimeout(suppress_Hotkey_CloseClip);
31963-
suppress_Hotkey_CloseClip = setTimeout(function () { suppress_Hotkey_CloseClip = null; }, 0);
31964-
}
32032+
BI_Suppress_Close_Hotkeys_For_Next_Tick();
3196532033
}
3196632034
}
3196732035
function BI_Hotkey_CloseClipPreviewAnimation()
3196832036
{
31969-
clipLoader.HideBigClipThumb();
32037+
if (suppress_Hotkey_CloseThings)
32038+
return;
32039+
if (clipLoader.HideBigClipThumb(undefined))
32040+
BI_Suppress_Close_Hotkeys_For_Next_Tick();
3197032041
}
3197132042
function BI_Hotkey_ClipPreviewAnimationUp()
3197232043
{

0 commit comments

Comments
 (0)