Files

148 lines
4.1 KiB
JavaScript

// Synchronization Utilities
// Handles sync logic and conflict resolution
(function() {
'use strict';
const SyncUtils = {
// Sync mode descriptions
MODES: {
'bi-directional': {
name: 'Bi-Directional',
description: 'Keep both versions; additions/updates replicate both ways',
deleteFromLinkding: true,
keepBothOnUpdate: true
},
'write-only': {
name: 'Write-Only',
description: 'Browser is authoritative; updates push to Linkding only',
deleteFromLinkding: true,
keepBothOnUpdate: false
},
'read-only': {
name: 'Read-Only',
description: 'Linkding is authoritative; download from Linkding only',
deleteFromLinkding: false,
keepBothOnUpdate: false
}
},
// Get sync mode config
getModeConfig(mode) {
return this.MODES[mode] || this.MODES['bi-directional'];
},
// Determine sync action based on mode
determineSyncAction(mode, action) {
const config = this.getModeConfig(mode);
switch (action) {
case 'create':
// New bookmark in browser
if (config.deleteFromLinkding) {
return { action: 'create', deleteFromLinkding: false };
}
return { action: 'create' };
case 'update':
// Existing bookmark with changes
if (config.keepBothOnUpdate) {
return { action: 'update', keepBoth: true };
}
return { action: 'update' };
case 'delete':
// Bookmark deleted from browser
if (config.deleteFromLinkding) {
return { action: 'delete' };
}
return { action: 'ignore' };
default:
return { action: 'none' };
}
},
// Resolve conflict when same URL exists in different folders
resolveConflict(browserBookmark, linkdingBookmark, browserNotes, linkdingNotes, mode) {
const config = this.getModeConfig(mode);
if (config.keepBothOnUpdate) {
// Bi-directional: keep both, use Linkding notes as primary
const mergedNotes = {
path: browserNotes.path || linkdingNotes.path,
userNotes: config.keepBothOnUpdate ? linkdingNotes.userNotes : browserNotes.userNotes,
autoTags: []
};
return {
action: 'update',
notes: mergedNotes,
note: 'Updated with browser path; Linkding notes preserved'
};
}
// Write-only or read-only: use browser data
return {
action: 'update',
notes: browserNotes,
note: 'Updated from browser'
};
},
// Check if bookmark needs sync
needsSync(browserBookmark, linkdingBookmark, browserNotes, linkdingNotes) {
// Check if URLs match
if (browserBookmark.url !== linkdingBookmark.url) {
return true;
}
// Check if path changed
if (browserNotes.path !== linkdingNotes.path) {
return true;
}
// Check if notes changed
if (browserNotes.userNotes !== linkdingNotes.userNotes) {
return true;
}
// Check if tags changed
const browserTags = browserNotes.autoTags.map(t => t.name);
const linkdingTags = linkdingNotes.autoTags.map(t => t.name);
if (JSON.stringify(browserTags) !== JSON.stringify(linkdingTags)) {
return true;
}
return false;
},
// Get last sync timestamp
getLastSyncTime() {
return new Date().toISOString();
},
// Format sync timestamp for display
formatTimestamp(timestamp) {
if (!timestamp) return 'Never';
const date = new Date(timestamp);
const options = {
year: 'numeric',
month: 'short',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
timeZoneName: 'short'
};
return date.toLocaleDateString('en-US', options);
}
};
// Export for use in other scripts
window.SyncUtils = SyncUtils;
})();