mirror of
https://github.com/NickKaramoff/shareon
synced 2025-03-11 00:40:18 +01:00
WIP first draft of url builder
Closes #61 Co-authored-by: Dario Vladovic <d.vladimyr@gmail.com>
This commit is contained in:
parent
ded589cfbe
commit
e3b1aa5736
314
src/shareon.js
314
src/shareon.js
@ -1,149 +1,209 @@
|
||||
// prettier-ignore
|
||||
/**
|
||||
* @typedef PublishPreset
|
||||
*
|
||||
* @property {string} url
|
||||
* @property {string} [title]
|
||||
* @property {string} [media]
|
||||
* @property {string} [text]
|
||||
* @property {string} [via]
|
||||
* @property {string} [hashtags]
|
||||
* @property {string} [fbAppId]
|
||||
* @property {string} [s2fInstance]
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a URL that a button will point to.
|
||||
*
|
||||
* @param {string} baseUrl [description]
|
||||
* @param {Record<string, string | undefined>} parameters [description]
|
||||
* @return {string} [description]
|
||||
*/
|
||||
const buildUrl = (baseUrl, parameters) => {
|
||||
const url = new URL(baseUrl);
|
||||
for (const [parameter, value] of Object.entries(parameters)) {
|
||||
if (value) {
|
||||
url.searchParams.append(parameter, value);
|
||||
}
|
||||
}
|
||||
|
||||
return url.href;
|
||||
};
|
||||
|
||||
/**
|
||||
* Map of social networks to their respective URL builders.
|
||||
*
|
||||
* The `d` argument of each builder is the object with the page metadata, such
|
||||
* as page title, URL, author name, etc.
|
||||
*
|
||||
* @type {{ [network: string]: (d: {
|
||||
* url: string,
|
||||
* title?: string,
|
||||
* media?: string,
|
||||
* text?: string,
|
||||
* via?: string,
|
||||
* fbAppId?: string,
|
||||
* s2fInstance?: string,
|
||||
* }) => string}}
|
||||
* @type {{ [network: string]: (d: PublishPreset) => URL}}
|
||||
*/
|
||||
const urlBuilderMap = {
|
||||
facebook: (d) => `https://www.facebook.com/sharer/sharer.php?u=${d.url}${d.hashtags ? `&hashtag=%23${d.hashtags.split('%2C')[0]}` : ''}`,
|
||||
fediverse: (d) => `https://${d.s2fInstance}/?text=${d.title}%0D%0A${d.url}${d.text ? `%0D%0A%0D%0A${d.text}` : ''}${d.via ? `%0D%0A%0D%0A${d.via}` : ''}`,
|
||||
email: (d) => `mailto:?subject=${d.title}&body=${d.url}`,
|
||||
linkedin: (d) => `https://www.linkedin.com/sharing/share-offsite/?url=${d.url}`,
|
||||
mastodon: (d) => `https://toot.kytta.dev/?text=${d.title}%0D%0A${d.url}${d.text ? `%0D%0A%0D%0A${d.text}` : ''}${d.via ? `%0D%0A%0D%0A${d.via}` : ''}`,
|
||||
messenger: (d) => `https://www.facebook.com/dialog/send?app_id=${d.fbAppId}&link=${d.url}&redirect_uri=${d.url}`,
|
||||
odnoklassniki: (d) => `https://connect.ok.ru/offer?url=${d.url}&title=${d.title}${d.media ? `&imageUrl=${d.media}` : ''}`,
|
||||
pinterest: (d) => `https://pinterest.com/pin/create/button/?url=${d.url}&description=${d.title}${d.media ? `&media=${d.media}` : ''}`,
|
||||
pocket: (d) => `https://getpocket.com/edit.php?url=${d.url}`,
|
||||
reddit: (d) => `https://www.reddit.com/submit?title=${d.title}&url=${d.url}`,
|
||||
teams: (d) => `https://teams.microsoft.com/share?href=${d.url}${d.text ? `&msgText=${d.text}` : ''}`,
|
||||
telegram: (d) => `https://telegram.me/share/url?url=${d.url}${d.text ? `&text=${d.text}` : ''}`,
|
||||
tumblr: (d) => `https://www.tumblr.com/widgets/share/tool?posttype=link${d.hashtags ? `&tags=${d.hashtags}` : ''}&title=${d.title}&content=${d.url}&canonicalUrl=${d.url}${d.text ? `&caption=${d.text}` : ''}${d.via ? `&show-via=${d.via}` : ''}`,
|
||||
twitter: (d) => `https://twitter.com/intent/tweet?url=${d.url}&text=${d.title}${d.via ? `&via=${d.via}` : ''}${d.hashtags ? `&hashtags=${d.hashtags}` : ''}`,
|
||||
viber: (d) => `viber://forward?text=${d.title}%0D%0A${d.url}${d.text ? `%0D%0A%0D%0A${d.text}` : ''}`,
|
||||
vkontakte: (d) => `https://vk.com/share.php?url=${d.url}&title=${d.title}${d.media ? `&image=${d.media}` : ''}`,
|
||||
whatsapp: (d) => `https://wa.me/?text=${d.title}%0D%0A${d.url}${d.text ? `%0D%0A%0D%0A${d.text}` : ''}`,
|
||||
};
|
||||
|
||||
const openUrl = (buttonUrl) => () => {
|
||||
window.open(buttonUrl, "_blank", "noopener,noreferrer");
|
||||
facebook: (d) =>
|
||||
buildUrl("https://www.facebook.com/sharer/sharer.php", {
|
||||
u: d.url,
|
||||
hashtag: d.hashtags?.split(",")[0],
|
||||
}),
|
||||
fediverse: (d) =>
|
||||
buildUrl(`https://${d.s2fInstance}`, {
|
||||
text: [d.title, d.url, d.via].filter(Boolean).join("\n\n"),
|
||||
}),
|
||||
email: (d) =>
|
||||
buildUrl("mailto:", {
|
||||
subject: d.title,
|
||||
body: d.url,
|
||||
}),
|
||||
linkedin: (d) =>
|
||||
buildUrl("https://www.linkedin.com/sharing/share-offsite", {
|
||||
url: d.url,
|
||||
}),
|
||||
mastodon: (d) =>
|
||||
buildUrl(`https://${d.s2fInstance}`, {
|
||||
text: [d.title, d.url, d.via].filter(Boolean).join("\n\n"),
|
||||
}),
|
||||
messenger: (d) =>
|
||||
buildUrl(`https://www.facebook.com/dialog/send`, {
|
||||
app_id: d.fbAppId,
|
||||
link: d.url,
|
||||
redirect_uri: d.url,
|
||||
}),
|
||||
odnoklassniki: (d) =>
|
||||
buildUrl("https://connect.ok.ru/offer", {
|
||||
url: d.url,
|
||||
title: d.title,
|
||||
imageUrl: d.media,
|
||||
}),
|
||||
pinterest: (d) =>
|
||||
buildUrl("https://pinterest.com/pin/create/button", {
|
||||
url: d.url,
|
||||
description: d.title,
|
||||
media: d.media,
|
||||
}),
|
||||
pocket: (d) =>
|
||||
buildUrl("https://getpocket.com/edit.php", {
|
||||
url: d.url,
|
||||
}),
|
||||
reddit: (d) =>
|
||||
buildUrl("https://www.reddit.com/submit", {
|
||||
title: d.title,
|
||||
url: d.url,
|
||||
}),
|
||||
teams: (d) =>
|
||||
buildUrl("https://teams.microsoft.com/share", {
|
||||
href: d.url,
|
||||
msgText: d.text,
|
||||
}),
|
||||
telegram: (d) =>
|
||||
buildUrl("https://telegram.me/share/url", {
|
||||
url: d.url,
|
||||
text: d.text,
|
||||
}),
|
||||
tumblr: (d) =>
|
||||
buildUrl("https://www.tumblr.com/widgets/share/tool", {
|
||||
posttype: "link",
|
||||
tags: d.hashtags,
|
||||
title: d.title,
|
||||
content: d.url,
|
||||
canonicalUrl: d.url,
|
||||
caption: d.text,
|
||||
"show-via": d.via,
|
||||
}),
|
||||
twitter: (d) =>
|
||||
buildUrl("https://twitter.com/intent/tweet", {
|
||||
url: d.url,
|
||||
text: d.title,
|
||||
via: d.via,
|
||||
hashtags: d.hashtags,
|
||||
}),
|
||||
viber: (d) =>
|
||||
buildUrl("viber://forward", {
|
||||
text: [d.title, d.url, d.text].filter(Boolean).join("\n\n"),
|
||||
}),
|
||||
vkontakte: (d) =>
|
||||
buildUrl("https://vk.com/share.php", {
|
||||
url: d.url,
|
||||
title: d.title,
|
||||
image: d.media,
|
||||
}),
|
||||
whatsapp: (d) =>
|
||||
buildUrl("https://wa.me", {
|
||||
text: [d.title, d.url, d.text].filter(Boolean).join("\n\n"),
|
||||
}),
|
||||
};
|
||||
|
||||
const init = () => {
|
||||
const shareonContainers = document.querySelectorAll(".shareon");
|
||||
|
||||
// iterate over <div class="shareon">
|
||||
for (const container of shareonContainers) {
|
||||
for (const container of document.querySelectorAll(".shareon")) {
|
||||
// iterate over children of <div class="shareon">
|
||||
for (const child of container.children) {
|
||||
if (child) {
|
||||
const classListLength = child.classList.length;
|
||||
if (!child) continue;
|
||||
|
||||
// iterate over classes of the child element
|
||||
for (let k = 0; k < classListLength; k += 1) {
|
||||
const cls = child.classList.item(k);
|
||||
// iterate over classes of the child element
|
||||
for (const cls of child.classList) {
|
||||
// if it's "Copy URL"
|
||||
if (cls === "copy-url") {
|
||||
child.addEventListener("click", () => {
|
||||
const url =
|
||||
child.dataset.url ||
|
||||
container.dataset.url ||
|
||||
window.location.href;
|
||||
navigator.clipboard.writeText(url);
|
||||
child.classList.add("done");
|
||||
setTimeout(() => {
|
||||
child.classList.remove("done");
|
||||
}, 1000);
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
// if it's "Copy URL"
|
||||
if (cls === "copy-url") {
|
||||
// if it's "Print"
|
||||
if (cls === "print") {
|
||||
child.addEventListener("click", () => {
|
||||
window.print();
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
// if it's "Web Share"
|
||||
if (cls === "web-share") {
|
||||
const data = {
|
||||
title:
|
||||
child.dataset.title || container.dataset.title || document.title,
|
||||
text: child.dataset.text || container.dataset.text || "",
|
||||
url:
|
||||
child.dataset.url ||
|
||||
container.dataset.url ||
|
||||
window.location.href,
|
||||
};
|
||||
|
||||
if (navigator.canShare?.(data)) {
|
||||
child.addEventListener("click", () => {
|
||||
const url =
|
||||
child.dataset.url ||
|
||||
container.dataset.url ||
|
||||
window.location.href;
|
||||
navigator.clipboard.writeText(url);
|
||||
child.classList.add("done");
|
||||
setTimeout(() => {
|
||||
child.classList.remove("done");
|
||||
}, 1000);
|
||||
navigator.share(data);
|
||||
});
|
||||
} else {
|
||||
child.style.display = "none";
|
||||
}
|
||||
}
|
||||
|
||||
// if it's one of the networks
|
||||
if (Object.prototype.hasOwnProperty.call(urlBuilderMap, cls)) {
|
||||
const url = urlBuilderMap[cls]({
|
||||
url: window.location.href,
|
||||
title: document.title,
|
||||
s2fInstance: "s2f.kytta.dev",
|
||||
...container.dataset,
|
||||
...child.dataset,
|
||||
});
|
||||
|
||||
if (child.tagName.toLowerCase() === "a") {
|
||||
child.setAttribute("href", url);
|
||||
child.setAttribute("rel", "noopener noreferrer");
|
||||
child.setAttribute("target", "_blank");
|
||||
} else {
|
||||
child.addEventListener("click", () => {
|
||||
window.open(url, "_blank", "noopener,noreferrer");
|
||||
});
|
||||
}
|
||||
|
||||
// if it's "Print"
|
||||
if (cls === "print") {
|
||||
child.addEventListener("click", () => {
|
||||
window.print();
|
||||
});
|
||||
}
|
||||
|
||||
// if it's "Web Share"
|
||||
if (cls === "web-share") {
|
||||
const data = {
|
||||
title:
|
||||
child.dataset.title ||
|
||||
container.dataset.title ||
|
||||
document.title,
|
||||
text: child.dataset.text || container.dataset.text || "",
|
||||
url:
|
||||
child.dataset.url ||
|
||||
container.dataset.url ||
|
||||
window.location.href,
|
||||
};
|
||||
|
||||
if (navigator.canShare && navigator.canShare(data)) {
|
||||
child.addEventListener("click", () => {
|
||||
navigator.share(data);
|
||||
});
|
||||
} else {
|
||||
child.style.display = "none";
|
||||
}
|
||||
}
|
||||
|
||||
// if it's one of the networks
|
||||
if (Object.prototype.hasOwnProperty.call(urlBuilderMap, cls)) {
|
||||
const preset = {
|
||||
url: encodeURIComponent(
|
||||
child.dataset.url ||
|
||||
container.dataset.url ||
|
||||
window.location.href,
|
||||
),
|
||||
title: encodeURIComponent(
|
||||
child.dataset.title ||
|
||||
container.dataset.title ||
|
||||
document.title,
|
||||
),
|
||||
media: encodeURIComponent(
|
||||
child.dataset.media || container.dataset.media || "",
|
||||
),
|
||||
text: encodeURIComponent(
|
||||
child.dataset.text || container.dataset.text || "",
|
||||
),
|
||||
via: encodeURIComponent(
|
||||
child.dataset.via || container.dataset.via || "",
|
||||
),
|
||||
hashtags: encodeURIComponent(
|
||||
child.dataset.hashtags || container.dataset.hashtags || "",
|
||||
),
|
||||
fbAppId: encodeURIComponent(
|
||||
child.dataset.fbAppId || container.dataset.fbAppId || "",
|
||||
),
|
||||
s2fInstance: encodeURIComponent(
|
||||
child.dataset.s2fInstance ||
|
||||
container.dataset.s2fInstance ||
|
||||
"s2f.kytta.dev",
|
||||
),
|
||||
};
|
||||
const url = urlBuilderMap[cls](preset);
|
||||
|
||||
if (child.tagName.toLowerCase() === "a") {
|
||||
child.setAttribute("href", url);
|
||||
child.setAttribute("rel", "noopener noreferrer");
|
||||
child.setAttribute("target", "_blank");
|
||||
} else {
|
||||
child.addEventListener("click", openUrl(url));
|
||||
}
|
||||
|
||||
break; // once a network is detected we don't want to check further
|
||||
}
|
||||
break; // once a network is detected we don't want to check further
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user