2018-05-24 17:32:30 +00:00
|
|
|
let browser_ = null;
|
|
|
|
if (typeof browser !== 'undefined') {
|
|
|
|
browser_ = browser;
|
|
|
|
browserSupportsPromises_ = true;
|
|
|
|
} else if (typeof chrome !== 'undefined') {
|
|
|
|
browser_ = chrome;
|
|
|
|
browserSupportsPromises_ = false;
|
|
|
|
}
|
|
|
|
|
2018-06-01 14:50:11 +00:00
|
|
|
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_;
|
|
|
|
|
2018-06-14 18:11:22 +00:00
|
|
|
const manifest = browser_.runtime.getManifest();
|
|
|
|
env_ = manifest.name.indexOf('[DEV]') >= 0 ? 'dev' : 'prod';
|
2018-06-01 14:50:11 +00:00
|
|
|
return env_;
|
2019-07-30 07:35:42 +00:00
|
|
|
};
|
2018-05-26 10:18:54 +00:00
|
|
|
|
2019-06-11 00:09:48 +00:00
|
|
|
async function browserCaptureVisibleTabs(windowId) {
|
|
|
|
const options = { format: 'jpeg' };
|
|
|
|
if (browserSupportsPromises_) return browser_.tabs.captureVisibleTab(windowId, options);
|
2018-05-24 17:32:30 +00:00
|
|
|
|
2019-09-12 22:16:42 +00:00
|
|
|
return new Promise((resolve) => {
|
2019-06-11 00:09:48 +00:00
|
|
|
browser_.tabs.captureVisibleTab(windowId, options, (image) => {
|
2018-05-24 17:32:30 +00:00
|
|
|
resolve(image);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-06-01 15:12:49 +00:00
|
|
|
async function browserGetZoom(tabId) {
|
|
|
|
if (browserSupportsPromises_) return browser_.tabs.getZoom(tabId);
|
|
|
|
|
2019-09-12 22:16:42 +00:00
|
|
|
return new Promise((resolve) => {
|
2018-06-01 15:12:49 +00:00
|
|
|
browser_.tabs.getZoom(tabId, (zoom) => {
|
|
|
|
resolve(zoom);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-09-12 22:16:42 +00:00
|
|
|
browser_.runtime.onInstalled.addListener(function() {
|
2018-06-01 14:50:11 +00:00
|
|
|
if (window.joplinEnv() === 'dev') {
|
2018-05-26 10:18:54 +00:00
|
|
|
browser_.browserAction.setIcon({
|
|
|
|
path: 'icons/32-dev.png',
|
|
|
|
});
|
|
|
|
}
|
2018-05-24 17:32:30 +00:00
|
|
|
});
|
|
|
|
|
2020-11-15 22:30:29 +00:00
|
|
|
async function getImageSize(dataUrl) {
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
const image = new Image();
|
|
|
|
|
|
|
|
image.onload = function() {
|
|
|
|
resolve({ width: image.width, height: image.height });
|
|
|
|
};
|
2018-05-24 17:32:30 +00:00
|
|
|
|
2020-11-15 22:30:29 +00:00
|
|
|
image.onerror = function(event) {
|
|
|
|
reject(event);
|
|
|
|
};
|
2018-06-01 15:12:49 +00:00
|
|
|
|
2020-11-15 22:30:29 +00:00
|
|
|
image.src = dataUrl;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
browser_.runtime.onMessage.addListener(async (command) => {
|
|
|
|
if (command.name === 'screenshotArea') {
|
|
|
|
const browserZoom = await browserGetZoom();
|
|
|
|
|
|
|
|
// The dimensions of the image returned by Firefox are the regular ones,
|
|
|
|
// while the one returned by Chrome depend on the screen pixel ratio. So
|
|
|
|
// it would return a 600*400 image if the window dimensions are 300x200
|
|
|
|
// and the screen pixel ratio is 2.
|
|
|
|
//
|
|
|
|
// Normally we could rely on window.devicePixelRatio to tell us that but
|
|
|
|
// since Firefox and Chrome handle this differently, we need to
|
|
|
|
// calculate the ratio ourselves. It's simply the image dimensions
|
|
|
|
// divided by the window inner width.
|
|
|
|
//
|
|
|
|
// The crop rectangle is always in real pixels, so we need to multiply
|
|
|
|
// it by the ratio we've calculated.
|
2019-06-11 00:09:48 +00:00
|
|
|
const imageDataUrl = await browserCaptureVisibleTabs(null);
|
2020-11-15 22:30:29 +00:00
|
|
|
const imageSize = await getImageSize(imageDataUrl);
|
|
|
|
const imagePixelRatio = imageSize.width / command.content.windowInnerWidth;
|
|
|
|
|
2019-07-30 07:35:42 +00:00
|
|
|
const content = Object.assign({}, command.content);
|
2018-06-01 15:12:49 +00:00
|
|
|
content.image_data_url = imageDataUrl;
|
2019-11-07 18:12:14 +00:00
|
|
|
if ('url' in content) content.source_url = content.url;
|
2018-06-01 15:12:49 +00:00
|
|
|
|
2020-11-15 22:30:29 +00:00
|
|
|
const ratio = browserZoom * imagePixelRatio;
|
2018-06-01 15:12:49 +00:00
|
|
|
const newArea = Object.assign({}, command.content.crop_rect);
|
2020-11-15 22:30:29 +00:00
|
|
|
newArea.x *= ratio;
|
|
|
|
newArea.y *= ratio;
|
|
|
|
newArea.width *= ratio;
|
|
|
|
newArea.height *= ratio;
|
2018-06-01 15:12:49 +00:00
|
|
|
content.crop_rect = newArea;
|
|
|
|
|
2019-09-19 21:51:18 +00:00
|
|
|
fetch(`${command.api_base_url}/notes`, {
|
2019-07-30 07:35:42 +00:00
|
|
|
method: 'POST',
|
2018-06-01 15:12:49 +00:00
|
|
|
headers: {
|
|
|
|
'Accept': 'application/json',
|
2019-07-30 07:35:42 +00:00
|
|
|
'Content-Type': 'application/json',
|
2018-06-01 15:12:49 +00:00
|
|
|
},
|
2019-07-30 07:35:42 +00:00
|
|
|
body: JSON.stringify(content),
|
2018-05-24 17:32:30 +00:00
|
|
|
});
|
|
|
|
}
|
2018-05-26 10:18:54 +00:00
|
|
|
});
|
2020-02-11 10:49:07 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
});
|