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

Clipper: Add ability to launch clipper window with shortcut (#2272)

* Clipper: Add ability to launch clipper window with shortcut

This change adds a command to the manifest.json file for the web clipper
which launches the webclipper rather than clicking on it.
Because this is a WebExtensions feature and not something homegrown,
 users are able to change (or remove) the shortcut using native browser functionality.

* Add commands for all clipping options

* Remove empty suggestedKeys property from extension manifest

* Add ability to focus the webclipper buttons

* Remove debug log

* Change sendClipMessage warning to error

* Refactor to add a sendContentToJoplin command

* Update index.js

Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
This commit is contained in:
Marcus Hill 2020-02-11 02:49:07 -08:00 committed by GitHub
parent d278809659
commit 4bd326f72c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 126 additions and 30 deletions

View File

@ -76,3 +76,59 @@ browser_.runtime.onMessage.addListener(async (command) => {
});
}
});
async function getActiveTabs() {
const options = { active: true, currentWindow: true };
if (browserSupportsPromises_) return browser_.tabs.query(options);
return new Promise((resolve) => {
browser_.tabs.query(options, (tabs) => {
resolve(tabs);
});
});
}
async function sendClipMessage(clipType) {
const tabs = await getActiveTabs();
if (!tabs || !tabs.length) {
console.error('No active tabs');
return;
}
const tabId = tabs[0].id;
// send a message to the content script on the active tab (assuming it's there)
const message = {
shouldSendToJoplin: true,
};
switch (clipType) {
case 'clipCompletePage':
message.name = 'completePageHtml';
message.preProcessFor = 'markdown';
break;
case 'clipCompletePageHtml':
message.name = 'completePageHtml';
message.preProcessFor = 'html';
break;
case 'clipSimplifiedPage':
message.name = 'simplifiedPageHtml';
break;
case 'clipUrl':
message.name = 'pageUrl';
break;
case 'clipSelection':
message.name = 'selectedHtml';
break;
default:
break;
}
if (message.name) {
browser_.tabs.sendMessage(tabId, message);
}
}
browser_.commands.onCommand.addListener(function(command) {
// We could enumerate these twice, but since we're in here first,
// why not save ourselves the trouble with this convention
if (command.startsWith('clip')) {
sendClipMessage(command);
}
});

View File

