Skip to content

Commit e3b1aa5

Browse files
kyttavladimyr
andcommitted
WIP first draft of url builder
Closes #61 Co-authored-by: Dario Vladovic <d.vladimyr@gmail.com>
1 parent ded589c commit e3b1aa5

File tree

1 file changed

+183
-123
lines changed

1 file changed

+183
-123
lines changed

src/shareon.js

+183-123
Original file line numberDiff line numberDiff line change
@@ -1,149 +1,209 @@
1-
// prettier-ignore
1+
/**
2+
* @typedef PublishPreset
3+
*
4+
* @property {string} url
5+
* @property {string} [title]
6+
* @property {string} [media]
7+
* @property {string} [text]
8+
* @property {string} [via]
9+
* @property {string} [hashtags]
10+
* @property {string} [fbAppId]
11+
* @property {string} [s2fInstance]
12+
*/
13+
14+
/**
15+
* Creates a URL that a button will point to.
16+
*
17+
* @param {string} baseUrl [description]
18+
* @param {Record<string, string | undefined>} parameters [description]
19+
* @return {string} [description]
20+
*/
21+
const buildUrl = (baseUrl, parameters) => {
22+
const url = new URL(baseUrl);
23+
for (const [parameter, value] of Object.entries(parameters)) {
24+
if (value) {
25+
url.searchParams.append(parameter, value);
26+
}
27+
}
28+
29+
return url.href;
30+
};
31+
232
/**
333
* Map of social networks to their respective URL builders.
434
*
535
* The `d` argument of each builder is the object with the page metadata, such
636
* as page title, URL, author name, etc.
737
*
8-
* @type {{ [network: string]: (d: {
9-
* url: string,
10-
* title?: string,
11-
* media?: string,
12-
* text?: string,
13-
* via?: string,
14-
* fbAppId?: string,
15-
* s2fInstance?: string,
16-
* }) => string}}
38+
* @type {{ [network: string]: (d: PublishPreset) => URL}}
1739
*/
1840
const urlBuilderMap = {
19-
facebook: (d) => `https://www.facebook.com/sharer/sharer.php?u=${d.url}${d.hashtags ? `&hashtag=%23${d.hashtags.split('%2C')[0]}` : ''}`,
20-
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}` : ''}`,
21-
email: (d) => `mailto:?subject=${d.title}&body=${d.url}`,
22-
linkedin: (d) => `https://www.linkedin.com/sharing/share-offsite/?url=${d.url}`,
23-
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}` : ''}`,
24-
messenger: (d) => `https://www.facebook.com/dialog/send?app_id=${d.fbAppId}&link=${d.url}&redirect_uri=${d.url}`,
25-
odnoklassniki: (d) => `https://connect.ok.ru/offer?url=${d.url}&title=${d.title}${d.media ? `&imageUrl=${d.media}` : ''}`,
26-
pinterest: (d) => `https://pinterest.com/pin/create/button/?url=${d.url}&description=${d.title}${d.media ? `&media=${d.media}` : ''}`,
27-
pocket: (d) => `https://getpocket.com/edit.php?url=${d.url}`,
28-
reddit: (d) => `https://www.reddit.com/submit?title=${d.title}&url=${d.url}`,
29-
teams: (d) => `https://teams.microsoft.com/share?href=${d.url}${d.text ? `&msgText=${d.text}` : ''}`,
30-
telegram: (d) => `https://telegram.me/share/url?url=${d.url}${d.text ? `&text=${d.text}` : ''}`,
31-
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}` : ''}`,
32-
twitter: (d) => `https://twitter.com/intent/tweet?url=${d.url}&text=${d.title}${d.via ? `&via=${d.via}` : ''}${d.hashtags ? `&hashtags=${d.hashtags}` : ''}`,
33-
viber: (d) => `viber://forward?text=${d.title}%0D%0A${d.url}${d.text ? `%0D%0A%0D%0A${d.text}` : ''}`,
34-
vkontakte: (d) => `https://vk.com/share.php?url=${d.url}&title=${d.title}${d.media ? `&image=${d.media}` : ''}`,
35-
whatsapp: (d) => `https://wa.me/?text=${d.title}%0D%0A${d.url}${d.text ? `%0D%0A%0D%0A${d.text}` : ''}`,
36-
};
37-
38-
const openUrl = (buttonUrl) => () => {
39-
window.open(buttonUrl, "_blank", "noopener,noreferrer");
41+
facebook: (d) =>
42+
buildUrl("https://www.facebook.com/sharer/sharer.php", {
43+
u: d.url,
44+
hashtag: d.hashtags?.split(",")[0],
45+
}),
46+
fediverse: (d) =>
47+
buildUrl(`https://${d.s2fInstance}`, {
48+
text: [d.title, d.url, d.via].filter(Boolean).join("\n\n"),
49+
}),
50+
email: (d) =>
51+
buildUrl("mailto:", {
52+
subject: d.title,
53+
body: d.url,
54+
}),
55+
linkedin: (d) =>
56+
buildUrl("https://www.linkedin.com/sharing/share-offsite", {
57+
url: d.url,
58+
}),
59+
mastodon: (d) =>
60+
buildUrl(`https://${d.s2fInstance}`, {
61+
text: [d.title, d.url, d.via].filter(Boolean).join("\n\n"),
62+
}),
63+
messenger: (d) =>
64+
buildUrl(`https://www.facebook.com/dialog/send`, {
65+
app_id: d.fbAppId,
66+
link: d.url,
67+
redirect_uri: d.url,
68+
}),
69+
odnoklassniki: (d) =>
70+
buildUrl("https://connect.ok.ru/offer", {
71+
url: d.url,
72+
title: d.title,
73+
imageUrl: d.media,
74+
}),
75+
pinterest: (d) =>
76+
buildUrl("https://pinterest.com/pin/create/button", {
77+
url: d.url,
78+
description: d.title,
79+
media: d.media,
80+
}),
81+
pocket: (d) =>
82+
buildUrl("https://getpocket.com/edit.php", {
83+
url: d.url,
84+
}),
85+
reddit: (d) =>
86+
buildUrl("https://www.reddit.com/submit", {
87+
title: d.title,
88+
url: d.url,
89+
}),
90+
teams: (d) =>
91+
buildUrl("https://teams.microsoft.com/share", {
92+
href: d.url,
93+
msgText: d.text,
94+
}),
95+
telegram: (d) =>
96+
buildUrl("https://telegram.me/share/url", {
97+
url: d.url,
98+
text: d.text,
99+
}),
100+
tumblr: (d) =>
101+
buildUrl("https://www.tumblr.com/widgets/share/tool", {
102+
posttype: "link",
103+
tags: d.hashtags,
104+
title: d.title,
105+
content: d.url,
106+
canonicalUrl: d.url,
107+
caption: d.text,
108+
"show-via": d.via,
109+
}),
110+
twitter: (d) =>
111+
buildUrl("https://twitter.com/intent/tweet", {
112+
url: d.url,
113+
text: d.title,
114+
via: d.via,
115+
hashtags: d.hashtags,
116+
}),
117+
viber: (d) =>
118+
buildUrl("viber://forward", {
119+
text: [d.title, d.url, d.text].filter(Boolean).join("\n\n"),
120+
}),
121+
vkontakte: (d) =>
122+
buildUrl("https://vk.com/share.php", {
123+
url: d.url,
124+
title: d.title,
125+
image: d.media,
126+
}),
127+
whatsapp: (d) =>
128+
buildUrl("https://wa.me", {
129+
text: [d.title, d.url, d.text].filter(Boolean).join("\n\n"),
130+
}),
40131
};
41132

