Clipboard updates (#2254)
* Rename * Rename vars * Refactor paste target * Prevent most CSS url() properties from loading * Add helper function to clear rich function * Add useRichText argument * Update condition for using readText * Fix indent * Update CSS
This commit is contained in:
parent
a370b46fae
commit
9ef7f9d383
@ -11,6 +11,7 @@
|
||||
<link rel="icon" type="image/png" href="/images/icon48.png" sizes="48x48">
|
||||
<link rel="icon" type="image/png" href="/images/icon64.png" sizes="64x64">
|
||||
<link rel="icon" type="image/png" href="/images/icon128.png" sizes="128x128">
|
||||
<link rel="stylesheet" type="text/css" href="/css/background.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@ -61,7 +62,7 @@
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1603985
|
||||
-->
|
||||
<!-- [html-validate-disable close-order] -->
|
||||
<div id="clipboard-image-paste-target" contenteditable="true">
|
||||
<div id="clipboard-rich-content-paste-target" contenteditable="true">
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
29
ext/css/background.css
Normal file
29
ext/css/background.css
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Yomichan Authors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* stylelint-disable declaration-no-important */
|
||||
#clipboard-rich-content-paste-target * {
|
||||
background-image: none !important;
|
||||
list-style-image: none !important;
|
||||
content: none !important;
|
||||
cursor: auto !important;
|
||||
border-image-source: none !important;
|
||||
offset-path: none !important;
|
||||
-webkit-mask-image: none !important;
|
||||
mask-image: none !important;
|
||||
}
|
||||
/* stylelint-enable declaration-no-important */
|
@ -53,7 +53,7 @@ class Backend {
|
||||
// eslint-disable-next-line no-undef
|
||||
document: (typeof document === 'object' && document !== null ? document : null),
|
||||
pasteTargetSelector: '#clipboard-paste-target',
|
||||
imagePasteTargetSelector: '#clipboard-image-paste-target'
|
||||
richContentPasteTargetSelector: '#clipboard-rich-content-paste-target'
|
||||
});
|
||||
this._clipboardMonitor = new ClipboardMonitor({
|
||||
japaneseUtil: this._japaneseUtil,
|
||||
@ -596,7 +596,7 @@ class Backend {
|
||||
}
|
||||
|
||||
async _onApiClipboardGet() {
|
||||
return this._clipboardReader.getText();
|
||||
return this._clipboardReader.getText(false);
|
||||
}
|
||||
|
||||
async _onApiGetDisplayTemplatesHtml() {
|
||||
@ -1773,7 +1773,7 @@ class Backend {
|
||||
|
||||
try {
|
||||
if (clipboardDetails !== null && clipboardDetails.text) {
|
||||
clipboardText = await this._clipboardReader.getText();
|
||||
clipboardText = await this._clipboardReader.getText(false);
|
||||
}
|
||||
} catch (e) {
|
||||
errors.push(serializeError(e));
|
||||
|
@ -39,7 +39,7 @@ class ClipboardMonitor extends EventDispatcher {
|
||||
|
||||
let text = null;
|
||||
try {
|
||||
text = await this._clipboardReader.getText();
|
||||
text = await this._clipboardReader.getText(false);
|
||||
} catch (e) {
|
||||
// NOP
|
||||
}
|
||||
|
@ -28,15 +28,15 @@ class ClipboardReader {
|
||||
* @param {object} details Details about how to set up the instance.
|
||||
* @param {?Document} details.document The Document object to be used, or null for no support.
|
||||
* @param {?string} details.pasteTargetSelector The selector for the paste target element.
|
||||
* @param {?string} details.imagePasteTargetSelector The selector for the image paste target element.
|
||||
* @param {?string} details.richContentPasteTargetSelector The selector for the rich content paste target element.
|
||||
*/
|
||||
constructor({document=null, pasteTargetSelector=null, imagePasteTargetSelector=null}) {
|
||||
constructor({document=null, pasteTargetSelector=null, richContentPasteTargetSelector=null}) {
|
||||
this._document = document;
|
||||
this._browser = null;
|
||||
this._pasteTarget = null;
|
||||
this._pasteTargetSelector = pasteTargetSelector;
|
||||
this._imagePasteTarget = null;
|
||||
this._imagePasteTargetSelector = imagePasteTargetSelector;
|
||||
this._richContentPasteTarget = null;
|
||||
this._richContentPasteTargetSelector = richContentPasteTargetSelector;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -56,13 +56,14 @@ class ClipboardReader {
|
||||
|
||||
/**
|
||||
* Gets the text in the clipboard.
|
||||
* @param {boolean} useRichText Whether or not to use rich text for pasting, when possible.
|
||||
* @returns {string} A string containing the clipboard text.
|
||||
* @throws {Error} Error if not supported.
|
||||
*/
|
||||
async getText() {
|
||||
async getText(useRichText) {
|
||||
/*
|
||||
Notes:
|
||||
document.execCommand('paste') doesn't work on Firefox.
|
||||
document.execCommand('paste') sometimes doesn't work on Firefox.
|
||||
See: https://bugzilla.mozilla.org/show_bug.cgi?id=1603985
|
||||
Therefore, navigator.clipboard.readText() is used on Firefox.
|
||||
|
||||
@ -72,7 +73,7 @@ class ClipboardReader {
|
||||
being an extension with clipboard permissions. It effectively asks for the
|
||||
non-extension permission for clipboard access.
|
||||
*/
|
||||
if (this._isFirefox()) {
|
||||
if (this._isFirefox() && !useRichText) {
|
||||
try {
|
||||
return await navigator.clipboard.readText();
|
||||
} catch (e) {
|
||||
@ -86,21 +87,22 @@ class ClipboardReader {
|
||||
throw new Error('Clipboard reading not supported in this context');
|
||||
}
|
||||
|
||||
let target = this._pasteTarget;
|
||||
if (target === null) {
|
||||
target = document.querySelector(this._pasteTargetSelector);
|
||||
if (target === null) {
|
||||
throw new Error('Clipboard paste target does not exist');
|
||||
}
|
||||
this._pasteTarget = target;
|
||||
if (useRichText) {
|
||||
const target = this._getRichContentPasteTarget();
|
||||
target.focus();
|
||||
document.execCommand('paste');
|
||||
const result = target.textContent;
|
||||
this._clearRichContent(target);
|
||||
return result;
|
||||
} else {
|
||||
const target = this._getPasteTarget();
|
||||
target.value = '';
|
||||
target.focus();
|
||||
document.execCommand('paste');
|
||||
const result = target.value;
|
||||
target.value = '';
|
||||
return (typeof result === 'string' ? result : '');
|
||||
}
|
||||
|
||||
target.value = '';
|
||||
target.focus();
|
||||
document.execCommand('paste');
|
||||
const result = target.value;
|
||||
target.value = '';
|
||||
return (typeof result === 'string' ? result : '');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -143,23 +145,12 @@ class ClipboardReader {
|
||||
throw new Error('Clipboard reading not supported in this context');
|
||||
}
|
||||
|
||||
let target = this._imagePasteTarget;
|
||||
if (target === null) {
|
||||
target = document.querySelector(this._imagePasteTargetSelector);
|
||||
if (target === null) {
|
||||
throw new Error('Clipboard paste target does not exist');
|
||||
}
|
||||
this._imagePasteTarget = target;
|
||||
}
|
||||
|
||||
const target = this._getRichContentPasteTarget();
|
||||
target.focus();
|
||||
document.execCommand('paste');
|
||||
const image = target.querySelector('img[src^="data:"]');
|
||||
const result = (image !== null ? image.getAttribute('src') : null);
|
||||
for (const image2 of target.querySelectorAll('img')) {
|
||||
image2.removeAttribute('src');
|
||||
}
|
||||
target.textContent = '';
|
||||
this._clearRichContent(target);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -177,4 +168,28 @@ class ClipboardReader {
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
}
|
||||
|
||||
_getPasteTarget() {
|
||||
if (this._pasteTarget === null) { this._pasteTarget = this._findPasteTarget(this._pasteTargetSelector); }
|
||||
return this._pasteTarget;
|
||||
}
|
||||
|
||||
_getRichContentPasteTarget() {
|
||||
if (this._richContentPasteTarget === null) { this._richContentPasteTarget = this._findPasteTarget(this._richContentPasteTargetSelector); }
|
||||
return this._richContentPasteTarget;
|
||||
}
|
||||
|
||||
_findPasteTarget(selector) {
|
||||
const target = this._document.querySelector(selector);
|
||||
if (target === null) { throw new Error('Clipboard paste target does not exist'); }
|
||||
return target;
|
||||
}
|
||||
|
||||
_clearRichContent(element) {
|
||||
for (const image of element.querySelectorAll('img')) {
|
||||
image.removeAttribute('src');
|
||||
image.removeAttribute('srcset');
|
||||
}
|
||||
element.textContent = '';
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user