3 Commits

Author SHA1 Message Date
19aa864579 Allows to add the page content into the email, server-side
Fix #4
2020-07-02 16:55:40 +02:00
8723154371 🚨 Add prettier
Fix #2
2019-05-06 17:01:54 +02:00
25fe0c5849 👌 Remove all innerHTML 2018-12-12 08:06:04 +01:00
14 changed files with 6448 additions and 211 deletions

View File

@@ -1,6 +1,6 @@
{ {
"name": "Shikiryu Read Later", "name": "Shikiryu Read Later",
"version": "0.0.2.1", "version": "0.0.2.2",
"manifest_version": 2, "manifest_version": 2,
"description": "__MSG_extensionDescription__", "description": "__MSG_extensionDescription__",
"icons": { "icons": {

View File

@@ -47,8 +47,16 @@
"gulp-sourcemaps": "^1.6.0", "gulp-sourcemaps": "^1.6.0",
"gulp-uglify": "^1.5.4", "gulp-uglify": "^1.5.4",
"gulp-zip": "^2.0.3", "gulp-zip": "^2.0.3",
"husky": "^2.2.0",
"preprocessify": "^1.0.1", "preprocessify": "^1.0.1",
"prettier": "^1.17.0",
"pretty-quick": "^1.10.0",
"vinyl-buffer": "^1.0.0", "vinyl-buffer": "^1.0.0",
"vinyl-source-stream": "^1.1.0" "vinyl-source-stream": "^1.1.0"
},
"husky": {
"hooks": {
"pre-commit": "pretty-quick --staged"
}
} }
} }

View File

@@ -23,6 +23,10 @@
"message": "Token:", "message": "Token:",
"description": "Token label" "description": "Token label"
}, },
"optionsExtract": {
"message": "Send page content into the email:",
"description": "Extract label"
},
"URLChanged": { "URLChanged": {
"message": "URL changed!", "message": "URL changed!",
"description": "Message when URL is changed." "description": "Message when URL is changed."
@@ -31,6 +35,10 @@
"message": "Token saved!", "message": "Token saved!",
"description": "Message when token is changed." "description": "Message when token is changed."
}, },
"optionSaved": {
"message": "Option saved!",
"description": "Message when option is changed."
},
"cantExtractTitle": { "cantExtractTitle": {
"message": "Sorry, could not extract this page's title and URL", "message": "Sorry, could not extract this page's title and URL",
"description": "Message when we could not extract the page's title and URL" "description": "Message when we could not extract the page's title and URL"
@@ -46,5 +54,9 @@
"defaultURL": { "defaultURL": {
"message": "https://app.readlater.shikiryu.com", "message": "https://app.readlater.shikiryu.com",
"description": "Default URL" "description": "Default URL"
},
"excerpt": {
"message": "Add content",
"description": "Option to add the webpage content into the email"
} }
} }

View File

@@ -23,14 +23,22 @@
"message": "Jeton :", "message": "Jeton :",
"description": "Token label" "description": "Token label"
}, },
"optionsExtract": {
"message": "Envoyer le contenu de la page dans le mail:",
"description": "Extract label"
},
"URLChanged": { "URLChanged": {
"message": "URL changed!", "message": "URL enregistrée !",
"description": "Message when URL is changed." "description": "Message when URL is changed."
}, },
"tokenSaved": { "tokenSaved": {
"message": "Token saved!", "message": "Jeton enregistré !",
"description": "Message when token is changed." "description": "Message when token is changed."
}, },
"optionSaved": {
"message": "Option enregistrée !",
"description": "Message when option is changed."
},
"cantExtractTitle": { "cantExtractTitle": {
"message": "Sorry, could not extract this page's title and URL", "message": "Sorry, could not extract this page's title and URL",
"description": "Message when we could not extract the page's title and URL" "description": "Message when we could not extract the page's title and URL"
@@ -46,5 +54,9 @@
"defaultURL": { "defaultURL": {
"message": "https://app.readlater.shikiryu.com", "message": "https://app.readlater.shikiryu.com",
"description": "Default URL" "description": "Default URL"
},
"excerpt": {
"message": "Ajouter le contenu",
"description": "Option to add the webpage content into the email"
} }
} }

View File

