Bug 1163111 - Update Pocket code to latest version (May 7th code drop). r=dolske a=dolske

This commit is contained in:
Jared Wein 2015-05-08 16:47:41 -04:00
parent 87acea298d
commit d17d883c96
19 changed files with 1406 additions and 214 deletions

View File

@ -12,6 +12,8 @@ browser.jar:
content/browser/pocket/panels/css/saved.css (panels/css/saved.css)
content/browser/pocket/panels/css/signup.css (panels/css/signup.css)
content/browser/pocket/panels/fonts/FiraSans-Regular.woff (panels/fonts/FiraSans-Regular.woff)
content/browser/pocket/panels/img/pocketerror@1x.png (panels/img/pocketerror@1x.png)
content/browser/pocket/panels/img/pocketerror@2x.png (panels/img/pocketerror@2x.png)
content/browser/pocket/panels/img/pocketlogo@1x.png (panels/img/pocketlogo@1x.png)
content/browser/pocket/panels/img/pocketlogo@2x.png (panels/img/pocketlogo@2x.png)
content/browser/pocket/panels/img/pocketlogosolo@1x.png (panels/img/pocketlogosolo@1x.png)
@ -40,6 +42,7 @@ browser.jar:
content/browser/pocket/panels/js/vendor/jquery-2.1.1.min.js (panels/js/vendor/jquery-2.1.1.min.js)
content/browser/pocket/panels/js/vendor/handlebars.runtime.js (panels/js/vendor/handlebars.runtime.js)
content/browser/pocket/panels/js/vendor/jquery.tokeninput.min.js (panels/js/vendor/jquery.tokeninput.min.js)
content/browser/pocket/panels/tmpl/saved_premiumextras.handlebars (panels/tmpl/saved_premiumextras.handlebars)
content/browser/pocket/panels/tmpl/saved_premiumshell.handlebars (panels/tmpl/saved_premiumshell.handlebars)
content/browser/pocket/panels/tmpl/saved_shell.handlebars (panels/tmpl/saved_shell.handlebars)
content/browser/pocket/panels/tmpl/signup_shell.handlebars (panels/tmpl/signup_shell.handlebars)

View File

