changeset 19:4a4d9527c06f

Add merge options Allow to merge loaded or imported bookmarks with the existing ones
author Guido Berhoerster <guido+booket@berhoerster.name>
date Thu, 02 Oct 2014 09:08:22 +0200
parents 3642bb668af1
children 55bc20390185
files booket.css booket.html booket.js
diffstat 3 files changed, 68 insertions(+), 34 deletions(-) [+]
line wrap: on
line diff
--- a/booket.css	Tue Sep 30 21:32:39 2014 +0200
+++ b/booket.css	Thu Oct 02 09:08:22 2014 +0200
@@ -140,9 +140,12 @@
     display: block;
 }
 
+#actions label.top-label {
+    font-weight: bold;
+}
+
 #actions label,
 .bookmark-editor-form label {
-    font-weight: bold;
     font-size: .75em;
 }
 
--- a/booket.html	Tue Sep 30 21:32:39 2014 +0200
+++ b/booket.html	Thu Oct 02 09:08:22 2014 +0200
@@ -39,8 +39,8 @@
   <datalist id="tag-datalist"></datalist>
 
   <template id="tag-input-template">
-    <li><label>Tag <input type="text" name="tag" pattern="[^,;]*"
-    size="20" list="tag-datalist" placeholder="tag"></input>
+    <li><label class="top-label">Tag <input type="text" name="tag"
+    pattern="[^,;]*" size="20" list="tag-datalist" placeholder="tag"></input>
     </label></li>
   </template>
 
@@ -49,18 +49,18 @@
       <fieldset>
         <legend></legend>
         <input type="hidden" name="original-url"></input>
-        <label>URL <input type="url" required="required"
+        <label class="top-label">URL <input type="url" required="required"
         name="url" size="60" placeholder="http://example.com/"></input></label>
-        <label>Title <input type="text" name="title" size="60"
+        <label class="top-label">Title <input type="text" name="title" size="60"
         placeholder="A Title"></input></label>
-        <label>Favicon <img width="16" height="16" src="missing-favicon.svg"
-        class="bookmark-favicon" alt=""></img><input type="hidden"
-        name="favicon"></input></label>
+        <label class="top-label">Favicon <img width="16" height="16"
+        src="missing-favicon.svg" class="bookmark-favicon" alt=""></img><input
+        type="hidden" name="favicon"></input></label>
         <div>
           <ul class="tag-input-list"></ul>
           <button type="button" name="more-tags">Add more tags</button>
         </div>
-        <label>Import from Bookmarklet
+        <label class="top-label">Import from Bookmarklet
         <textarea name="bookmarklet-import" cols="60" rows="4"
         spellcheck="false"></textarea></label>
         <button type="reset" name="cancel">Cancel</button><button type="submit"
@@ -101,8 +101,11 @@
     <form id="load-form">
       <fieldset>
         <legend>Load Bookmarks</legend>
-        <label accesskey="i">File <input type="file" accept="application/json"
-        required="required" name="file"></input></label>
+        <label accesskey="i" class="top-label">File <input type="file"
+        accept="application/json" required="required"
+        name="file"></input></label>
+        <label><input type="checkbox" name="merge"></input> Merge with existing
+        bookmarks</label>
         <button type="submit" name="load-file" accesskey="l">Load</button>
       </fieldset>
     </form>
@@ -122,8 +125,10 @@
     <form id="import-form">
       <fieldset>
         <legend>Import Bookmarks</legend>
-        <label accesskey="e">File <input type="file" accept="text/html"
-        required="required" name="file"></input></label>
+        <label accesskey="e" class="top-label">File <input type="file"
+        accept="text/html" required="required" name="file"></input></label>
+        <label><input type="checkbox" name="merge"></input> Merge with existing
+        bookmarks</label>
         <button type="submit" name="import-file" accesskey="m">Import</button>
       </fieldset>
     </form>
