让飞书文档不受权限限制,可以复制任意内容,可以打开右键菜单(图片需点击2次右键才可弹出菜单),可以将复制内容粘贴到新的飞书文档
// ==UserScript==
// @name 放开飞书复制和右键
// @license GPL License
// @namespace http://tampermonkey.net/
// @version 0.5
// @description 让飞书文档不受权限限制,可以复制任意内容,可以打开右键菜单(图片需点击2次右键才可弹出菜单),可以将复制内容粘贴到新的飞书文档
// @author qijunhao
// @match *://bytedance.larkoffice.com/*
// @icon https://sf3-scmcdn2-cn.feishucdn.com/ccm/pc/web/resource/bear/src/common/assets/favicons/icon_file_doc_nor-32x32.8cb0fef16653221e74b9.png
// @grant GM_registerMenuCommand
// @grant GM_notification
// @run-at document-start
// ==/UserScript==
(function () {
document.addEventListener('DOMContentLoaded', function () {
createToast();
// 拦截权限接口,修改响应,获取复制权限
rewritePermissionRequest();
// 增加右键菜单,转换复制的内容
addContextMenu();
// 给图片增加右键菜单,可复制、下载等
imgContextMenu();
});
})();
function rewritePermissionRequest() {
XMLHttpRequest.prototype._open = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function (...args) {
const [method, url] = args;
if (method === 'POST' && url.includes('space/api/suite/permission/document/actions/state/')) {
this.addEventListener("readystatechange", function () {
if (this.readyState !== 4) {
return;
}
let { response } = this;
try {
response = JSON.parse(response);
} catch (e) {}
response.data.actions.copy = 1;
response.data.actions.duplicate = 1;
response.data.actions.export = 1;
Object.defineProperty(this, 'response', {
get() {
return response;
}
});
Object.defineProperty(this, 'responseText', {
get() {
return JSON.stringify(response);
}
});
}, false);
}/* else if (method === 'POST' && url.includes('space/api/box/file/multi_copy/')) {
this.addEventListener("readystatechange", function () {
if (this.readyState !== 4) {
return;
}
let { response } = this;
try {
response = JSON.parse(response);
} catch (e) {}
const params = JSON.parse(this._data);
const token = params.files[0].file_token;
response.code = 0;
response.data = {
succ_files: {
// [token]: '123'
}
};
response.message = 'Success';
Object.defineProperty(this, 'response', {
get() {
return response;
}
});
Object.defineProperty(this, 'responseText', {
get() {
return JSON.stringify(response);
}
});
}, false);
} */
return this._open(...args);
};
}
function addContextMenu() {
// 增加右键菜单
GM_registerMenuCommand ("转换复制的飞书文档内容", async function() {
const clipboardItems = await navigator.clipboard.read();
for (const clipboardItem of clipboardItems) {
for (const type of clipboardItem.types) {
const blob = await clipboardItem.getType(type);
if (type === 'text/html') {
const reader = new FileReader();
reader.readAsText(blob, 'utf-8');
reader.onload = async function (e) {
const htmlStr = await formatHtml(reader.result);
const htmlBlob = new Blob([htmlStr], {
type: 'text/html',
});
console.log(type);
console.log(URL.createObjectURL(htmlBlob));
await navigator.clipboard.write([new ClipboardItem({ [htmlBlob.type]: htmlBlob })]);
// 无效
// document.execCommand('paste');
toast('转换成功,可以粘贴了!');
};
} else {
console.log(type);
console.log(URL.createObjectURL(blob));
}
}
}
});
}
function imgContextMenu() {
// 图片的右键
document.addEventListener('contextmenu', e => {
if (e.target.nodeName === 'IMG') {
console.log(e);
const elements = e.composedPath();
for (let index = 0; index < elements.length - 2; index++) {
const ele = elements[index];
try {
ele.removeAttribute('data-copyable');
ele.removeAttribute('data-printable');
ele.removeAttribute('data-exportable');
} catch (err) {
console.log(ele, err);
}
}
}
});
}
function getBase64Image(img) {
const canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0, img.width, img.height);
const dataURL = canvas.toDataURL('image/png');
return dataURL;
}
function setImage(img) {
return new Promise((resolve, reject) => {
let src = img.src;
if (src.startsWith('http')) {
src = img.getAttribute('data-src')
.replace(/\?.*/, '?preview_type=16')
.replace(/\/all\//, '/preview/');
const tempImg = document.createElement('img');
tempImg.src = src;
tempImg.crossOrigin = 'use-credentials';
tempImg.onload = function () {
const base64 = getBase64Image(tempImg);
img.setAttribute('src', base64);
img.setAttribute('default-src', src);
img.setAttribute('crossorigin', 'use-credentials');
img.style.maxHeight = '100%';
img.style.maxWidth = '100%';
img.removeAttribute('data-single-block');
img.removeAttribute('data-snapshot');
img.removeAttribute('data-suite');
img.removeAttribute('data-src');
img.removeAttribute('data-width');
img.removeAttribute('data-height');
img.parentElement.removeAttribute('data-ace-gallery-json');
resolve();
};
tempImg.onerror = function (e) {
reject(e);
};
}
if (src.startsWith('blob')) {
const fileReader = new FileReader();
fileReader.onload = function (e) {
resolve(e.target.result);
};
}
});
}
function formatHtml(str) {
const div = document.createElement('div');
div.innerHTML = str;
div.childNodes[div.childElementCount - 1].remove();
const imgArray = div.querySelectorAll('tbody img');
const promises = [...imgArray].map(setImage);
return Promise.allSettled(promises).then(() => div.innerHTML);
}
function createToast() {
const style = document.createElement('style');
style.innerHTML = `
.m_toast {
position: fixed;
top: 20px;
left: 50%;
font-size: 14px;
color: #fff;
background: #000b;
padding: 6px 10px;
transform: translate(-50%, -100px);
border-radius: 2px;
transition: transform 0.4s ease 0s;
z-index: 9999;
}
`;
document.head.append(style);
const div = document.createElement('div');
div.className = 'm_toast';
div.id = 'toast';
div.innerHTML = '12345';
document.body.appendChild(div);
}
function toast(text) {
const toast = document.querySelector('#toast');
toast.innerHTML = text;
toast.style.transform = 'translate(-50%, 0)';
setTimeout(() => {
toast.style.transform = 'translate(-50%, -100px)';
}, 2000);
}