@ -49,13 +49,21 @@ var pktUI = (function() {
// -- Initialization (on startup and new windows) -- //
var inited = false;
var currentPanelDidShow, currentPanelDidHide;
var _currentPanelDidShow;
var _currentPanelDidHide;
var _isHidden = false;
var _notificationTimeout;
var prefBranch = Services.prefs.getBranch("browser.pocket.settings.");
// Init panel id at 0. The first actual panel id will have the number 1 so
// in case at some point any panel has the id 0 we know there is something
// wrong
var _panelId = 0;
var prefBranch = Services.prefs.getBranch("browser.pocket.settings.");
var savePanelWidth = 350;
var savePanelHeights = {collapsed: 153, expanded: 272};
/**
* Initalizes Pocket UI and panels
*/
@ -162,15 +170,15 @@ var pktUI = (function() {
}
function pocketPanelDidShow(event) {
if (currentPanelDidShow) {
currentPanelDidShow(event);
if (_currentPanelDidShow) {
_currentPanelDidShow(event);
}
}
function pocketPanelDidHide(event) {
if (currentPanelDidHide) {
currentPanelDidHide(event);
if (_currentPanelDidHide) {
_currentPanelDidHide(event);
}
// clear the panel
@ -299,7 +307,7 @@ var pktUI = (function() {
startheight = 436;
}
}
showPanel("chrome://browser/content/pocket/panels/signup.html?pockethost=" + Services.prefs.getCharPref("browser.pocket.site") + "&fxasignedin=" + fxasignedin + "&variant=" + pktApi.getSignupAB(), {
var panelId = showPanel("chrome://browser/content/pocket/panels/signup.html?pockethost=" + Services.prefs.getCharPref("browser.pocket.site") + "&fxasignedin=" + fxasignedin + "&variant=" + pktApi.getSignupAB(), {
onShow: function() {
},
onHide: panelDidHide,
@ -321,15 +329,30 @@ var pktUI = (function() {
var isValidURL = (typeof url !== 'undefined' && (url.startsWith("http") || url.startsWith('https')));
showPanel("chrome://browser/content/pocket/panels/saved.html?pockethost=" + Services.prefs.getCharPref("browser.pocket.site") + "&premiumStatus=" + (pktApi.isPremiumUser() ? '1' : '0'), {
var panelId = showPanel("chrome://browser/content/pocket/panels/saved.html?pockethost=" + Services.prefs.getCharPref("browser.pocket.site") + "&premiumStatus=" + (pktApi.isPremiumUser() ? '1' : '0'), {
onShow: function() {
var saveLinkMessageId = 'saveLink';
// Send error message for invalid url
if (!isValidURL) {
var error = new Error('Only links can be saved');
sendErrorMessage('saveLink', error);
// TODO: Pass key for localized error in error object
var error = {
message: 'Only links can be saved',
localizedKey: "onlylinkssaved"
};
pktUIMessaging.sendErrorMessageToPanel(panelId, saveLinkMessageId, error);
return;
}
// Check online state
if (!navigator.onLine) {
// TODO: Pass key for localized error in error object
var error = {
message: 'You must be connected to the Internet in order to save to Pocket. Please connect to the Internet and try again.'
};
pktUIMessaging.sendErrorMessageToPanel(panelId, saveLinkMessageId, error); return;
}
// Add url
var options = {
success: function(data, request) {
@ -338,7 +361,7 @@ var pktUI = (function() {
status: "success",
item: item
};
sendMessage('saveLink', successResponse);
pktUIMessaging.sendMessageToPanel(panelId, saveLinkMessageId, successResponse);
},
error: function(error, request) {
// If user is not authorized show singup page
@ -347,8 +370,13 @@ var pktUI = (function() {
return;
}
// Send error message to panel
sendErrorMessage('saveLink', error);
// If there is no error message in the error use a
// complete catch-all
var errorMessage = error.message || "There was an error when trying to save to Pocket.";
var panelError = { message: errorMessage}
// Send error message to panel
pktUIMessaging.sendErrorMessageToPanel(panelId, saveLinkMessageId, panelError);
}
}
@ -361,8 +389,8 @@ var pktUI = (function() {
pktApi.addLink(url, options);
},
onHide: panelDidHide,
width: 350,
height: 267
width: savePanelWidth,
height: pktApi.isPremiumUser() && isValidURL ? savePanelHeights.expanded : savePanelHeights.collapsed
});
}
@ -370,6 +398,9 @@ var pktUI = (function() {
* Open a generic panel
*/
function showPanel(url, options) {
// Add new panel id
_panelId += 1;
url += ("&panelId=" + _panelId);
// We don't have to hide and show the panel again if it's already shown
// as if the user tries to click again on the toolbar button the overlay
@ -389,13 +420,15 @@ var pktUI = (function() {
// For some reason setting onpopupshown and onpopuphidden on the panel directly didn't work, so
// do it this hacky way for now
currentPanelDidShow = options.onShow;
currentPanelDidHide = options.onHide;
_currentPanelDidShow = options.onShow;
_currentPanelDidHide = options.onHide;
resizePanel({
width: options.width,
height: options.height
});
return _panelId;
}
/**
@ -421,168 +454,132 @@ var pktUI = (function() {
function panelDidHide() {
}
// -- Communication to Panels -- //
// https://developer.mozilla.org/en-US/Add-ons/Code_snippets/Interaction_between_privileged_and_non-privileged_pages
/**
* Register a listener and callback for a specific messageId
*/
function addMessageListener(messageId, callback) {
document.addEventListener('PKT_'+messageId, function(e) {
// ignore to ensure we do not pick up other events in the browser
if (e.target.tagName !== 'PKTMESSAGEFROMPANELELEMENT') {
return;
}
// Send payload to callback
callback(JSON.parse(e.target.getAttribute("payload"))[0]);
// Cleanup the element
e.target.parentNode.removeChild(e.target);
}, false, true);
}
/**
* Remove a message listener
*/
function removeMessageListener(messageId, callback) {
document.removeMessageListener('PKT_'+messageId, callback);
}
/**
* Send a message to the panel's iframe
*/
function sendMessage(messageId, payload) {
var doc = getPanelFrame().contentWindow.document;
var AnswerEvt = doc.createElement("PKTMessage");
AnswerEvt.setAttribute("payload", JSON.stringify([payload]));
doc.documentElement.appendChild(AnswerEvt);
var event = doc.createEvent("HTMLEvents");
event.initEvent('PKT_'+messageId, true, false);
AnswerEvt.dispatchEvent(event);
}
/**
* Helper function to package an error object and send it to the panel iframe as a message response
*/
function sendErrorMessage(messageId, error) {
var errorResponse = {status: "error", error: error.message};
sendMessage(messageId, errorResponse);
}
/**
* Register all of the messages needed for the panels
*/
function registerEventMessages() {
// TODO : There are likely some possible race conditions possible here, for example if the user clicks the button quickly multiple times, due to the async property of the messages, a message may be picked up for an older panel. We should consider updating this to include some sort of panelId that changes per open.
var iframe = getPanelFrame();
// Only register the messages once
if (iframe.getAttribute('did_init') == 1) {
return;
var didInitAttributeKey = 'did_init';
var didInitMessageListener = iframe.getAttribute(didInitAttributeKey);
if (typeof didInitMessageListener !== "undefined" && didInitMessageListener == 1) {
return;
}
iframe.setAttribute('did_init', 1);
iframe.setAttribute(didInitAttributeKey, 1);
// When the panel is displayed it generated an event called
// "show": we will listen for that event and when it happens,
// send our own "show" event to the panel's script, so the
// script can prepare the panel for display.
addMessageListener("show", function(payload) {
var _showMessageId = "show";
pktUIMessaging.addMessageListener(_showMessageId, function(panelId, data) {
// Let panel know that it is ready
sendMessage('show');
pktUIMessaging.sendMessageToPanel(panelId, _showMessageId);
});
// Open a new tab with a given url and activate if
addMessageListener("openTabWithUrl", function(payload) {
// Open a new tab with a given url and activate if
var _openTabWithUrlMessageId = "openTabWithUrl";
pktUIMessaging.addMessageListener(_openTabWithUrlMessageId, function(panelId, data) {
// Check if the tab should become active after opening
var activate = true;
if (typeof payload.activate !== "undefined") {
activate = payload.activate;
if (typeof data.activate !== "undefined") {
activate = data.activate;
}
openTabWithUrl(payload.url, activate);
sendMessage("openTabWithUrlResponse", payload.url);
var url = data.url;
openTabWithUrl(url, activate);
pktUIMessaging.sendResponseMessageToPanel(panelId, _openTabWithUrlMessageId, url);
});
// Close the panel
addMessageListener("close", function(payload) {
var _closeMessageId = "close";
pktUIMessaging.addMessageListener(_closeMessageId, function(panelId, data) {
getPanel().hidePopup();
});
// Send the current url to the panel
addMessageListener("getCurrentURL", function(payload) {
sendMessage('getCurrentURLResponse', getCurrentUrl());
var _getCurrentURLMessageId = "getCurrentURL";
pktUIMessaging.addMessageListener(_getCurrentURLMessageId, function(panelId, data) {
pktUIMessaging.sendResponseMessageToPanel(panelId, _getCurrentURLMessageId, getCurrentUrl());
});
var _resizePanelMessageId = "resizePanel";
pktUIMessaging.addMessageListener(_resizePanelMessageId, function(panelId, data) {
resizePanel(data);
});
// Callback post initialization to tell background script that panel is "ready" for communication.
addMessageListener("listenerReady", function(payload) {
pktUIMessaging.addMessageListener("listenerReady", function(panelId, data) {
});
pktUIMessaging.addMessageListener("collapseSavePanel", function(panelId, data) {
if (!pktApi.isPremiumUser())
resizePanel({width:savePanelWidth, height:savePanelHeights.collapsed});
});
addMessageListener("resizePanel", function(payload) {
resizePanel(payload);
pktUIMessaging.addMessageListener("expandSavePanel", function(panelId, data) {
resizePanel({width:savePanelWidth, height:savePanelHeights.expanded});
});
// Ask for recently accessed/used tags for auto complete
addMessageListener("getTags", function(payload) {
var _getTagsMessageId = "getTags";
pktUIMessaging.addMessageListener(_getTagsMessageId, function(panelId, data) {
pktApi.getTags(function(tags, usedTags) {
sendMessage('getTagsResponse', {tags, usedTags});
pktUIMessaging.sendResponseMessageToPanel(panelId, _getTagsMessageId, {
tags: tags,
usedTags: usedTags
});
});
});
// Ask for suggested tags based on passed url
addMessageListener("getSuggestedTags", function(payload) {
var responseMessageId = "getSuggestedTagsResponse";
pktApi.getSuggestedTagsForURL(payload.url, {
var _getSuggestedTagsMessageId = "getSuggestedTags";
pktUIMessaging.addMessageListener(_getSuggestedTagsMessageId, function(panelId, data) {
pktApi.getSuggestedTagsForURL(data.url, {
success: function(data, response) {
var suggestedTags = data.suggested_tags;
var successResponse = {
status: "success",
value: {
"suggestedTags" : suggestedTags
suggestedTags : suggestedTags
}
}
sendMessage(responseMessageId, successResponse);
pktUIMessaging.sendResponseMessageToPanel(panelId, _getSuggestedTagsMessageId, successResponse);
},
error: function(error, response) {
sendErrorMessage(responseMessageId, error);
pktUIMessaging.sendErrorResponseMessageToPanel(panelId, _getSuggestedTagsMessageId, error);
}
})
});
// Pass url and array list of tags, add to existing save item accordingly
addMessageListener("addTags", function(payload) {
var responseMessageId = "addTagsResponse";
pktApi.addTagsToURL(payload.url, payload.tags, {
var _addTagsMessageId = "addTags";
pktUIMessaging.addMessageListener(_addTagsMessageId, function(panelId, data) {
pktApi.addTagsToURL(data.url, data.tags, {
success: function(data, response) {
var successResponse = {status: "success"};
sendMessage(responseMessageId, successResponse);
var successResponse = {status: "success"};
pktUIMessaging.sendResponseMessageToPanel(panelId, _addTagsMessageId, successResponse);
},
error: function(error, response) {
sendErrorMessage(responseMessageId, error);
pktUIMessaging.sendErrorResponseMessageToPanel(panelId, _addTagsMessageId, error);
}
});
});
// Based on clicking "remove page" CTA, and passed unique item id, remove the item
addMessageListener("deleteItem", function(payload) {
var responseMessageId = "deleteItemResponse";
pktApi.deleteItem(payload.itemId, {
var _deleteItemMessageId = "deleteItem";
pktUIMessaging.addMessageListener(_deleteItemMessageId, function(panelId, data) {
pktApi.deleteItem(data.itemId, {
success: function(data, response) {
var successResponse = {status: "success"};
sendMessage(responseMessageId, successResponse);
var successResponse = {status: "success"};
pktUIMessaging.sendResponseMessageToPanel(panelId, _deleteItemMessageId, successResponse);
},
error: function(error, response) {
sendErrorMessage(responseMessageId, error);
pktUIMessaging.sendErrorResponseMessageToPanel(panelId, _deleteItemMessageId, error);
}
})
});
@ -748,3 +745,149 @@ var pktUI = (function() {
isHidden
};
}());
// -- Communication to Background -- //
// https://developer.mozilla.org/en-US/Add-ons/Code_snippets/Interaction_between_privileged_and_non-privileged_pages
var pktUIMessaging = (function() {
/**
* Prefix message id for message listening
*/
function prefixedMessageId(messageId) {
return 'PKT_' + messageId;
}
/**
* Register a listener and callback for a specific messageId
*/
function addMessageListener(messageId, callback) {
document.addEventListener(prefixedMessageId(messageId), function(e) {
// ignore to ensure we do not pick up other events in the browser
if (e.target.tagName !== 'PKTMESSAGEFROMPANELELEMENT') {
return;
}
// Pass in information to callback
var payload = JSON.parse(e.target.getAttribute("payload"))[0];
var panelId = payload.panelId;
var data = payload.data;
callback(panelId, data);
// Cleanup the element
e.target.parentNode.removeChild(e.target);
}, false, true);
}
/**
* Remove a message listener
*/
function removeMessageListener(messageId, callback) {
document.removeEventListener(prefixedMessageId(messageId), callback);
}
/**
* Send a message to the panel's iframe
*/
function sendMessageToPanel(panelId, messageId, payload) {
if (!isPanelIdValid(panelId)) { return; };
var panelFrame = document.getElementById('pocket-panel-iframe');
if (!isPocketPanelFrameValid(panelFrame)) { return; }
var doc = panelFrame.contentWindow.document;
var documentElement = doc.documentElement;
// Send message to panel
var panelMessageId = prefixedMessageId(panelId + '_' + messageId);
var AnswerEvt = doc.createElement("PKTMessage");
AnswerEvt.setAttribute("payload", JSON.stringify([payload]));
documentElement.appendChild(AnswerEvt);
var event = doc.createEvent("HTMLEvents");
event.initEvent(panelMessageId, true, false);
AnswerEvt.dispatchEvent(event);
}
function sendResponseMessageToPanel(panelId, messageId, payload) {
var responseMessageId = messageId + "Response";
sendMessageToPanel(panelId, responseMessageId, payload);
}
/**
* Helper function to package an error object and send it to the panel
* iframe as a message response
*/
function sendErrorMessageToPanel(panelId, messageId, error) {
var errorResponse = {status: "error", error: error};
sendMessageToPanel(panelId, messageId, errorResponse);
}
function sendErrorResponseMessageToPanel(panelId, messageId, error) {
var errorResponse = {status: "error", error: error};
sendResponseMessageToPanel(panelId, messageId, errorResponse);
}
/**
* Validation
*/
function isPanelIdValid(panelId) {
// First check if panelId has a valid value > 0. We set the panelId to
// 0 to start. But if for some reason the message is attempted to be
// sent before the panel has a panelId, then it's going to send out
// a message with panelId 0, which is never going to be heard. If this
// happens, it means some race condition occurred where the panel was
// trying to communicate before it should.
if (panelId === 0) {
console.warn("Tried to send message to panel with id 0.")
return false;
}
return true
}
function isPocketPanelFrameValid(panelFrame) {
// Check if panel is available if not throw a warning and bailout.
// We likely try to send to a panel that is not visible anymore
if (typeof panelFrame === "undefined") {
console.warn("Pocket panel frame is undefined");
return false;
}
var contentWindow = panelFrame.contentWindow;
if (typeof contentWindow == "undefined") {
console.warn("Pocket panel frame content window is undefined");
return false;
}
var doc = contentWindow.document;
if (typeof doc === "undefined") {
console.warn("Pocket panel frame content window document is undefined");
return false;
}
var documentElement = doc.documentElement;
if (typeof documentElement === "undefined") {
console.warn("Pocket panel frame content window document document element is undefined");
return false;
}
return true;
}
/**
* Public
*/
return {
addMessageListener: addMessageListener,
removeMessageListener: removeMessageListener,
sendMessageToPanel: sendMessageToPanel,
sendResponseMessageToPanel: sendResponseMessageToPanel,
sendErrorMessageToPanel: sendErrorMessageToPanel,
sendErrorResponseMessageToPanel: sendErrorResponseMessageToPanel
}
}());

View File

@ -397,3 +397,28 @@ td,
th {
padding: 0;
}
/* Normalization for FF panel defauts
========================================================================== */
html {
outline: none;
padding: 0;
}
a {
color: #0095dd;
margin: 0;
outline: none;
padding: 0;
text-decoration: none;
}
a:hover,
a:active {
color: #008acb;
text-decoration: underline;
}
a:active {
color: #006b9d;
}

View File

@ -52,12 +52,15 @@
.pkt_ext_containersaved .pkt_ext_loadingspinner {
position: relative;
display: inline-block;
width: 2.5em;
height: 2.5em;
margin: 2em 0 0;
left: 50%;
margin: 2em 0 0 -1.25em;
font-size: 10px;
text-indent: 999em;
position: absolute;
top: 4em;
overflow: hidden;
width: 2.5em;
animation: pkt_ext_spin 0.7s infinite steps(8);
}
.pkt_ext_containersaved .pkt_ext_loadingspinner:before,
@ -96,7 +99,7 @@
.pkt_ext_containersaved .pkt_ext_initload {
left: 0;
position: absolute;
top: 1em;
top: 0;
width: 100%;
}
.pkt_ext_containersaved .pkt_ext_detail {
@ -106,7 +109,6 @@
z-index: 10;
}
.pkt_ext_container_detailactive .pkt_ext_initload {
transition: opacity 0.2s ease-out;
opacity: 0;
}
.pkt_ext_container_detailactive .pkt_ext_initload .pkt_ext_loadingspinner,
@ -116,7 +118,6 @@
.pkt_ext_container_detailactive .pkt_ext_detail {
max-height: 20em;
opacity: 1;
transition: opacity 0.2s ease-out;
}
.pkt_ext_container_finalstate .pkt_ext_edit_msg,
.pkt_ext_container_finalstate .pkt_ext_tag_detail,
@ -151,30 +152,9 @@
@keyframes fade_in_out {
0% {
opacity: 1;
top: 0;
}
50% {
opacity: 0;
top: 0;
}
51% {
opacity: 0;
top: 10px;
}
100% {
opacity: 1;
top: 10px;
}
}
@keyframes fade_in_outalt {
0% {
opacity: 1;
}
50% {
opacity: 0;
}
51% {
opacity: 0;
}
100% {
opacity: 1;
@ -182,18 +162,17 @@
}
.pkt_ext_container_finalstate h2 {
animation: fade_in_out 0.4s ease-out;
top: 10px;
}
.pkt_ext_container_finalerrorstate h2 {
animation: fade_int_outalt 0.4s ease-out;
animation: none;
color: #d74345;
top: 0;
}
.pkt_ext_containersaved .pkt_ext_errordetail {
display: none;
font-size: 12px;
font-weight: normal;
left: 6.4em;
max-width: 21em;
opacity: 0;
position: absolute;
top: 2.7em;
@ -220,20 +199,33 @@
background-size: 44px 40px;
}
}
.pkt_ext_container_finalerrorstate .pkt_ext_logo {
background-image: url(../img/pocketerror@1x.png);
height: 44px;
width: 44px;
}
@media (min-resolution: 1.1dppx) {
.pkt_ext_container_finalerrorstate .pkt_ext_logo {
background-image: url(../img/pocketerror@2x.png);
background-size: 44px 44px;
}
}
.pkt_ext_containersaved .pkt_ext_topdetail {
float: left;
}
.pkt_ext_containersaved .pkt_ext_edit_msg {
box-sizing: border-box;
display: none;
font-size: 0.875em;
font-size: 0.75em;
left: auto;
padding: 0 1.4em;
position: absolute;
text-align: center;
top: 4.3em;
text-align: left;
top: 8.7em;
width: 100%;
}
.pkt_ext_containersaved .pkt_ext_edit_msg_error {
color: #c10000;
color: #d74345;
}
.pkt_ext_containersaved .pkt_ext_edit_msg_active {
display: block;
@ -357,6 +349,9 @@
padding: 0;
display: flex;
}
.pkt_ext_containersaved .pkt_ext_tag_error {
border: none;
}
.pkt_ext_containersaved .pkt_ext_tag_input_wrapper {
box-sizing: border-box;
flex: 1;
@ -374,6 +369,9 @@
padding-left: 0.5em;
padding-right: 0.5em;
}
.pkt_ext_containersaved .pkt_ext_tag_error .pkt_ext_tag_input_wrapper {
border: 1px solid #d74345;
}
.pkt_ext_containersaved .pkt_ext_tag_input_wrapper .token-input-list {
display: block;
left: 0;
@ -418,6 +416,7 @@
}
.pkt_ext_containersaved .pkt_ext_btn {
box-sizing: border-box;
color: #333;
float: none;
font-size: 0.875em;
font-size: 14px;
@ -425,13 +424,27 @@
height: 2.2em;
min-width: 4em;
padding: 0.5em 0;
text-decoration: none;
text-transform: none;
width: auto;
}
.pkt_ext_containersaved .pkt_ext_btn_disabled {
background-color: #ededed;
.pkt_ext_containersaved .pkt_ext_btn:hover {
background-color: #ebebeb;
}
.pkt_ext_containersaved .pkt_ext_btn:active {
background-color: #dadada;
}
.pkt_ext_containersaved .pkt_ext_btn_disabled,
.pkt_ext_containersaved .pkt_ext_btn_disabled:hover,
.pkt_ext_containersaved .pkt_ext_btn_disabled:active {
background-color: transparent;
cursor: default;
opacity: 0.5;
opacity: 0.4;
}
.pkt_ext_containersaved .pkt_ext_tag_error .pkt_ext_btn {
border: 1px solid #c3c3c3;
border-width: 1px 1px 1px 0;
height: 2.35em;
}
.pkt_ext_containersaved .autocomplete-suggestions {
margin-top: 2.2em;
@ -439,19 +452,27 @@
/*=Recent/suggested tags
--------------------------------------------------------------------------------------- */
.pkt_ext_containersaved .pkt_ext_suggestedtag_detail {
.pkt_ext_containersaved .pkt_ext_suggestedtag_detail,
.pkt_ext_containersaved .pkt_ext_suggestedtag_detailshown {
border-top: 1px solid #c1c1c1;
bottom: 0;
background: #ebebeb;
clear: both;
left: 0;
opacity: 0;
visibility: hidden;
min-height: 110px;
position: fixed;
visibility: hidden;
width: 100%;
}
.pkt_ext_container_detailactive .pkt_ext_suggestedtag_detail {
.pkt_ext_container_detailactive .pkt_ext_suggestedtag_detail,
.pkt_ext_containersaved .pkt_ext_suggestedtag_detailshown {
opacity: 1;
transition: opacity 0.2s ease-out, visibility 0.2s ease-out;
visibility: visible;
}
.pkt_ext_containersaved .pkt_ext_suggestedtag_detailshown {
padding: 4px 0;
}
.pkt_ext_container_finalstate .pkt_ext_suggestedtag_detail {
opacity: 0;
visibility: hidden;
@ -488,6 +509,11 @@
overflow: hidden;
padding: 2px 0 0 0;
}
.pkt_ext_containersaved .pkt_ext_suggestedtag_detail ul {
height: auto;
margin: 0 2em 0 0;
padding-top: 6px;
}
.pkt_ext_containersaved .pkt_ext_recenttag_detail li,
.pkt_ext_containersaved .pkt_ext_suggestedtag_detail li {
background: none;
@ -512,6 +538,9 @@
text-align: left;
top: 2em;
}
.pkt_ext_containersaved .pkt_ext_suggestedtag_detail .suggestedtag_msg {
margin-right: 1.3em;
}
.pkt_ext_containersaved .token_tag {
border-radius: 4px;
background: #f7f7f7;
@ -522,7 +551,7 @@
font-weight: normal;
letter-spacing: normal;
margin-right: 0.5em;
padding: 0.125em 0.3125em;
padding: 0.125em 0.625em;
text-decoration: none;
text-transform: none;
}
@ -639,7 +668,7 @@
border: 1px solid #c3c3c3;
overflow: hidden;
margin: 0;
padding: 0 5px;
padding: 0 8px;
background-color: #f7f7f7;
color: #000;
font-weight: normal;
@ -688,7 +717,7 @@
cursor: pointer;
display: inline-block;
height: 8px;
margin: 0 2px 0 8px;
margin: 0 0 0 8px;
overflow: hidden;
width: 8px;
text-indent: -99px;

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 KiB

After

Width:  |  Height:  |  Size: 145 KiB

View File

@ -3,10 +3,12 @@ Translations.en =
{
addtags: "Add Tags",
alreadyhaveacct: "Already a Pocket user?",
errorgeneric: "There was an error when trying to save to Pocket.",
learnmore: "Learn More",
loginnow: "Log in",
maxtaglength: "Tags are limited to 25 characters",
mustbeconnected: "You must be connected to the Internet in order to save to Pocket. Please check your connection and try again.",
onlylinkssaved: "Only links can be saved",
or: "or",
pagenotsaved: "Page Not Saved",
pageremoved: "Page Removed",
pagesaved: "Saved to Pocket",
@ -14,6 +16,7 @@ Translations.en =
processingtags: "Adding tags...",
removepage: "Remove Page",
save: "Save",
saving: "Saving...",
signupemail: "Sign up with email",
signuptosave: "Sign up for Pocket. Its free.",
suggestedtags: "Suggested Tags",

View File

@ -1,11 +1,27 @@
// Documentation of methods used here are at:
// https://developer.mozilla.org/en-US/Add-ons/Code_snippets/Interaction_between_privileged_and_non-privileged_pages
var Messaging = (function() {
var pktPanelMessaging = (function() {
function addMessageListener(messageId, callback) {
function panelIdFromURL(url) {
var panelId = url.match(/panelId=([\w|\d|\.]*)&?/);
if (panelId && panelId.length > 1) {
return panelId[1];
}
document.addEventListener('PKT_' + messageId, function(e) {
return 0;
}
function prefixedMessageId(messageId) {
return 'PKT_' + messageId;
}
function panelPrefixedMessageId(panelId, messageId) {
return prefixedMessageId(panelId + '_' + messageId);
}
function addMessageListener(panelId, messageId, callback) {
document.addEventListener(panelPrefixedMessageId(panelId, messageId), function(e) {
callback(JSON.parse(e.target.getAttribute("payload"))[0]);
@ -16,33 +32,36 @@ var Messaging = (function() {
}
function removeMessageListener(messageId, callback) {
document.removeEventListener('PKT_' + messageId, callback);
function removeMessageListener(panelId, messageId, callback) {
document.removeEventListener(panelPrefixedMessageId(panelId, messageId), callback);
}
function sendMessage(messageId, payload, callback) {
function sendMessage(panelId, messageId, payload, callback) {
// Payload needs to be an object in format:
// { panelId: panelId, data: {} }
var messagePayload = {
panelId: panelId,
data: (payload || {})
};
// Create a callback to listen for a response
if (callback) {
// Message response id is messageId + "Response"
var messageResponseId = messageId + "Response";
var responseListener = function(responsePayload) {
callback(responsePayload);
removeMessageListener(messageResponseId, responseListener);
removeMessageListener(panelId, messageResponseId, responseListener);
}
addMessageListener(messageResponseId, responseListener);
addMessageListener(panelId, messageResponseId, responseListener);
}
// Send message
var element = document.createElement("PKTMessageFromPanelElement");
element.setAttribute("payload", JSON.stringify([payload]));
element.setAttribute("payload", JSON.stringify([messagePayload]));
document.documentElement.appendChild(element);
var evt = document.createEvent("Events");
evt.initEvent('PKT_'+messageId, true, false);
evt.initEvent(prefixedMessageId(messageId), true, false);
element.dispatchEvent(evt);
}
@ -51,6 +70,7 @@ var Messaging = (function() {
* Public functions
*/
return {
panelIdFromURL: panelIdFromURL,
addMessageListener : addMessageListener,
removeMessageListener : removeMessageListener,
sendMessage: sendMessage

View File

@ -11,6 +11,7 @@ var PKT_SAVED_OVERLAY = function (options)
this.savedItemId = 0;
this.savedUrl = '';
this.premiumStatus = false;
this.panelId = 0;
this.preventCloseTimerCancel = false;
this.closeValid = true;
this.mouseInside = false;
@ -33,14 +34,8 @@ var PKT_SAVED_OVERLAY = function (options)
var newtag = $('<li><a href="#" class="token_tag ' + tagclass + '">' + tags[i] + '</a></li>');
container.append(newtag);
var templeft = newtag.position().left;
if (templeft > newtagleft) {
this.cxt_suggested_available++;
newtagleft = templeft;
}
else {
newtag.remove();
break;
}
this.cxt_suggested_available++;
newtagleft = templeft;
}
};
this.fillUserTags = function() {
@ -190,9 +185,6 @@ var PKT_SAVED_OVERLAY = function (options)
}
}
}
else {
returnlist.push({name:'blah'});
}
if (!$('.token-input-dropdown-tag').data('init')) {
$('.token-input-dropdown-tag').css('width',inputwrapper.outerWidth()).data('init');
inputwrapper.append($('.token-input-dropdown-tag'));
@ -202,7 +194,7 @@ var PKT_SAVED_OVERLAY = function (options)
textToData: function(text) {
if($.trim(text).length > 25 || !$.trim(text).length) {
if (text.length > 25) {
$('.pkt_ext_edit_msg').addClass('pkt_ext_edit_msg_error pkt_ext_edit_msg_active').text(myself.dictJSON.invalidTags);
myself.showTagsError(myself.dictJSON.maxtaglength);
changestamp = Date.now();
setTimeout(function() {
$('.token-input-input-token input').val(text).focus();
@ -211,7 +203,7 @@ var PKT_SAVED_OVERLAY = function (options)
return null;
}
else {
$('.pkt_ext_edit_msg').removeClass('pkt_ext_edit_msg_error pkt_ext_edit_msg_active').text('');
myself.hideTagsError();
return {name:myself.sanitizeText(text.toLowerCase())};
}
},
@ -258,6 +250,12 @@ var PKT_SAVED_OVERLAY = function (options)
changestamp = Date.now();
myself.showActiveTags();
myself.checkPlaceholderStatus();
},
onShowDropdown: function() {
thePKT_SAVED.sendMessage("expandSavePanel");
},
onHideDropdown: function() {
thePKT_SAVED.sendMessage("collapseSavePanel");
}
});
$('body').on('keydown',function(e) {
@ -364,6 +362,14 @@ var PKT_SAVED_OVERLAY = function (options)
myself.closePopup();
});
};
this.showTagsError = function(msg) {
$('.pkt_ext_edit_msg').addClass('pkt_ext_edit_msg_error pkt_ext_edit_msg_active').text(msg);
$('.pkt_ext_tag_detail').addClass('pkt_ext_tag_error');
};
this.hideTagsError = function(msg) {
$('.pkt_ext_edit_msg').removeClass('pkt_ext_edit_msg_error pkt_ext_edit_msg_active').text('');
$('.pkt_ext_tag_detail').removeClass('pkt_ext_tag_error');
};
this.showActiveTags = function() {
if (!$('.pkt_ext_suggestedtag_detail').length) {
return;
@ -567,6 +573,7 @@ PKT_SAVED_OVERLAY.prototype = {
if (this.premiumStatus && !$('.pkt_ext_suggestedtag_detail').length)
{
$('body').append(Handlebars.templates.saved_premiumshell(this.dictJSON));
$('.pkt_ext_initload').append(Handlebars.templates.saved_premiumextras(this.dictJSON));
}
}
};
@ -586,11 +593,11 @@ PKT_SAVED.prototype = {
},
addMessageListener: function(messageId, callback) {
Messaging.addMessageListener(messageId, callback);
pktPanelMessaging.addMessageListener(this.overlay.panelId, messageId, callback);
},
sendMessage: function(messageId, payload, callback) {
Messaging.sendMessage(messageId, payload, callback);
pktPanelMessaging.sendMessage(this.overlay.panelId, messageId, payload, callback);
},
create: function() {
@ -605,6 +612,9 @@ PKT_SAVED.prototype = {
{
myself.overlay.pockethost = host[1];
}
myself.overlay.panelId = pktPanelMessaging.panelIdFromURL(window.location.href);
myself.overlay.create();
// tell back end we're ready
@ -614,7 +624,21 @@ PKT_SAVED.prototype = {
thePKT_SAVED.addMessageListener("saveLink",function(resp)
{
if (resp.status == 'error') {
myself.overlay.showStateError(myself.overlay.dictJSON.pagenotsaved,myself.overlay.dictJSON.onlylinkssaved);
if (typeof resp.error == 'object')
{
if (resp.error.localizedKey)
{
myself.overlay.showStateError(myself.overlay.dictJSON.pagenotsaved,myself.overlay.dictJSON[resp.error.localizedKey]);
}
else
{
myself.overlay.showStateError(myself.overlay.dictJSON.pagenotsaved,resp.error.message);
}
}
else
{
myself.overlay.showStateError(myself.overlay.dictJSON.pagenotsaved,myself.overlay.dictJSON.errorgeneric);
}
return;
}

View File

@ -22,6 +22,7 @@ var PKT_SIGNUP_OVERLAY = function (options)
this.variant = "";
this.pockethost = "getpocket.com";
this.fxasignedin = false;
this.panelId = 0;
this.dictJSON = {};
this.initCloseTabEvents = function() {
$('.btn,.pkt_ext_learnmore,.alreadyhave > a').click(function(e)
@ -162,6 +163,8 @@ PKT_SIGNUP_OVERLAY.prototype = {
this.pockethost = host[1];
}
this.panelId = pktPanelMessaging.panelIdFromURL(window.location.href);
if (this.active)
{
return;
@ -207,11 +210,11 @@ PKT_SIGNUP.prototype = {
},
addMessageListener: function(messageId, callback) {
Messaging.addMessageListener(messageId, callback);
pktPanelMessaging.addMessageListener(this.overlay.panelId, messageId, callback);
},
sendMessage: function(messageId, payload, callback) {
Messaging.sendMessage(messageId, payload, callback);
pktPanelMessaging.sendMessage(this.overlay.panelId, messageId, payload, callback);
},
create: function() {

View File

@ -1,5 +1,8 @@
(function() {
var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
templates['saved_premiumextras'] = template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
return "<div class=\"pkt_ext_suggestedtag_detailshown\">\n</div>";
},"useData":true});
templates['saved_premiumshell'] = template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
return "<div class=\"pkt_ext_suggestedtag_detail pkt_ext_suggestedtag_detail_loading\">\n <h4>"
@ -8,19 +11,21 @@ templates['saved_premiumshell'] = template({"compiler":[6,">= 2.0.0-beta.1"],"ma
},"useData":true});
templates['saved_shell'] = template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
return "<div class=\"pkt_ext_initload\"> \n <div class=\"pkt_ext_loadingspinner\"><div></div></div>\n</div> \n<div class=\"pkt_ext_detail\"> \n <div class=\"pkt_ext_logo\"></div>\n <div class=\"pkt_ext_topdetail\">\n <h2>"
return "<div class=\"pkt_ext_initload\">\n <div class=\"pkt_ext_logo\"></div> \n <div class=\"pkt_ext_topdetail\">\n <h2>"
+ escapeExpression(((helper = (helper = helpers.saving || (depth0 != null ? depth0.saving : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"saving","hash":{},"data":data}) : helper)))
+ "</h2>\n </div> \n <div class=\"pkt_ext_loadingspinner\"><div></div></div>\n</div> \n<div class=\"pkt_ext_detail\"> \n <div class=\"pkt_ext_logo\"></div>\n <div class=\"pkt_ext_topdetail\">\n <h2>"
+ escapeExpression(((helper = (helper = helpers.pagesaved || (depth0 != null ? depth0.pagesaved : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pagesaved","hash":{},"data":data}) : helper)))
+ "</h2>\n <h3 class=\"pkt_ext_errordetail\"></h3>\n <nav class=\"pkt_ext_item_actions pkt_ext_cf\">\n <ul>\n <li><a class=\"pkt_ext_removeitem\" href=\"#\">"
+ escapeExpression(((helper = (helper = helpers.removepage || (depth0 != null ? depth0.removepage : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"removepage","hash":{},"data":data}) : helper)))
+ "</a></li>\n <li class=\"pkt_ext_actions_separator\"></li> \n <li><a class=\"pkt_ext_openpocket\" href=\"http://"
+ "</a></li>\n <li class=\"pkt_ext_actions_separator\"></li> \n <li><a class=\"pkt_ext_openpocket\" href=\"https://"
+ escapeExpression(((helper = (helper = helpers.pockethost || (depth0 != null ? depth0.pockethost : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pockethost","hash":{},"data":data}) : helper)))
+ "/a?src=ff_ext_saved\" target=\"_blank\">"
+ escapeExpression(((helper = (helper = helpers.viewlist || (depth0 != null ? depth0.viewlist : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"viewlist","hash":{},"data":data}) : helper)))
+ "</a></li>\n </ul>\n </nav> \n </div>\n <p class=\"pkt_ext_edit_msg\"></p> \n <div class=\"pkt_ext_tag_detail pkt_ext_cf\">\n <div class=\"pkt_ext_tag_input_wrapper\">\n <div class=\"pkt_ext_tag_input_blocker\"></div>\n <input class=\"pkt_ext_tag_input\" type=\"text\" placeholder=\""
+ "</a></li>\n </ul>\n </nav> \n </div>\n <div class=\"pkt_ext_tag_detail pkt_ext_cf\">\n <div class=\"pkt_ext_tag_input_wrapper\">\n <div class=\"pkt_ext_tag_input_blocker\"></div>\n <input class=\"pkt_ext_tag_input\" type=\"text\" placeholder=\""
+ escapeExpression(((helper = (helper = helpers.addtags || (depth0 != null ? depth0.addtags : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"addtags","hash":{},"data":data}) : helper)))
+ "\">\n </div>\n <a href=\"#\" class=\"pkt_ext_btn pkt_ext_btn_disabled\">"
+ escapeExpression(((helper = (helper = helpers.save || (depth0 != null ? depth0.save : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"save","hash":{},"data":data}) : helper)))
+ "</a>\n </div>\n</div>";
+ "</a>\n </div>\n <p class=\"pkt_ext_edit_msg\"></p> \n</div>";
},"useData":true});
templates['signup_shell'] = template({"1":function(depth0,helpers,partials,data) {
var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,2 @@
<div class="pkt_ext_suggestedtag_detailshown">
</div>

View File

@ -1,4 +1,8 @@
<div class="pkt_ext_initload">
<div class="pkt_ext_initload">
<div class="pkt_ext_logo"></div>
<div class="pkt_ext_topdetail">
<h2>{{saving}}</h2>
</div>
<div class="pkt_ext_loadingspinner"><div></div></div>
</div>
<div class="pkt_ext_detail">
@ -10,11 +14,10 @@
<ul>
<li><a class="pkt_ext_removeitem" href="#">{{removepage}}</a></li>
<li class="pkt_ext_actions_separator"></li>
<li><a class="pkt_ext_openpocket" href="http://{{pockethost}}/a?src=ff_ext_saved" target="_blank">{{viewlist}}</a></li>
<li><a class="pkt_ext_openpocket" href="https://{{pockethost}}/a?src=ff_ext_saved" target="_blank">{{viewlist}}</a></li>
</ul>
</nav>
</div>
<p class="pkt_ext_edit_msg"></p>
<div class="pkt_ext_tag_detail pkt_ext_cf">
<div class="pkt_ext_tag_input_wrapper">
<div class="pkt_ext_tag_input_blocker"></div>
@ -22,4 +25,5 @@
</div>
<a href="#" class="pkt_ext_btn pkt_ext_btn_disabled">{{save}}</a>
</div>
<p class="pkt_ext_edit_msg"></p>
</div>

View File

@ -223,8 +223,6 @@ var pktApi = (function() {
}
return;
}
// TODO: Better error handling
if (options.error) {
// In case the user did revoke the access token or it's not
// valid anymore clear the user data
@ -232,15 +230,10 @@ var pktApi = (function() {
clearUserData();
}
// Check to handle Pocket error
var errorMessage = request.getResponseHeader("X-Error");
if (typeof errorMessage !== "undefined") {
options.error(new Error(errorMessage), request);
return;
}
// Handle other error
options.error(new Error(request.statusText), request);
// Handle error message
var errorMessage = request.getResponseHeader("X-Error") || request.statusText;
var error = {message: errorMessage};
options.error(error, request);
}
}
};