1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-11-24 08:12:24 +02:00

Clipper: Added first files

This commit is contained in:
Laurent Cozic 2018-05-16 14:16:14 +01:00
parent 795fd8b58c
commit 6c5d208893
33 changed files with 22301 additions and 98 deletions

View File

@ -0,0 +1 @@
*.bundle.js

View File

@ -0,0 +1,121 @@
(function() {
if (window.jopext_hasRun) return;
window.jopext_hasRun = true;
console.info('jopext: Loading content script');
function pageTitle() {
const titleElements = document.getElementsByTagName("title");
if (titleElements.length) return titleElements[0].text.trim();
return document.title.trim();
}
function baseUrl() {
let output = location.origin + location.pathname;
if (output[output.length - 1] !== '/') {
output = output.split('/');
output.pop();
output = output.join('/');
}
return output;
}
// Cleans up element by removing all its invisible children (which we don't want to render as Markdown)
function cleanUpElement(element) {
const childNodes = element.childNodes;
for (let i = 0; i < childNodes.length; i++) {
const node = childNodes[i];
const isVisible = node.nodeType === 1 ? window.getComputedStyle(node).display !== 'none' : true;
if (!isVisible) {
element.removeChild(node);
} else {
cleanUpElement(node);
}
}
}
function readabilityProcess() {
var uri = {
spec: location.href,
host: location.host,
prePath: location.protocol + "//" + location.host,
scheme: location.protocol.substr(0, location.protocol.indexOf(":")),
pathBase: location.protocol + "//" + location.host + location.pathname.substr(0, location.pathname.lastIndexOf("/") + 1)
};
// Readability directly change the passed document so clone it so as
// to preserve the original web page.
const documentClone = document.cloneNode(true);
const readability = new window.Readability(uri, documentClone);
const article = readability.parse();
if (!article) throw new Error('Could not parse HTML document with Readability');
return {
title: article.title,
body: article.content,
}
}
async function prepareCommandResponse(command) {
if (command.name === "simplifiedPageHtml") {
let article = null;
try {
article = readabilityProcess();
} catch (error) {
console.warn(error);
console.warn('Sending full page HTML instead');
const newCommand = Object.assign({}, command, { name: 'completePageHtml' });
const response = await prepareCommandResponse(newCommand);
response.warning = 'Could not retrieve simplified version of page - full page has been saved instead.';
return response;
}
return {
name: 'clippedContent',
html: article.body,
title: article.title,
baseUrl: baseUrl(),
url: location.origin + location.pathname,
};
} else if (command.name === "completePageHtml") {
const cleanDocument = document.body.cloneNode(true);
cleanUpElement(cleanDocument);
return {
name: 'clippedContent',
html: cleanDocument.innerHTML,
title: pageTitle(),
baseUrl: baseUrl(),
url: location.origin + location.pathname,
};
} else if (command.name === "pageTitle") {
return {
name: 'pageTitle',
text: pageTitle(),
};
} else {
throw new Error('Unknown command', command);
}
}
async function execCommand(command) {
const response = await prepareCommandResponse(command);
browser.runtime.sendMessage(response);
}
browser.runtime.onMessage.addListener((command) => {
console.info('jopext: Got command:', command);
execCommand(command);
});
})();

View File

@ -0,0 +1 @@
const Readability = require('readability-node').Readability;

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -0,0 +1,3 @@
//document.body.style.border = "5px solid red";
// const Readability = require('readability-node').Readability;

View File

@ -0,0 +1,39 @@
{
"manifest_version": 2,
"name": "Joplin Web Clipper",
"version": "1.0",
"description": "Gets and saves content from your browser to Joplin.",
"homepage_url": "https://joplin.cozic.net",
"icons": {
"48": "icons/48.png",
"96": "icons/96.png"
},
"permissions": [
"activeTab"
],
"browser_action": {
"default_icon": "icons/32.png",
"default_title": "Joplin Web Clipper",
"default_popup": "popup/build/index.html"
},
"content_scripts": [
{
"matches": ["*://*/"],
"js": ["main.js"]
}
],
"applications": {
"gecko": {
"id": "{8419486a-54e9-11e8-9401-ac9e17909436}"
}
}
}

View File

@ -0,0 +1,13 @@
{
"name": "joplin-webclipper",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"readability-node": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/readability-node/-/readability-node-0.1.0.tgz",
"integrity": "sha1-DUBacMLCFZRKf0qbX3UGzQWpsao="
}
}
}

View File

@ -0,0 +1,14 @@
{
"name": "joplin-webclipper",
"version": "1.0.0",
"description": "",
"main": "main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "MIT",
"dependencies": {
"readability-node": "^0.1.0"
}
}

View File

@ -0,0 +1,21 @@
# See https://help.github.com/ignore-files/ for more about ignoring files.
# dependencies
node_modules
# testing
coverage
# production
build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="style.css"/>
</head>
<body>
<div id="popup-content">
<div class="button" data-action="getCompletePageHtml">Complete HTMLxx</div>
<div class="button beast">Turtle</div>
<div class="button beast">Snake</div>
<div class="button reset">Reset</div>
</div>
<div id="error-content" class="hidden">
<p>Can't beastify this web page.</p><p>Try a different page.</p>
</div>
<script src="index.js"></script>
</body>
</html>

View File