--- a/booket.js	Tue Sep 30 21:32:39 2014 +0200
+++ b/booket.js	Thu Oct 02 09:08:22 2014 +0200
@@ -705,8 +705,11 @@
 };
 
 BookmarkModel.prototype.parseLoadedBookmarks = function (data) {
+    var wasEmpty = !this._bookmarks.size;
     var parsedData;
     var bookmarks = [];
+    var bookmark;
+    var oldBookmark;
 
     try {
         parsedData = JSON.parse(data);
@@ -724,9 +727,13 @@
     // create a temporary list of valid bookmarks
     parsedData.bookmarks.forEach(function (bookmark) {
         if (isString(bookmark.url) && bookmark.url !== '') {
-            bookmarks.push(new Bookmark(bookmark.url, bookmark.title,
-                bookmark.favicon, bookmark.tags, bookmark.ctime,
-                bookmark.mtime));
+            bookmark = new Bookmark(bookmark.url, bookmark.title,
+                bookmark.favicon, bookmark.tags, bookmark.ctime, bookmark.mtime)
+            oldBookmark = this.get(bookmark.url);
+            if (oldBookmark === undefined ||
+                    oldBookmark.mtime < bookmark.mtime) {
+                bookmarks.push(bookmark);
+            }
         }
     }, this);
 
@@ -734,10 +741,14 @@
     this.add(bookmarks.sort(function (bookmark1, bookmark2) {
         return bookmark1.ctime - bookmark2.ctime;
     }));
-    this.unsavedChanges = false;
+    if (wasEmpty) {
+        // if there were no bookmarks before there cannot be any unsaved changes
+        this.unsavedChanges = false;
+    }
 };
 
 BookmarkModel.prototype.parseImportedBookmarks = function (data) {
+    var wasEmpty = (this._bookmarks.size > 0);
     var bookmarkDoc;
     var bookmarkElements;
     var i;
@@ -748,6 +759,8 @@
     var ctime;
     var mtime;
     var bookmarks = [];
+    var bookmark;
+    var oldBookmark;
 
     bookmarkDoc = document.implementation.createHTMLDocument();
     bookmarkDoc.open();
@@ -769,7 +782,12 @@
             mtime = !isNaN(mtime =
                 parseInt(bookmarkElements[i].getAttribute('last_modified'),
                 10)) ?  mtime * 1000 : undefined;
-            bookmarks.push(new Bookmark(url, title, favicon, tags, ctime, mtime));
+            bookmark = new Bookmark(url, title, favicon, tags, ctime, mtime);
+            oldBookmark = this.get(bookmark.url);
+            if (oldBookmark === undefined ||
+                    oldBookmark.mtime < bookmark.mtime) {
+                bookmarks.push(bookmark);
+            }
         }
     }
 
@@ -777,14 +795,18 @@
     this.add(bookmarks.sort(function (bookmark1, bookmark2) {
         return bookmark1.ctime - bookmark2.ctime;
     }));
-
-    this.unsavedChanges = false;
+    if (!wasEmpty) {
+        // if there were no bookmarks before there cannot be any unsaved changes
+        this.unsavedChanges = false;
+    }
 };
 
-BookmarkModel.prototype.loadFile = function (bookmarkFile) {
-    // delete all existing bookmarks first
-    this.delete(this._bookmarks.keys());
-    this.unsavedChanges = false;
+BookmarkModel.prototype.loadFile = function (bookmarkFile, merge) {
+    if (!merge) {
+        // delete all existing bookmarks first
+        this.delete(this._bookmarks.keys());
+        this.unsavedChanges = false;
+    }
 
     this.loadFileReader = new FileReader();
     this.loadFileReader.addEventListener('error', this);
@@ -792,10 +814,12 @@
     this.loadFileReader.readAsText(bookmarkFile);
 };
 
-BookmarkModel.prototype.importFile = function (bookmarkFile) {
-    // delete all existing bookmarks first
-    this.delete(this._bookmarks.keys());
-    this.unsavedChanges = false;
+BookmarkModel.prototype.importFile = function (bookmarkFile, merge) {
+    if (!merge) {
+        // delete all existing bookmarks first
+        this.delete(this._bookmarks.keys());
+        this.unsavedChanges = false;
+    }
 
     this.importFileReader = new FileReader();
     this.importFileReader.addEventListener('error', this);
@@ -1183,13 +1207,15 @@
             e.preventDefault();
             e.target.blur();
 
-            this.notify('load-file', e.target.file.files[0]);
+            this.notify('load-file', e.target.file.files[0],
+                e.target.merge.checked);
             e.target.reset();
         } else if (e.target.id === 'import-form') {
             e.preventDefault();
             e.target.blur();
 
-            this.notify('import-file', e.target.file.files[0]);
+            this.notify('import-file', e.target.file.files[0],
+                e.target.merge.checked);
             e.target.reset();
         } else if (e.target.id === 'export-form') {
             e.preventDefault();
@@ -1731,7 +1757,7 @@
     history.pushState(null, null, serializeHash(url, hashData));
 };
 
-BooketController.prototype.onLoadFile = function (bookmarkFile) {
+BooketController.prototype.onLoadFile = function (bookmarkFile, merge) {
     if (this.bookmarkModel.unsavedChanges) {
         if (!this.actionsView.confirmLoadFile()) {
             return;
@@ -1739,10 +1765,10 @@
         this.bookmarkModel.unsavedChanges = false;
     }
 
-    this.bookmarkModel.loadFile(bookmarkFile);
+    this.bookmarkModel.loadFile(bookmarkFile, merge);
 };
 
-BooketController.prototype.onImportFile = function (bookmarkFile) {
+BooketController.prototype.onImportFile = function (bookmarkFile, merge) {
     if (this.bookmarkModel.unsavedChanges) {
         if (!this.actionsView.confirmLoadFile()) {
             return;
@@ -1750,7 +1776,7 @@
         this.bookmarkModel.unsavedChanges = false;
     }
 
-    this.bookmarkModel.importFile(bookmarkFile);
+    this.bookmarkModel.importFile(bookmarkFile, merge);
 };
 
 BooketController.prototype.onEditBookmark = function (bookmarkUrl) {