Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
856a715130 | |||
b8717bd08f | |||
a0af8e31a5 | |||
78680fac49 | |||
bedb5a22b6 | |||
b571af29c5 | |||
c5cadb1557 | |||
45cf59be52 | |||
19aa864579 | |||
8723154371 | |||
25fe0c5849 |
127
README.md
127
README.md
@ -1,28 +1,67 @@
|
|||||||
<div align="center">
|
# ReadLater WebExtension ![language](https://img.shields.io/badge/language-webextension-blue.svg)
|
||||||
<h1>
|
|
||||||
Extension Boilerplate
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<p>
|
> ReadLaterByEmail webextension generator
|
||||||
<strong>A foundation for creating browser extensions for Chrome, Opera & Firefox.</strong>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
Now that Firefox supports WebExtensions, it has become a lot easier to build browser extensions/addons for multiple browsers without duplicating the codebase. This project serves as a sensible starting point to help you get started.
|
## :books: Table of Contents
|
||||||
|
|
||||||
<div align="center">
|
- [Installation](#package-installation)
|
||||||
<a href="https://www.emailthis.me/open-source/extension-boilerplate">
|
- [Usage](#rocket-usage)
|
||||||
<img src="./resources/chrome-promo/large.png" alt="Extension Boilerplate">
|
- [Features](#sparkles-features)
|
||||||
</a>
|
- [Support](#hammer_and_wrench-support)
|
||||||
</div>
|
- [Contributing](#memo-contributing)
|
||||||
|
- [License](#scroll-license)
|
||||||
|
|
||||||
I have extracted this from the browser extensions that I built for my side-project, [Email This](https://www.emailthis.me).
|
## :package: Installation
|
||||||
|
|
||||||
> Side note: Do check out [**Email This**](https://www.emailthis.me). It is a simpler alternative to bookmarking tools like Pocket, Readability & Instapaper. Email This will remove ads & distractions from an article and send you a nice email with just the text/images. No need to install any additional applications or login to another app just to access your bookmarks.
|
### First check if you have composer installed
|
||||||
The Chrome Extensions is available [on the Chrome Web Store](https://chrome.google.com/webstore/detail/email-this/lgblkllcjgihfnlefhnnpppndbbjallh).
|
|
||||||
|
|
||||||
|
Before installing this, you need to check if you have `NPM` installed on your computer.
|
||||||
|
|
||||||
## Features
|
### Then install this script
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git clone ssh://gogs@git.shikiryu.com:2200/ReadLaterByEmail/webextensions.git
|
||||||
|
cd webextensions
|
||||||
|
npm install
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
## :rocket: Usage
|
||||||
|
|
||||||
|
### Load the extension in Chrome & Opera
|
||||||
|
|
||||||
|
1. Open Chrome/Opera browser and navigate to chrome://extensions
|
||||||
|
2. Select "Developer Mode" and then click "Load unpacked extension..."
|
||||||
|
3. From the file browser, choose to `extension-boilerplate/build/chrome` or (`extension-boilerplate/build/opera`)
|
||||||
|
|
||||||
|
### Load the extension in Firefox
|
||||||
|
|
||||||
|
1. Open Firefox browser and navigate to about:debugging
|
||||||
|
2. Click "Load Temporary Add-on" and from the file browser, choose `extension-boilerplate/build/firefox`
|
||||||
|
|
||||||
|
### Developing
|
||||||
|
|
||||||
|
The following tasks can be used when you want to start developing the extension and want to enable live reload -
|
||||||
|
|
||||||
|
- `npm run chrome-watch`
|
||||||
|
- `npm run opera-watch`
|
||||||
|
- `npm run firefox-watch`
|
||||||
|
|
||||||
|
### Packaging
|
||||||
|
|
||||||
|
Run `npm run dist` to create a zipped, production-ready extension for each browser. You can then upload that to the appstore.
|
||||||
|
|
||||||
|
#### Firefox
|
||||||
|
|
||||||
|
Run `npm run sourcezip` for firefox submission
|
||||||
|
|
||||||
|
Update <https://addons.mozilla.org/fr/developers/addon/shikiryu-readlater/versions/submit/>
|
||||||
|
|
||||||
|
#### Opera
|
||||||
|
|
||||||
|
Update <https://addons.opera.com/developer/package/250537/?tab=versions>
|
||||||
|
|
||||||
|
## :sparkles: Features
|
||||||
|
|
||||||
<dl>
|
<dl>
|
||||||
<dt>Write once and deploy to Chrome, Opera & Firefox</dt>
|
<dt>Write once and deploy to Chrome, Opera & Firefox</dt>
|
||||||
@ -67,56 +106,20 @@ The Chrome Extensions is available [on the Chrome Web Store](https://chrome.goog
|
|||||||
You might need to specify different data variables based on your environment. For example, you might want to use a localhost API endpoint during development and a production API endpoint once the extension is submitted to the appstore. You can specify such data in the json files inside `config` directory.
|
You might need to specify different data variables based on your environment. For example, you might want to use a localhost API endpoint during development and a production API endpoint once the extension is submitted to the appstore. You can specify such data in the json files inside `config` directory.
|
||||||
|
|
||||||
You can also set custom data variables based on the platform (different variable for Chrome, FF, Opera).
|
You can also set custom data variables based on the platform (different variable for Chrome, FF, Opera).
|
||||||
|
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
|
## :hammer_and_wrench: Support
|
||||||
|
|
||||||
|
Please [open an issue](https://git.shikiryu.com/ReadLaterByEmail/webextensions/issues/new) for support.
|
||||||
|
|
||||||
## Installation
|
## :memo: Contributing
|
||||||
1. Clone the repository `git clone https://github.com/EmailThis/extension-boilerplate.git`
|
|
||||||
2. Run `npm install`
|
|
||||||
3. Run `npm run build`
|
|
||||||
|
|
||||||
Alternately, if you want to try out the sample extension, here are the download links. After you download it, unzip the file and load it in your browser using the steps mentioned below.
|
Please contribute using [Github Flow](https://guides.github.com/introduction/flow/). Create a branch, add commits, and [open a pull request](https://git.shikiryu.com/ReadLaterByEmail/webextensions/compare/master...master).
|
||||||
- [**Download Chrome Extension**](https://github.com/EmailThis/extension-boilerplate/releases/download/v1.0/chrome.zip)
|
|
||||||
- [**Download Opera Extension**](https://github.com/EmailThis/extension-boilerplate/releases/download/v1.0/opera.zip)
|
|
||||||
- [**Download Firefox Extension**](https://github.com/EmailThis/extension-boilerplate/releases/download/v1.0/firefox.zip)
|
|
||||||
|
|
||||||
|
## :scroll: License
|
||||||
|
|
||||||
##### Load the extension in Chrome & Opera
|
[Creative Commons Attribution NonCommercial (CC-BY-NC)](<https://tldrlegal.com/license/creative-commons-attribution-noncommercial-(cc-nc)>) Β© [Chouchen](https://github.com/Chouchen/)
|
||||||
1. Open Chrome/Opera browser and navigate to chrome://extensions
|
|
||||||
2. Select "Developer Mode" and then click "Load unpacked extension..."
|
|
||||||
3. From the file browser, choose to `extension-boilerplate/build/chrome` or (`extension-boilerplate/build/opera`)
|
|
||||||
|
|
||||||
|
Based on [Email This](https://www.emailthis.me) which is licensed under the MIT license.
|
||||||
##### Load the extension in Firefox
|
|
||||||
1. Open Firefox browser and navigate to about:debugging
|
|
||||||
2. Click "Load Temporary Add-on" and from the file browser, choose `extension-boilerplate/build/firefox`
|
|
||||||
|
|
||||||
|
|
||||||
## Developing
|
|
||||||
The following tasks can be used when you want to start developing the extension and want to enable live reload -
|
|
||||||
|
|
||||||
- `npm run chrome-watch`
|
|
||||||
- `npm run opera-watch`
|
|
||||||
- `npm run firefox-watch`
|
|
||||||
|
|
||||||
|
|
||||||
## Packaging
|
|
||||||
Run `npm run dist` to create a zipped, production-ready extension for each browser. You can then upload that to the appstore.
|
|
||||||
|
|
||||||
|
|
||||||
## TODO
|
|
||||||
- [ ] Add support for Safari
|
|
||||||
- [x] Add Firefox & Opera Promo images
|
|
||||||
- [x] Add sample screenshot templates
|
|
||||||
- [ ] Write a guide for using config variables & JS preprocessor
|
|
||||||
|
|
||||||
|
|
||||||
-----------
|
|
||||||
This project is licensed under the MIT license.
|
|
||||||
|
|
||||||
If you have any questions or comments, please create a new issue. I'd be happy to hear your thoughts.
|
|
||||||
|
|
||||||
|
|
||||||
Bharani, [Email This](https://www.emailthis.me)
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "Shikiryu Read Later",
|
"name": "Read Later by Email",
|
||||||
"version": "0.0.2.1",
|
"version": "0.0.3",
|
||||||
"manifest_version": 2,
|
"manifest_version": 2,
|
||||||
"description": "__MSG_extensionDescription__",
|
"description": "__MSG_extensionDescription__",
|
||||||
"icons": {
|
"icons": {
|
||||||
@ -9,26 +9,16 @@
|
|||||||
},
|
},
|
||||||
"default_locale": "en",
|
"default_locale": "en",
|
||||||
"background": {
|
"background": {
|
||||||
"scripts": [
|
"scripts": ["scripts/background.js"]
|
||||||
"scripts/background.js"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"permissions": [
|
"permissions": ["activeTab", "storage"],
|
||||||
"activeTab",
|
|
||||||
"storage"
|
|
||||||
],
|
|
||||||
"options_ui": {
|
"options_ui": {
|
||||||
"page": "options.html"
|
"page": "options.html"
|
||||||
},
|
},
|
||||||
"content_scripts": [
|
"content_scripts": [
|
||||||
{
|
{
|
||||||
"matches": [
|
"matches": ["http://*/*", "https://*/*"],
|
||||||
"http://*/*",
|
"js": ["scripts/contentscript.js"],
|
||||||
"https://*/*"
|
|
||||||
],
|
|
||||||
"js": [
|
|
||||||
"scripts/contentscript.js"
|
|
||||||
],
|
|
||||||
"run_at": "document_end",
|
"run_at": "document_end",
|
||||||
"all_frames": false
|
"all_frames": false
|
||||||
}
|
}
|
||||||
@ -39,12 +29,12 @@
|
|||||||
"32": "icons/favicon-32x32.png",
|
"32": "icons/favicon-32x32.png",
|
||||||
"96": "icons/favicon-96x96.png"
|
"96": "icons/favicon-96x96.png"
|
||||||
},
|
},
|
||||||
"default_title": "Shikiryu Bookmarklet",
|
"default_title": "Read Later by Email",
|
||||||
"default_popup": "popup.html"
|
"default_popup": "popup.html"
|
||||||
},
|
},
|
||||||
"applications": {
|
"applications": {
|
||||||
"gecko": {
|
"gecko": {
|
||||||
"id": "bookmarklet@shikiryu.com"
|
"id": "bookmarklet@shikiryu.com"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
27
privacy_policy.md
Executable file
27
privacy_policy.md
Executable file
@ -0,0 +1,27 @@
|
|||||||
|
#English
|
||||||
|
This extension collect the instance URL you'll be sending your page to and the token used to identify yourself on this instance.
|
||||||
|
This will be saved on your browser local storage.
|
||||||
|
|
||||||
|
The following elements are sent to the instance:
|
||||||
|
|
||||||
|
- title
|
||||||
|
- description
|
||||||
|
- image
|
||||||
|
|
||||||
|
They are automatically generated with the current tab content. With your current token, you can also send a comment which will reach the instance.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# French
|
||||||
|
|
||||||
|
Cette extension collecte l'URL de l'instance vers laquelle vous allez envoyer les informations and le jeton vous permettant de vous identifier sur cette instance.
|
||||||
|
Ces deux donnΓ©es sont enregistrΓ©es localement dans le local storage de votre navigateur.
|
||||||
|
|
||||||
|
Les Γ©lΓ©ments suivant seront envoyΓ©s Γ l'instance :
|
||||||
|
|
||||||
|
- titre
|
||||||
|
- description
|
||||||
|
- image
|
||||||
|
|
||||||
|
Ils seront gΓ©nΓ©rΓ©s automatiquement Γ partir des mΓͺmes informations utilisΓ©es sur l'onglet actuellement ouvert.
|
||||||
|
Avec votre jeton en cours, vous pourrez aussi envoyer un commentaire de cet onglet vers l'instance.
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"extensionName": {
|
"extensionName": {
|
||||||
"message": "Shikiryu Read Later",
|
"message": "Read Later by Email",
|
||||||
"description": "The name of the extension."
|
"description": "The name of the extension."
|
||||||
},
|
},
|
||||||
"extensionDescription": {
|
"extensionDescription": {
|
||||||
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"extensionName": {
|
"extensionName": {
|
||||||
"message": "Shikiryu Read Later",
|
"message": "Read Later by Email",
|
||||||
"description": "The name of the extension."
|
"description": "The name of the extension."
|
||||||
},
|
},
|
||||||
"extensionDescription": {
|
"extensionDescription": {
|
||||||
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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">
|
© <a href="https://readlater.shikiryu.com">ReadLaterByEmail</a>
|
||||||
© <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>
|
||||||
|
@ -1,20 +1,37 @@
|
|||||||
<!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">
|
||||||
<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">
|
||||||
© <a href="https://readlater.shikiryu.com">Shikiryu</a>
|
©
|
||||||
|
<a href="https://readlater.shikiryu.com">ReadLaterByEmail</a>
|
||||||
</p>
|
</p>
|
||||||
<p class="js-options" data-message="optionsAndSettings"></p>
|
<p class="js-options" data-message="optionsAndSettings"></p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -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
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
});
|
||||||
|
@ -16,33 +16,39 @@ 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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,19 +1,21 @@
|
|||||||
'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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,30 +3,45 @@ 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;
|
if (this.value.endsWith("/")) {
|
||||||
storage.set({ url: value }, function() {
|
this.value = this.value.substring(0, this.value.length - 1);
|
||||||
message.innerHTML = ext.i18n.getMessage("URLChanged");
|
}
|
||||||
});
|
var value = this.value;
|
||||||
|
storage.set({ url: value }, function() {
|
||||||
|
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);
|
||||||
});
|
});
|
||||||
|
@ -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") });
|
||||||
});
|
});
|
||||||
|
@ -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();
|
@ -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;
|
||||||
|
Loadingβ¦
Reference in New Issue
Block a user