mirror of
https://github.com/laurent22/joplin.git
synced 2025-01-11 18:24:43 +02:00
Clipper: Made extension compatible with Chrome and started screenshot clipping
This commit is contained in:
parent
9db9d98419
commit
4640d6d6e3
40
Clipper/joplin-webclipper/background.js
Normal file
40
Clipper/joplin-webclipper/background.js
Normal file
@ -0,0 +1,40 @@
|
||||
let browser_ = null;
|
||||
if (typeof browser !== 'undefined') {
|
||||
browser_ = browser;
|
||||
browserSupportsPromises_ = true;
|
||||
} else if (typeof chrome !== 'undefined') {
|
||||
browser_ = chrome;
|
||||
browserSupportsPromises_ = false;
|
||||
}
|
||||
|
||||
async function browserCaptureVisibleTabs(windowId, options) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (browserSupportsPromises_) return browser_.tabs.captureVisibleTab(null, { format: 'jpeg' });
|
||||
|
||||
browser_.tabs.captureVisibleTab(null, { format: 'jpeg' }, (image) => {
|
||||
resolve(image);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
chrome.runtime.onInstalled.addListener(function() {
|
||||
|
||||
});
|
||||
|
||||
browser_.runtime.onMessage.addListener((command) => {
|
||||
if (command.name === 'screenshotArea') {
|
||||
browserCaptureVisibleTabs(null, { format: 'jpeg' }).then((image) => {
|
||||
content = Object.assign({}, command.content);
|
||||
content.imageBase64 = image;
|
||||
|
||||
fetch(command.apiBaseUrl + "/notes", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(content)
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
@ -5,6 +5,15 @@
|
||||
|
||||
console.info('jopext: Loading content script');
|
||||
|
||||
let browser_ = null;
|
||||
if (typeof browser !== 'undefined') {
|
||||
browser_ = browser;
|
||||
browserSupportsPromises_ = true;
|
||||
} else if (typeof chrome !== 'undefined') {
|
||||
browser_ = chrome;
|
||||
browserSupportsPromises_ = false;
|
||||
}
|
||||
|
||||
function pageTitle() {
|
||||
const titleElements = document.getElementsByTagName("title");
|
||||
if (titleElements.length) return titleElements[0].text.trim();
|
||||
@ -63,6 +72,8 @@
|
||||
}
|
||||
|
||||
async function prepareCommandResponse(command) {
|
||||
console.info('Got command: ' + command.name);
|
||||
|
||||
if (command.name === "simplifiedPageHtml") {
|
||||
|
||||
let article = null;
|
||||
@ -98,17 +109,101 @@
|
||||
url: location.origin + location.pathname,
|
||||
};
|
||||
|
||||
} else if (command.name === 'screenshot') {
|
||||
|
||||
const overlay = document.createElement('div');
|
||||
overlay.style.opacity = '0.5';
|
||||
overlay.style.background = 'black';
|
||||
overlay.style.width = '100%';
|
||||
overlay.style.height = '100%';
|
||||
overlay.style.zIndex = 99999999;
|
||||
overlay.style.top = 0;
|
||||
overlay.style.left = 0;
|
||||
overlay.style.position = 'fixed';
|
||||
|
||||
document.body.appendChild(overlay);
|
||||
|
||||
const selection = document.createElement('div');
|
||||
selection.style.opacity = '0.5';
|
||||
selection.style.background = 'blue';
|
||||
selection.style.zIndex = overlay.style.zIndex - 1;
|
||||
selection.style.top = 0;
|
||||
selection.style.left = 0;
|
||||
selection.style.position = 'fixed';
|
||||
|
||||
document.body.appendChild(selection);
|
||||
|
||||
let isDragging = false;
|
||||
let draggingStartPos = null;
|
||||
let selectionArea = {};
|
||||
|
||||
function updateSelection() {
|
||||
selection.style.left = selectionArea.x;
|
||||
selection.style.top = selectionArea.y;
|
||||
selection.style.width = selectionArea.width;
|
||||
selection.style.height = selectionArea.height;
|
||||
}
|
||||
|
||||
function setSelectionSizeFromMouse(event) {
|
||||
selectionArea.width = Math.max(1, event.pageX - draggingStartPos.x);
|
||||
selectionArea.height = Math.max(1, event.pageY - draggingStartPos.y);
|
||||
updateSelection();
|
||||
}
|
||||
|
||||
function selection_mouseDown(event) {
|
||||
selectionArea = { x: event.pageX - document.body.scrollLeft, y: event.pageY - document.body.scrollTop, width: 0, height: 0 }
|
||||
draggingStartPos = { x: event.pageX, y: event.pageY };
|
||||
isDragging = true;
|
||||
updateSelection();
|
||||
}
|
||||
|
||||
function selection_mouseMove(event) {
|
||||
if (!isDragging) return;
|
||||
setSelectionSizeFromMouse(event);
|
||||
}
|
||||
|
||||
function selection_mouseUp(event) {
|
||||
setSelectionSizeFromMouse(event);
|
||||
|
||||
isDragging = false;
|
||||
|
||||
overlay.removeEventListener('mousedown', selection_mouseDown);
|
||||
overlay.removeEventListener('mousemove', selection_mouseMove);
|
||||
overlay.removeEventListener('mouseup', selection_mouseUp);
|
||||
|
||||
document.body.removeChild(overlay);
|
||||
document.body.removeChild(selection);
|
||||
|
||||
const content = {
|
||||
title: pageTitle(),
|
||||
area: selectionArea,
|
||||
url: location.origin + location.pathname,
|
||||
};
|
||||
|
||||
browser_.runtime.sendMessage({
|
||||
name: 'screenshotArea',
|
||||
content: content,
|
||||
apiBaseUrl: command.apiBaseUrl,
|
||||
});
|
||||
}
|
||||
|
||||
overlay.addEventListener('mousedown', selection_mouseDown);
|
||||
overlay.addEventListener('mousemove', selection_mouseMove);
|
||||
overlay.addEventListener('mouseup', selection_mouseUp);
|
||||
|
||||
return {};
|
||||
|
||||
} else {
|
||||
throw new Error('Unknown command', command);
|
||||
throw new Error('Unknown command: ' + JSON.stringify(command));
|
||||
}
|
||||
}
|
||||
|
||||
async function execCommand(command) {
|
||||
const response = await prepareCommandResponse(command);
|
||||
browser.runtime.sendMessage(response);
|
||||
browser_.runtime.sendMessage(response);
|
||||
}
|
||||
|
||||
browser.runtime.onMessage.addListener((command) => {
|
||||
browser_.runtime.onMessage.addListener((command) => {
|
||||
console.info('jopext: Got command:', command);
|
||||
|
||||
execCommand(command);
|
||||
|
@ -1,39 +1,48 @@
|
||||
{
|
||||
|
||||
"manifest_version": 2,
|
||||
"name": "Joplin Web Clipper",
|
||||
"version": "1.0",
|
||||
"manifest_version": 2,
|
||||
"name": "Joplin Web Clipper",
|
||||
"version": "1.0",
|
||||
|
||||
"description": "Gets and saves content from your browser to Joplin.",
|
||||
"description": "Gets and saves content from your browser to Joplin.",
|
||||
|
||||
"homepage_url": "https://joplin.cozic.net",
|
||||
"homepage_url": "https://joplin.cozic.net",
|
||||
|
||||
"icons": {
|
||||
"48": "icons/48.png",
|
||||
"96": "icons/96.png"
|
||||
},
|
||||
"icons": {
|
||||
"48": "icons/48.png",
|
||||
"96": "icons/96.png"
|
||||
},
|
||||
|
||||
"permissions": [
|
||||
"activeTab"
|
||||
],
|
||||
"permissions": [
|
||||
"activeTab",
|
||||
"tabs",
|
||||
"http://*/",
|
||||
"https://*/",
|
||||
"<all_urls>"
|
||||
],
|
||||
|
||||
"browser_action": {
|
||||
"default_icon": "icons/32.png",
|
||||
"default_title": "Joplin Web Clipper",
|
||||
"default_popup": "popup/build/index.html"
|
||||
},
|
||||
"browser_action": {
|
||||
"default_icon": "icons/32.png",
|
||||
"default_title": "Joplin Web Clipper",
|
||||
"default_popup": "popup/build/index.html"
|
||||
},
|
||||
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": ["*://*/"],
|
||||
"js": ["main.js"]
|
||||
}
|
||||
],
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": ["*://*/"],
|
||||
"js": ["main.js"]
|
||||
}
|
||||
],
|
||||
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"id": "{8419486a-54e9-11e8-9401-ac9e17909436}"
|
||||
}
|
||||
}
|
||||
"background": {
|
||||
"scripts": ["background.js"],
|
||||
"persistent": false
|
||||
},
|
||||
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"id": "{8419486a-54e9-11e8-9401-ac9e17909436}"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -6,7 +6,7 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #162b3d;
|
||||
font-size: 1em;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.App h2 {
|
||||
@ -39,13 +39,15 @@
|
||||
|
||||
.App a.Button {
|
||||
background-color: #0269c2;
|
||||
padding: 8px 14px;
|
||||
padding: 0 14px;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
color: #eee;
|
||||
font-weight: normal;
|
||||
font-size: .8em;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
min-height: 31px;
|
||||
}
|
||||
|
||||
.App a.Button:hover {
|
||||
|
@ -26,7 +26,7 @@ class AppComponent extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
async clipSimplified_click() {
|
||||
clipSimplified_click() {
|
||||
bridge().sendCommandToActiveTab({
|
||||
name: 'simplifiedPageHtml',
|
||||
});
|
||||
@ -38,10 +38,17 @@ class AppComponent extends Component {
|
||||
});
|
||||
}
|
||||
|
||||
clipScreenshot_click() {
|
||||
bridge().sendCommandToActiveTab({
|
||||
name: 'screenshot',
|
||||
apiBaseUrl: 'http://127.0.0.1:9967',
|
||||
});
|
||||
}
|
||||
|
||||
async loadContentScripts() {
|
||||
await Global.browser().tabs.executeScript({file: "/content_scripts/JSDOMParser.js"});
|
||||
await Global.browser().tabs.executeScript({file: "/content_scripts/Readability.js"});
|
||||
await Global.browser().tabs.executeScript({file: "/content_scripts/index.js"});
|
||||
await bridge().tabsExecuteScript({file: "/content_scripts/JSDOMParser.js"});
|
||||
await bridge().tabsExecuteScript({file: "/content_scripts/Readability.js"});
|
||||
await bridge().tabsExecuteScript({file: "/content_scripts/index.js"});
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
@ -103,6 +110,7 @@ class AppComponent extends Component {
|
||||
<ul>
|
||||
<li><a className="Button" onClick={this.clipSimplified_click}>Clip simplified page</a></li>
|
||||
<li><a className="Button" onClick={this.clipComplete_click}>Clip complete page</a></li>
|
||||
<li><a className="Button" onClick={this.clipScreenshot_click}>Clip screenshot</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
{ warningComponent }
|
||||
|
@ -1,10 +1,11 @@
|
||||
class Bridge {
|
||||
|
||||
init(browser, dispatch) {
|
||||
init(browser, browserSupportsPromises, dispatch) {
|
||||
console.info('Popup: Init bridge');
|
||||
|
||||
this.browser_ = browser;
|
||||
this.dispatch_ = dispatch;
|
||||
this.browserSupportsPromises_ = browserSupportsPromises;
|
||||
|
||||
this.browser_notify = async (command) => {
|
||||
console.info('Popup: Got command: ' + command.name);
|
||||
@ -39,8 +40,38 @@ class Bridge {
|
||||
return this.dispatch_(action);
|
||||
}
|
||||
|
||||
async tabsExecuteScript(options) {
|
||||
if (this.browserSupportsPromises_) return this.browser().tabs.executeScript(options);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
this.browser().tabs.executeScript(options, () => {
|
||||
resolve();
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
async tabsQuery(options) {
|
||||
if (this.browserSupportsPromises_) return this.browser().tabs.query(options);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
this.browser().tabs.query(options, (tabs) => {
|
||||
resolve(tabs);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async tabsSendMessage(tabId, command) {
|
||||
if (this.browserSupportsPromises_) return this.browser().tabs.sendMessage(tabId, command);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
this.browser().tabs.sendMessage(tabId, command, (result) => {
|
||||
resolve(result);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async sendCommandToActiveTab(command) {
|
||||
const tabs = await this.browser().tabs.query({ active: true, currentWindow: true });
|
||||
const tabs = await this.tabsQuery({ active: true, currentWindow: true });
|
||||
if (!tabs.length) {
|
||||
console.warn('No valid tab');
|
||||
return;
|
||||
@ -48,7 +79,9 @@ class Bridge {
|
||||
|
||||
this.dispatch({ type: 'CONTENT_UPLOAD', operation: null });
|
||||
|
||||
await this.browser().tabs.sendMessage(tabs[0].id, command);
|
||||
console.info('Sending message ', command);
|
||||
|
||||
await this.tabsSendMessage(tabs[0].id, command);
|
||||
}
|
||||
|
||||
async sendContentToJoplin(content) {
|
||||
|
@ -45,7 +45,7 @@ function reducer(state = defaultState, action) {
|
||||
|
||||
const store = createStore(reducer);
|
||||
|
||||
bridge().init(window.browser, store.dispatch);
|
||||
bridge().init(window.browser ? window.browser : window.chrome, !!window.browser, store.dispatch);
|
||||
|
||||
console.info('Popup: Creating React app...');
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user