@ -266,12 +266,13 @@
async function prepareCommandResponse(command) {
console.info(`Got command: ${command.name}`);
const shouldSendToJoplin = !!command.shouldSendToJoplin;
const convertToMarkup = command.preProcessFor ? command.preProcessFor : 'markdown';
const clippedContentResponse = (title, html, imageSizes, anchorNames, stylesheets) => {
return {
name: 'clippedContent',
name: shouldSendToJoplin ? 'sendContentToJoplin' : 'clippedContent',
title: title,
html: html,
base_url: baseUrl(),

View File

@ -1,7 +1,7 @@
{
"manifest_version": 2,
"name": "Joplin Web Clipper [DEV]",
"version": "1.0.19",
"version": "1.0.20",
"description": "Capture and save web pages and screenshots from your browser to Joplin.",
"homepage_url": "https://joplinapp.org",
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
@ -33,6 +33,31 @@
]
}
],
"commands": {
"_execute_browser_action": {
"suggested_key": {
"default": "Alt+Shift+J"
}
},
"clipCompletePage": {
"suggested_key": {
"default": "Alt+Shift+C"
},
"description": "Clip complete page (uses last selected notebook)"
},
"clipCompletePageHtml": {
"description": "Clip complete page (HTML) (uses last selected notebook)"
},
"clipSimplifiedPage": {
"description": "Clip simplified page (uses last selected notebook)"
},
"clipUrl": {
"description": "Clip url (uses last selected notebook)"
},
"clipSelection": {
"description": "Clip selection (uses last selected notebook)"
}
},
"background": {
"scripts": [
"background.js"

View File

@ -52,9 +52,11 @@
cursor: pointer;
align-items: center;
min-height: 31px;
text-decoration: none;
}
.App a.Button:hover {
.App a.Button:hover,
.App a.Button:focus {
background-color: #1E89E6;
}

View File

@ -49,7 +49,7 @@ class PreviewComponent extends React.PureComponent {
<h2>Title:</h2>
<input className={'Title'} value={this.props.title} onChange={this.props.onTitleChange}/>
<p><span>Type:</span> {commandUserString(this.props.command)}</p>
<a className={'Confirm Button'} onClick={this.props.onConfirmClick}>Confirm</a>
<a className={'Confirm Button'} href="#" onClick={this.props.onConfirmClick}>Confirm</a>
</div>
);
@ -384,12 +384,12 @@ class AppComponent extends Component {
<div className="App">
<div className="Controls">
<ul>
<li><a className="Button" onClick={this.clipSimplified_click} title={simplifiedPageButtonTooltip}>{simplifiedPageButtonLabel}</a></li>
<li><a className="Button" onClick={this.clipComplete_click}>Clip complete page</a></li>
<li><a className="Button" onClick={this.clipCompleteHtml_click}>Clip complete page (HTML) (Beta)</a></li>
<li><a className="Button" onClick={this.clipSelection_click}>Clip selection</a></li>
<li><a className="Button" onClick={this.clipScreenshot_click}>Clip screenshot</a></li>
<li><a className="Button" onClick={this.clipUrl_click}>Clip URL</a></li>
<li><a className="Button" href="#" onClick={this.clipSimplified_click} title={simplifiedPageButtonTooltip}>{simplifiedPageButtonLabel}</a></li>
<li><a className="Button" href="#" onClick={this.clipComplete_click}>Clip complete page</a></li>
<li><a className="Button" href="#" onClick={this.clipCompleteHtml_click}>Clip complete page (HTML) (Beta)</a></li>
<li><a className="Button" href="#" onClick={this.clipSelection_click}>Clip selection</a></li>
<li><a className="Button" href="#" onClick={this.clipScreenshot_click}>Clip screenshot</a></li>
<li><a className="Button" href="#" onClick={this.clipUrl_click}>Clip URL</a></li>
</ul>
</div>
{ foldersComp() }

View File

@ -6,15 +6,32 @@ class Bridge {
this.nounce_ = Date.now();
}
async init(browser, browserSupportsPromises, dispatch) {
async init(browser, browserSupportsPromises, store) {
console.info('Popup: Init bridge');
this.browser_ = browser;
this.dispatch_ = dispatch;
this.dispatch_ = store.dispatch;
this.store_ = store;
this.browserSupportsPromises_ = browserSupportsPromises;
this.clipperServerPort_ = null;
this.clipperServerPortStatus_ = 'searching';
function convertCommandToContent(command) {
return {
title: command.title,
body_html: command.html,
base_url: command.base_url,
source_url: command.url,
parent_id: command.parent_id,
tags: command.tags || '',
image_sizes: command.image_sizes || {},
anchor_names: command.anchor_names || [],
source_command: command.source_command,
convert_to: command.convert_to,
stylesheets: command.stylesheets,
};
}
this.browser_notify = async (command) => {
console.info('Popup: Got command:', command);
@ -26,30 +43,26 @@ class Bridge {
}
if (command.name === 'clippedContent') {
const content = {
title: command.title,
body_html: command.html,
base_url: command.base_url,
source_url: command.url,
parent_id: command.parent_id,
tags: command.tags || '',
image_sizes: command.image_sizes || {},
anchor_names: command.anchor_names || [],
source_command: command.source_command,
convert_to: command.convert_to,
stylesheets: command.stylesheets,
};
const content = convertCommandToContent(command);
this.dispatch({ type: 'CLIPPED_CONTENT_SET', content: content });
}
if (command.name === 'sendContentToJoplin') {
const content = convertCommandToContent(command);
this.dispatch({ type: 'CLIPPED_CONTENT_SET', content: content });
const state = this.store_.getState();
content.parent_id = state.selectedFolderId;
if (content.parent_id) {
this.sendContentToJoplin(content);
}
}
if (command.name === 'isProbablyReaderable') {
this.dispatch({ type: 'IS_PROBABLY_READERABLE', value: command.value });
}
};
this.browser_.runtime.onMessage.addListener(this.browser_notify);
const backgroundPage = await this.backgroundPage(this.browser_);
// Not sure why the getBackgroundPage() sometimes returns null, so
@ -354,7 +367,6 @@ class Bridge {
}
}
}
}
const bridge_ = new Bridge();

View File

@ -105,7 +105,7 @@ async function main() {
console.info('Popup: Init bridge and restore state...');
await bridge().init(window.browser ? window.browser : window.chrome, !!window.browser, store.dispatch);
await bridge().init(window.browser ? window.browser : window.chrome, !!window.browser, store);
console.info('Popup: Creating React app...');