@@ -1,57 +1,63 @@
<!doctype html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8" />
<link href="styles/options.css" rel="stylesheet"> <link href="styles/options.css" rel="stylesheet" />
<meta name="viewport" content="width=device-width,initial-scale=1"> <meta name="viewport" content="width=device-width,initial-scale=1" />
<title data-message="optionsAndSettings"></title> <title data-message="optionsAndSettings"></title>
</head> </head>
<body class="wrap"> <body class="wrap">
<div class="grid">
<div class="unit whole center-on-mobiles">
<div class="heading">
<h1 data-message="extensionName"></h1>
<p class="lead" data-message="optionsPageSubtitle"></p>
</div>
</div>
</div>
<section>
<div class="grid">
<div class="unit whole center-on-mobiles">
<div id="msg"></div>
</div>
</div>
</section>
<section class="content">
<div class="grid"> <div class="grid">
<div class="unit whole center-on-mobiles"> <div class="unit whole center-on-mobiles">
<div class="option"> <div class="heading">
<h5 data-message="optionsURL"></h5> <h1 data-message="extensionName"></h1>
<input type="text" name="url" value="https://app.readlater.shikiryu.com" /> <p class="lead" data-message="optionsPageSubtitle"></p>
</div> </div>
</div>
</div>
<div class="option"> <section>
<div class="grid">
<div class="unit whole center-on-mobiles">
<div id="msg"></div>
</div>
</div>
</section>
<section class="content">
<div class="grid">
<div class="unit whole center-on-mobiles">
<div class="option">
<h5 data-message="optionsURL"></h5>
<input
type="text"
name="url"
value="https://app.readlater.shikiryu.com"
/>
</div>
<div class="option">
<h5 data-message="optionsToken"></h5> <h5 data-message="optionsToken"></h5>
<input type="text" name="token" value="" /> <input type="text" name="token" value="" />
</div>
<div class="option">
<h5 data-message="optionsExtract"></h5>
<input type="checkbox" name="extract" value="1" />
</div>
</div> </div>
</div> </div>
</div> </section>
</section>
<footer class="main-footer">
<footer class="main-footer"> <div class="grid">
<div class="grid"> <div class="unit whole center-on-mobiles">
<div class="unit whole center-on-mobiles"> <p class="text-center text-muted">
<p class="text-center text-muted"> &copy; <a href="https://readlater.shikiryu.com">Shikiryu</a>
&copy; <a href="https://readlater.shikiryu.com">Shikiryu</a> </p>
</p> </div>
</div> </div>
</div> </footer>
<script src="scripts/options.js"></script>
</footer> </body>
<script src="scripts/options.js"></script>
</body>
</html> </html>

View File

@@ -1,14 +1,30 @@
<!doctype html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8" />
<link href="styles/popup.css" rel="stylesheet"> <link href="styles/popup.css" rel="stylesheet" />
</head> </head>
<body> <body>
<div id="app" class="popup-content"> <div id="app" class="popup-content">
<h1 data-message="extensionName"></h1> <h1 data-message="extensionName"></h1>
<div id="display-container"></div> <div id="display-container">
<div class="site-description">
<h3 class="title" data-template="title"></h3>
<p class="description" data-template="description"></p>
<p class="image" data-template="image"></p>
<div>
<label for="comment">Comment:</label>
<textarea id="comment" name="comment"></textarea>
</div>
<a href="" target="_blank" class="url" data-template="url"></a>
</div>
<div class="action-container">
<label for="save-content" data-message="excerpt"></label>
<input type="checkbox" id="save-content" name="save-content" />
<button id="save-btn" class="btn btn-primary">Save</button>
</div>
</div>
<footer class="main-footer"> <footer class="main-footer">
<div class="grid"> <div class="grid">
@@ -21,7 +37,7 @@
</div> </div>
</footer> </footer>
</div> </div>
<script src="scripts/popup.js"></script> <script src="scripts/popup.js"></script>
</body> </body>
</html> </html>

View File

