changeset 11:ef5d75bcac5e

Add Netscape bookmark file export function
author Guido Berhoerster <guido+booket@berhoerster.name>
date Wed, 17 Sep 2014 21:12:38 +0200
parents 20902b548d9f
children 948048e40fab
files booket.html booket.js
diffstat 2 files changed, 92 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/booket.html	Wed Sep 17 19:55:26 2014 +0200
+++ b/booket.html	Wed Sep 17 21:12:38 2014 +0200
@@ -89,6 +89,8 @@
         <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>x</kbd></dt>
+        <dd>Export selected file</dd>
         <dt><kbd>Prefix</kbd>+<kbd>f</kbd></dt>
         <dd>Focus search field</dd>
       </dl>
@@ -121,6 +123,16 @@
         <button type="submit" name="import-file" accesskey="m">Import</button>
       </fieldset>
     </form>
+
+    <form id="export-form">
+      <fieldset>
+        <legend>Export Bookmarks</legend>
+        <a href="#" id="export-link" hidden="hidden"
+        download="bookmarks.html"></a>
+        <button type="submit" name="export-file"
+        accesskey="x">Export&#8230;</button>
+      </fieldset>
+    </form>
   </section>
 
   <main>
--- a/booket.js	Wed Sep 17 19:55:26 2014 +0200
+++ b/booket.js	Wed Sep 17 21:12:38 2014 +0200
@@ -807,6 +807,65 @@
     this.unsavedChanges = false;
 };
 
+BookmarkModel.prototype.exportFile = function () {
+    var htmlBlob;
+    var bookmarkDoc;
+    var commentNode;
+    var metaElement;
+    var titleElement;
+    var headingElement;
+    var bookmarkListElement;
+    var bookmarkLinkElement;
+    var bookmarkElement;
+
+    bookmarkDoc = document.implementation.createHTMLDocument();
+
+    // construct Netscape bookmarks format within body
+    commentNode = bookmarkDoc.createComment('This is an automatically ' +
+        'generated file.\nIt will be read and overwritten.\nDO NOT EDIT!');
+    bookmarkDoc.body.appendChild(commentNode);
+
+    metaElement = bookmarkDoc.createElement('meta');
+    metaElement.setAttribute('http-equiv', 'Content-Type');
+    metaElement.setAttribute('content', 'text/html; charset=UTF-8');
+    bookmarkDoc.body.appendChild(metaElement);
+
+    titleElement = bookmarkDoc.createElement('title');
+    titleElement.textContent = 'Bookmarks';
+    bookmarkDoc.body.appendChild(titleElement);
+
+    headingElement = bookmarkDoc.createElement('h1');
+    headingElement.textContent = 'Bookmarks';
+    bookmarkDoc.body.appendChild(headingElement);
+
+    bookmarkListElement = bookmarkDoc.createElement('dl');
+    bookmarkDoc.body.appendChild(bookmarkListElement);
+
+    this._bookmarks.forEach(function (bookmark) {
+        bookmarkElement = bookmarkDoc.createElement('dt');
+
+        bookmarkLinkElement = bookmarkDoc.createElement('a');
+        bookmarkLinkElement.href = bookmark.url;
+        bookmarkLinkElement.textContent = bookmark.title;
+        bookmarkLinkElement.setAttribute('icon', bookmark.favicon);
+        bookmarkLinkElement.setAttribute('tags',
+            bookmark.tags.values().join(','));
+        bookmarkLinkElement.setAttribute('add_date',
+            Math.round(bookmark.ctime.getTime() / 1000));
+        bookmarkLinkElement.setAttribute('last_modified',
+            Math.round(bookmark.mtime.getTime() / 1000));
+
+        bookmarkElement.appendChild(bookmarkLinkElement);
+
+        bookmarkListElement.appendChild(bookmarkElement);
+        bookmarkListElement.appendChild(bookmarkDoc.createElement('dd'));
+    }, this);
+
+    htmlBlob = new Blob(['<!DOCTYPE NETSCAPE-Bookmark-file-1>\n' +
+        bookmarkDoc.body.innerHTML], {type: 'text/html'});
+    this.notify('export-file', htmlBlob);
+};
+
 BookmarkModel.prototype.handleEvent = function (e) {
     if (e.type === 'load') {
         if (e.target === this.loadFileReader) {
@@ -948,6 +1007,7 @@
     var saveFormElement;
     var loadFormElement;
     var importFormElement;
+    var exportFormElement;
     var newNode;
 
     ObservableMixin.call(this);
@@ -964,6 +1024,9 @@
     importFormElement = document.querySelector('form#import-form');
     importFormElement.addEventListener('submit', this);
 
+    exportFormElement = document.querySelector('form#export-form');
+    exportFormElement.addEventListener('submit', this);
+
     // create new editor form from template
     newNode = document.importNode(
         document.querySelector('#bookmark-editor-template').content, true);
@@ -1074,6 +1137,11 @@
 
             this.notify('import-file', e.target.file.files[0]);
             e.target.reset();
+        } else if (e.target.id === 'export-form') {
+            e.preventDefault();
+            e.target.blur();
+
+            this.notify('export-file');
         } else if (e.target.classList.contains('bookmark-editor-form')) {
             e.preventDefault();
             e.target.blur();
@@ -1115,6 +1183,14 @@
     this.saveLinkElement.click();
 };
 
+ActionsView.prototype.onExportFile = function (htmlBlob) {
+    var exportLinkElement;
+
+    exportLinkElement = document.querySelector('a#export-link');
+    exportLinkElement.href = URL.createObjectURL(htmlBlob);
+    exportLinkElement.click();
+};
+
 ActionsView.prototype.confirmLoadFile = function () {
     return window.confirm('There are unsaved changes to your bookmarks.\n' +
         'Proceed loading the bookmark file?');
@@ -1506,6 +1582,8 @@
         this.actionsView.onParseFileError.bind(this.actionsView));
     this.bookmarkModel.addObserver('save-file',
         this.actionsView.onSaveFile.bind(this.actionsView));
+    this.bookmarkModel.addObserver('export-file',
+        this.actionsView.onExportFile.bind(this.actionsView));
     this.bookmarkModel.addObserver('tag-added',
         this.tagView.onTagAdded.bind(this.tagView));
     this.bookmarkModel.addObserver('tag-count-changed',
@@ -1522,6 +1600,8 @@
     window.addEventListener('beforeunload', this.onBeforeUnload.bind(this));
     this.actionsView.addObserver('save-file',
         this.bookmarkModel.saveFile.bind(this.bookmarkModel));
+    this.actionsView.addObserver('export-file',
+        this.bookmarkModel.exportFile.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',