Commits

Aaron Toth  committed 28740dd

Changed Preferences account list to better manage and display accounts. Modified Bookmarks list panel to show useful account info in the header. Added throttling to the calls to the APIs.

  • Participants
  • Parent commits 0119eeb

Comments (0)

Files changed (15)

 
     // Libraries
     "library/base64.js",
+    "library/throttle.js",
 
     // Views
     "source/views/Main.js",
     "styles/AccountsPanel.css",
     "styles/BookmarksPanel.css",
     "styles/DefaultViewerPanel.css",
+    "styles/Preferences.css",
     "styles/Welcome.css"
 );

File images/delicious_favicon.gif

Added
New image

File images/pinboard_favicon.gif

Added
New image

File library/throttle.js

+/**
+ * Debouncer for JavaScript functions
+ */
+
+if (!Function.prototype.throttle) {
+    Function.prototype.throttle = function (delayBetweenRequests, execAsap) {
+        var func = this, timeout;
+        var lastDebounce = new Date().getTime();
+
+        return function debounced () {
+            var obj = this, args = arguments;
+            function delayed () {
+                if (!execAsap)
+                    func.apply(obj, args);
+                timeout = null;
+            };
+
+            if (timeout)
+                clearTimeout(timeout);
+            else if (execAsap)
+                func.apply(obj, args);
+
+            var timeToNext = delayBetweenRequests - (new Date().getTime() - lastDebounce);
+            timeout = setTimeout(function() {
+                delayed();
+                lastDebounce = new Date().getTime();
+            }, timeToNext > 0 ? timeToNext : 0);
+        };
+
+    }
+}

File source/dialogs/Error.js

     },
     components: [
         {name: "errorContent", className: "enyo-text-error warning-icon"},
-        {kind: "Button", caption: "OK", onclick: "closePopup", className: "enyo-button-negative", style: "margin-top: 15px;"}
+        {kind: "Button", caption: "OK", onclick: "closePopup", className: "enyo-button-negative"}
     ],
     errorParser: {
-        "Forbidden": $L("The account login is incorrect")
+        401: $L("The account login is incorrect."),
+        999: $L("You've blown your account quota. Try again later.")
     },
     create: function() {
         this.inherited(arguments);
     },
-    gotError: function(errorText) {
-        this.$.errorContent.setContent(this.errorParser.hasOwnProperty(errorText) ? this.errorParser[errorText] : errorText);
+    gotError: function(errorNumber, errorText) {
+        this.$.errorContent.setContent(this.errorParser.hasOwnProperty(errorNumber) ? this.errorParser[errorNumber] : "Error " + errorNumber.toString() + ": " +errorText);
     },
     closePopup: function(inSender) {
         this.doClose();

File source/dialogs/Tag.js

         this.inherited(arguments);
         this.tags = [];
         this.doSetup();
-        this.$.bmarkAlchemy.getAllTags(this.account);
+        this.$.bmarkAlchemy.get("tags", "all", this.account);
     },
     receiveAccountAndGetTags: function(account) {
         this.account = account;

File source/panels/BookmarksPanel.js

     name: "me.aaront.BookmarksPanel",
     kind: enyo.VFlexBox,
     published: {
-        headerText: "",
         loadData: ""
     },
     events: {
         onSelectBookmark: ""
     },
     components: [
-        {name: "header", kind: "Header"},
+        {name: "header", kind: "Header", components: [
+            {name: "serviceIcon", kind: "Image", className: "bookmarks-header-icon"},
+            {name: "pageName", flex: 1, className: "bookmarks-header-page"},
+            {name: "accountUsername", className: "bookmarks-header-username"}
+        ]},
         {name: "scrim", kind: "Scrim", layoutKind: "VFlexLayout", align: "center", pack: "center", components: [
             {kind: "SpinnerLarge"}
         ]},
             ]},
             {kind: "Spacer", flex: 1}
         ]},
-        {name: "bmarkAlchemy", kind: "me.aaront.BmarkAlchemy", onResults: "gotBookmarks", onErrorClosed: "errorClosed"}
+        {name: "bmarkAlchemy", kind: "me.aaront.BmarkAlchemy", onResults: "gotBookmarks", onErrorClosed: "errorClosed"},
+        {name: "accountUtilities", kind: "me.aaront.AccountUtilities"}
     ],
     create: function() {
         this.inherited(arguments);
-        this.headerTextChanged();
+        this.loadDataChanged();
         this.bookmarks = [];
         this.$.bookmarksList.render();
         this.currentSort = 0;
     },
