@@ -18,7 +18,7 @@ function filterEntries(entries, filterText) {
18
18
}
19
19
20
20
async function renderEntries ( filterText = '' , tagFilter = '' ) {
21
- const { entries = [ ] } = await chrome . storage . sync . get ( 'entries' ) ;
21
+ const { entries = [ ] } = await chrome . storage . local . get ( 'entries' ) ;
22
22
23
23
if ( ! window . location . search . includes ( filterText ) ) {
24
24
window . history . pushState ( { } , '' , `?search=${ filterText } ` ) ;
@@ -111,7 +111,7 @@ function downloadJson(entries) {
111
111
112
112
// Add this function near the other event handlers
113
113
async function handleDeleteFiltered ( filterText = '' ) {
114
- const { entries = [ ] } = await chrome . storage . sync . get ( 'entries' ) ;
114
+ const { entries = [ ] } = await chrome . storage . local . get ( 'entries' ) ;
115
115
const filteredEntries = filterEntries ( entries , filterText ) ;
116
116
117
117
if ( ! filteredEntries . length ) {
@@ -132,15 +132,15 @@ async function handleDeleteFiltered(filterText = '') {
132
132
const remainingEntries = entries . filter ( e => ! idsToDelete . has ( e . id ) ) ;
133
133
134
134
// Save remaining entries
135
- await chrome . storage . sync . set ( { entries : remainingEntries } ) ;
135
+ await chrome . storage . local . set ( { entries : remainingEntries } ) ;
136
136
137
137
// Refresh the view
138
138
await renderEntries ( filterText ) ;
139
139
}
140
140
141
141
// Add these functions near the top
142
142
async function loadConfig ( ) {
143
- const config = await chrome . storage . sync . get ( [
143
+ const config = await chrome . storage . local . get ( [
144
144
'archivebox_server_url' ,
145
145
'archivebox_api_key' , // Added this
146
146
'match_urls' ,
@@ -181,7 +181,7 @@ function createAutosaveHandler() {
181
181
exclude_urls : document . getElementById ( 'exclude_urls' ) . value || ''
182
182
} ;
183
183
184
- await chrome . storage . sync . set ( config ) ;
184
+ await chrome . storage . local . set ( config ) ;
185
185
186
186
status_div . textContent = 'Saved.' ;
187
187
setTimeout ( ( ) => {
@@ -319,7 +319,7 @@ async function testApiKey() {
319
319
320
320
// Add this function near the other utility functions
321
321
async function syncToArchiveBox ( entry ) {
322
- const { archivebox_server_url, archivebox_api_key } = await chrome . storage . sync . get ( [
322
+ const { archivebox_server_url, archivebox_api_key } = await chrome . storage . local . get ( [
323
323
'archivebox_server_url' ,
324
324
'archivebox_api_key'
325
325
] ) ;
@@ -358,7 +358,7 @@ async function syncToArchiveBox(entry) {
358
358
359
359
// Add this function to handle the sync operation
360
360
async function handleSync ( filterText = '' ) {
361
- const { entries = [ ] } = await chrome . storage . sync . get ( 'entries' ) ;
361
+ const { entries = [ ] } = await chrome . storage . local . get ( 'entries' ) ;
362
362
const filteredEntries = filterEntries ( entries , filterText ) ;
363
363
364
364
if ( ! filteredEntries . length ) {
@@ -450,6 +450,123 @@ async function testAdding() {
450
450
}
451
451
}
452
452
453
+ // Import functionality
454
+ async function loadHistoryItems ( days ) {
455
+ const startTime = new Date ( ) ;
456
+ startTime . setDate ( startTime . getDate ( ) - days ) ;
457
+
458
+ return new Promise ( ( resolve ) => {
459
+ chrome . history . search ( {
460
+ text : '' ,
461
+ startTime : startTime . getTime ( ) ,
462
+ maxResults : 10000
463
+ } , resolve ) ;
464
+ } ) ;
465
+ }
466
+
467
+ async function loadBookmarkItems ( bookmarks = [ ] ) {
468
+ const results = [ ] ;
469
+
470
+ function processNode ( node ) {
471
+ if ( node . url ) {
472
+ results . push ( {
473
+ url : node . url ,
474
+ title : node . title ,
475
+ dateAdded : node . dateAdded
476
+ } ) ;
477
+ }
478
+ if ( node . children ) {
479
+ node . children . forEach ( processNode ) ;
480
+ }
481
+ }
482
+
483
+ return new Promise ( ( resolve ) => {
484
+ chrome . bookmarks . getTree ( tree => {
485
+ tree . forEach ( processNode ) ;
486
+ resolve ( results ) ;
487
+ } ) ;
488
+ } ) ;
489
+ }
490
+
491
+ async function updateImportList ( items , filter = '' , onlyNew = false ) {
492
+ const { entries = [ ] } = await chrome . storage . local . get ( 'entries' ) ;
493
+ const existingUrls = new Set ( entries . map ( e => e . url ) ) ;
494
+
495
+ // Filter and sort items
496
+ const filteredItems = items
497
+ . filter ( item => {
498
+ const matchesFilter = ! filter ||
499
+ item . url . toLowerCase ( ) . includes ( filter . toLowerCase ( ) ) ||
500
+ ( item . title && item . title . toLowerCase ( ) . includes ( filter . toLowerCase ( ) ) ) ;
501
+ const isNew = ! existingUrls . has ( item . url ) ;
502
+ return matchesFilter && ( ! onlyNew || isNew ) ;
503
+ } )
504
+ . sort ( ( a , b ) => ( b . lastVisited || b . dateAdded || 0 ) - ( a . lastVisited || a . dateAdded || 0 ) ) ;
505
+
506
+ // Update the list
507
+ const importList = document . getElementById ( 'importList' ) ;
508
+ importList . innerHTML = filteredItems . map ( item => `
509
+ <div class="list-group-item">
510
+ <div class="form-check">
511
+ <input class="form-check-input import-check" type="checkbox" value="${ item . url } "
512
+ id="check-${ item . url } " ${ existingUrls . has ( item . url ) ? 'disabled' : '' } >
513
+ <label class="form-check-label" for="check-${ item . url } ">
514
+ <div>
515
+ <strong>${ item . title || 'Untitled' } </strong>
516
+ <small class="text-muted">
517
+ (${ new Date ( item . lastVisited || item . dateAdded ) . toLocaleString ( ) } )
518
+ </small>
519
+ </div>
520
+ <small class="text-muted">${ item . url } </small>
521
+ </label>
522
+ </div>
523
+ </div>
524
+ ` ) . join ( '' ) ;
525
+
526
+ updateSelectedCount ( ) ;
527
+ }
528
+
529
+ function updateSelectedCount ( ) {
530
+ const count = document . querySelectorAll ( '.import-check:checked' ) . length ;
531
+ document . getElementById ( 'selectedCount' ) . textContent = count ;
532
+ document . getElementById ( 'importSelected' ) . disabled = count === 0 ;
533
+ }
534
+
535
+ async function importSelected ( ) {
536
+ const selectedUrls = Array . from ( document . querySelectorAll ( '.import-check:checked' ) )
537
+ . map ( checkbox => ( {
538
+ url : checkbox . value ,
539
+ title : checkbox . closest ( '.list-group-item' ) . querySelector ( 'strong' ) . textContent
540
+ } ) ) ;
541
+
542
+ const { entries = [ ] } = await chrome . storage . local . get ( 'entries' ) ;
543
+
544
+ // Create new entries
545
+ const newEntries = selectedUrls . map ( ( { url, title } ) => ( {
546
+ id : crypto . randomUUID ( ) ,
547
+ url,
548
+ title,
549
+ timestamp : new Date ( ) . toISOString ( ) ,
550
+ tags : [ ] ,
551
+ notes : ''
552
+ } ) ) ;
553
+
554
+ // Add to storage
555
+ await chrome . storage . local . set ( {
556
+ entries : [ ...entries , ...newEntries ]
557
+ } ) ;
558
+
559
+ // Refresh the list
560
+ const filter = document . getElementById ( 'importFilter' ) . value ;
561
+ const onlyNew = document . getElementById ( 'showOnlyNew' ) . checked ;
562
+ await updateImportList ( window . importItems || [ ] , filter , onlyNew ) ;
563
+
564
+ // Update the main entries list if we're on that tab
565
+ if ( document . getElementById ( 'urls-tab' ) . classList . contains ( 'active' ) ) {
566
+ await renderEntries ( ) ;
567
+ }
568
+ }
569
+
453
570
// Modify the loadOptions function to include config initialization
454
571
async function loadOptions ( ) {
455
572
// Initial render
@@ -471,7 +588,7 @@ async function loadOptions() {
471
588
} ) ;
472
589
473
590
// Collect and display all unique tags
474
- const { entries = [ ] } = await chrome . storage . sync . get ( 'entries' ) ;
591
+ const { entries = [ ] } = await chrome . storage . local . get ( 'entries' ) ;
475
592
const allTags = [ ...new Set ( entries . flatMap ( entry => entry . tags ) ) ] ;
476
593
const tagsList = document . getElementById ( 'tagsList' ) ;
477
594
tagsList . innerHTML = allTags . map ( tag => `
@@ -499,14 +616,14 @@ async function loadOptions() {
499
616
500
617
downloadBtn . addEventListener ( 'click' , async ( ) => {
501
618
const filterInput = document . getElementById ( 'filterInput' ) ;
502
- const { entries = [ ] } = await chrome . storage . sync . get ( 'entries' ) ;
619
+ const { entries = [ ] } = await chrome . storage . local . get ( 'entries' ) ;
503
620
const filteredEntries = filterEntries ( entries , filterInput . value ) ;
504
621
downloadCsv ( filteredEntries ) ;
505
622
} ) ;
506
623
507
624
downloadJsonBtn . addEventListener ( 'click' , async ( ) => {
508
625
const filterInput = document . getElementById ( 'filterInput' ) ;
509
- const { entries = [ ] } = await chrome . storage . sync . get ( 'entries' ) ;
626
+ const { entries = [ ] } = await chrome . storage . local . get ( 'entries' ) ;
510
627
const filteredEntries = filterEntries ( entries , filterInput . value ) ;
511
628
downloadJson ( filteredEntries ) ;
512
629
} ) ;
@@ -611,6 +728,54 @@ async function loadOptions() {
611
728
612
729
// Add test adding button handler
613
730
document . getElementById ( 'testAdding' ) . addEventListener ( 'click' , testAdding ) ;
731
+
732
+ // Import tab handlers
733
+ let importItems = [ ] ;
734
+
735
+ document . getElementById ( 'loadHistory' ) . addEventListener ( 'click' , async ( ) => {
736
+ const days = parseInt ( document . getElementById ( 'historyDays' ) . value , 10 ) ;
737
+ window . importItems = await loadHistoryItems ( days ) ;
738
+ const filter = document . getElementById ( 'importFilter' ) . value ;
739
+ const onlyNew = document . getElementById ( 'showOnlyNew' ) . checked ;
740
+ await updateImportList ( window . importItems , filter , onlyNew ) ;
741
+ } ) ;
742
+
743
+ document . getElementById ( 'loadBookmarks' ) . addEventListener ( 'click' , async ( ) => {
744
+ window . importItems = await loadBookmarkItems ( ) ;
745
+ const filter = document . getElementById ( 'importFilter' ) . value ;
746
+ const onlyNew = document . getElementById ( 'showOnlyNew' ) . checked ;
747
+ await updateImportList ( window . importItems , filter , onlyNew ) ;
748
+ } ) ;
749
+
750
+ document . getElementById ( 'importFilter' ) . addEventListener ( 'input' , async ( e ) => {
751
+ const filter = e . target . value ;
752
+ const onlyNew = document . getElementById ( 'showOnlyNew' ) . checked ;
753
+ await updateImportList ( window . importItems || [ ] , filter , onlyNew ) ;
754
+ } ) ;
755
+
756
+ document . getElementById ( 'showOnlyNew' ) . addEventListener ( 'change' , async ( e ) => {
757
+ const filter = document . getElementById ( 'importFilter' ) . value ;
758
+ const onlyNew = e . target . checked ;
759
+ await updateImportList ( window . importItems || [ ] , filter , onlyNew ) ;
760
+ } ) ;
761
+
762
+ document . getElementById ( 'importList' ) . addEventListener ( 'change' , updateSelectedCount ) ;
763
+
764
+ document . getElementById ( 'selectAll' ) . addEventListener ( 'click' , ( ) => {
765
+ document . querySelectorAll ( '.import-check:not(:disabled)' ) . forEach ( checkbox => {
766
+ checkbox . checked = true ;
767
+ } ) ;
768
+ updateSelectedCount ( ) ;
769
+ } ) ;
770
+
771
+ document . getElementById ( 'deselectAll' ) . addEventListener ( 'click' , ( ) => {
772
+ document . querySelectorAll ( '.import-check' ) . forEach ( checkbox => {
773
+ checkbox . checked = false ;
774
+ } ) ;
775
+ updateSelectedCount ( ) ;
776
+ } ) ;
777
+
778
+ document . getElementById ( 'importSelected' ) . addEventListener ( 'click' , importSelected ) ;
614
779
}
615
780
616
781
document . addEventListener ( 'DOMContentLoaded' , loadOptions ) ;
0 commit comments