@ -0,0 +1,145 @@
/**
* CSS to hide everything on the page,
* except for elements that have the "beastify-image" class.
*/
const hidePage = `body > :not(.beastify-image) {
display: none;
}`;
/**
* Listen for clicks on the buttons, and send the appropriate message to
* the content script in the page.
*/
function listenForClicks() {
document.addEventListener('click', async (event) => {
const tabs = await browser.tabs.query({active: true, currentWindow: true});
const html = await browser.tabs.sendMessage(tabs[0].id, {
command: "getCompletePageHtml",
});
console.info('RRRRRRRRR', html);
});
// console.info('Listin');
// document.addEventListener("click", (event) => {
// /**
// * Insert the page-hiding CSS into the active tab,
// * then get the beast URL and
// * send a "beastify" message to the content script in the active tab.
// */
// // function beastify(tabs) {
// // browser.tabs.insertCSS({code: hidePage}).then(() => {
// // let url = beastNameToURL(e.target.textContent);
// // browser.tabs.sendMessage(tabs[0].id, {
// // command: "beastify",
// // beastURL: url
// // });
// // });
// // }
// // *
// // * Remove the page-hiding CSS from the active tab,
// // * send a "reset" message to the content script in the active tab.
// // function reset(tabs) {
// // browser.tabs.removeCSS({code: hidePage}).then(() => {
// // browser.tabs.sendMessage(tabs[0].id, {
// // command: "reset",
// // });
// // });
// // }
// /**
// * Just log the error to the console.
// */
// function reportError(error) {
// console.error(`Could not beastify: ${error}`);
// }
// // const action = event.currentTarget.getAttribute('data-action');
// console.info(event.currentTarget);
// /**
// * Get the active tab,
// * then call "beastify()" or "reset()" as appropriate.
// */
// // if (e.target.classList.contains("beast")) {
// // browser.tabs.query({active: true, currentWindow: true})
// // .then(beastify)
// // .catch(reportError);
// // }
// // else if (e.target.classList.contains("reset")) {
// // browser.tabs.query({active: true, currentWindow: true})
// // .then(reset)
// // .catch(reportError);
// // }
// });
}
/**
* There was an error executing the script.
* Display the popup's error message, and hide the normal UI.
*/
function reportExecuteScriptError(error) {
document.querySelector("#popup-content").classList.add("hidden");
document.querySelector("#error-content").classList.remove("hidden");
console.error(`Failed to execute beastify content script: ${error.message}`);
}
browser.runtime.onMessage.addListener(notify);
function notify(message) {
if (message.command === 'setCompletePageHtml') {
console.info('UUUUUUUUUUUUU', message.baseUrl);
fetch("http://127.0.0.1:9967/notes", {
method: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
//make sure to serialize your JSON body
body: JSON.stringify({
title: message.title,
baseUrl: message.baseUrl,
bodyHtml: message.html,
url: message.url,
})
})
.then( async (response) => {
console.info('GOT RESPNSE', response);
const json = await response.json();
console.info(json);
//do something awesome that makes the world a better place
});
// console.info('aaaaaaaaaa', message.html);
}
//console.info('Popup: got message', message);
// browser.notifications.create({
// "type": "basic",
// "iconUrl": browser.extension.getURL("link.png"),
// "title": "You clicked a link!",
// "message": message.url
// });
}
/**
* When the popup loads, inject a content script into the active tab,
* and add a click handler.
* If we couldn't inject the script, handle the error.
*/
browser.tabs.executeScript({file: "/content_scripts/vendor.bundle.js"})
.then(() => {
return browser.tabs.executeScript({file: "/content_scripts/index.js"})
})
.then(listenForClicks)
.catch(reportExecuteScriptError);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,23 @@
{
"name": "joplin-webclipper-popup",
"version": "0.1.0",
"private": true,
"homepage": ".",
"dependencies": {
"react": "^16.3.2",
"react-dom": "^16.3.2",
"react-redux": "^5.0.7",
"react-scripts": "1.1.4",
"redux": "^4.0.0"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject",
"watch": "cra-build-watch"
},
"devDependencies": {
"cra-build-watch": "^1.0.1"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -0,0 +1,40 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<!--
manifest.json provides metadata used when your web app is added to the
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>

View File

@ -0,0 +1,15 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
}
],
"start_url": "./index.html",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

View File

@ -0,0 +1,30 @@
.App {
text-align: center;
width: 400px;
height: 400px;
}
.App-logo {
animation: App-logo-spin infinite 20s linear;
height: 80px;
}
.App-header {
background-color: #222;
height: 150px;
padding: 20px;
color: white;
}
.App-title {
font-size: 1.5em;
}
.App-intro {
font-size: large;
}
@keyframes App-logo-spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}

View File

