1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-01-11 18:24:43 +02:00

Clipper: More consistent REST API

This commit is contained in:
Laurent Cozic 2018-06-01 15:50:11 +01:00
parent 3822309657
commit bdd9da3d22
6 changed files with 80 additions and 36 deletions

View File

@ -1,15 +1,25 @@
let browser_ = null;
let browserName_ = null;
if (typeof browser !== 'undefined') {
browser_ = browser;
browserSupportsPromises_ = true;
browserName_ = 'firefox';
} else if (typeof chrome !== 'undefined') {
browser_ = chrome;
browserSupportsPromises_ = false;
browserName_ = 'chrome';
}
function env() {
return 'prod';
return !('update_url' in browser_.runtime.getManifest()) ? 'dev' : 'prod';
let env_ = null;
// Make this function global so that it can be accessed
// from the popup too.
// https://stackoverflow.com/questions/6323184/communication-between-background-page-and-popup-page-in-a-chrome-extension
window.joplinEnv = function() {
if (env_) return env_;
env_ = !('update_url' in browser_.runtime.getManifest()) ? 'dev' : 'prod';
return env_;
}
async function browserCaptureVisibleTabs(windowId, options) {
@ -22,8 +32,19 @@ async function browserCaptureVisibleTabs(windowId, options) {
});
}
browser_.runtime.onInstalled.addListener(function() {
if (env() === 'dev') {
browser_.runtime.onInstalled.addListener(function(details) {
if (details && details.temporary) {
// In Firefox - https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/runtime/onInstalled
env_ = 'dev';
} else if (browserName_ === 'chrome') {
// In Chrome
env_ = !('update_url' in browser_.runtime.getManifest()) ? 'dev' : 'prod';
} else {
// If we don't know, be safe and default to prod
env_ = 'prod';
}
if (window.joplinEnv() === 'dev') {
browser_.browserAction.setIcon({
path: 'icons/32-dev.png',
});
@ -34,9 +55,9 @@ browser_.runtime.onMessage.addListener((command) => {
if (command.name === 'screenshotArea') {
browserCaptureVisibleTabs(null, { format: 'jpeg' }).then((imageDataUrl) => {
content = Object.assign({}, command.content);
content.imageDataUrl = imageDataUrl;
content.image_data_url = imageDataUrl;
fetch(command.apiBaseUrl + "/notes", {
fetch(command.api_base_url + "/notes", {
method: "POST",
headers: {
'Accept': 'application/json',

View File

@ -92,9 +92,9 @@
name: 'clippedContent',
html: article.body,
title: article.title,
baseUrl: baseUrl(),
base_url: baseUrl(),
url: location.origin + location.pathname,
parentId: command.parentId,
parent_id: command.parent_id,
};
} else if (command.name === "completePageHtml") {
@ -106,9 +106,9 @@
name: 'clippedContent',
html: cleanDocument.innerHTML,
title: pageTitle(),
baseUrl: baseUrl(),
base_url: baseUrl(),
url: location.origin + location.pathname,
parentId: command.parentId,
parent_id: command.parent_id,
};
} else if (command.name === 'screenshot') {
@ -207,15 +207,15 @@
setTimeout(() => {
const content = {
title: pageTitle(),
cropRect: selectionArea,
crop_rect: selectionArea,
url: location.origin + location.pathname,
parentId: command.parentId,
parent_id: command.parent_id,
};
browser_.runtime.sendMessage({
name: 'screenshotArea',
content: content,
apiBaseUrl: command.apiBaseUrl,
api_base_url: command.api_base_url,
});
}, 100);
}

View File

@ -30,14 +30,14 @@ class AppComponent extends Component {
this.clipSimplified_click = () => {
bridge().sendCommandToActiveTab({
name: 'simplifiedPageHtml',
parentId: this.props.selectedFolderId,
parent_id: this.props.selectedFolderId,
});
}
this.clipComplete_click = () => {
bridge().sendCommandToActiveTab({
name: 'completePageHtml',
parentId: this.props.selectedFolderId,
parent_id: this.props.selectedFolderId,
});
}
@ -47,8 +47,8 @@ class AppComponent extends Component {
await bridge().sendCommandToActiveTab({
name: 'screenshot',
apiBaseUrl: baseUrl,
parentId: this.props.selectedFolderId,
api_base_url: baseUrl,
parent_id: this.props.selectedFolderId,
});
window.close();
@ -118,7 +118,7 @@ class AppComponent extends Component {
<div className="Preview">
<input className={"Title"} value={content.title} onChange={this.contentTitle_change}/>
<div className={"BodyWrapper"}>
<div className={"Body"} dangerouslySetInnerHTML={{__html: content.bodyHtml}}></div>
<div className={"Body"} dangerouslySetInnerHTML={{__html: content.body_html}}></div>
</div>
<a className={"Confirm Button"} onClick={this.confirm_click}>Confirm</a>
</div>
@ -182,7 +182,7 @@ class AppComponent extends Component {
return (
<div className="Folders">
<label>In notebook: </label>
<select value={this.props.selectedFolderId} onChange={this.folderSelect_change}>
<select value={this.props.selectedFolderId || ''} onChange={this.folderSelect_change}>
{ optionComps }
</select>
</div>

View File

@ -12,7 +12,7 @@ class Bridge {
this.clipperServerPortStatus_ = 'searching';
this.browser_notify = async (command) => {
console.info('Popup: Got command: ' + command.name);
console.info('Popup: Got command:', command);
if (command.warning) {
console.warn('Popup: Got warning: ' + command.warning);
@ -24,10 +24,10 @@ class Bridge {
if (command.name === 'clippedContent') {
const content = {
title: command.title,
bodyHtml: command.html,
baseUrl: command.baseUrl,
url: command.url,
parentId: command.parentId,
body_html: command.html,
base_url: command.base_url,
source_url: command.url,
parent_id: command.parent_id,
};
this.dispatch({ type: 'CLIPPED_CONTENT_SET', content: content });
@ -36,14 +36,21 @@ class Bridge {
this.browser_.runtime.onMessage.addListener(this.browser_notify);
console.info('Popup: Env: ', this.env());
const backgroundPage = this.browser_.extension.getBackgroundPage();
this.env_ = backgroundPage.joplinEnv();
console.info('Popup: Env:', this.env());
this.dispatch({
type: 'ENV_SET',
env: this.env(),
});
this.findClipperServerPort();
}
env() {
return 'prod';
return !('update_url' in this.browser().runtime.getManifest()) ? 'dev' : 'prod';
return this.env_;
}
browser() {
@ -149,6 +156,12 @@ class Bridge {
return new Promise((resolve, reject) => {
this.browser().tabs.executeScript(options, () => {
const e = this.browser().runtime.lastError;
if (e) {
const msg = ['tabsExecuteScript: Cannot load ' + JSON.stringify(options)]
if (e.message) msg.push(e.message);
reject(new Error(msg.join(': ')));
}
resolve();
});
})

View File

@ -17,6 +17,7 @@ const defaultState = {
},
folders: [],
selectedFolderId: null,
env: 'prod',
};
const reduxMiddleware = store => next => async (action) => {
@ -60,6 +61,10 @@ function reducer(state = defaultState, action) {
newState = Object.assign({}, state);
newState.folders = action.folders;
if (!newState.selectedFolderId && action.folders.length) {
newState.selectedFolderId = action.folders[0].id;
}
} else if (action.type === 'SELECTED_FOLDER_SET') {
newState = Object.assign({}, state);
@ -73,6 +78,11 @@ function reducer(state = defaultState, action) {
if ('port' in action) clipperServer.port = action.port;
newState.clipperServer = clipperServer;
} else if (action.type === 'ENV_SET') {
newState = Object.assign({}, state);
newState.env = action.env;
}
return newState;

View File

@ -76,24 +76,24 @@ class ClipperServer {
body: requestNote.body ? requestNote.body : '',
};
if (requestNote.bodyHtml) {
if (requestNote.body_html) {
// 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 : '',
output.body = await this.htmlToMdParser().parse('<div>' + requestNote.body_html + '</div>', {
baseUrl: requestNote.base_url ? requestNote.base_url : '',
});
}
if (requestNote.parentId) {
output.parent_id = requestNote.parentId;
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;
}
if (requestNote.url) output.source_url = requestNote.url;
if (requestNote.source_url) output.source_url = requestNote.source_url;
return output;
}
@ -277,8 +277,8 @@ class ClipperServer {
note = await Note.save(note);
if (requestNote.imageDataUrl) {
await this.attachImageFromDataUrl_(note, requestNote.imageDataUrl, requestNote.cropRect);
if (requestNote.image_data_url) {
await this.attachImageFromDataUrl_(note, requestNote.image_data_url, requestNote.crop_rect);
}
this.logger().info('Request (' + requestId + '): Created note ' + note.id);