@@ -71,7 +71,7 @@ export const TYPE = {
7171class TabManager {
7272 constructor ( arr ) {
7373 const stored = JSON . parse ( localStorage . getItem ( 'options' ) ) || { } ;
74-
74+
7575 Object . assign ( this , {
7676 unsupported : CONFIG . unsupported ,
7777 filter : CONFIG . filter ,
@@ -95,7 +95,7 @@ class TabManager {
9595
9696 const els = [ 'tabs-cont' , 'tab-btn' , 'fcn' , 'url' , 'class-portal' ]
9797 . reduce ( ( acc , id ) => ( { ...acc , [ id ] : document . getElementById ( id ) } ) , { } ) ;
98-
98+
9999 Object . assign ( this , {
100100 tc : els [ 'tabs-cont' ] ,
101101 ab : els [ 'tab-btn' ] ,
@@ -145,7 +145,7 @@ class TabManager {
145145 ex = ( ( ) => {
146146 const endpoints = Object . values ( TYPE )
147147 . map ( p => {
148- switch ( p ) {
148+ switch ( p ) {
149149 case TYPE . scr : return 'scramjet' ;
150150 case TYPE . uv : return 'uv/service' ;
151151 case TYPE . uv1 : return 'assignments' ;
@@ -227,7 +227,7 @@ class TabManager {
227227 if ( this . isNewTab ( t . url ) ) {
228228 f . src = t . url ;
229229 f . onload = ( ) => {
230- try { contentObserver . unbind ( ) ; contentObserver . bind ( ) ; } catch { }
230+ try { contentObserver . unbind ( ) ; contentObserver . bind ( ) ; } catch { }
231231 } ;
232232 }
233233 this . ic . appendChild ( f ) ;
@@ -254,6 +254,7 @@ class TabManager {
254254 handler . navigate ( decodedUrl , this , activeTab , iframe ) ;
255255 if ( this . ui ) this . ui . value = decodedUrl ;
256256 console . log ( '[info] back(): navigated to' , decodedUrl ) ;
257+ this . emitNewFrame ( ) ;
257258 }
258259 } ;
259260
@@ -275,6 +276,7 @@ class TabManager {
275276 handler . navigate ( decodedUrl , this , activeTab , iframe ) ;
276277 if ( this . ui ) this . ui . value = decodedUrl ;
277278 console . log ( '[info] forward(): navigated to' , decodedUrl ) ;
279+ this . emitNewFrame ( ) ;
278280 }
279281 } ;
280282
@@ -305,7 +307,7 @@ class TabManager {
305307 try {
306308 const newUrl = f . contentWindow . location . href ;
307309 if ( newUrl && newUrl !== t . url && newUrl !== 'about:blank' ) this . updateTabMeta ( t , f , newUrl ) ;
308- } catch { }
310+ } catch { }
309311 } ) ;
310312 } ;
311313
@@ -332,8 +334,8 @@ class TabManager {
332334 f . style . opacity = 1 ;
333335 return ;
334336 }
335- } catch { }
336-
337+ } catch { }
338+
337339 const decodedUrl = this . ex ( newUrl ) ;
338340 const hist = this . history . get ( t . id ) || { urls : [ decodedUrl ] , position : 0 } ;
339341
@@ -365,6 +367,7 @@ class TabManager {
365367 if ( t . active && this . ui && t . url !== this . newTabUrl ) {
366368 this . ui . value = decodedUrl ;
367369 this . showBg ( false ) ;
370+ this . emitNewFrame ( ) ;
368371 }
369372 } ;
370373
@@ -379,6 +382,7 @@ class TabManager {
379382 this . updateAddBtn ( ) ;
380383 this . track ( t . id ) ;
381384 if ( this . ui ) this . ui . value = '' ;
385+ this . emitNewFrame ( ) ;
382386 } ;
383387
384388
@@ -397,6 +401,7 @@ class TabManager {
397401 this . tabs [ newIdx ] . active = true ;
398402 this . showActive ( ) ;
399403 if ( this . ui ) this . ui . value = this . isNewTab ( this . tabs [ newIdx ] . url ) ? '' : this . ex ( this . tabs [ newIdx ] . url ) ;
404+ this . emitNewFrame ( ) ;
400405 }
401406 this . render ( ) ;
402407 this . updateAddBtn ( ) ;
@@ -412,6 +417,23 @@ class TabManager {
412417 const activeTab = this . active ( ) ;
413418 this . ui . value = activeTab && ! this . isNewTab ( activeTab . url ) ? this . ex ( activeTab . url ) : '' ;
414419 }
420+ this . emitNewFrame ( ) ;
421+ } ;
422+
423+ returnMeta = ( ) => {
424+ const t = this . active ( ) ;
425+ if ( ! t ) return { name : '' , url : '' } ;
426+ const url = ( t . url && ! this . isNewTab ( t . url ) ) ? this . ex ( t . url ) : '' ;
427+ return { name : t . title || '' , url } ;
428+ } ;
429+
430+ emitNewFrame = ( ) => {
431+ const t = this . active ( ) ;
432+ const meta = this . returnMeta ( ) ;
433+ const detail = { ...meta , tabId : t ?. id } ;
434+ const ev = new CustomEvent ( 'newFrame' , { detail } ) ;
435+ try { document . dispatchEvent ( ev ) ; } catch ( err ) { }
436+ try { window . dispatchEvent ( ev ) ; } catch ( err ) { }
415437 } ;
416438
417439 updateUrl = async ( input ) => {
@@ -436,7 +458,7 @@ class TabManager {
436458 t . url = this . newTabUrl ;
437459 t . title = this . newTabTitle ;
438460 if ( this . ui ) this . ui . value = '' ;
439- f . onload = ( ) => { try { contentObserver . unbind ( ) ; contentObserver . bind ( ) ; } catch { } } ;
461+ f . onload = ( ) => { try { contentObserver . unbind ( ) ; contentObserver . bind ( ) ; } catch { } } ;
440462 this . showActive ( ) ;
441463 this . render ( ) ;
442464 return ;
@@ -455,6 +477,7 @@ class TabManager {
455477 try { t . title = new URL ( url ) . hostname . replace ( 'www.' , '' ) ; } catch { t . title = input ; }
456478 this . showActive ( ) ;
457479 this . render ( ) ;
480+ if ( t . active ) this . emitNewFrame ( ) ;
458481 } ;
459482
460483 getTabWidth = ( ) => {
@@ -483,25 +506,24 @@ class TabManager {
483506 render = ( ( ) => {
484507 const tabTemplate = ( t , w , i , op , showClose ) => `
485508 <div ${ t . justAdded ? 'data-m="bounce-up" data-m-duration="0.2"' : '' }
486- class="tab-item relative flex items-center rounded-b-none justify-between pl-2.5 pr-1.5 py-[0.28rem] rounded-[6px] cursor-pointer transition-all duration-200 ease-in-out ${
487- t . active ? `border border-b-0 text-[${ op . bodyText || '#8a9bb8' } ]` : 'hover:bg-[#cccccc2f]'
488- } ${ i === 0 ? 'ml-0' : '-ml-px' } "
509+ class="tab-item relative flex items-center rounded-b-none justify-between pl-2.5 pr-1.5 py-[0.28rem] rounded-[6px] cursor-pointer transition-all duration-200 ease-in-out ${ t . active ? `border border-b-0 text-[${ op . bodyText || '#8a9bb8' } ]` : 'hover:bg-[#cccccc2f]'
510+ } ${ i === 0 ? 'ml-0' : '-ml-px' } "
489511 style="width:${ w } px;min-width:${ this . minW } px;background-color:${ t . active ? op . urlBarBg || '#1d303f' : undefined } "
490512 data-tab-id="${ t . id } ">
491513 <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-globe-icon lucide-globe"><circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/></svg>
492514 <span class="text-[12px] font-medium truncate flex-1 mr-2 ml-1.5" title="${ this . escapeHTML ( t . title ) } ">${ this . escapeHTML ( t . title ) } </span>
493515 ${ showClose ? `<button class="close-tab shrink-0 w-4 h-4 rounded-full hover:bg-[#b6bfc748] active:bg-[#d0dbe467] flex items-center justify-center transition-colors" data-tab-id="${ t . id } " title="Close ${ this . escapeHTML ( t . title ) } "><svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/></svg></button>` : '' }
494516 </div>` . trim ( ) ;
495517
496- return function ( ) {
518+ return function ( ) {
497519 const w = this . getTabWidth ( ) ;
498520 const op = JSON . parse ( localStorage . getItem ( 'options' ) || '{}' ) ;
499521 const showClose = this . tabs . length > 1 ;
500-
522+
501523 this . tc . innerHTML = this . tabs
502524 . map ( ( t , i ) => tabTemplate ( t , w , i , op , showClose ) )
503525 . join ( '' ) ;
504-
526+
505527 this . tabs . forEach ( t => delete t . justAdded ) ;
506528 } ;
507529 } ) ( ) ;
@@ -555,7 +577,7 @@ window.addEventListener('load', async () => {
555577 { path : '/s_sw.js' , scope : '/scramjet/' } ,
556578 { path : '/uv/sw.js' } ,
557579 ] ;
558-
580+
559581 for ( const sw of sws ) {
560582 try {
561583 await navigator . serviceWorker . register ( sw . path , sw . scope ? { scope : sw . scope } : undefined ) ;
@@ -600,4 +622,36 @@ window.addEventListener('load', async () => {
600622
601623 ( tabManager . options . showTb ?? true ) && domMap [ 'tabs-btn' ] ( ) ;
602624 Object . entries ( domMap ) . forEach ( ( [ id , fn ] ) => document . getElementById ( id ) ?. addEventListener ( 'click' , fn ) ) ;
625+
626+ document . getElementById ( "bookmark-btn" ) . addEventListener ( "click" , ( ) => {
627+ const bookmark = document . getElementById ( "bookmark" ) ;
628+ const setBookmark = add => {
629+ const old = JSON . parse ( localStorage . getItem ( 'options' ) ) ;
630+ const metaInfo = tabManager . returnMeta ( ) ;
631+ const result = {
632+ ...old ,
633+ quickLinks : add
634+ ? [ ...old . quickLinks , { link : metaInfo . url , icon : "null" , name : metaInfo . name } ]
635+ : old . quickLinks . filter ( q => ! ( q . link === metaInfo . url && q . name === metaInfo . name ) )
636+ } ;
637+ localStorage . setItem ( 'options' , JSON . stringify ( result ) ) ;
638+ } ;
639+
640+ if ( bookmark . getAttribute ( "fill" ) === "currentColor" ) {
641+ bookmark . setAttribute ( "fill" , "none" ) ;
642+ setBookmark ( false ) ;
643+ } else {
644+ bookmark . setAttribute ( "fill" , "currentColor" ) ;
645+ setBookmark ( true ) ;
646+ }
647+ } ) ;
648+
649+ document . addEventListener ( 'newFrame' , e => {
650+ const bookmark = document . getElementById ( "bookmark" ) ;
651+ const options = JSON . parse ( localStorage . getItem ( 'options' ) ) || { quickLinks : [ ] } ;
652+ bookmark . setAttribute (
653+ "fill" ,
654+ options . quickLinks . some ( q => q . link === e . detail . url ) ? "currentColor" : "none"
655+ ) ;
656+ } ) ;
603657} ) ;
0 commit comments