changeset 10:20902b548d9f

Add Netscape bookmark file import function
author Guido Berhoerster <guido+booket@berhoerster.name>
date Wed, 17 Sep 2014 19:55:26 +0200
parents 19900803f7d0
children ef5d75bcac5e
files booket.html booket.js
diffstat 2 files changed, 103 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/booket.html	Sun Sep 14 23:14:02 2014 +0200
+++ b/booket.html	Wed Sep 17 19:55:26 2014 +0200
@@ -85,6 +85,10 @@
         <dd>Save bookmark file</dd>
         <dt><kbd>Prefix</kbd>+<kbd>a</kbd></dt>
         <dd>Focus bookmark editor</dd>
+        <dt><kbd>Prefix</kbd>+<kbd>e</kbd></dt>
+        <dd>Select bookmark file to import</dd>
+        <dt><kbd>Prefix</kbd>+<kbd>m</kbd></dt>
+        <dd>Import selected file</dd>
         <dt><kbd>Prefix</kbd>+<kbd>f</kbd></dt>
         <dd>Focus search field</dd>
       </dl>
@@ -108,6 +112,15 @@
         accesskey="s">Save&#8230;</button>
       </fieldset>
     </form>
+
+    <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>
+        <button type="submit" name="import-file" accesskey="m">Import</button>
+      </fieldset>
+    </form>
   </section>
 
   <main>
--- a/booket.js	Sun Sep 14 23:14:02 2014 +0200
+++ b/booket.js	Wed Sep 17 19:55:26 2014 +0200
@@ -454,6 +454,8 @@
     ObservableMixin.call(this);
 
     this.unsavedChanges = false;
+    this.loadFileReader = null;
+    this.importFileReader= null;
     this._bookmarks = new StringMap();
     this._tagCount = new StringMap();
     this._filterTags = new StringSet();
@@ -723,17 +725,70 @@
     this.unsavedChanges = false;
 };
 
+BookmarkModel.prototype.parseImportedBookmarks = function (data) {
+    var bookmarkDoc;
+    var bookmarkElements;
+    var i;
+    var url;
+    var title;
+    var favicon;
+    var tags;
+    var ctime;
+    var mtime;
+    var bookmarks = [];
+
+    bookmarkDoc = document.implementation.createHTMLDocument();
+    bookmarkDoc.open();
+    bookmarkDoc.write(data);
+    bookmarkDoc.close();
+
+    // create a temporary list of valid bookmarks
+    bookmarkElements = bookmarkDoc.querySelectorAll('dt > a[href]');
+    for (i = 0; i < bookmarkElements.length; i++) {
+        url = bookmarkElements[i].href;
+        if (url !== '') {
+            title = bookmarkElements[i].textContent;
+            favicon = bookmarkElements[i].getAttribute('icon');
+            tags = ((tags = bookmarkElements[i].getAttribute('tags')) !==
+                null) ? tags.split(',') : [];
+            ctime = !isNaN(ctime =
+                parseInt(bookmarkElements[i].getAttribute('add_date'), 10)) ?
+                ctime * 1000 : undefined;
+            mtime = !isNaN(mtime =
+                parseInt(bookmarkElements[i].getAttribute('last_modified'),
+                10)) ?  mtime * 1000 : undefined;
+            bookmarks.push(new Bookmark(url, title, favicon, tags, ctime, mtime));
+        }
+    }
+
+    // add each bookmark to the model ordered by the last modification time
+    this.add(bookmarks.sort(function (bookmark1, bookmark2) {
+        return bookmark1.ctime - bookmark2.ctime;
+    }));
+
+    this.unsavedChanges = false;
+};
+
 BookmarkModel.prototype.loadFile = function (bookmarkFile) {
-    var bookmarkFileReader;
-
     // delete all existing bookmarks first
     this.delete(this._bookmarks.keys());
     this.unsavedChanges = false;
 
-    bookmarkFileReader = new FileReader();
-    bookmarkFileReader.addEventListener('error', this);
-    bookmarkFileReader.addEventListener('load', this);
-    bookmarkFileReader.readAsText(bookmarkFile);
+    this.loadFileReader = new FileReader();
+    this.loadFileReader.addEventListener('error', this);
+    this.loadFileReader.addEventListener('load', this);
+    this.loadFileReader.readAsText(bookmarkFile);
+};
+
+BookmarkModel.prototype.importFile = function (bookmarkFile) {
+    // delete all existing bookmarks first
+    this.delete(this._bookmarks.keys());
+    this.unsavedChanges = false;
+
+    this.importFileReader = new FileReader();
+    this.importFileReader.addEventListener('error', this);
+    this.importFileReader.addEventListener('load', this);
+    this.importFileReader.readAsText(bookmarkFile);
 };
 
 BookmarkModel.prototype.saveFile = function () {
@@ -754,7 +809,13 @@
 
 BookmarkModel.prototype.handleEvent = function (e) {
     if (e.type === 'load') {
-        this.parseLoadedBookmarks(e.target.result);
+        if (e.target === this.loadFileReader) {
+            this.parseLoadedBookmarks(e.target.result);
+            this.loadFileReader = null;
+        } else if (e.target === this.importFileReader) {
+            this.parseImportedBookmarks(e.target.result);
+            this.importFileReader = null;
+        }
     } else if (e.type === 'error') {
         this.notify('load-file-error', e.target.error.message);
     }
@@ -886,6 +947,7 @@
 var ActionsView = function () {
     var saveFormElement;
     var loadFormElement;
+    var importFormElement;
     var newNode;
 
     ObservableMixin.call(this);
@@ -899,6 +961,9 @@
     loadFormElement = document.querySelector('form#load-form');
     loadFormElement.addEventListener('submit', this);
 
+    importFormElement = document.querySelector('form#import-form');
+    importFormElement.addEventListener('submit', this);
+
     // create new editor form from template
     newNode = document.importNode(
         document.querySelector('#bookmark-editor-template').content, true);
@@ -1003,6 +1068,12 @@
 
             this.notify('load-file', e.target.file.files[0]);
             e.target.reset();
+        } else if (e.target.id === 'import-form') {
+            e.preventDefault();
+            e.target.blur();
+
+            this.notify('import-file', e.target.file.files[0]);
+            e.target.reset();
         } else if (e.target.classList.contains('bookmark-editor-form')) {
             e.preventDefault();
             e.target.blur();
@@ -1452,6 +1523,7 @@
     this.actionsView.addObserver('save-file',
         this.bookmarkModel.saveFile.bind(this.bookmarkModel));
     this.actionsView.addObserver('load-file', this.onLoadFile.bind(this));
+    this.actionsView.addObserver('import-file', this.onImportFile.bind(this));
     this.actionsView.addObserver('save-bookmark',
         this.onSaveBookmark.bind(this));
     this.bookmarkView.addObserver('edit-bookmark',
@@ -1530,6 +1602,17 @@
     this.bookmarkModel.loadFile(bookmarkFile);
 };
 
+BooketController.prototype.onImportFile = function (bookmarkFile) {
+    if (this.bookmarkModel.unsavedChanges) {
+        if (!this.actionsView.confirmLoadFile()) {
+            return;
+        }
+        this.bookmarkModel.unsavedChanges = false;
+    }
+
+    this.bookmarkModel.importFile(bookmarkFile);
+};
+
 BooketController.prototype.onEditBookmark = function (bookmarkUrl) {
     this.bookmarkView.displayBookmarkEditor(
         this.bookmarkModel.get(bookmarkUrl));