From b5570d3e680570343c1552bfc972b19b161209cd Mon Sep 17 00:00:00 2001 From: Norwin Date: Thu, 21 Jan 2021 14:51:52 +0000 Subject: Display current stopwatch in navbar (#14122) * add notification about running stopwatch to header * serialize seconds, duration in stopwatches api * ajax update stopwatch i should get my testenv working locally... * new variant: hover dialog * noscript compatibility * js: live-update stopwatch time * js live update robustness --- web_src/js/features/stopwatch.js | 91 ++++++++++++++++++++++++++++++++++++++++ web_src/js/index.js | 2 + 2 files changed, 93 insertions(+) create mode 100644 web_src/js/features/stopwatch.js (limited to 'web_src/js') diff --git a/web_src/js/features/stopwatch.js b/web_src/js/features/stopwatch.js new file mode 100644 index 0000000000..d500fb5f0f --- /dev/null +++ b/web_src/js/features/stopwatch.js @@ -0,0 +1,91 @@ +import prettyMilliseconds from 'pretty-ms'; +const {AppSubUrl, csrf, NotificationSettings} = window.config; + +let updateTimeInterval = null; // holds setInterval id when active + +export async function initStopwatch() { + const stopwatchEl = $('.active-stopwatch-trigger'); + + stopwatchEl.removeAttr('href'); // intended for noscript mode only + stopwatchEl.popup({ + position: 'bottom right', + hoverable: true, + }); + + // form handlers + $('form > button', stopwatchEl).on('click', function () { + $(this).parent().trigger('submit'); + }); + + if (!stopwatchEl || NotificationSettings.MinTimeout <= 0) { + return; + } + + const fn = (timeout) => { + setTimeout(async () => { + await updateStopwatchWithCallback(fn, timeout); + }, timeout); + }; + + fn(NotificationSettings.MinTimeout); + + const currSeconds = $('.stopwatch-time').data('seconds'); + if (currSeconds) { + updateTimeInterval = updateStopwatchTime(currSeconds); + } +} + +async function updateStopwatchWithCallback(callback, timeout) { + const isSet = await updateStopwatch(); + + if (!isSet) { + timeout = NotificationSettings.MinTimeout; + } else if (timeout < NotificationSettings.MaxTimeout) { + timeout += NotificationSettings.TimeoutStep; + } + + callback(timeout); +} + +async function updateStopwatch() { + const data = await $.ajax({ + type: 'GET', + url: `${AppSubUrl}/api/v1/user/stopwatches`, + headers: {'X-Csrf-Token': csrf}, + }); + + if (updateTimeInterval) { + clearInterval(updateTimeInterval); + updateTimeInterval = null; + } + + const watch = data[0]; + const btnEl = $('.active-stopwatch-trigger'); + if (!watch) { + btnEl.addClass('hidden'); + } else { + const {repo_owner_name, repo_name, issue_index, seconds} = watch; + const issueUrl = `${AppSubUrl}/${repo_owner_name}/${repo_name}/issues/${issue_index}`; + $('.stopwatch-link').attr('href', issueUrl); + $('.stopwatch-commit').attr('action', `${issueUrl}/times/stopwatch/toggle`); + $('.stopwatch-cancel').attr('action', `${issueUrl}/times/stopwatch/cancel`); + $('.stopwatch-issue').text(`${repo_owner_name}/${repo_name}#${issue_index}`); + $('.stopwatch-time').text(prettyMilliseconds(seconds * 1000)); + updateStopwatchTime(seconds); + btnEl.removeClass('hidden'); + } + + return !!data.length; +} + +async function updateStopwatchTime(seconds) { + const secs = parseInt(seconds); + if (!Number.isFinite(secs)) return; + + const start = Date.now(); + updateTimeInterval = setInterval(() => { + const delta = Date.now() - start; + const dur = prettyMilliseconds(secs * 1000 + delta, {compact: true}); + $('.stopwatch-time').text(dur); + }, 1000); +} diff --git a/web_src/js/index.js b/web_src/js/index.js index 541f32507d..9a35507bab 100644 --- a/web_src/js/index.js +++ b/web_src/js/index.js @@ -22,6 +22,7 @@ import createDropzone from './features/dropzone.js'; import initTableSort from './features/tablesort.js'; import ActivityTopAuthors from './components/ActivityTopAuthors.vue'; import {initNotificationsTable, initNotificationCount} from './features/notification.js'; +import {initStopwatch} from './features/stopwatch.js'; import {createCodeEditor, createMonaco} from './features/codeeditor.js'; import {svg, svgs} from './svg.js'; import {stripTags} from './utils.js'; @@ -2626,6 +2627,7 @@ $(document).ready(async () => { initProject(), initServiceWorker(), initNotificationCount(), + initStopwatch(), renderMarkdownContent(), initGithook(), ]); -- cgit v1.2.3