@@ -1,44 +1,50 @@
import ext from "./utils/ext"; import ext from "./utils/ext";
import storage from "./utils/storage"; import storage from "./utils/storage";
ext.runtime.onMessage.addListener( ext.runtime.onMessage.addListener(function(request, sender, sendResponse) {
function(request, sender, sendResponse) { if (request.action === "perform-save") {
if(request.action === "perform-save") { var data = request.data;
var data = request.data; var url;
var url; var token;
var token; storage.get(["url", "token"], function(resp) {
storage.get(['url', 'token'], function(resp) { url = resp.url;
url = resp.url; token = resp.token;
token = resp.token; var params = {
var params = { v: 1,
v: 1, u: encodeURIComponent(data.url),
u: encodeURIComponent(data.url), t: encodeURIComponent(data.title),
t: encodeURIComponent(data.title), d: encodeURIComponent(data.description),
d: encodeURIComponent(data.description), api_token: encodeURIComponent(token),
api_token: encodeURIComponent(token), i: encodeURIComponent(data.image),
i: encodeURIComponent(data.image), c: encodeURIComponent(data.comment)
c: encodeURIComponent(data.comment), };
}; if (data.extract) {
var queryString = Object.keys(params).map((key) => { params["e"] = true;
return key + '=' + params[key]; }
}).join('&'); var queryString = Object.keys(params)
fetch(url + "/api/links", { .map(key => {
method: 'POST', return key + "=" + params[key];
headers: {
'Accept': 'application/json'
},
body: new URLSearchParams(queryString)
}) })
.then(function(response) { .join("&");
if (200 === response.status) { fetch(url + "/api/links", {
sendResponse({action: "saved"}); method: "POST",
} else { headers: {
sendResponse({action: "error", status: response.status, error: response.statusText}); Accept: "application/json"
} },
}); body: new URLSearchParams(queryString)
}).then(function(response) {
if (200 === response.status) {
sendResponse({ action: "saved" });
} else {
sendResponse({
action: "error",
status: response.status,
error: response.statusText
});
}
}); });
});
return true; // https://stackoverflow.com/a/20077854 return true; // https://stackoverflow.com/a/20077854
}
} }
); });

View File

@@ -16,34 +16,40 @@ var extractTags = () => {
}; };
var ogTitle = document.querySelector("meta[property='og:title']"); var ogTitle = document.querySelector("meta[property='og:title']");
if(ogTitle) { if (ogTitle) {
data.title = ogTitle.getAttribute("content"); data.title = ogTitle.getAttribute("content");
} else { } else {
data.title = document.title; data.title = document.title;
} }
var descriptionTag = document.querySelector("meta[property='og:description']") || document.querySelector("meta[name='description']"); var descriptionTag =
if(descriptionTag) { document.querySelector("meta[property='og:description']") ||
data.description = descriptionTag.getAttribute("content") document.querySelector("meta[name='description']");
if (descriptionTag) {
data.description = descriptionTag.getAttribute("content");
} }
var imgTag = document.querySelector("meta[property='og:image']") || document.querySelector("meta[property='twitter-image']"); var imgTag =
if(imgTag) { document.querySelector("meta[property='og:image']") ||
data.image = imgTag.getAttribute("content") document.querySelector("meta[property='twitter-image']");
} else { if (imgTag) {
imgTag = document.querySelector("link[rel=icon]") || document.querySelector("link[rel=apple-touch-icon]"); data.image = imgTag.getAttribute("content");
if (imgTag) { } else {
data.image = imgTag.getAttribute("href"); imgTag =
} document.querySelector("link[rel=icon]") ||
document.querySelector("link[rel=apple-touch-icon]");
if (imgTag) {
data.image = imgTag.getAttribute("href");
} }
}
return data; return data;
}; };
function onRequest(request, sender, sendResponse) { function onRequest(request, sender, sendResponse) {
if (request.action === 'process-page') { if (request.action === "process-page") {
sendResponse(extractTags()) sendResponse(extractTags());
} }
} }
ext.runtime.onMessage.addListener(onRequest); ext.runtime.onMessage.addListener(onRequest);

View File

@@ -1,20 +1,22 @@
'use strict'; "use strict";
import ext from "./utils/ext"; import ext from "./utils/ext";
var LIVERELOAD_HOST = 'localhost:'; var LIVERELOAD_HOST = "localhost:";
var LIVERELOAD_PORT = 35729; var LIVERELOAD_PORT = 35729;
var connection = new WebSocket('ws://' + LIVERELOAD_HOST + LIVERELOAD_PORT + '/livereload'); var connection = new WebSocket(
"ws://" + LIVERELOAD_HOST + LIVERELOAD_PORT + "/livereload"
);
connection.onerror = function (error) { connection.onerror = function(error) {
console.log('reload connection got error:', error); console.log("reload connection got error:", error);
}; };
connection.onmessage = function (e) { connection.onmessage = function(e) {
if (e.data) { if (e.data) {
var data = JSON.parse(e.data); var data = JSON.parse(e.data);
if (data && data.command === 'reload') { if (data && data.command === "reload") {
ext.runtime.reload(); ext.runtime.reload();
} }
} }
}; };

