Source code

Revision control

Copy as Markdown

Other Tools

/******/ (() => { // webpackBootstrap
/******/ "use strict";
/******/ var __webpack_modules__ = ({
/***/ 720:
/***/ ((__unused_webpack___webpack_module__, __unused_webpack___webpack_exports__, __webpack_require__) => {
// EXTERNAL MODULE: ./node_modules/react/index.js
var react = __webpack_require__(504);
// EXTERNAL MODULE: ./node_modules/react-dom/index.js
var react_dom = __webpack_require__(104);
;// CONCATENATED MODULE: ./content/panels/js/components/Header/Header.jsx
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
function Header(props) {
return /*#__PURE__*/react.createElement("h1", {
className: "stp_header"
}, /*#__PURE__*/react.createElement("div", {
className: "stp_header_logo"
}), props.children);
}
/* harmony default export */ const Header_Header = (Header);
;// CONCATENATED MODULE: ./content/panels/js/messages.mjs
/* global RPMRemoveMessageListener:false, RPMAddMessageListener:false, RPMSendAsyncMessage:false */
var pktPanelMessaging = {
removeMessageListener(messageId, callback) {
RPMRemoveMessageListener(messageId, callback);
},
addMessageListener(messageId, callback = () => {}) {
RPMAddMessageListener(messageId, callback);
},
sendMessage(messageId, payload = {}, callback) {
if (callback) {
// If we expect something back, we use RPMSendAsyncMessage and not RPMSendQuery.
// Even though RPMSendQuery returns something, our frame could be closed at any moment,
// and we don't want to close a RPMSendQuery promise loop unexpectedly.
// So instead we setup a response event.
const responseMessageId = `${messageId}_response`;
var responseListener = responsePayload => {
callback(responsePayload);
this.removeMessageListener(responseMessageId, responseListener);
};
this.addMessageListener(responseMessageId, responseListener);
}
// Send message
RPMSendAsyncMessage(messageId, payload);
},
// Click helper to reduce bugs caused by oversight
// from different implementations of similar code.
clickHelper(element, { source = "", position }) {
element?.addEventListener(`click`, event => {
event.preventDefault();
this.sendMessage("PKT_openTabWithUrl", {
url: event.currentTarget.getAttribute(`href`),
source,
position,
});
});
},
log() {
RPMSendAsyncMessage("PKT_log", arguments);
},
};
/* harmony default export */ const messages = (pktPanelMessaging);
;// CONCATENATED MODULE: ./content/panels/js/components/TelemetryLink/TelemetryLink.jsx
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
function TelemetryLink(props) {
function onClick(event) {
if (props.onClick) {
props.onClick(event);
} else {
event.preventDefault();
messages.sendMessage("PKT_openTabWithUrl", {
url: event.currentTarget.getAttribute(`href`),
source: props.source,
model: props.model,
position: props.position
});
}
}
return /*#__PURE__*/react.createElement("a", {
href: props.href,
onClick: onClick,
target: "_blank",
className: props.className
}, props.children);
}
/* harmony default export */ const TelemetryLink_TelemetryLink = (TelemetryLink);
;// CONCATENATED MODULE: ./content/panels/js/components/ArticleList/ArticleList.jsx
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
function ArticleUrl(props) {
// We turn off the link if we're either a saved article, or if the url doesn't exist.
if (props.savedArticle || !props.url) {
return /*#__PURE__*/react.createElement("div", {
className: "stp_article_list_saved_article"
}, props.children);
}
return /*#__PURE__*/react.createElement(TelemetryLink_TelemetryLink, {
className: "stp_article_list_link",
href: props.url,
source: props.source,
position: props.position,
model: props.model
}, props.children);
}
function Article(props) {
function encodeThumbnail(rawSource) {
}
const [thumbnailLoaded, setThumbnailLoaded] = (0,react.useState)(false);
const [thumbnailLoadFailed, setThumbnailLoadFailed] = (0,react.useState)(false);
const {
article,
savedArticle,
position,
source,
model,
utmParams,
openInPocketReader
} = props;
if (!article.url && !article.resolved_url && !article.given_url) {
return null;
}
const url = new URL(article.url || article.resolved_url || article.given_url);
const urlSearchParams = new URLSearchParams(utmParams);
if (openInPocketReader && article.item_id && !url.href.match(/getpocket\.com\/read/)) {
url.href = `https://getpocket.com/read/${article.item_id}`;
}
for (let [key, val] of urlSearchParams.entries()) {
url.searchParams.set(key, val);
}
// Using array notation because there is a key titled `1` (`images` is an object)
const thumbnail = article.thumbnail || encodeThumbnail(article?.top_image_url || article?.images?.["1"]?.src);
const alt = article.alt || "thumbnail image";
const title = article.title || article.resolved_title || article.given_title;
// Sometimes domain_metadata is not there, depending on the source.
const publisher = article.publisher || article.domain_metadata?.name || article.resolved_domain;
return /*#__PURE__*/react.createElement("li", {
className: "stp_article_list_item"
}, /*#__PURE__*/react.createElement(ArticleUrl, {
url: url.href,
savedArticle: savedArticle,
position: position,
source: source,
model: model,
utmParams: utmParams
}, /*#__PURE__*/react.createElement(react.Fragment, null, thumbnail && !thumbnailLoadFailed ? /*#__PURE__*/react.createElement("img", {
className: "stp_article_list_thumb",
src: thumbnail,
alt: alt,
width: "40",
height: "40",
onLoad: () => {
setThumbnailLoaded(true);
},
onError: () => {
setThumbnailLoadFailed(true);
},
style: {
visibility: thumbnailLoaded ? `visible` : `hidden`
}
}) : /*#__PURE__*/react.createElement("div", {
className: "stp_article_list_thumb_placeholder"
}), /*#__PURE__*/react.createElement("div", {
className: "stp_article_list_meta"
}, /*#__PURE__*/react.createElement("header", {
className: "stp_article_list_header"
}, title), /*#__PURE__*/react.createElement("p", {
className: "stp_article_list_publisher"
}, publisher)))));
}
function ArticleList(props) {
return /*#__PURE__*/react.createElement("ul", {
className: "stp_article_list"
}, props.articles?.map((article, position) => /*#__PURE__*/react.createElement(Article, {
article: article,
savedArticle: props.savedArticle,
position: position,
source: props.source,
model: props.model,
utmParams: props.utmParams,
openInPocketReader: props.openInPocketReader
})));
}
/* harmony default export */ const ArticleList_ArticleList = (ArticleList);
;// CONCATENATED MODULE: ./content/panels/js/components/PopularTopics/PopularTopics.jsx
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
function PopularTopics(props) {
return /*#__PURE__*/react.createElement("ul", {
className: "stp_popular_topics"
}, props.topics?.map((topic, position) => /*#__PURE__*/react.createElement("li", {
key: `item-${topic.topic}`,
className: "stp_popular_topic"
}, /*#__PURE__*/react.createElement(TelemetryLink_TelemetryLink, {
className: "stp_popular_topic_link",
href: `https://${props.pockethost}/explore/${topic.topic}?${props.utmParams}`,
source: props.source,
position: position
}, topic.title))));
}
/* harmony default export */ const PopularTopics_PopularTopics = (PopularTopics);
;// CONCATENATED MODULE: ./content/panels/js/components/Button/Button.jsx
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
function Button(props) {
return /*#__PURE__*/react.createElement(TelemetryLink_TelemetryLink, {
href: props.url,
onClick: props.onClick,
className: `stp_button${props?.style && ` stp_button_${props.style}`}`,
source: props.source
}, props.children);
}
/* harmony default export */ const Button_Button = (Button);
;// CONCATENATED MODULE: ./content/panels/js/components/Home/Home.jsx
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
function Home(props) {
const {
locale,
topics,
pockethost,
hideRecentSaves,
utmSource,
utmCampaign,
utmContent
} = props;
const [{
articles,
status
}, setArticlesState] = (0,react.useState)({
articles: [],
// Can be success, loading, or error.
status: ""
});
const utmParams = `utm_source=${utmSource}${utmCampaign && utmContent ? `&utm_campaign=${utmCampaign}&utm_content=${utmContent}` : ``}`;
const loadingRecentSaves = (0,react.useCallback)(() => {
setArticlesState(prevState => ({
...prevState,
status: "loading"
}));
}, []);
const renderRecentSaves = (0,react.useCallback)(resp => {
const {
data
} = resp;
if (data.status === "error") {
setArticlesState(prevState => ({
...prevState,
status: "error"
}));
return;
}
setArticlesState({
articles: data,
status: "success"
});
}, []);
(0,react.useEffect)(() => {
if (!hideRecentSaves) {
// We don't display the loading message until instructed. This is because cache
// loads should be fast, so using the loading message for cache just adds loading jank.
messages.addMessageListener("PKT_loadingRecentSaves", loadingRecentSaves);
messages.addMessageListener("PKT_renderRecentSaves", renderRecentSaves);
}
}, [hideRecentSaves, loadingRecentSaves, renderRecentSaves]);
(0,react.useEffect)(() => {
// tell back end we're ready
messages.sendMessage("PKT_show_home");
}, []);
let recentSavesSection = null;
if (status === "error" || hideRecentSaves) {
recentSavesSection = /*#__PURE__*/react.createElement("h3", {
className: "header_medium",
"data-l10n-id": "pocket-panel-home-new-user-cta"
});
} else if (status === "loading") {
recentSavesSection = /*#__PURE__*/react.createElement("span", {
"data-l10n-id": "pocket-panel-home-most-recent-saves-loading"
});
} else if (status === "success") {
if (articles?.length) {
recentSavesSection = /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement("h3", {
className: "header_medium",
"data-l10n-id": "pocket-panel-home-most-recent-saves"
}), articles.length > 3 ? /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement(ArticleList_ArticleList, {
articles: articles.slice(0, 3),
source: "home_recent_save",
utmParams: utmParams,
openInPocketReader: true
}), /*#__PURE__*/react.createElement("span", {
className: "stp_button_wide"
}, /*#__PURE__*/react.createElement(Button_Button, {
style: "secondary",
url: `https://${pockethost}/a?${utmParams}`,
source: "home_view_list"
}, /*#__PURE__*/react.createElement("span", {
"data-l10n-id": "pocket-panel-button-show-all"
})))) : /*#__PURE__*/react.createElement(ArticleList_ArticleList, {
articles: articles,
source: "home_recent_save",
utmParams: utmParams
}));
} else {
recentSavesSection = /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement("h3", {
className: "header_medium",
"data-l10n-id": "pocket-panel-home-new-user-cta"
}), /*#__PURE__*/react.createElement("h3", {
className: "header_medium",
"data-l10n-id": "pocket-panel-home-new-user-message"
}));
}
}
return /*#__PURE__*/react.createElement("div", {
className: "stp_panel_container"
}, /*#__PURE__*/react.createElement("div", {
className: "stp_panel stp_panel_home"
}, /*#__PURE__*/react.createElement(Header_Header, null, /*#__PURE__*/react.createElement(Button_Button, {
style: "primary",
url: `https://${pockethost}/a?${utmParams}`,
source: "home_view_list"
}, /*#__PURE__*/react.createElement("span", {
"data-l10n-id": "pocket-panel-header-my-saves"
}))), /*#__PURE__*/react.createElement("hr", null), recentSavesSection, /*#__PURE__*/react.createElement("hr", null), pockethost && locale?.startsWith("en") && topics?.length && /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement("h3", {
className: "header_medium"
}, "Explore popular topics:"), /*#__PURE__*/react.createElement(PopularTopics_PopularTopics, {
topics: topics,
pockethost: pockethost,
utmParams: utmParams,
source: "home_popular_topic"
}))));
}
/* harmony default export */ const Home_Home = (Home);
;// CONCATENATED MODULE: ./content/panels/js/home/overlay.jsx
/*
HomeOverlay is the view itself and contains all of the methods to manipute the overlay and messaging.
It does not contain any logic for saving or communication with the extension or server.
*/
var HomeOverlay = function () {
this.inited = false;
this.active = false;
};
HomeOverlay.prototype = {
create({
pockethost
}) {
const {
searchParams
} = new URL(window.location.href);
const locale = searchParams.get(`locale`) || ``;
const hideRecentSaves = searchParams.get(`hiderecentsaves`) === `true`;
const utmSource = searchParams.get(`utmSource`);
const utmCampaign = searchParams.get(`utmCampaign`);
const utmContent = searchParams.get(`utmContent`);
if (this.active) {
return;
}
this.active = true;
react_dom.render( /*#__PURE__*/react.createElement(Home_Home, {
locale: locale,
hideRecentSaves: hideRecentSaves,
pockethost: pockethost,
utmSource: utmSource,
utmCampaign: utmCampaign,
utmContent: utmContent
}), document.querySelector(`body`));
if (window?.matchMedia(`(prefers-color-scheme: dark)`).matches) {
document.querySelector(`body`).classList.add(`theme_dark`);
}
}
};
/* harmony default export */ const overlay = (HomeOverlay);
;// CONCATENATED MODULE: ./content/panels/js/components/Signup/Signup.jsx
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
function Signup(props) {
const {
locale,
pockethost,
utmSource,
utmCampaign,
utmContent
} = props;
const utmParams = `utm_source=${utmSource}${utmCampaign && utmContent ? `&utm_campaign=${utmCampaign}&utm_content=${utmContent}` : ``}`;
return /*#__PURE__*/react.createElement("div", {
className: "stp_panel_container"
}, /*#__PURE__*/react.createElement("div", {
className: "stp_panel stp_panel_signup"
}, /*#__PURE__*/react.createElement(Header_Header, null, /*#__PURE__*/react.createElement(Button_Button, {
style: "secondary",
url: `https://${pockethost}/login?${utmParams}`,
source: "log_in"
}, /*#__PURE__*/react.createElement("span", {
"data-l10n-id": "pocket-panel-signup-login"
}))), /*#__PURE__*/react.createElement("hr", null), locale?.startsWith("en") ? /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement("div", {
className: "stp_signup_content_wrapper"
}, /*#__PURE__*/react.createElement("h3", {
className: "header_medium",
"data-l10n-id": "pocket-panel-signup-cta-a-fix"
}), /*#__PURE__*/react.createElement("p", {
"data-l10n-id": "pocket-panel-signup-cta-b-updated"
})), /*#__PURE__*/react.createElement("div", {
className: "stp_signup_content_wrapper"
}, /*#__PURE__*/react.createElement("hr", null)), /*#__PURE__*/react.createElement("div", {
className: "stp_signup_content_wrapper"
}, /*#__PURE__*/react.createElement("div", {
className: "stp_signup_img_rainbow_reader"
}), /*#__PURE__*/react.createElement("h3", {
className: "header_medium"
}, "Get thought-provoking article recommendations"), /*#__PURE__*/react.createElement("p", null, "Find stories that go deep into a subject or offer a new perspective."))) : /*#__PURE__*/react.createElement("div", {
className: "stp_signup_content_wrapper"
}, /*#__PURE__*/react.createElement("h3", {
className: "header_large",
"data-l10n-id": "pocket-panel-signup-cta-a-fix"
}), /*#__PURE__*/react.createElement("p", {
"data-l10n-id": "pocket-panel-signup-cta-b-short"
}), /*#__PURE__*/react.createElement("strong", null, /*#__PURE__*/react.createElement("p", {
"data-l10n-id": "pocket-panel-signup-cta-c-updated"
}))), /*#__PURE__*/react.createElement("hr", null), /*#__PURE__*/react.createElement("span", {
className: "stp_button_wide"
}, /*#__PURE__*/react.createElement(Button_Button, {
style: "primary",
url: `https://${pockethost}/ff_signup?${utmParams}`,
source: "sign_up_1"
}, /*#__PURE__*/react.createElement("span", {
"data-l10n-id": "pocket-panel-button-activate"
})))));
}
/* harmony default export */ const Signup_Signup = (Signup);
;// CONCATENATED MODULE: ./content/panels/js/signup/overlay.jsx
/*
SignupOverlay is the view itself and contains all of the methods to manipute the overlay and messaging.
It does not contain any logic for saving or communication with the extension or server.
*/
var SignupOverlay = function () {
this.inited = false;
this.active = false;
this.create = function ({
pockethost
}) {
// Extract local variables passed into template via URL query params
const {
searchParams
} = new URL(window.location.href);
const locale = searchParams.get(`locale`) || ``;
const utmSource = searchParams.get(`utmSource`);
const utmCampaign = searchParams.get(`utmCampaign`);
const utmContent = searchParams.get(`utmContent`);
if (this.active) {
return;
}
this.active = true;
// Create actual content
react_dom.render( /*#__PURE__*/react.createElement(Signup_Signup, {
pockethost: pockethost,
utmSource: utmSource,
utmCampaign: utmCampaign,
utmContent: utmContent,
locale: locale
}), document.querySelector(`body`));
if (window?.matchMedia(`(prefers-color-scheme: dark)`).matches) {
document.querySelector(`body`).classList.add(`theme_dark`);
}
// tell back end we're ready
messages.sendMessage("PKT_show_signup");
};
};
/* harmony default export */ const signup_overlay = (SignupOverlay);
;// CONCATENATED MODULE: ./content/panels/js/components/TagPicker/TagPicker.jsx
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
function TagPicker(props) {
const [tags, setTags] = (0,react.useState)(props.tags); // New tag group to store
const [allTags, setAllTags] = (0,react.useState)([]); // All tags ever used (in no particular order)
const [recentTags, setRecentTags] = (0,react.useState)([]); // Most recently used tags
const [duplicateTag, setDuplicateTag] = (0,react.useState)(null);
const [inputValue, setInputValue] = (0,react.useState)("");
// Status can be success, waiting, or error.
const [{
tagInputStatus,
tagInputErrorMessage
}, setTagInputStatus] = (0,react.useState)({
tagInputStatus: "",
tagInputErrorMessage: ""
});
let handleKeyDown = e => {
const enterKey = e.keyCode === 13;
const commaKey = e.keyCode === 188;
const tabKey = inputValue && e.keyCode === 9;
// Submit tags on enter with no input.
// Enter tag on comma, tab, or enter with input.
// Tab to next element with no input.
if (commaKey || enterKey || tabKey) {
e.preventDefault();
if (inputValue) {
addTag(inputValue.trim());
setInputValue(``); // Clear out input
} else if (enterKey) {
submitTags();
}
}
};
let addTag = tagToAdd => {
if (!tagToAdd?.length) {
return;
}
let newDuplicateTag = tags.find(item => item === tagToAdd);
if (!newDuplicateTag) {
setTags([...tags, tagToAdd]);
} else {
setDuplicateTag(newDuplicateTag);
setTimeout(() => {
setDuplicateTag(null);
}, 1000);
}
};
let removeTag = index => {
let updatedTags = tags.slice(0); // Shallow copied array
updatedTags.splice(index, 1);
setTags(updatedTags);
};
let submitTags = () => {
let tagsToSubmit = [];
if (tags?.length) {
tagsToSubmit = tags;
}
// Capture tags that have been typed in but not explicitly added to the tag collection
if (inputValue?.trim().length) {
tagsToSubmit.push(inputValue.trim());
}
if (!props.itemUrl || !tagsToSubmit?.length) {
return;
}
setTagInputStatus({
tagInputStatus: "waiting",
tagInputErrorMessage: ""
});
messages.sendMessage("PKT_addTags", {
url: props.itemUrl,
tags: tagsToSubmit
}, function (resp) {
const {
data
} = resp;
if (data.status === "success") {
setTagInputStatus({
tagInputStatus: "success",
tagInputErrorMessage: ""
});
} else if (data.status === "error") {
setTagInputStatus({
tagInputStatus: "error",
tagInputErrorMessage: data.error.message
});
}
});
};
(0,react.useEffect)(() => {
messages.sendMessage("PKT_getTags", {}, resp => {
setAllTags(resp?.data?.tags);
});
}, []);
(0,react.useEffect)(() => {
messages.sendMessage("PKT_getRecentTags", {}, resp => {
setRecentTags(resp?.data?.recentTags);
});
}, []);
return /*#__PURE__*/react.createElement("div", {
className: "stp_tag_picker"
}, !tagInputStatus && /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement("h3", {
className: "header_small",
"data-l10n-id": "pocket-panel-signup-add-tags"
}), /*#__PURE__*/react.createElement("div", {
className: "stp_tag_picker_tags"
}, tags.map((tag, i) => /*#__PURE__*/react.createElement("div", {
className: `stp_tag_picker_tag${duplicateTag === tag ? ` stp_tag_picker_tag_duplicate` : ``}`
}, /*#__PURE__*/react.createElement("button", {
onClick: () => removeTag(i),
className: `stp_tag_picker_tag_remove`
}, "X"), tag)), /*#__PURE__*/react.createElement("div", {
className: "stp_tag_picker_input_wrapper"
}, /*#__PURE__*/react.createElement("input", {
className: "stp_tag_picker_input",
type: "text",
list: "tag-list",
value: inputValue,
onChange: e => setInputValue(e.target.value),
onKeyDown: e => handleKeyDown(e),
maxlength: "25"
}), /*#__PURE__*/react.createElement("datalist", {
id: "tag-list"
}, allTags.sort((a, b) => a.search(inputValue) - b.search(inputValue)).map(item => /*#__PURE__*/react.createElement("option", {
key: item,
value: item
}))), /*#__PURE__*/react.createElement("button", {
className: "stp_tag_picker_button",
disabled: !inputValue?.length && !tags.length,
"data-l10n-id": "pocket-panel-saved-save-tags",
onClick: () => submitTags()
}))), /*#__PURE__*/react.createElement("div", {
className: "recent_tags"
}, recentTags.slice(0, 3).filter(recentTag => {
return !tags.find(item => item === recentTag);
}).map(tag => /*#__PURE__*/react.createElement("div", {
className: "stp_tag_picker_tag"
}, /*#__PURE__*/react.createElement("button", {
className: "stp_tag_picker_tag_remove",
onClick: () => addTag(tag)
}, "+ ", tag))))), tagInputStatus === "waiting" && /*#__PURE__*/react.createElement("h3", {
className: "header_large",
"data-l10n-id": "pocket-panel-saved-processing-tags"
}), tagInputStatus === "success" && /*#__PURE__*/react.createElement("h3", {
className: "header_large",
"data-l10n-id": "pocket-panel-saved-tags-saved"
}), tagInputStatus === "error" && /*#__PURE__*/react.createElement("h3", {
className: "header_small"
}, tagInputErrorMessage));
}
/* harmony default export */ const TagPicker_TagPicker = (TagPicker);
;// CONCATENATED MODULE: ./content/panels/js/components/Saved/Saved.jsx
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
function Saved(props) {
const {
locale,
pockethost,
utmSource,
utmCampaign,
utmContent
} = props;
// savedStatus can be success, loading, or error.
const [{
savedStatus,
savedErrorId,
itemId,
itemUrl
}, setSavedStatusState] = (0,react.useState)({
savedStatus: "loading"
});
// removedStatus can be removed, removing, or error.
const [{
removedStatus,
removedErrorMessage
}, setRemovedStatusState] = (0,react.useState)({});
const [savedStory, setSavedStoryState] = (0,react.useState)();
const [articleInfoAttempted, setArticleInfoAttempted] = (0,react.useState)();
const utmParams = `utm_source=${utmSource}${utmCampaign && utmContent ? `&utm_campaign=${utmCampaign}&utm_content=${utmContent}` : ``}`;
function removeItem(event) {
event.preventDefault();
setRemovedStatusState({
removedStatus: "removing"
});
messages.sendMessage("PKT_deleteItem", {
itemId
}, function (resp) {
const {
data
} = resp;
if (data.status == "success") {
setRemovedStatusState({
removedStatus: "removed"
});
} else if (data.status == "error") {
let errorMessage = "";
// The server returns English error messages, so in the case of
// non English, we do our best with a generic translated error.
if (data.error.message && locale?.startsWith("en")) {
errorMessage = data.error.message;
}
setRemovedStatusState({
removedStatus: "error",
removedErrorMessage: errorMessage
});
}
});
}
(0,react.useEffect)(() => {
// Wait confirmation of save before flipping to final saved state
messages.addMessageListener("PKT_saveLink", function (resp) {
const {
data
} = resp;
if (data.status == "error") {
// Use localizedKey or fallback to a generic catch all error.
setSavedStatusState({
savedStatus: "error",
savedErrorId: data?.error?.localizedKey || "pocket-panel-saved-error-generic"
});
return;
}
// Success, so no localized error id needed.
setSavedStatusState({
savedStatus: "success",
itemId: data.item?.item_id,
itemUrl: data.item?.given_url,
savedErrorId: ""
});
});
messages.addMessageListener("PKT_articleInfoFetched", function (resp) {
setSavedStoryState(resp?.data?.item_preview);
});
messages.addMessageListener("PKT_getArticleInfoAttempted", function () {
setArticleInfoAttempted(true);
});
// tell back end we're ready
messages.sendMessage("PKT_show_saved");
}, []);
if (savedStatus === "error") {
return /*#__PURE__*/react.createElement("div", {
className: "stp_panel_container"
}, /*#__PURE__*/react.createElement("div", {
className: "stp_panel stp_panel_error"
}, /*#__PURE__*/react.createElement("div", {
className: "stp_panel_error_icon"
}), /*#__PURE__*/react.createElement("h3", {
className: "header_large",
"data-l10n-id": "pocket-panel-saved-error-not-saved"
}), /*#__PURE__*/react.createElement("p", {
"data-l10n-id": savedErrorId
})));
}
return /*#__PURE__*/react.createElement("div", {
className: "stp_panel_container"
}, /*#__PURE__*/react.createElement("div", {
className: "stp_panel stp_panel_saved"
}, /*#__PURE__*/react.createElement(Header_Header, null, /*#__PURE__*/react.createElement(Button_Button, {
style: "primary",
url: `https://${pockethost}/a?${utmParams}`,
source: "view_list"
}, /*#__PURE__*/react.createElement("span", {
"data-l10n-id": "pocket-panel-header-my-saves"
}))), /*#__PURE__*/react.createElement("hr", null), !removedStatus && savedStatus === "success" && /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement("h3", {
className: "header_large header_flex"
}, /*#__PURE__*/react.createElement("span", {
"data-l10n-id": "pocket-panel-saved-page-saved-b"
}), /*#__PURE__*/react.createElement(Button_Button, {
style: "text",
onClick: removeItem
}, /*#__PURE__*/react.createElement("span", {
"data-l10n-id": "pocket-panel-button-remove"
}))), savedStory && /*#__PURE__*/react.createElement(ArticleList_ArticleList, {
articles: [savedStory],
openInPocketReader: true,
utmParams: utmParams
}), articleInfoAttempted && /*#__PURE__*/react.createElement(TagPicker_TagPicker, {
tags: [],
itemUrl: itemUrl
})), savedStatus === "loading" && /*#__PURE__*/react.createElement("h3", {
className: "header_large",
"data-l10n-id": "pocket-panel-saved-saving-tags"
}), removedStatus === "removing" && /*#__PURE__*/react.createElement("h3", {
className: "header_large header_center",
"data-l10n-id": "pocket-panel-saved-processing-remove"
}), removedStatus === "removed" && /*#__PURE__*/react.createElement("h3", {
className: "header_large header_center",
"data-l10n-id": "pocket-panel-saved-removed-updated"
}), removedStatus === "error" && /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement("h3", {
className: "header_large",
"data-l10n-id": "pocket-panel-saved-error-remove"
}), removedErrorMessage && /*#__PURE__*/react.createElement("p", null, removedErrorMessage))));
}
/* harmony default export */ const Saved_Saved = (Saved);
;// CONCATENATED MODULE: ./content/panels/js/saved/overlay.jsx
/*
SavedOverlay is the view itself and contains all of the methods to manipute the overlay and messaging.
It does not contain any logic for saving or communication with the extension or server.
*/
var SavedOverlay = function () {
this.inited = false;
this.active = false;
};
SavedOverlay.prototype = {
create({
pockethost
}) {
if (this.active) {
return;
}
this.active = true;
const {
searchParams
} = new URL(window.location.href);
const locale = searchParams.get(`locale`) || ``;
const utmSource = searchParams.get(`utmSource`);
const utmCampaign = searchParams.get(`utmCampaign`);
const utmContent = searchParams.get(`utmContent`);
react_dom.render( /*#__PURE__*/react.createElement(Saved_Saved, {
locale: locale,
pockethost: pockethost,
utmSource: utmSource,
utmCampaign: utmCampaign,
utmContent: utmContent
}), document.querySelector(`body`));
if (window?.matchMedia(`(prefers-color-scheme: dark)`).matches) {
document.querySelector(`body`).classList.add(`theme_dark`);
}
}
};
/* harmony default export */ const saved_overlay = (SavedOverlay);
;// CONCATENATED MODULE: ./content/panels/js/style-guide/overlay.jsx
var StyleGuideOverlay = function () {};
StyleGuideOverlay.prototype = {
create() {
// TODO: Wrap popular topics component in JSX to work without needing an explicit container hierarchy for styling
react_dom.render( /*#__PURE__*/react.createElement("div", null, /*#__PURE__*/react.createElement("h3", null, "JSX Components:"), /*#__PURE__*/react.createElement("h4", {
className: "stp_styleguide_h4"
}, "Buttons"), /*#__PURE__*/react.createElement("h5", {
className: "stp_styleguide_h5"
}, "text"), /*#__PURE__*/react.createElement(Button_Button, {
style: "text",
source: "styleguide"
}, "Text Button"), /*#__PURE__*/react.createElement("h5", {
className: "stp_styleguide_h5"
}, "primary"), /*#__PURE__*/react.createElement(Button_Button, {
style: "primary",
source: "styleguide"
}, "Primary Button"), /*#__PURE__*/react.createElement("h5", {
className: "stp_styleguide_h5"
}, "secondary"), /*#__PURE__*/react.createElement(Button_Button, {
style: "secondary",
source: "styleguide"
}, "Secondary Button"), /*#__PURE__*/react.createElement("h5", {
className: "stp_styleguide_h5"
}, "primary wide"), /*#__PURE__*/react.createElement("span", {
className: "stp_button_wide"
}, /*#__PURE__*/react.createElement(Button_Button, {
style: "primary",
source: "styleguide"
}, "Primary Wide Button")), /*#__PURE__*/react.createElement("h5", {
className: "stp_styleguide_h5"
}, "secondary wide"), /*#__PURE__*/react.createElement("span", {
className: "stp_button_wide"
}, /*#__PURE__*/react.createElement(Button_Button, {
style: "secondary",
source: "styleguide"
}, "Secondary Wide Button")), /*#__PURE__*/react.createElement("h4", {
className: "stp_styleguide_h4"
}, "Header"), /*#__PURE__*/react.createElement(Header_Header, null, /*#__PURE__*/react.createElement(Button_Button, {
style: "primary",
source: "styleguide"
}, "View My List")), /*#__PURE__*/react.createElement("h4", {
className: "stp_styleguide_h4"
}, "PopularTopics"), /*#__PURE__*/react.createElement(PopularTopics_PopularTopics, {
pockethost: `getpocket.com`,
source: `styleguide`,
utmParams: `utm_source=styleguide`,
topics: [{
title: "Self Improvement",
topic: "self-improvement"
}, {
title: "Food",
topic: "food"
}, {
title: "Entertainment",
topic: "entertainment"
}, {
title: "Science",
topic: "science"
}]
}), /*#__PURE__*/react.createElement("h4", {
className: "stp_styleguide_h4"
}, "ArticleList"), /*#__PURE__*/react.createElement(ArticleList_ArticleList, {
source: `styleguide`,
articles: [{
title: "Article Title",
publisher: "Publisher",
alt: "Alt Text"
}, {
title: "Article Title (No Publisher)",
alt: "Alt Text"
}, {
title: "Article Title (No Thumbnail)",
publisher: "Publisher",
alt: "Alt Text"
}]
}), /*#__PURE__*/react.createElement("h4", {
className: "stp_styleguide_h4"
}, "TagPicker"), /*#__PURE__*/react.createElement(TagPicker_TagPicker, {
tags: [`futurism`, `politics`, `mozilla`]
}), /*#__PURE__*/react.createElement("h3", null, "Typography:"), /*#__PURE__*/react.createElement("h2", {
className: "header_large"
}, ".header_large"), /*#__PURE__*/react.createElement("h3", {
className: "header_medium"
}, ".header_medium"), /*#__PURE__*/react.createElement("p", null, "paragraph"), /*#__PURE__*/react.createElement("h3", null, "Native Elements:"), /*#__PURE__*/react.createElement("h4", {
className: "stp_styleguide_h4"
}, "Horizontal Rule"), /*#__PURE__*/react.createElement("hr", null)), document.querySelector(`#stp_style_guide_components`));
}
};
/* harmony default export */ const style_guide_overlay = (StyleGuideOverlay);
;// CONCATENATED MODULE: ./content/panels/js/main.mjs
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
/* global RPMGetStringPref:false */
var PKT_PANEL = function () {};
PKT_PANEL.prototype = {
initHome() {
this.overlay = new overlay();
this.init();
},
initSignup() {
this.overlay = new signup_overlay();
this.init();
},
initSaved() {
this.overlay = new saved_overlay();
this.init();
},
initStyleGuide() {
this.overlay = new style_guide_overlay();
this.init();
},
setupObservers() {
this.setupMutationObserver();
// Mutation observer isn't always enough for fast loading, static pages.
// Sometimes the mutation observer fires before the page is totally visible.
// In this case, the resize tries to fire with 0 height,
// and because it's a static page, it only does one mutation.
// So in this case, we have a backup intersection observer that fires when
// the page is first visible, and thus, the page is going to guarantee a height.
this.setupIntersectionObserver();
},
init() {
if (this.inited) {
return;
}
this.setupObservers();
this.inited = true;
},
resizeParent() {
let clientHeight = document.body.clientHeight;
if (this.overlay.tagsDropdownOpen) {
clientHeight = Math.max(clientHeight, 252);
}
// We can ignore 0 height here.
// We rely on intersection observer to do the
// resize for 0 height loads.
if (clientHeight) {
messages.sendMessage("PKT_resizePanel", {
width: document.body.clientWidth,
height: clientHeight,
});
}
},
setupIntersectionObserver() {
const observer = new IntersectionObserver(entries => {
if (entries.find(e => e.isIntersecting)) {
this.resizeParent();
observer.unobserve(document.body);
}
});
observer.observe(document.body);
},
setupMutationObserver() {
// Select the node that will be observed for mutations
const targetNode = document.body;
// Options for the observer (which mutations to observe)
const config = { attributes: false, childList: true, subtree: true };
// Callback function to execute when mutations are observed
const callback = mutationList => {
mutationList.forEach(mutation => {
switch (mutation.type) {
case "childList": {
/* One or more children have been added to and/or removed
from the tree.
(See mutation.addedNodes and mutation.removedNodes.) */
this.resizeParent();
break;
}
}
});
};
// Create an observer instance linked to the callback function
const observer = new MutationObserver(callback);
// Start observing the target node for configured mutations
observer.observe(targetNode, config);
},
create() {
const pockethost =
RPMGetStringPref("extensions.pocket.site") || "getpocket.com";
this.overlay.create({ pockethost });
},
};
window.PKT_PANEL = PKT_PANEL;
window.pktPanelMessaging = messages;
/***/ })
/******/ });
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = __webpack_modules__;
/******/
/************************************************************************/
/******/ /* webpack/runtime/chunk loaded */
/******/ (() => {
/******/ var deferred = [];
/******/ __webpack_require__.O = (result, chunkIds, fn, priority) => {
/******/ if(chunkIds) {
/******/ priority = priority || 0;
/******/ for(var i = deferred.length; i > 0 && deferred[i - 1][2] > priority; i--) deferred[i] = deferred[i - 1];
/******/ deferred[i] = [chunkIds, fn, priority];
/******/ return;
/******/ }
/******/ var notFulfilled = Infinity;
/******/ for (var i = 0; i < deferred.length; i++) {
/******/ var [chunkIds, fn, priority] = deferred[i];
/******/ var fulfilled = true;
/******/ for (var j = 0; j < chunkIds.length; j++) {
/******/ if ((priority & 1 === 0 || notFulfilled >= priority) && Object.keys(__webpack_require__.O).every((key) => (__webpack_require__.O[key](chunkIds[j])))) {
/******/ chunkIds.splice(j--, 1);
/******/ } else {
/******/ fulfilled = false;
/******/ if(priority < notFulfilled) notFulfilled = priority;
/******/ }
/******/ }
/******/ if(fulfilled) {
/******/ deferred.splice(i--, 1)
/******/ var r = fn();
/******/ if (r !== undefined) result = r;
/******/ }
/******/ }
/******/ return result;
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/hasOwnProperty shorthand */
/******/ (() => {
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
/******/ })();
/******/
/******/ /* webpack/runtime/jsonp chunk loading */
/******/ (() => {
/******/ // no baseURI
/******/
/******/ // object to store loaded and loading chunks
/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched
/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded
/******/ var installedChunks = {
/******/ 590: 0
/******/ };
/******/
/******/ // no chunk on demand loading
/******/
/******/ // no prefetching
/******/
/******/ // no preloaded
/******/
/******/ // no HMR
/******/
/******/ // no HMR manifest
/******/
/******/ __webpack_require__.O.j = (chunkId) => (installedChunks[chunkId] === 0);
/******/
/******/ // install a JSONP callback for chunk loading
/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => {
/******/ var [chunkIds, moreModules, runtime] = data;
/******/ // add "moreModules" to the modules object,
/******/ // then flag all "chunkIds" as loaded and fire callback
/******/ var moduleId, chunkId, i = 0;
/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) {
/******/ for(moduleId in moreModules) {
/******/ if(__webpack_require__.o(moreModules, moduleId)) {
/******/ __webpack_require__.m[moduleId] = moreModules[moduleId];
/******/ }
/******/ }
/******/ if(runtime) var result = runtime(__webpack_require__);
/******/ }
/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data);
/******/ for(;i < chunkIds.length; i++) {
/******/ chunkId = chunkIds[i];
/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) {
/******/ installedChunks[chunkId][0]();
/******/ }
/******/ installedChunks[chunkId] = 0;
/******/ }
/******/ return __webpack_require__.O(result);
/******/ }
/******/
/******/ var chunkLoadingGlobal = self["webpackChunksave_to_pocket_ff"] = self["webpackChunksave_to_pocket_ff"] || [];
/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));
/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));
/******/ })();
/******/
/************************************************************************/
/******/
/******/ // startup
/******/ // Load entry module and return exports
/******/ // This entry module depends on other loaded chunks and execution need to be delayed
/******/ var __webpack_exports__ = __webpack_require__.O(undefined, [968], () => (__webpack_require__(720)))
/******/ __webpack_exports__ = __webpack_require__.O(__webpack_exports__);
/******/
/******/ })()
;