@@ -38,8 +38,8 @@ async function initCountdownTimer() {
3838 await LSI ;
3939
4040 // ── Configuration ──────────────────────────────────────────────────────────
41- var DURATION_SEC = 300 ;
42- var DISABLE_SUBMIT = false ;
41+ const DURATION_SEC = 300 ;
42+ const DISABLE_SUBMIT = false ;
4343
4444 // ── Cleanup previous instance ──────────────────────────────────────────────
4545 if ( window . __cdtInterval ) clearInterval ( window . __cdtInterval ) ;
@@ -50,41 +50,40 @@ async function initCountdownTimer() {
5050
5151 // ── Resolve current project & task IDs ─────────────────────────────────────
5252 function getProjectId ( ) {
53- var m = window . location . pathname . match ( / p r o j e c t s \/ ( \d + ) / ) ;
53+ const m = window . location . pathname . match ( / p r o j e c t s \/ ( \d + ) / ) ;
5454 return m ? m [ 1 ] : "unknown" ;
5555 }
5656
5757 function getTaskId ( ) {
58- // LSI.task.id is the most reliable source (works in label stream)
59- if ( LSI . task && LSI . task . id ) return String ( LSI . task . id ) ;
60- var params = new URLSearchParams ( window . location . search ) ;
58+ if ( LSI . task ?. id ) return String ( LSI . task . id ) ;
59+ const params = new URLSearchParams ( window . location . search ) ;
6160 return params . get ( "task" ) || "unknown" ;
6261 }
6362
64- var projectId = getProjectId ( ) ;
65- var taskId = getTaskId ( ) ;
66- var storageKey = " cdt_" + projectId + "_" + taskId ;
63+ const projectId = getProjectId ( ) ;
64+ const taskId = getTaskId ( ) ;
65+ const storageKey = ` cdt_${ projectId } _ ${ taskId } ` ;
6766
6867 // ── Restore or create remaining seconds ────────────────────────────────────
69- var saved = localStorage . getItem ( storageKey ) ;
70- var remaining = ( saved !== null ) ? Math . max ( 0 , parseInt ( saved , 10 ) ) : DURATION_SEC ;
71- var BAR_ID = "cdt-timer-bar" ;
68+ const saved = localStorage . getItem ( storageKey ) ;
69+ let remaining = ( saved !== null ) ? Math . max ( 0 , parseInt ( saved , 10 ) ) : DURATION_SEC ;
70+ const BAR_ID = "cdt-timer-bar" ;
7271
7372 // ── Progress bar DOM ───────────────────────────────────────────────────────
74- var bar = document . createElement ( "div" ) ;
73+ const bar = document . createElement ( "div" ) ;
7574 bar . id = BAR_ID ;
7675 bar . style . cssText =
7776 "position:relative;flex:1 1 auto;min-width:120px;height:26px;min-height:26px;" +
7877 "background:#e0e0e0;font-family:system-ui,sans-serif;border-radius:4px;" +
7978 "margin:0 8px;cursor:default;display:flex;align-items:center;justify-content:center;" ;
8079
81- var fill = document . createElement ( "div" ) ;
80+ const fill = document . createElement ( "div" ) ;
8281 fill . style . cssText =
8382 "position:absolute;left:0;top:0;height:100%;width:100%;" +
8483 "transition:width 1s linear,background .6s;" +
8584 "background:#43a047;border-radius:4px;" ;
8685
87- var label = document . createElement ( "span" ) ;
86+ const label = document . createElement ( "span" ) ;
8887 label . style . cssText =
8988 "position:relative;z-index:1;font-size:12px;font-weight:700;" +
9089 "color:#fff;pointer-events:none;text-shadow:0 1px 2px rgba(0,0,0,.4);" ;
@@ -94,36 +93,28 @@ async function initCountdownTimer() {
9493 window . __cdtBar = bar ;
9594
9695 // ── Inject bar — universal mount chain ───────────────────────────────────
97- // Mounts INSIDE the annotation panel (left column), not across the full
98- // page width. Tries anchors in order:
99- // 1. MIG pagination row (before copy-prev btn or after pagination)
100- // 2. Annotation panel content area (prepended as first child)
101- // 3. Fallback: top of document body
10296 function injectBar ( ) {
103- var old = document . getElementById ( BAR_ID ) ;
97+ const old = document . getElementById ( BAR_ID ) ;
10498 if ( old && old !== bar ) old . remove ( ) ;
10599
106- // 1. MIG pagination row — insert before copy-prev button or after pagination
107- var copyBtn = document . getElementById ( "cpf-copy-btn" ) ;
100+ const copyBtn = document . getElementById ( "cpf-copy-btn" ) ;
108101 if ( copyBtn ) { copyBtn . before ( bar ) ; return ; }
109102
110- var pagination = document . querySelector ( ".lsf-pagination" ) ;
111- if ( pagination && pagination . parentElement ) {
103+ const pagination = document . querySelector ( ".lsf-pagination" ) ;
104+ if ( pagination ? .parentElement ) {
112105 pagination . parentElement . appendChild ( bar ) ;
113106 return ;
114107 }
115108
116- // 2. Annotation panel — the left column that holds image + controls.
117- // These selectors target the annotation area only (not the side panel).
118- var selectors = [
109+ const selectors = [
119110 ".lsf-main-view__annotation" ,
120111 "[class*='main-view__annotation']" ,
121112 ".lsf-main-content__task" ,
122113 "[class*='content__task']" ,
123114 ".lsf-panel__content" ,
124115 ] ;
125- for ( var i = 0 ; i < selectors . length ; i ++ ) {
126- var panel = document . querySelector ( selectors [ i ] ) ;
116+ for ( let i = 0 ; i < selectors . length ; i ++ ) {
117+ const panel = document . querySelector ( selectors [ i ] ) ;
127118 if ( panel ) {
128119 bar . style . flex = "none" ;
129120 bar . style . width = "100%" ;
@@ -132,17 +123,16 @@ async function initCountdownTimer() {
132123 }
133124 }
134125
135- // 3. Last resort
136126 document . body . prepend ( bar ) ;
137127 }
138128
139129 window . __cdtInjectTimer = setTimeout ( injectBar , 600 ) ;
140130
141131 // ── Helpers ────────────────────────────────────────────────────────────────
142132 function fmt ( sec ) {
143- var m = Math . floor ( sec / 60 ) ;
144- var s = sec % 60 ;
145- return ( m < 10 ? "0" : "" ) + m + ":" + ( s < 10 ? "0" : "" ) + s ;
133+ const m = Math . floor ( sec / 60 ) ;
134+ const s = sec % 60 ;
135+ return ` ${ m < 10 ? "0" : "" } ${ m } : ${ s < 10 ? "0" : "" } ${ s } ` ;
146136 }
147137
148138 function barColor ( fraction ) {
@@ -154,15 +144,15 @@ async function initCountdownTimer() {
154144
155145 function updateTooltip ( ) {
156146 if ( remaining > 0 ) {
157- var minLeft = Math . ceil ( remaining / 60 ) ;
158- bar . title = minLeft + " min remaining.\nThe Submit button will be blocked when time runs out." ;
147+ const minLeft = Math . ceil ( remaining / 60 ) ;
148+ bar . title = ` ${ minLeft } min remaining.\nThe Submit button will be blocked when time runs out.` ;
159149 } else {
160150 bar . title = "Time limit exceeded for this task." ;
161151 }
162152 }
163153
164154 // ── Submit blocking (only when DISABLE_SUBMIT = true) ──────────────────────
165- var expired = remaining <= 0 ;
155+ let expired = remaining <= 0 ;
166156
167157 if ( DISABLE_SUBMIT ) {
168158 LSI . on ( "beforeSaveAnnotation" , function ( ) {
@@ -177,11 +167,10 @@ async function initCountdownTimer() {
177167 }
178168
179169 // ── Task change detection (label stream) ───────────────────────────────────
180- // Poll every 2s: if LSI.task.id changed, re-init the whole plugin.
181170 window . __cdtTaskPoll = setInterval ( function ( ) {
182- var currentTaskId = getTaskId ( ) ;
171+ const currentTaskId = getTaskId ( ) ;
183172 if ( currentTaskId !== taskId && currentTaskId !== "unknown" ) {
184- console . log ( " [CountdownTimer] Task changed: " + taskId + " → " + currentTaskId + " . Re-initializing." ) ;
173+ console . log ( ` [CountdownTimer] Task changed: ${ taskId } → ${ currentTaskId } . Re-initializing.` ) ;
185174 initCountdownTimer ( ) ;
186175 }
187176 } , 2000 ) ;
@@ -192,8 +181,8 @@ async function initCountdownTimer() {
192181 if ( remaining < 0 ) remaining = 0 ;
193182 localStorage . setItem ( storageKey , String ( remaining ) ) ;
194183
195- var fraction = remaining / DURATION_SEC ;
196- fill . style . width = ( fraction * 100 ) . toFixed ( 2 ) + "%" ;
184+ const fraction = remaining / DURATION_SEC ;
185+ fill . style . width = ` ${ ( fraction * 100 ) . toFixed ( 2 ) } %` ;
197186 fill . style . background = barColor ( fraction ) ;
198187 label . textContent = fmt ( remaining ) ;
199188 updateTooltip ( ) ;
@@ -215,7 +204,6 @@ async function initCountdownTimer() {
215204 }
216205 }
217206
218- // Warning-only mode: red bar with exceeded message, submit still works
219207 function onExpiredWarning ( ) {
220208 fill . style . width = "100%" ;
221209 fill . style . background = "#d32f2f" ;
@@ -225,7 +213,7 @@ async function initCountdownTimer() {
225213 label . style . letterSpacing = "0.05em" ;
226214 bar . style . animation = "cdt-pulse 2s ease-in-out 3" ;
227215
228- var style = document . getElementById ( "cdt-pulse-style" ) ;
216+ let style = document . getElementById ( "cdt-pulse-style" ) ;
229217 if ( ! style ) {
230218 style = document . createElement ( "style" ) ;
231219 style . id = "cdt-pulse-style" ;
@@ -235,35 +223,34 @@ async function initCountdownTimer() {
235223
236224 console . log ( "[CountdownTimer] Time exceeded — warning shown (submit NOT blocked)." ) ;
237225 }
238-
239- // Blocking mode: overlay + submit disabled
226+
240227 function onExpiredBlocking ( ) {
241228 bar . style . display = "none" ;
242229
243- var overlay = document . createElement ( "div" ) ;
230+ const overlay = document . createElement ( "div" ) ;
244231 overlay . style . cssText =
245232 "position:fixed;top:0;left:0;width:100%;height:100%;z-index:100000;" +
246233 "background:rgba(0,0,0,.55);display:flex;align-items:center;" +
247234 "justify-content:center;font-family:system-ui,sans-serif;" ;
248235
249- var box = document . createElement ( "div" ) ;
236+ const box = document . createElement ( "div" ) ;
250237 box . style . cssText =
251238 "background:#fff;border-radius:12px;padding:32px 48px;text-align:center;" +
252239 "box-shadow:0 8px 32px rgba(0,0,0,.3);max-width:420px;" ;
253240
254- var icon = document . createElement ( "div" ) ;
241+ const icon = document . createElement ( "div" ) ;
255242 icon . textContent = "\u23F0" ;
256243 icon . style . cssText = "font-size:48px;margin-bottom:12px;" ;
257244
258- var title = document . createElement ( "div" ) ;
245+ const title = document . createElement ( "div" ) ;
259246 title . textContent = "Time is up!" ;
260247 title . style . cssText = "font-size:22px;font-weight:800;color:#d32f2f;margin-bottom:8px;" ;
261248
262- var msg = document . createElement ( "div" ) ;
249+ const msg = document . createElement ( "div" ) ;
263250 msg . textContent = "Your time has expired. You can no longer submit this task." ;
264251 msg . style . cssText = "font-size:14px;color:#555;line-height:1.5;margin-bottom:20px;" ;
265252
266- var okBtn = document . createElement ( "button" ) ;
253+ const okBtn = document . createElement ( "button" ) ;
267254 okBtn . textContent = "OK" ;
268255 okBtn . style . cssText =
269256 "background:#1890ff;color:#fff;border:none;border-radius:6px;" +
@@ -294,20 +281,17 @@ async function initCountdownTimer() {
294281 label . textContent = "00:00" ;
295282 setTimeout ( function ( ) { onExpired ( ) ; } , 700 ) ;
296283 } else {
297- var initFraction = remaining / DURATION_SEC ;
298- fill . style . width = ( initFraction * 100 ) . toFixed ( 2 ) + "%" ;
284+ const initFraction = remaining / DURATION_SEC ;
285+ fill . style . width = ` ${ ( initFraction * 100 ) . toFixed ( 2 ) } %` ;
299286 fill . style . background = barColor ( initFraction ) ;
300287 label . textContent = fmt ( remaining ) ;
301288 updateTooltip ( ) ;
302289 window . __cdtInterval = setInterval ( tick , 1000 ) ;
303290 }
304291
305292 console . log (
306- "[CountdownTimer] Plugin loaded. Key=" + storageKey +
307- ", remaining=" + fmt ( remaining ) +
308- ", DISABLE_SUBMIT=" + DISABLE_SUBMIT +
309- ( expired ? " (EXPIRED)" : "" ) + "."
293+ `[CountdownTimer] Plugin loaded. Key=${ storageKey } , remaining=${ fmt ( remaining ) } , DISABLE_SUBMIT=${ DISABLE_SUBMIT } ${ expired ? " (EXPIRED)" : "" } .`
310294 ) ;
311295 }
312296
313- initCountdownTimer ( ) ;
297+ initCountdownTimer ( ) ;
0 commit comments