View File

@@ -3,30 +3,42 @@ import storage from "./utils/storage";
var urlInput = document.querySelector("[name=url]"); var urlInput = document.querySelector("[name=url]");
var tokenInput = document.querySelector("[name=token]"); var tokenInput = document.querySelector("[name=token]");
var extractInput = document.querySelector("[name=extract]");
var message = document.getElementById("msg"); var message = document.getElementById("msg");
storage.get('url', function(resp) { storage.get("url", function(resp) {
urlInput.value = resp.url || "https://app.readlater.shikiryu.com"; urlInput.value = resp.url || "https://app.readlater.shikiryu.com";
}); });
storage.get('token', function(resp) { storage.get("token", function(resp) {
tokenInput.value = resp.token; tokenInput.value = resp.token;
});
storage.get("extract", function(resp) {
extractInput.value = resp.extract;
}); });
urlInput.addEventListener("blur", function(e) { urlInput.addEventListener("blur", function(e) {
var value = this.value; var value = this.value;
storage.set({ url: value }, function() { storage.set({ url: value }, function() {
message.innerHTML = ext.i18n.getMessage("URLChanged"); message.textContent = ext.i18n.getMessage("URLChanged");
}); });
}); });
tokenInput.addEventListener("blur", function(e) { tokenInput.addEventListener("blur", function(e) {
var value = this.value; var value = this.value;
storage.set({ token: value }, function() { storage.set({ token: value }, function() {
message.innerHTML = ext.i18n.getMessage("tokenSaved"); message.textContent = ext.i18n.getMessage("tokenSaved");
}); });
});
extractInput.addEventListener("change", function(e) {
var value = this.value;
storage.set({ extract: value }, function() {
message.textContent = ext.i18n.getMessage("optionSaved");
});
}); });
document.querySelectorAll("[data-message]").forEach(function(elt) { document.querySelectorAll("[data-message]").forEach(function(elt) {
elt.innerHTML = ext.i18n.getMessage(elt.dataset.message); elt.textContent = ext.i18n.getMessage(elt.dataset.message);
}); });

View File

@@ -2,80 +2,83 @@ import ext from "./utils/ext";
import storage from "./utils/storage"; import storage from "./utils/storage";
var page_data = { var page_data = {
title: "", title: "",
description: "", description: "",
image: "", image: "",
comment: "", comment: "",
url: document.location.href url: document.location.href
}; };
var popup = document.getElementById("app"); var popup = document.getElementById("app");
storage.get('color', function(resp) { storage.get("extract", function(resp) {
var color = resp.color; var extract = resp.extract;
if(color) { if (extract) {
popup.style.backgroundColor = color document.getElementById("save-content").checked = extract
? "checked"
: false;
} }
}); });
var template = (data) => { var renderMessage = message => {
return (`
<div class="site-description">
<h3 class="title">${data.title}</h3>
<p class="description">${data.description}</p>
<p class="image"><img src="${data.image}"></p>
<div>
<label for="comment">Comment:</label>
<textarea id="comment" name="comment"></textarea>
</div>
<a href="${data.url}" target="_blank" class="url">${data.url}</a>
</div>
<div class="action-container">
<button id="save-btn" class="btn btn-primary">Save</button>
</div>
`);
};
var renderMessage = (message) => {
var displayContainer = document.getElementById("display-container"); var displayContainer = document.getElementById("display-container");
displayContainer.innerHTML = `<p class='message'>${message}</p>`; displayContainer.textContent = message;
}; };
var renderBookmark = (data) => { var renderBookmark = data => {
var displayContainer = document.getElementById("display-container"); if (data) {
if(data) { page_data = data;
page_data = data; document.querySelector("[data-template=title]").textContent =
displayContainer.innerHTML = template(data); page_data.title;
document.querySelector("[data-template=description]").textContent =
page_data.description;
if ("" !== img) {
var img = document.createElement("image");
img.src = page_data.image;
document.querySelector("[data-template=image]").appendChild(img);
}
document.querySelector("[data-template=url]").textContent = page_data.url;
document
.querySelector("[data-template=url]")
.setAttribute("href", page_data.url);
} else { } else {
renderMessage(ext.i18n.getMessage("cantExtractTitle")); renderMessage(ext.i18n.getMessage("cantExtractTitle"));
} }
}; };
ext.tabs.query({active: true, currentWindow: true}, function(tabs) { ext.tabs.query({ active: true, currentWindow: true }, function(tabs) {
var activeTab = tabs[0]; var activeTab = tabs[0];
chrome.tabs.sendMessage(activeTab.id, { action: 'process-page' }, renderBookmark); ext.tabs.sendMessage(
activeTab.id,
{ action: "process-page" },
renderBookmark
);
}); });
popup.addEventListener("click", function(e) { popup.addEventListener("click", function(e) {
if(e.target && e.target.matches("#save-btn")) { if (e.target && e.target.matches("#save-btn")) {
e.preventDefault(); e.preventDefault();
page_data.comment = document.getElementById("comment").value; page_data.comment = document.getElementById("comment").value;
ext.runtime.sendMessage({action: "perform-save", data: page_data}, function (response) { page_data.extract = document.getElementById("save-content").checked;
if (response && response.action === "saved") { ext.runtime.sendMessage(
renderMessage(ext.i18n.getMessage("savedSuccessfully")); { action: "perform-save", data: page_data },
} else { function(response) {
renderMessage(response.error + " ("+response.status+")"); if (response && response.action === "saved") {
} renderMessage(ext.i18n.getMessage("savedSuccessfully"));
}); } else {
renderMessage(response.error + " (" + response.status + ")");
}
}
);
} }
}); });
var dataMessages = document.querySelectorAll("[data-message]"); var dataMessages = document.querySelectorAll("[data-message]");
[].forEach.call(dataMessages, function(elt) { [].forEach.call(dataMessages, function(elt) {
console.log(elt.dataset.message); elt.textContent = ext.i18n.getMessage(elt.dataset.message);
elt.innerHTML = ext.i18n.getMessage(elt.dataset.message);
}); });
var optionsLink = document.querySelector(".js-options"); var optionsLink = document.querySelector(".js-options");
optionsLink.addEventListener("click", function(e) { optionsLink.addEventListener("click", function(e) {
e.preventDefault(); e.preventDefault();
ext.tabs.create({'url': ext.extension.getURL('options.html')}); ext.tabs.create({ url: ext.extension.getURL("options.html") });
}); });