42133
const init = () => {
43-
const shareonContainers = document.querySelectorAll(".shareon");
44-
45134
// iterate over <div class="shareon">
46-
for (const container of shareonContainers) {
135+
for (const container of document.querySelectorAll(".shareon")) {
47136
// iterate over children of <div class="shareon">
48137
for (const child of container.children) {
49-
if (child) {
50-
const classListLength = child.classList.length;
138+
if (!child) continue;
51139

52-
// iterate over classes of the child element
53-
for (let k = 0; k < classListLength; k += 1) {
54-
const cls = child.classList.item(k);
140+
// iterate over classes of the child element
141+
for (const cls of child.classList) {
142+
// if it's "Copy URL"
143+
if (cls === "copy-url") {
144+
child.addEventListener("click", () => {
145+
const url =
146+
child.dataset.url ||
147+
container.dataset.url ||
148+
window.location.href;
149+
navigator.clipboard.writeText(url);
150+
child.classList.add("done");
151+
setTimeout(() => {
152+
child.classList.remove("done");
153+
}, 1000);
154+
});
155+
break;
156+
}
55157

56-
// if it's "Copy URL"
57-
if (cls === "copy-url") {
58-
child.addEventListener("click", () => {
59-
const url =
60-
child.dataset.url ||
61-
container.dataset.url ||
62-
window.location.href;
63-
navigator.clipboard.writeText(url);
64-
child.classList.add("done");
65-
setTimeout(() => {
66-
child.classList.remove("done");
67-
}, 1000);
68-
});
69-
}
158+
// if it's "Print"
159+
if (cls === "print") {
160+
child.addEventListener("click", () => {
161+
window.print();
162+
});
163+
break;
164+
}
165+
166+
// if it's "Web Share"
167+
if (cls === "web-share") {
168+
const data = {
169+
title:
170+
child.dataset.title || container.dataset.title || document.title,
171+
text: child.dataset.text || container.dataset.text || "",
172+
url:
173+
child.dataset.url ||
174+
container.dataset.url ||
175+
window.location.href,
176+
};
70177

71-
// if it's "Print"
72-
if (cls === "print") {
178+
if (navigator.canShare?.(data)) {
73179
child.addEventListener("click", () => {
74-
window.print();
180+
navigator.share(data);
75181
});
182+
} else {
183+
child.style.display = "none";
76184
}
185+
}
77186

78-
// if it's "Web Share"
79-
if (cls === "web-share") {
80-
const data = {
81-
title:
82-
child.dataset.title ||
83-
container.dataset.title ||
84-
document.title,
85-
text: child.dataset.text || container.dataset.text || "",
86-
url:
87-
child.dataset.url ||
88-
container.dataset.url ||
89-
window.location.href,
90-
};
91-
92-
if (navigator.canShare && navigator.canShare(data)) {
93-
child.addEventListener("click", () => {
94-
navigator.share(data);
95-
});
96-
} else {
97-
child.style.display = "none";
98-
}
99-
}
100-
101-
// if it's one of the networks
102-
if (Object.prototype.hasOwnProperty.call(urlBuilderMap, cls)) {
103-
const preset = {
104-
url: encodeURIComponent(
105-
child.dataset.url ||
106-
container.dataset.url ||
107-
window.location.href,
108-
),
109-
title: encodeURIComponent(
110-
child.dataset.title ||
111-
container.dataset.title ||
112-
document.title,
113-
),
114-
media: encodeURIComponent(
115-
child.dataset.media || container.dataset.media || "",
116-
),
117-
text: encodeURIComponent(
118-
child.dataset.text || container.dataset.text || "",
119-
),
120-
via: encodeURIComponent(
121-
child.dataset.via || container.dataset.via || "",
122-
),
123-
hashtags: encodeURIComponent(
124-
child.dataset.hashtags || container.dataset.hashtags || "",
125-
),
126-
fbAppId: encodeURIComponent(
127-
child.dataset.fbAppId || container.dataset.fbAppId || "",
128-
),
129-
s2fInstance: encodeURIComponent(
130-
child.dataset.s2fInstance ||
131-
container.dataset.s2fInstance ||
132-
"s2f.kytta.dev",
133-
),
134-
};
135-
const url = urlBuilderMap[cls](preset);
136-
137-
if (child.tagName.toLowerCase() === "a") {
138-
child.setAttribute("href", url);
139-
child.setAttribute("rel", "noopener noreferrer");
140-
child.setAttribute("target", "_blank");
141-
} else {
142-
child.addEventListener("click", openUrl(url));
143-
}
187+
// if it's one of the networks
188+
if (Object.prototype.hasOwnProperty.call(urlBuilderMap, cls)) {
189+
const url = urlBuilderMap[cls]({
190+
url: window.location.href,
191+
title: document.title,
192+
s2fInstance: "s2f.kytta.dev",
193+
...container.dataset,
194+
...child.dataset,
195+
});
144196

145-
break; // once a network is detected we don't want to check further
197+
if (child.tagName.toLowerCase() === "a") {
198+
child.setAttribute("href", url);
199+
child.setAttribute("rel", "noopener noreferrer");
200+
child.setAttribute("target", "_blank");
201+
} else {
202+
child.addEventListener("click", () => {
203+
window.open(url, "_blank", "noopener,noreferrer");
204+
});
146205
}
206+
break; // once a network is detected we don't want to check further
147207
}
148208
}
149209
}

0 commit comments

Comments
 (0)