@ -0,0 +1,74 @@
import React, { Component } from 'react';
import './App.css';
const { connect } = require('react-redux');
const Global = require('./Global');
const { bridge } = require('./bridge');
class AppComponent extends Component {
constructor() {
super();
this.state = ({
contentScriptLoaded: false,
});
}
async clipSimplified_click() {
bridge().sendCommandToActiveTab({
name: 'simplifiedPageHtml',
});
}
clipComplete_click() {
bridge().sendCommandToActiveTab({
name: 'completePageHtml',
});
}
async loadContentScripts() {
await Global.browser().tabs.executeScript({file: "/content_scripts/vendor.bundle.js"});
await Global.browser().tabs.executeScript({file: "/content_scripts/index.js"});
}
async componentDidMount() {
await this.loadContentScripts();
this.setState({
contentScriptLoaded: true,
});
bridge().sendCommandToActiveTab({
name: 'pageTitle',
});
}
render() {
if (!this.state.contentScriptLoaded) return 'Loading...';
const warningComponent = !this.props.warning ? null : <div>{ this.props.warning }</div>
return (
<div className="App">
<p>Title: { this.props.pageTitle }</p>
<ul>
<li><button onClick={this.clipSimplified_click}>Clip simplified page</button></li>
<li><button onClick={this.clipComplete_click}>Clip complete page</button></li>
</ul>
{ warningComponent }
</div>
);
}
}
const mapStateToProps = (state) => {
return {
warning: state.warning,
pageTitle: state.pageTitle,
};
};
const App = connect(mapStateToProps)(AppComponent);
export default App;

View File

@ -0,0 +1,7 @@
const Global = {}
Global.browser = function() {
return window.browser;
}
module.exports = Global;

View File

@ -0,0 +1,81 @@
class Bridge {
init(browser, dispatch) {
console.info('Popup: Init bridge');
this.browser_ = browser;
this.dispatch_ = dispatch;
this.browser_notify = async (command) => {
console.info('Popup: Got command: ' + command.name);
if (command.warning) {
console.warn('Popup: Got warning: ' + command.warning);
this.dispatch({ type: 'WARNING_SET', text: command.warning });
} else {
this.dispatch({ type: 'WARNING_SET', text: '' });
}
if (command.name === 'clippedContent') {
console.info('Popup: Sending to Joplin...');
try {
const response = await fetch("http://127.0.0.1:9967/notes", {
method: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
//make sure to serialize your JSON body
body: JSON.stringify({
title: command.title,
baseUrl: command.baseUrl,
bodyHtml: command.html,
url: command.url,
})
})
console.info('GOT RESPNSE', response);
const json = await response.json();
console.info(json);
} catch (error) {
console.error('Popup: Cannot send to Joplin', error)
}
} else if (command.name === 'pageTitle') {
this.dispatch({ type: 'PAGE_TITLE_SET', text: command.text });
}
}
this.browser_.runtime.onMessage.addListener(this.browser_notify);
}
browser() {
return this.browser_;
}
dispatch(action) {
return this.dispatch_(action);
}
async sendCommandToActiveTab(command) {
const tabs = await this.browser().tabs.query({ active: true, currentWindow: true });
if (!tabs.length) {
console.warn('No valid tab');
return;
}
await this.browser().tabs.sendMessage(tabs[0].id, command);
}
}
const bridge_ = new Bridge();
const bridge = function() {
return bridge_;
}
export { bridge }

View File

@ -0,0 +1,5 @@
body {
margin: 0;
padding: 0;
font-family: sans-serif;
}

View File

@ -0,0 +1,39 @@
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
const { connect, Provider } = require('react-redux');
const { bridge } = require('./bridge');
const { createStore } = require('redux');
const defaultState = {
warning: '',
pageTitle: '',
};
function reducer(state = defaultState, action) {
let newState = state;
if (action.type === 'WARNING_SET') {
newState = Object.assign({}, state);
newState.warning = action.text;
} else if (action.type === 'PAGE_TITLE_SET') {
newState = Object.assign({}, state);
newState.pageTitle = action.text;
}
return newState;
}
const store = createStore(reducer);
bridge().init(window.browser, store.dispatch);
console.info('Popup: Creating React app...');
ReactDOM.render(<Provider store={store}><App /></Provider>, document.getElementById('root'));

View File

@ -0,0 +1,31 @@
html, body {
width: 100px;
}
.hidden {
display: none;
}
.button {
margin: 3% auto;
padding: 4px;
text-align: center;
font-size: 1.5em;
cursor: pointer;
}
.beast:hover {
background-color: #CFF2F2;
}
.beast {
background-color: #E5F2F2;
}
.reset {
background-color: #FBFBC9;
}
.reset:hover {
background-color: #EAEA9D;
}

File diff suppressed because it is too large Load Diff

View File