View File

@@ -1,68 +1,66 @@
const apis = [ const apis = [
'alarms', "alarms",
'bookmarks', "bookmarks",
'browserAction', "browserAction",
'commands', "commands",
'contextMenus', "contextMenus",
'cookies', "cookies",
'downloads', "downloads",
'events', "events",
'extension', "extension",
'extensionTypes', "extensionTypes",
'history', "history",
'i18n', "i18n",
'idle', "idle",
'notifications', "notifications",
'pageAction', "pageAction",
'runtime', "runtime",
'storage', "storage",
'tabs', "tabs",
'webNavigation', "webNavigation",
'webRequest', "webRequest",
'windows', "windows"
] ];
function Extension () { function Extension() {
const _this = this const _this = this;
apis.forEach(function (api) { apis.forEach(function(api) {
_this[api] = null;
_this[api] = null
try { try {
if (chrome[api]) { if (chrome[api]) {
_this[api] = chrome[api] _this[api] = chrome[api];
} }
} catch (e) {} } catch (e) {}
try { try {
if (window[api]) { if (window[api]) {
_this[api] = window[api] _this[api] = window[api];
} }
} catch (e) {} } catch (e) {}
try { try {
if (browser[api]) { if (browser[api]) {
_this[api] = browser[api] _this[api] = browser[api];
} }
} catch (e) {} } catch (e) {}
try { try {
_this.api = browser.extension[api] _this.api = browser.extension[api];
} catch (e) {} } catch (e) {}
}) });
try { try {
if (browser && browser.runtime) { if (browser && browser.runtime) {
this.runtime = browser.runtime this.runtime = browser.runtime;
} }
} catch (e) {} } catch (e) {}
try { try {
if (browser && browser.browserAction) { if (browser && browser.browserAction) {
this.browserAction = browser.browserAction this.browserAction = browser.browserAction;
} }
} catch (e) {} } catch (e) {}
} }
module.exports = new Extension(); module.exports = new Extension();

View File

@@ -1,3 +1,3 @@
import ext from "./ext"; import ext from "./ext";
module.exports = (ext.storage.sync ? ext.storage.sync : ext.storage.local); module.exports = ext.storage.sync ? ext.storage.sync : ext.storage.local;

6156
yarn.lock Normal file

File diff suppressed because it is too large Load Diff