Files

229 lines
6.4 KiB
JavaScript

// Conflict Resolution Utilities
// Handles bookmark conflict resolution strategies
(function() {
'use strict';
const ConflictResolver = {
// Sync mode configurations
MODES: {
'bi-directional': {
name: 'bi-directional',
description: 'Bi-directional Sync',
keepBoth: true,
prioritizeLinkding: false,
prioritizeBrowser: false
},
'write-only': {
name: 'write-only',
description: 'Write-Only (Browser Authoritative)',
keepBoth: false,
prioritizeLinkding: false,
prioritizeBrowser: true
},
'read-only': {
name: 'read-only',
description: 'Read-Only (Linkding Authoritative)',
keepBoth: false,
prioritizeLinkding: true,
prioritizeBrowser: false
}
},
// Get mode config
getModeConfig(mode) {
return this.MODES[mode] || this.MODES['bi-directional'];
},
// Resolve conflict when same URL exists in different locations
resolve(browserBookmark, linkdingBookmark, browserNotes, linkdingNotes, mode, action) {
const config = this.getModeConfig(mode);
const timestamp = Date.now();
switch (action) {
case 'create':
// New bookmark in browser
return {
action: 'create',
result: {
...linkdingBookmark,
notes: this.formatNotes(browserNotes),
title: browserBookmark.title,
description: browserBookmark.description
},
note: `Created new bookmark: ${browserBookmark.url}`,
timestamp: timestamp
};
case 'update':
// Update existing bookmark
if (config.keepBoth) {
// Bi-directional: keep Linkding data, merge browser notes
return {
action: 'update',
result: {
...linkdingBookmark,
notes: this.mergeNotes(linkdingNotes, browserNotes),
title: browserBookmark.title || linkdingBookmark.title,
description: browserBookmark.description || linkdingBookmark.description
},
note: `Updated existing bookmark. Kept Linkding data.`,
timestamp: timestamp
};
}
// Write-only or read-only: use browser data
return {
action: 'update',
result: {
...linkdingBookmark,
notes: this.formatNotes(browserNotes),
title: browserBookmark.title,
description: browserBookmark.description
},
note: `Updated from browser`,
timestamp: timestamp
};
case 'delete':
// Bookmark deleted
if (config.prioritizeBrowser) {
return {
action: 'delete',
result: linkdingBookmark,
note: `Deleted from Linkding (browser is authoritative)`,
timestamp: timestamp
};
}
if (config.prioritizeLinkding) {
return {
action: 'ignore',
result: linkdingBookmark,
note: `Kept Linkding version (read-only mode)`,
timestamp: timestamp
};
}
return {
action: 'delete',
result: linkdingBookmark,
note: `Deleted from Linkding`,
timestamp: timestamp
};
default:
return {
action: 'none',
result: linkdingBookmark,
note: 'No action needed',
timestamp: timestamp
};
}
},
// Format notes object for storage
formatNotes(notes) {
if (!notes) {
return '';
}
return JSON.stringify({
path: notes.path || '',
userNotes: notes.userNotes || '',
autoTags: notes.autoTags || []
});
},
// Merge two notes objects
mergeNotes(notes1, notes2) {
const p1 = this.parseNotes(notes1);
const p2 = this.parseNotes(notes2);
return {
path: p1.path || p2.path,
userNotes: p1.userNotes || p2.userNotes,
autoTags: [...(p1.autoTags || []), ...(p2.autoTags || [])]
.filter((v, i, a) => a.indexOf(v) === i)
};
},
// Parse notes string
parseNotes(noteString) {
if (!noteString) {
return {
path: '',
userNotes: '',
autoTags: []
};
}
try {
const parsed = JSON.parse(noteString);
if (typeof parsed === 'object' && parsed !== null) {
return {
path: parsed.path || '',
userNotes: parsed.userNotes || '',
autoTags: parsed.autoTags || []
};
}
} catch (e) {
// Invalid JSON
}
return {
path: '',
userNotes: noteString,
autoTags: []
};
},
// Get conflict report
getConflictReport(browserBookmark, linkdingBookmark) {
const browserNotes = this.parseNotes(browserBookmark.notes || '');
const linkdingNotes = this.parseNotes(linkdingBookmark.notes || '');
return {
url: browserBookmark.url,
browserPath: browserNotes.path,
linkdingPath: linkdingNotes.path,
browserNotes: browserNotes.userNotes,
linkdingNotes: linkdingNotes.userNotes,
differs: browserNotes.path !== linkdingNotes.path ||
browserNotes.userNotes !== linkdingNotes.userNotes
};
},
// Check if sync is needed
needsSync(browserBookmark, linkdingBookmark) {
if (!linkdingBookmark) {
return true; // New bookmark
}
const browserNotes = this.parseNotes(browserBookmark.notes || '');
const linkdingNotes = this.parseNotes(linkdingBookmark.notes || '');
// Check if paths differ
if (browserNotes.path !== linkdingNotes.path) {
return true;
}
// Check if notes differ
if (browserNotes.userNotes !== linkdingNotes.userNotes) {
return true;
}
// Check if titles differ
if (browserBookmark.title !== linkdingBookmark.title) {
return true;
}
return false;
}
};
// Export for use in other scripts
window.ConflictResolver = ConflictResolver;
})();