-    headerTextChanged: function() {
-        this.$.header.setContent(this.headerText);
-    },
     loadDataChanged: function() {
-        this.showBookmarks(this.loadData);
+        if (this.loadData.username) {
+            this.showBookmarks(this.loadData);
+            this.$.serviceIcon.setSrc(this.$.accountUtilities.smallServiceIconFromNumber(this.loadData.service));
+            this.$.pageName.setContent(this.loadData.page);
+            this.$.accountUsername.setContent(this.loadData.username);
+        }
     },
     setupBookmarksRow: function(inSender, inIndex) {
         var row = this.bookmarks[inIndex];
         this.doSelectBookmark(bookmark);
     },
     showBookmarks: function(data) {
+        this.bookmarks = [];
+        this.$.bookmarksList.refresh();
         this.$.scrim.show();
         this.$.spinnerLarge.show();
-        this.requestByPage(data);
+        this.$.bmarkAlchemy.get("bookmarks", data.page, data);
     },
     gotBookmarks: function(inSender, inBookmarks) {
         this.bookmarks = inBookmarks;
         this.$.scrim.hide();
         this.$.bookmarksList.refresh();
     },
-    requestByPage: function(data) {
-        switch(data.page) {
-            case "all":
-                return this.$.bmarkAlchemy.getAllBookmarks(data);
-            case "date":
-                return this.$.bmarkAlchemy.getBookmarksByDate(data);
-            case "tag":
-                return this.$.bmarkAlchemy.getBookmarksByTag(data);
-        }
-    },
     sortByName: function() {
         this.bookmarks.sort(function(a, b) {
             var newA = a.description.toLowerCase(),

File source/services/accounts/AccountUtilities.js

      1: "images/pinboard.png",
      2: "images/delicious.png"
    },
+   numberToSmallServiceIcon: {
+     1: "images/pinboard_favicon.gif",
+     2: "images/delicious_favicon.gif"
+   },
    numberToServiceName: {
      1: "Pinboard",
      2: "Delicious"
    serviceIconFromNumber: function(number) {
        return this.numberToServiceIcon[number];
    },
+   smallServiceIconFromNumber: function(number) {
+       return this.numberToSmallServiceIcon[number];
+   },
    serviceNameFromNumber: function(number) {
        return this.numberToServiceName[number];
    },

File source/services/bookmarks/BmarkAlchemy.js

         this.inherited(arguments);
         this.serviceEnum = this.$.accountUtilities.getServiceNameToNumber();
     },
+    get: function(type, page, data) {
+        switch(type) {
+            case "bookmarks":
+                switch(page) {
+                    case "all":
+                        this.getAllBookmarks(data);
+                        break;
+                    case "date":
+                        this.getBookmarksByDate(data);
+                        break;
+                    case "tag":
+                        this.getBookmarksByTag(data);
+                        break;
+                }
+                break;
+            case "tags":
+                switch(page) {
+                    case "all":
+                        this.getAllTags(data);
+                        break;
+                }
+        }
+    }.throttle(1200, false),
     getAllBookmarks: function(account) {
         switch(account.service) {
             case this.serviceEnum.pinboard:
     },
     gotBookmarksFailure: function(inSender, inResponse, inRequest) {
         this.$.error.validateComponents();
-        this.$.error.gotError(inRequest.xhr.statusText);
+        this.$.error.gotError(inRequest.xhr.status, inRequest.xhr.statusText);
         this.$.error.openAtCenter();
     }
 });

File source/services/bookmarks/DeliciousApi.js

         onTagsFailure: ""
     },
     components: [
-        {name: "getBookmarks", kind: "WebService", handleAs: "xml", contentType: "application/xml", onSuccess: "gotBookmarks", onFailure: "gotBookmarksFailure"},
+        {name: "getBookmarks", kind: "WebService", handleAs: "xml", contentType: "application/xml", onSuccess: "gotBookmarks", onFailure: "gotBookmarksFailure", onResponse: "gotBookmarksResponse"},
         {name: "getTags", kind: "WebService", handleAs: "xml", contentType: "application/xml", onSuccess: "gotTags", onFailure: "gotBookmarksFailure"}
     ],
     create: function() {
         }
         this.doResults(bookmarks);
     },