@ -48,6 +48,24 @@
"integrity": "sha512-jjpyQsKGsOF/wUElNjfPULk+d8PKvJOIXk3IUeBYYmNCy5dMWfrI+JiixYNw8ppKOlcRwWTXFl0B+i5oGrf95Q==",
"dev": true
},
"abab": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/abab/-/abab-1.0.4.tgz",
"integrity": "sha1-X6rZwsB/YN12dw9xzwJbYqY8/U4="
},
"acorn": {
"version": "4.0.13",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz",
"integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c="
},
"acorn-globals": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-3.1.0.tgz",
"integrity": "sha1-/YJw9x+7SZawBPqIDuXUZXOnMb8=",
"requires": {
"acorn": "^4.0.4"
}
},
"ajv": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.2.0.tgz",
@ -199,6 +217,11 @@
"dev": true,
"optional": true
},
"array-equal": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz",
"integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM="
},
"array-find-index": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
@ -220,14 +243,18 @@
"asn1": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz",
"integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=",
"dev": true
"integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y="
},
"assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
"dev": true
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
},
"async": {
"version": "0.9.2",
"resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz",
"integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=",
"optional": true
},
"async-each": {
"version": "1.0.1",
@ -255,14 +282,12 @@
"aws-sign2": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=",
"dev": true
"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
},
"aws4": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz",
"integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=",
"dev": true
"integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4="
},
"babel-cli": {
"version": "6.26.0",
@ -591,7 +616,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz",
"integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=",
"dev": true,
"optional": true,
"requires": {
"tweetnacl": "^0.14.3"
@ -623,7 +647,6 @@
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz",
"integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=",
"dev": true,
"requires": {
"hoek": "4.x.x"
}
@ -910,8 +933,7 @@
"caseless": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
"dev": true
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
},
"chalk": {
"version": "1.1.3",
@ -1019,8 +1041,7 @@
"co": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
"integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
"dev": true
"integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
},
"code-point-at": {
"version": "1.1.0",
@ -1098,6 +1119,11 @@
"xdg-basedir": "^3.0.0"
}
},
"content-type-parser": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/content-type-parser/-/content-type-parser-1.0.2.tgz",
"integrity": "sha512-lM4l4CnMEwOLHAHr/P6MEZwZFPJFtAAKgL6pogbXmVZggIqXhdB6RbBtPOTsw2FcXwYhehRGERJmRrjOiIB8pQ=="
},
"convert-source-map": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.0.tgz",
@ -1153,7 +1179,6 @@
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz",
"integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=",
"dev": true,
"requires": {
"boom": "5.x.x"
},
@ -1162,7 +1187,6 @@
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz",
"integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==",
"dev": true,
"requires": {
"hoek": "4.x.x"
}
@ -1175,6 +1199,25 @@
"integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=",
"dev": true
},
"cssom": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.2.tgz",
"integrity": "sha1-uANhcMefB6kP8vFuIihAJ6JDhIs="
},
"cssstyle": {
"version": "0.2.37",
"resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-0.2.37.tgz",
"integrity": "sha1-VBCXI0yyUTyDzu06zdwn/yeYfVQ=",
"requires": {
"cssom": "0.3.x"
}
},
"ctype": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz",
"integrity": "sha1-gsGMJGH3QRTvFsE1IkrQuRRMoS8=",
"optional": true
},
"currently-unhandled": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
@ -1480,7 +1523,6 @@
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
"integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
"dev": true,
"requires": {
"assert-plus": "^1.0.0"
}
@ -1745,7 +1787,6 @@
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz",
"integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=",
"dev": true,
"optional": true,
"requires": {
"jsbn": "~0.1.0"
@ -2210,17 +2251,46 @@
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"dev": true
},
"escodegen": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.9.1.tgz",
"integrity": "sha512-6hTjO1NAWkHnDk3OqQ4YrCuwwmGHL9S3nPlzBOUG/R44rda3wLNrfvQ5fkSGjyhHFKM7ALPKcKGrwvCLe0lC7Q==",
"requires": {
"esprima": "^3.1.3",
"estraverse": "^4.2.0",
"esutils": "^2.0.2",
"optionator": "^0.8.1",
"source-map": "~0.6.1"
},
"dependencies": {
"esprima": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz",
"integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM="
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"optional": true
}
}
},
"esprima": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz",
"integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==",
"dev": true
},
"estraverse": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz",
"integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM="
},
"esutils": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
"integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
"dev": true
"integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs="
},
"execa": {
"version": "0.7.0",
@ -2277,8 +2347,7 @@
"extend": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz",
"integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=",
"dev": true
"integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ="
},
"extglob": {
"version": "0.3.2",
@ -2316,20 +2385,22 @@
"extsprintf": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
"dev": true
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
},
"fast-deep-equal": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz",
"integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=",
"dev": true
"integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8="
},
"fast-json-stable-stringify": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
"integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=",
"dev": true
"integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I="
},
"fast-levenshtein": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc="
},
"fbjs": {
"version": "0.8.16",
@ -2434,8 +2505,7 @@
"forever-agent": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
"integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
"dev": true
"integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
},
"form-data": {
"version": "2.3.1",
@ -2584,7 +2654,7 @@
"bundled": true,
"dev": true,
"requires": {
"inherits": "2.0.3"
"inherits": "~2.0.0"
}
},
"boom": {
@ -2592,7 +2662,7 @@
"bundled": true,
"dev": true,
"requires": {
"hoek": "2.16.3"
"hoek": "2.x.x"
}
},
"brace-expansion": {
@ -2600,14 +2670,15 @@
"bundled": true,
"dev": true,
"requires": {
"balanced-match": "0.4.2",
"balanced-match": "^0.4.1",
"concat-map": "0.0.1"
}
},
"buffer-shims": {
"version": "1.0.0",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"caseless": {
"version": "0.12.0",
@ -2624,14 +2695,16 @@
"code-point-at": {
"version": "1.1.0",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"combined-stream": {
"version": "1.0.5",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"delayed-stream": "1.0.0"
"delayed-stream": "~1.0.0"
}
},
"concat-map": {
@ -2642,19 +2715,21 @@
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"core-util-is": {
"version": "1.0.2",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"cryptiles": {
"version": "2.0.5",
"bundled": true,
"dev": true,
"requires": {
"boom": "2.10.1"
"boom": "2.x.x"
}
},
"dashdash": {
@ -2663,7 +2738,7 @@
"dev": true,
"optional": true,
"requires": {
"assert-plus": "1.0.0"
"assert-plus": "^1.0.0"
},
"dependencies": {
"assert-plus": {
@ -2692,7 +2767,8 @@
"delayed-stream": {
"version": "1.0.0",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"delegates": {
"version": "1.0.0",
@ -2712,7 +2788,7 @@
"dev": true,
"optional": true,
"requires": {
"jsbn": "0.1.1"
"jsbn": "~0.1.0"
}
},
"extend": {
@ -2724,7 +2800,8 @@
"extsprintf": {
"version": "1.0.2",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"forever-agent": {
"version": "0.6.1",
@ -2792,7 +2869,7 @@
"dev": true,
"optional": true,
"requires": {
"assert-plus": "1.0.0"
"assert-plus": "^1.0.0"
},
"dependencies": {
"assert-plus": {
@ -2907,7 +2984,8 @@
"isarray": {
"version": "1.0.0",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"isstream": {
"version": "0.1.2",
@ -2921,7 +2999,7 @@
"dev": true,
"optional": true,
"requires": {
"jsbn": "0.1.1"
"jsbn": "~0.1.0"
}
},
"jsbn": {
@ -3418,7 +3496,6 @@
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
"integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
"dev": true,
"requires": {
"assert-plus": "^1.0.0"
}
@ -3527,14 +3604,12 @@
"har-schema": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
"integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=",
"dev": true
"integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
},
"har-validator": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz",
"integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=",
"dev": true,
"requires": {
"ajv": "^5.1.0",
"har-schema": "^2.0.0"
@ -3544,7 +3619,6 @@
"version": "5.5.2",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
"integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
"dev": true,
"requires": {
"co": "^4.6.0",
"fast-deep-equal": "^1.0.0",
@ -3573,7 +3647,6 @@
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz",
"integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==",
"dev": true,
"requires": {
"boom": "4.x.x",
"cryptiles": "3.x.x",
@ -3594,8 +3667,7 @@
"hoek": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.0.tgz",
"integrity": "sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ==",
"dev": true
"integrity": "sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ=="
},
"hoist-non-react-statics": {
"version": "2.3.1",
@ -3624,6 +3696,14 @@
"integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==",
"dev": true
},
"html-encoding-sniffer": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz",
"integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==",
"requires": {
"whatwg-encoding": "^1.0.1"
}
},
"html-entities": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz",
@ -3633,7 +3713,6 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
"integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
"dev": true,
"requires": {
"assert-plus": "^1.0.0",
"jsprim": "^1.2.2",
@ -3871,8 +3950,7 @@
"is-typedarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
"dev": true
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
},
"is-utf8": {
"version": "0.2.1",
@ -3926,8 +4004,7 @@
"isstream": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
"dev": true
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
},
"js-tokens": {
"version": "3.0.2",
@ -3948,9 +4025,34 @@
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
"dev": true,
"optional": true
},
"jsdom": {
"version": "9.12.0",
"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-9.12.0.tgz",
"integrity": "sha1-6MVG//ywbADUgzyoRBD+1/igl9Q=",
"requires": {
"abab": "^1.0.3",
"acorn": "^4.0.4",
"acorn-globals": "^3.1.0",
"array-equal": "^1.0.0",
"content-type-parser": "^1.0.1",
"cssom": ">= 0.3.2 < 0.4.0",
"cssstyle": ">= 0.2.37 < 0.3.0",
"escodegen": "^1.6.1",
"html-encoding-sniffer": "^1.0.1",
"nwmatcher": ">= 1.3.9 < 2.0.0",
"parse5": "^1.5.1",
"request": "^2.79.0",
"sax": "^1.2.1",
"symbol-tree": "^3.2.1",
"tough-cookie": "^2.3.2",
"webidl-conversions": "^4.0.0",
"whatwg-encoding": "^1.0.1",
"whatwg-url": "^4.3.0",
"xml-name-validator": "^2.0.1"
}
},
"jsesc": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz",
@ -3960,20 +4062,17 @@
"json-schema": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
"dev": true
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
},
"json-schema-traverse": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
"integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=",
"dev": true
"integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A="
},
"json-stringify-safe": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
"dev": true
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
},
"json5": {
"version": "0.5.1",
@ -3993,7 +4092,6 @@
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
"integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
"dev": true,
"requires": {
"assert-plus": "1.0.0",
"extsprintf": "1.3.0",
@ -4061,6 +4159,15 @@
"resolved": "https://registry.npmjs.org/levenshtein/-/levenshtein-1.0.5.tgz",
"integrity": "sha1-ORFzepy1baNF0Aj1V4LG8TiXm6M="
},
"levn": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
"integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
"requires": {
"prelude-ls": "~1.1.2",
"type-check": "~0.3.2"
}
},
"linkify-it": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.0.3.tgz",
@ -4425,6 +4532,180 @@
"which": "^1.2.12"
}
},
"node-readability": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/node-readability/-/node-readability-3.0.0.tgz",
"integrity": "sha512-PzvPq/AVWJB6gO3jzeL2X3unreALzIVQFnkdjrNjSFUdoUhnKn7EsZ+kkDlb2wV2Amwjx+a78mFWZwKQfrOreg==",
"requires": {
"encoding": "~0.1.7",
"jsdom": "^9.12.0",
"minimist": "^1.2.0",
"request": "~2.40.0"
},
"dependencies": {
"asn1": {
"version": "0.1.11",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz",
"integrity": "sha1-VZvhg3bQik7E2+gId9J4GGObLfc=",
"optional": true
},
"assert-plus": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz",
"integrity": "sha1-7nQAlBMALYTOxyGcasgRgS5yMWA=",
"optional": true
},
"aws-sign2": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz",
"integrity": "sha1-xXED96F/wDfwLXwuZLYC6iI/fWM=",
"optional": true
},
"boom": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/boom/-/boom-0.4.2.tgz",
"integrity": "sha1-emNune1O/O+xnO9JR6PGffrukRs=",
"requires": {
"hoek": "0.9.x"
}
},
"combined-stream": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz",
"integrity": "sha1-ATfmV7qlp1QcV6w3rF/AfXO03B8=",
"optional": true,
"requires": {
"delayed-stream": "0.0.5"
}
},
"cryptiles": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-0.2.2.tgz",
"integrity": "sha1-7ZH/HxetE9N0gohZT4pIoNJvMlw=",
"optional": true,
"requires": {
"boom": "0.4.x"
}
},
"delayed-stream": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz",
"integrity": "sha1-1LH0OpPoKW3+AmlPRoC8N6MTxz8=",
"optional": true
},
"forever-agent": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz",
"integrity": "sha1-bQ4JxJIflKJ/Y9O0nF/v8epMUTA="
},
"form-data": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-0.1.4.tgz",
"integrity": "sha1-kavXiKupcCsaq/qLwBAxoqyeOxI=",
"optional": true,
"requires": {
"async": "~0.9.0",
"combined-stream": "~0.0.4",
"mime": "~1.2.11"
}
},
"hawk": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/hawk/-/hawk-1.1.1.tgz",
"integrity": "sha1-h81JH5tG5OKurKM1QWdmiF0tHtk=",
"optional": true,
"requires": {
"boom": "0.4.x",
"cryptiles": "0.2.x",
"hoek": "0.9.x",
"sntp": "0.2.x"
}
},
"hoek": {
"version": "0.9.1",
"resolved": "https://registry.npmjs.org/hoek/-/hoek-0.9.1.tgz",
"integrity": "sha1-PTIkYrrfB3Fup+uFuviAec3c5QU="
},
"http-signature": {
"version": "0.10.1",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.10.1.tgz",
"integrity": "sha1-T72sEyVZqoMjEh5UB3nAoBKyfmY=",
"optional": true,
"requires": {
"asn1": "0.1.11",
"assert-plus": "^0.1.5",
"ctype": "0.5.3"
}
},
"mime": {
"version": "1.2.11",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz",
"integrity": "sha1-WCA+7Ybjpe8XrtK32evUfwpg3RA=",
"optional": true
},
"mime-types": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-1.0.2.tgz",
"integrity": "sha1-mVrhOSq4r/y/yyZB3QVOlDwNXc4="
},
"minimist": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
},
"node-uuid": {
"version": "1.4.8",
"resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz",
"integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc="
},
"oauth-sign": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.3.0.tgz",
"integrity": "sha1-y1QPk7srIqfVlBaRoojWDo6pOG4=",
"optional": true
},
"qs": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-1.0.2.tgz",
"integrity": "sha1-UKk+K1r2aRwxvOpdrnjubqGQN2g="
},
"request": {
"version": "2.40.0",
"resolved": "https://registry.npmjs.org/request/-/request-2.40.0.tgz",
"integrity": "sha1-TdZw9pbx5uhC5mtLXoOTAaub62c=",
"requires": {
"aws-sign2": "~0.5.0",
"forever-agent": "~0.5.0",
"form-data": "~0.1.0",
"hawk": "1.1.1",
"http-signature": "~0.10.0",
"json-stringify-safe": "~5.0.0",
"mime-types": "~1.0.1",
"node-uuid": "~1.4.0",
"oauth-sign": "~0.3.0",
"qs": "~1.0.0",
"stringstream": "~0.0.4",
"tough-cookie": ">=0.12.0",
"tunnel-agent": "~0.4.0"
}
},
"sntp": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/sntp/-/sntp-0.2.4.tgz",
"integrity": "sha1-+4hfGLDzqtGJ+CSGJTa87ux1CQA=",
"optional": true,
"requires": {
"hoek": "0.9.x"
}
},
"tunnel-agent": {
"version": "0.4.3",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz",
"integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=",
"optional": true
}
}
},
"normalize-package-data": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
@ -4484,11 +4765,15 @@
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
"dev": true
},
"nwmatcher": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/nwmatcher/-/nwmatcher-1.4.4.tgz",
"integrity": "sha512-3iuY4N5dhgMpCUrOVnuAdGrgxVqV2cJpM+XNccjR2DKOB1RUP0aA+wGXEiNziG/UKboFyGBIoKOaNlJxx8bciQ=="
},
"oauth-sign": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz",
"integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=",
"dev": true
"integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM="
},
"object-assign": {
"version": "4.1.1",
@ -4521,6 +4806,26 @@
"wrappy": "1"
}
},
"optionator": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz",
"integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=",
"requires": {
"deep-is": "~0.1.3",
"fast-levenshtein": "~2.0.4",
"levn": "~0.3.0",
"prelude-ls": "~1.1.2",
"type-check": "~0.3.2",
"wordwrap": "~1.0.0"
},
"dependencies": {
"deep-is": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
"integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ="
}
}
},
"os-homedir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
@ -4636,6 +4941,11 @@
"error-ex": "^1.2.0"
}
},
"parse5": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-1.5.1.tgz",
"integrity": "sha1-m387DeMr543CQBsXVzzK8Pb1nZQ="
},
"path-exists": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
@ -4687,8 +4997,7 @@
"performance-now": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
"dev": true
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
},
"pify": {
"version": "3.0.0",
@ -4736,6 +5045,11 @@
}
}
},
"prelude-ls": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
"integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ="
},
"prepend-http": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz",
@ -4807,8 +5121,7 @@
"punycode": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
"dev": true
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
},
"pupa": {
"version": "1.0.0",
@ -4823,8 +5136,7 @@
"qs": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz",
"integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==",
"dev": true
"integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A=="
},
"query-string": {
"version": "5.0.1",
@ -5013,6 +5325,11 @@
"read-pkg": "^1.0.0"
}
},
"readability-node": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/readability-node/-/readability-node-0.1.0.tgz",
"integrity": "sha1-DUBacMLCFZRKf0qbX3UGzQWpsao="
},
"readable-stream": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz",
@ -5128,7 +5445,6 @@
"version": "2.83.0",
"resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz",
"integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==",
"dev": true,
"requires": {
"aws-sign2": "~0.7.0",
"aws4": "^1.6.0",
@ -5302,7 +5618,6 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz",
"integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==",
"dev": true,
"requires": {
"hoek": "4.x.x"
}
@ -6086,7 +6401,6 @@
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz",
"integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=",
"dev": true,
"requires": {
"asn1": "~0.2.3",
"assert-plus": "^1.0.0",
@ -6145,8 +6459,7 @@
"stringstream": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",
"integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=",
"dev": true
"integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg="
},
"strip-ansi": {
"version": "3.0.1",
@ -6208,6 +6521,11 @@
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.4.tgz",
"integrity": "sha1-Kb9hXUqnEhvdiYsi1LP5vE4qoD0="
},
"symbol-tree": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz",
"integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY="
},
"tar": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/tar/-/tar-4.4.0.tgz",
@ -6317,11 +6635,15 @@
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz",
"integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=",
"dev": true,
"requires": {
"punycode": "^1.4.1"
}
},
"tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
},
"trim-newlines": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz",
@ -6347,7 +6669,6 @@
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
"integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
"dev": true,
"requires": {
"safe-buffer": "^5.0.1"
}
@ -6356,9 +6677,16 @@
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
"dev": true,
"optional": true
},
"type-check": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
"integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
"requires": {
"prelude-ls": "~1.1.2"
}
},
"typedarray": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
@ -6515,7 +6843,6 @@
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
"integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
"dev": true,
"requires": {
"assert-plus": "^1.0.0",
"core-util-is": "1.0.2",
@ -6527,11 +6854,40 @@
"resolved": "https://registry.npmjs.org/w3c-blob/-/w3c-blob-0.0.1.tgz",
"integrity": "sha1-sM01KhpQ9RVWNCD/1YYflQ8dhbg="
},
"webidl-conversions": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
"integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg=="
},
"whatwg-encoding": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.3.tgz",
"integrity": "sha512-jLBwwKUhi8WtBfsMQlL4bUUcT8sMkAtQinscJAe/M4KHCkHuUJAF6vuB0tueNIw4c8ziO6AkRmgY+jL3a0iiPw==",
"requires": {
"iconv-lite": "0.4.19"
}
},
"whatwg-fetch": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz",
"integrity": "sha1-nITsLc9oGH/wC8ZOEnS0QhduHIQ="
},
"whatwg-url": {
"version": "4.8.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-4.8.0.tgz",
"integrity": "sha1-0pgaqRSMHgCkHFphMRZqtGg7vMA=",
"requires": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
},
"dependencies": {
"webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
}
}
},
"which": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz",
@ -6588,6 +6944,11 @@
}
}
},
"wordwrap": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
"integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus="
},
"wrap-ansi": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
@ -6621,6 +6982,11 @@
"integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=",
"dev": true
},
"xml-name-validator": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-2.0.1.tgz",
"integrity": "sha1-TYuPHszTQZqjYgYb7O9RXh5VljU="
},
"xml2js": {
"version": "0.4.19",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz",

View File

@ -107,6 +107,7 @@
"react-datetime": "^2.11.0",
"react-dom": "^16.0.0",
"react-redux": "^5.0.6",
"readability-node": "^0.1.0",
"redux": "^3.7.2",
"smalltalk": "^2.5.1",
"sprintf-js": "^1.1.1",

View File

@ -34,6 +34,7 @@ const SyncTargetDropbox = require('lib/SyncTargetDropbox.js');
const EncryptionService = require('lib/services/EncryptionService');
const DecryptionWorker = require('lib/services/DecryptionWorker');
const BaseService = require('lib/services/BaseService');
const ClipperServer = require('lib/ClipperServer');
SyncTargetRegistry.addClass(SyncTargetFilesystem);
SyncTargetRegistry.addClass(SyncTargetOneDrive);
@ -466,6 +467,9 @@ class BaseApplication {
if (!currentFolder) currentFolder = await Folder.defaultFolder();
Setting.setValue('activeFolderId', currentFolder ? currentFolder.id : '');
this.clipperServer_ = new ClipperServer();
this.clipperServer_.start();
return argv;
}

View File

@ -0,0 +1,178 @@
const { netUtils } = require('lib/net-utils');
const urlParser = require("url");
const Note = require('lib/models/Note');
const Folder = require('lib/models/Folder');
const HtmlToMd = require('lib/HtmlToMd');
class ClipperServer {
htmlToMdParser() {
if (this.htmlToMdParser_) return this.htmlToMdParser_;
this.htmlToMdParser_ = new HtmlToMd();
return this.htmlToMdParser_;
}
readabilityProcess(url) {
return new Promise((resolve, reject) => {
// const Readability = require('readability-node').Readability;
// var location = document.location;
// var uri = {
// spec: location.href,
// host: location.host,
// prePath: location.protocol + "//" + location.host,
// scheme: location.protocol.substr(0, location.protocol.indexOf(":")),
// pathBase: location.protocol + "//" + location.host + location.pathname.substr(0, location.pathname.lastIndexOf("/") + 1)
// };
// var article = new Readability(uri, document).parse();
// const read = require('node-readability');
// read(url, function(error, article, meta) {
// if (error) {
// reject(error);
// return;
// }
// const output = {
// body: article.content,
// title: article.title,
// }
// article.close();
// resolve(output);
// });
// // Main Article
// console.log(article.content);
// // Title
// console.log(article.title);
// // HTML Source Code
// console.log(article.html);
// // DOM
// console.log(article.document);
// // Response Object from Request Lib
// console.log(meta);
// // Close article to clean up jsdom and prevent leaks
// article.close();
});
}
async requestNoteToNote(requestNote) {
// if (requestNote.url) {
// console.info('Clipper: Got URL: ' + requestNote.url);
// const result = await this.readabilityProcess(requestNote.url);
// return {
// title: result.title,
// body: result.body,
// }
// } else {
const output = {
title: requestNote.title ? requestNote.title : '',
body: requestNote.body ? requestNote.body : '',
};
if (requestNote.bodyHtml) {
console.info(requestNote.bodyHtml);
// Parsing will not work if the HTML is not wrapped in a top level tag, which is not guaranteed
// when getting the content from elsewhere. So here wrap it - it won't change anything to the final
// rendering but it makes sure everything will be parsed.
output.body = await this.htmlToMdParser().parse('<div>' + requestNote.bodyHtml + '</div>', {
baseUrl: requestNote.baseUrl ? requestNote.baseUrl : '',
});
}
if (requestNote.parent_id) {
output.parent_id = requestNote.parent_id;
} else {
const folder = await Folder.defaultFolder();
if (!folder) throw new Error('Cannot find folder for note');
output.parent_id = folder.id;
}
return output;
// }
}
async start() {
const port = await netUtils.findAvailablePort([9967, 8967, 8867], 0); // TODO: Make it shared with OneDrive server
if (!port) throw new Error('All potential ports are in use or not available.');
const server = require('http').createServer();
server.on('request', (request, response) => {
const writeCorsHeaders = (code) => {
response.writeHead(code, {
"Content-Type": "application/json",
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS, PUT, PATCH, DELETE',
'Access-Control-Allow-Headers': 'X-Requested-With,content-type',
});
}
const writeResponseJson = (code, object) => {
writeCorsHeaders(code);
// response.writeHead(code, {
// "Content-Type": "application/json",
// 'Access-Control-Allow-Origin': '*',
// 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS, PUT, PATCH, DELETE',
// 'Access-Control-Allow-Headers': 'X-Requested-With,content-type',
// });
response.write(JSON.stringify(object));
response.end();
}
console.info('GOT REQUEST', request.method + ' ' + request.url);
if (request.method === 'POST') {
const url = urlParser.parse(request.url, true);
if (url.pathname === '/notes') {
let body = '';
request.on('data', (data) => {
body += data;
});
request.on('end', async () => {
try {
// console.info('GOT BODY', body);
const requestNote = JSON.parse(body);
// console.info('GOT REQUEST',
let note = await this.requestNoteToNote(requestNote);
note = await Note.save(note);
return writeResponseJson(200, note);
} catch (error) {
console.warn(error);
return writeResponseJson(400, { errorCode: 'exception', errorMessage: error.message });
}
});
} else {
return writeResponseJson(404, { errorCode: 'not_found' });
}
} else if (request.method === 'OPTIONS') {
writeCorsHeaders(200);
response.end();
} else {
return writeResponseJson(405, { errorCode: 'method_not_allowed' });
}
});
server.on('close', () => {
});
console.info('Starting Clipper server on port ' + port);
server.listen(port);
}
}
module.exports = ClipperServer;

View File

@ -1,14 +0,0 @@
const { enexXmlToMd } = require('lib/import-enex-md-gen.js');
class HtmlToMarkdownParser {
async parse(html, options = {}) {
if (!options.baseUrl) options.baseUrl = '';
const markdown = await enexXmlToMd(html, [], options);
return markdown;
}
}
module.exports = HtmlToMarkdownParser;

View File

@ -0,0 +1,13 @@
const TurndownService = require('turndown')
class HtmlToMd {
parse(html) {
const turndownService = new TurndownService()
let markdown = turndownService.turndown(html)
return markdown;
}
}
module.exports = HtmlToMd;