cocopy
https://gyazo.com/ebaeb13e6c8d268f2bfd92881ff3bd56
code:js
/**
* Copy plain title and url.
* @param {Object} page
* @returns {(string|undefined|Promise)}
*/
({ title, url, content, selectingText }) => {
// Amazon の短い URL を取得する
const amazon = ({ title, url, content, selectingText }) => {
if (url.host !== "www.amazon.co.jp") {
return { title, url, content, selectingText };
}
const asin = url.pathname.match(/\/(?:dp|gp\/product)\/\dA-Z+/); if (!asin) {
return { title, url, content, selectingText };
}
url = new URL(https://${url.host}${asin[0]}/);
return { title, url, content, selectingText };
};
// Wikipedia の URL を正規化する
const wikipedia = ({ title, url, content, selectingText }) => {
const matchHost = url.host.match(/^(a-z+)\.(?:m\.)?wikipedia\.org$/); if (!matchHost) {
return { title, url, content, selectingText };
}
url = new URL(
https://${matchHost[1]}.wikipedia.org${url.pathname}${url.hash},
);
return { title, url, content, selectingText };
};
// URL から tracking 用の query を除く
const trimUtm = ({ title, url, content, selectingText }) => {
const searchParams = new URLSearchParams();
for (const k, v of url.searchParams) { if (!k.startsWith("utm_")) {
searchParams.append(k, v);
}
}
url.search = searchParams.toString();
return { title, url, content, selectingText };
};
const concatHash = ({ title, url, content, selectingText }) => {
// ※64 文字と云ふ文字數に根據は無い
const trimSubtitle = (text) =>
text.replaceAll("\n", " ").trimStart().slice(0, 64).trimEnd();
if (selectingText && /\S/.test(selectingText)) {
// 文字列が選擇されてゐる場合は、文字列を highlight する URL を取得する
title = ${title}#:~:${trimSubtitle(selectingText)};
url.hash = #:~:text=${encodeURIComponent(selectingText)};
} else if (url.host !== "docs.google.com" && url.hash) {
// URL に hash が附いてゐる場合は、target の內容を title に入れる
const dom = new DOMParser().parseFromString(content, "text/html");
const elem =
dom.getElementById(url.hash.slice(1)) ||
dom.querySelector(a[name="${url.hash.slice(1)}"]);
const subtitle = elem ? trimSubtitle(elem.textContent) : "";
if (subtitle !== "") {
title = ${title}#${subtitle};
} else {
title = ${title}${decodeURIComponent(url.hash)};
}
}
return { title, url, content, selectingText };
};
// Cosense 用に [] を置き換へる
const escapeTitle = ({ title, url, content, selectingText }) => {
title = title.replaceAll(""[").replaceAll("", "]");
return { title, url, content, selectingText };
};
const pipeProcessers = (...processers) => {
return ({ title, url, content, selectingText }) => {
for (const processer of processers) {
const res = processer({ title, url, content, selectingText });
title = res.title;
url = res.url;
content = res.content;
selectingText = res.selectingText;
}
return { title, url, content, selectingText };
};
};
const plaintext = ({ title, url, content, selectingText }) =>
${title} ${url};
const html = ({ title, url, content, selectingText }) =>
<a href="${url}">${title.replaceAll("<", "<").replaceAll(">", ">")}</a>
const processor = pipeProcessers(
trimUtm,
amazon,
wikipedia,
concatHash,
escapeTitle,
);
url = new URL(url);
const processed = processor({ title, url, content, selectingText });
return {
html: html(processed),
text: plaintext(processed),
};
};
$ npx prettier --parser babel