+    gotBookmarksResponse: function(inSender, inResponse, inRequest) {
+        errorCodes = [401, 403, 404, 999];
+        console.log(inRequest.xhr.status);
+        if (errorCodes.indexOf(inRequest.xhr.status) != -1) {
+            this.doBookmarksFailure(inResponse, inRequest);
+        }
+    },
     gotTags: function(inSender, inResponse, inRequest) {
         var xmldom = new DOMParser().parseFromString(inRequest.xhr.responseText, "text/xml");
         var tagsXml = xmldom.getElementsByTagName("tag");

File source/views/Main.js

                 break;
             default:
                 this.currentState.page = "all";
-                this.$.bookmarksPanel.setHeaderText(this.currentState.page.toUpperCase());
                 this.$.bookmarksPanel.setLoadData(this.currentState);
         }
     },
     tagSubmitted: function(inSender) {
         this.closePopup(inSender);
         this.currentState.tag = inSender.tag();
-        this.$.bookmarksPanel.setHeaderText(this.currentState.page.toLocaleUpperCase() + ": " + this.currentState.tag)
         this.$.bookmarksPanel.setLoadData(this.currentState);
     },
     dateSubmitted: function(inSender) {
         this.closePopup(inSender);
         this.currentState.fromDate = this.toISODateString(inSender.fromDate());
         this.currentState.toDate = this.toISODateString(inSender.toDate());
-        this.$.bookmarksPanel.setHeaderText(this.currentState.page.toUpperCase())
         this.$.bookmarksPanel.setLoadData(this.currentState);
     },
     toISODateString: function(date) {

File source/views/Preferences.js

     components: [
         {kind: "PageHeader", content: "Pinnned Preferences"},
         {kind: "VFlexBox", style: "width: 650px; margin: 20px auto;", flex: 1, components: [
-            {kind: "RowGroup", caption: "Accounts", components: [
-                {name: "accountsList", kind: "VirtualRepeater", onSetupRow: "setupAccountRow", components: [
-                    {kind: "SwipeableItem", onConfirm: "deleteAccountConfirmed", layoutKind: "HFlexLayout", components: [
-                        {name: "username", flex: 1},
-                        {name: "service"}
-                    ]}
-                ]}
-            ]},
+            {kind: "RowGroup", name: "accountsList", caption: "Accounts"},
             {kind: "HFlexBox", pack: "end", style: "padding: 0 10px;", components: [
                 {name: "addButton", kind: "Button", content: "Add", onclick: "addClicked"},
                 {kind: "Spacer"},
     create: function() {
         this.inherited(arguments);
         this.accounts = this.$.accountUtilities.getAccounts();
+        this.setupAccounts();
+    },
+    setupAccounts: function() {
+        var componentsToAdd = [];
+        this.$.accountsList.destroyControls();
+        for (var i = 0; i < this.accounts.length; i++) {
+            componentsToAdd.push({kind: "RowItem", layoutKind: "HFlexLayout", components: [
+                {name: i, content: this.accounts[i].username, className: "preferences-account-username", flex: 2},
+                {kind: "Spacer", flex: 1},
+                {name: "serviceIcon"+i, kind: "Image", src: this.$.accountUtilities.smallServiceIconFromNumber(this.accounts[i].service), className: "preferences-account-serviceicon"},
+                {name: "service"+i, content: this.$.accountUtilities.serviceNameFromNumber(this.accounts[i].service), className: "preferences-account-service"},
+                {name: "Spacer", flex: 2},
+                {name: "deleteAccount", kind: "Button", className: "enyo-button-negative", caption: "Delete", onclick: "deleteAccount"}
+                
+            ]});
+        }
+        this.$.accountsList.createComponents(componentsToAdd, {owner: this});
         this.$.accountsList.render();
     },
-    setupAccountRow: function(inSender, inIndex) {
-        var row = this.accounts[inIndex];
-        if (row) {
-            var serviceName = this.$.accountUtilities.serviceNameFromNumber(row.service);
-            this.$.username.setContent(row.username);
-            this.$.service.setContent(serviceName);
-            return true;
-        }
-    },
-    deleteAccountConfirmed: function(inIndex) {
-        this.accounts.splice(inIndex, 1);
-        this.$.accountsList.render();
+    deleteAccount: function(inSender, inEvent) {
+        var index = parseInt(inEvent.dispatchTarget.container.components[0].name);
+        enyo.log(index);
+        this.accounts.splice(index, 1);
+        console.log(this.accounts);
+        this.setupAccounts();
     },
     addClicked: function(inSender) {
         this.$.addAccountPopup.openAtCenter();
         this.$.accountUtilities.addAccount(account);
         this.accounts = this.$.accountUtilities.getAccounts();
         inSender.clear();
-        this.$.accountsList.render();
+        this.setupAccounts();
     },
     newAccountRegister: function(inSender) {
         this.closePopup(inSender);

File styles/BookmarksPanel.css

+.bookmarks-header-icon {
+    margin-left: 3px;
+}
+
+.bookmarks-header-page {
+    margin-left: 10px;
+    text-transform: capitalize;
+}
+
+.bookmarks-header-username {
+    color: #999;
+    font-size: 0.9em;
+}
+
 .bookmark-item {
 
 }

File styles/Pinnned.css

 
 .enyo-text-error.warning-icon {
     margin-left: 7px;
-    padding-left: 30px;
+    padding-left: 40px;
+    padding-bottom: 15px;
 }
 
 .warning-icon {

File styles/Preferences.css

+.preferences-account-username, .preferences-account-serviceicon, .preferences-account-service {
+    padding-top: 8px;
+}
+
+.preferences-account-username {
+    padding-left: 8px;
+}
+
+.preferences-account-serviceicon {
+    padding-right: 10px;
+    padding-top: 12px;
+    opacity: 0.7;
+}
+
+.preferences-account-service {
+    padding-right: 20px;
+    color: #888;
+}