Add file size to link preview

This commit is contained in:
Raqbit 2019-08-09 22:20:08 +02:00
parent 8a224809dd
commit 95cc9a47fb
7 changed files with 98 additions and 32 deletions

View File

@ -0,0 +1,34 @@
<template>
<span class="preview-size">({{ previewSize }})</span>
</template>
<script>
const constants = require("../js/constants");
export default {
name: "LinkPreviewFileSize",
props: {
size: Number,
},
computed: {
previewSize() {
let size = this.size;
// Threshold for SI units
const thresh = 1024;
let u = 0;
do {
size /= thresh;
++u;
} while (size >= thresh && u < constants.sizeUnits.length - 1);
const displaySize = size.toFixed(1);
const unit = constants.sizeUnits[u];
return `${displaySize} ${unit}`;
},
},
};
</script>

View File

@ -1475,6 +1475,11 @@ background on hover (unless active) */
border-left: 1px solid var(--highlight-bg-color); border-left: 1px solid var(--highlight-bg-color);
} }
#chat .preview-size {
margin-left: 5px;
user-select: none;
}
#chat .toggle-content.opened .more-caret, /* Expand/Collapse link previews */ #chat .toggle-content.opened .more-caret, /* Expand/Collapse link previews */
#chat .toggle-button.opened, /* Thumbnail toggle */ #chat .toggle-button.opened, /* Thumbnail toggle */
#chat .msg.condensed:not(.closed) .toggle-button { /* Expanded status message toggle */ #chat .msg.condensed:not(.closed) .toggle-button { /* Expanded status message toggle */

View File

@ -27,10 +27,13 @@ const timeFormats = {
msgWithSeconds: "HH:mm:ss", msgWithSeconds: "HH:mm:ss",
}; };
const sizeUnits = ["B", "KiB", "MiB", "GiB", "TiB"];
module.exports = { module.exports = {
colorCodeMap, colorCodeMap,
commands: [], commands: [],
condensedTypes, condensedTypes,
condensedTypesQuery, condensedTypesQuery,
timeFormats, timeFormats,
sizeUnits,
}; };

View File

@ -9,6 +9,7 @@ const merge = require("./ircmessageparser/merge");
const colorClass = require("./colorClass"); const colorClass = require("./colorClass");
const emojiMap = require("../fullnamemap.json"); const emojiMap = require("../fullnamemap.json");
const LinkPreviewToggle = require("../../../components/LinkPreviewToggle.vue").default; const LinkPreviewToggle = require("../../../components/LinkPreviewToggle.vue").default;
const LinkPreviewFileSize = require("../../../components/LinkPreviewFileSize.vue").default;
const emojiModifiersRegex = /[\u{1f3fb}-\u{1f3ff}]/gu; const emojiModifiersRegex = /[\u{1f3fb}-\u{1f3ff}]/gu;
// Create an HTML `span` with styling information for a given fragment // Create an HTML `span` with styling information for a given fragment
@ -96,12 +97,16 @@ module.exports = function parse(createElement, text, message = undefined, networ
// Wrap these potentially styled fragments with links and channel buttons // Wrap these potentially styled fragments with links and channel buttons
if (textPart.link) { if (textPart.link) {
const preview = message && message.previews.find((p) => p.link === textPart.link); const preview =
message &&
message.previews &&
message.previews.find((p) => p.link === textPart.link);
const link = createElement( const link = createElement(
"a", "a",
{ {
attrs: { attrs: {
href: textPart.link, href: textPart.link,
dir: preview ? null : "auto",
target: "_blank", target: "_blank",
rel: "noopener", rel: "noopener",
}, },
@ -113,6 +118,28 @@ module.exports = function parse(createElement, text, message = undefined, networ
return link; return link;
} }
const linkEls = [link];
if (preview.size > 0) {
linkEls.push(
createElement(LinkPreviewFileSize, {
props: {
size: preview.size,
},
})
);
}
linkEls.push(
createElement(LinkPreviewToggle, {
props: {
link: preview,
},
})
);
// We wrap the link, size, and the toggle button into <span dir="auto">
// to correctly keep the left-to-right order of these elements
return createElement( return createElement(
"span", "span",
{ {
@ -120,19 +147,7 @@ module.exports = function parse(createElement, text, message = undefined, networ
dir: "auto", dir: "auto",
}, },
}, },
[ linkEls
link,
createElement(
LinkPreviewToggle,
{
class: ["toggle-button", "toggle-preview"],
props: {
link: preview,
},
},
fragments
),
]
); );
} else if (textPart.channel) { } else if (textPart.channel) {
return createElement( return createElement(

View File

@ -43,6 +43,7 @@ module.exports = function(client, chan, msg) {
head: "", head: "",
body: "", body: "",
thumb: "", thumb: "",
size: -1,
link: link.link, // Send original matched link to the client link: link.link, // Send original matched link to the client
shown: true, shown: true,
}; };
@ -181,8 +182,11 @@ function parseHtmlMedia($, preview, client) {
function parse(msg, chan, preview, res, client) { function parse(msg, chan, preview, res, client) {
let promise; let promise;
preview.size = res.size;
switch (res.type) { switch (res.type) {
case "text/html": case "text/html":
preview.size = -1;
promise = parseHtml(preview, res, client); promise = parseHtml(preview, res, client);
break; break;

View File

@ -25,7 +25,7 @@ describe("parse Handlebars helper", () => {
{ {
input: "<img onerror='location.href=\"//youtube.com\"'>", input: "<img onerror='location.href=\"//youtube.com\"'>",
expected: expected:
'&lt;img onerror=\'location.href=&quot;<a href="http://youtube.com" target="_blank" rel="noopener">//youtube.com</a>&quot;\'&gt;', '&lt;img onerror=\'location.href=&quot;<a href="http://youtube.com" dir="auto" target="_blank" rel="noopener">//youtube.com</a>&quot;\'&gt;',
}, },
{ {
input: '#&">bug', input: '#&">bug',
@ -61,14 +61,14 @@ describe("parse Handlebars helper", () => {
{ {
input: "irc://freenode.net/thelounge", input: "irc://freenode.net/thelounge",
expected: expected:
'<a href="irc://freenode.net/thelounge" target="_blank" rel="noopener">' + '<a href="irc://freenode.net/thelounge" dir="auto" target="_blank" rel="noopener">' +
"irc://freenode.net/thelounge" + "irc://freenode.net/thelounge" +
"</a>", "</a>",
}, },
{ {
input: "www.nooooooooooooooo.com", input: "www.nooooooooooooooo.com",
expected: expected:
'<a href="http://www.nooooooooooooooo.com" target="_blank" rel="noopener">' + '<a href="http://www.nooooooooooooooo.com" dir="auto" target="_blank" rel="noopener">' +
"www.nooooooooooooooo.com" + "www.nooooooooooooooo.com" +
"</a>", "</a>",
}, },
@ -76,7 +76,7 @@ describe("parse Handlebars helper", () => {
input: "look at https://thelounge.chat/ for more information", input: "look at https://thelounge.chat/ for more information",
expected: expected:
"look at " + "look at " +
'<a href="https://thelounge.chat/" target="_blank" rel="noopener">' + '<a href="https://thelounge.chat/" dir="auto" target="_blank" rel="noopener">' +
"https://thelounge.chat/" + "https://thelounge.chat/" +
"</a>" + "</a>" +
" for more information", " for more information",
@ -85,7 +85,7 @@ describe("parse Handlebars helper", () => {
input: "use www.duckduckgo.com for privacy reasons", input: "use www.duckduckgo.com for privacy reasons",
expected: expected:
"use " + "use " +
'<a href="http://www.duckduckgo.com" target="_blank" rel="noopener">' + '<a href="http://www.duckduckgo.com" dir="auto" target="_blank" rel="noopener">' +
"www.duckduckgo.com" + "www.duckduckgo.com" +
"</a>" + "</a>" +
" for privacy reasons", " for privacy reasons",
@ -93,7 +93,7 @@ describe("parse Handlebars helper", () => {
{ {
input: "svn+ssh://example.org", input: "svn+ssh://example.org",
expected: expected:
'<a href="svn+ssh://example.org" target="_blank" rel="noopener">' + '<a href="svn+ssh://example.org" dir="auto" target="_blank" rel="noopener">' +
"svn+ssh://example.org" + "svn+ssh://example.org" +
"</a>", "</a>",
}, },
@ -110,7 +110,7 @@ describe("parse Handlebars helper", () => {
"bonuspunkt: your URL parser misparses this URL: https://msdn.microsoft.com/en-us/library/windows/desktop/ms644989(v=vs.85).aspx"; "bonuspunkt: your URL parser misparses this URL: https://msdn.microsoft.com/en-us/library/windows/desktop/ms644989(v=vs.85).aspx";
const correctResult = const correctResult =
"bonuspunkt: your URL parser misparses this URL: " + "bonuspunkt: your URL parser misparses this URL: " +
'<a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms644989(v=vs.85).aspx" target="_blank" rel="noopener">' + '<a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms644989(v=vs.85).aspx" dir="auto" target="_blank" rel="noopener">' +
"https://msdn.microsoft.com/en-us/library/windows/desktop/ms644989(v=vs.85).aspx" + "https://msdn.microsoft.com/en-us/library/windows/desktop/ms644989(v=vs.85).aspx" +
"</a>"; "</a>";
@ -125,7 +125,7 @@ describe("parse Handlebars helper", () => {
input: "<https://theos.kyriasis.com/~kyrias/stats/archlinux.html>", input: "<https://theos.kyriasis.com/~kyrias/stats/archlinux.html>",
expected: expected:
"&lt;" + "&lt;" +
'<a href="https://theos.kyriasis.com/~kyrias/stats/archlinux.html" target="_blank" rel="noopener">' + '<a href="https://theos.kyriasis.com/~kyrias/stats/archlinux.html" dir="auto" target="_blank" rel="noopener">' +
"https://theos.kyriasis.com/~kyrias/stats/archlinux.html" + "https://theos.kyriasis.com/~kyrias/stats/archlinux.html" +
"</a>" + "</a>" +
"&gt;", "&gt;",
@ -134,7 +134,7 @@ describe("parse Handlebars helper", () => {
input: "abc (www.example.com)", input: "abc (www.example.com)",
expected: expected:
"abc (" + "abc (" +
'<a href="http://www.example.com" target="_blank" rel="noopener">' + '<a href="http://www.example.com" dir="auto" target="_blank" rel="noopener">' +
"www.example.com" + "www.example.com" +
"</a>" + "</a>" +
")", ")",
@ -142,14 +142,14 @@ describe("parse Handlebars helper", () => {
{ {
input: "http://example.com/Test_(Page)", input: "http://example.com/Test_(Page)",
expected: expected:
'<a href="http://example.com/Test_(Page)" target="_blank" rel="noopener">' + '<a href="http://example.com/Test_(Page)" dir="auto" target="_blank" rel="noopener">' +
"http://example.com/Test_(Page)" + "http://example.com/Test_(Page)" +
"</a>", "</a>",
}, },
{ {
input: "www.example.com/Test_(Page)", input: "www.example.com/Test_(Page)",
expected: expected:
'<a href="http://www.example.com/Test_(Page)" target="_blank" rel="noopener">' + '<a href="http://www.example.com/Test_(Page)" dir="auto" target="_blank" rel="noopener">' +
"www.example.com/Test_(Page)" + "www.example.com/Test_(Page)" +
"</a>", "</a>",
}, },
@ -386,7 +386,7 @@ describe("parse Handlebars helper", () => {
users: ["MaxLeiter, test"], users: ["MaxLeiter, test"],
input: "https://www.MaxLeiter.com/test", input: "https://www.MaxLeiter.com/test",
expected: expected:
'<a href="https://www.MaxLeiter.com/test" target="_blank" rel="noopener">' + '<a href="https://www.MaxLeiter.com/test" dir="auto" target="_blank" rel="noopener">' +
"https://www.MaxLeiter.com/test" + "https://www.MaxLeiter.com/test" +
"</a>", "</a>",
}, },
@ -403,7 +403,7 @@ describe("parse Handlebars helper", () => {
{ {
input: "\x02irc\x0f://\x1dfreenode.net\x0f/\x034,8thelounge", input: "\x02irc\x0f://\x1dfreenode.net\x0f/\x034,8thelounge",
expected: expected:
'<a href="irc://freenode.net/thelounge" target="_blank" rel="noopener">' + '<a href="irc://freenode.net/thelounge" dir="auto" target="_blank" rel="noopener">' +
'<span class="irc-bold">irc</span>' + '<span class="irc-bold">irc</span>' +
"://" + "://" +
'<span class="irc-italic">freenode.net</span>' + '<span class="irc-italic">freenode.net</span>' +
@ -470,7 +470,7 @@ describe("parse Handlebars helper", () => {
input: "https://i.❤️.thelounge.chat", input: "https://i.❤️.thelounge.chat",
// FIXME: Emoji in text should be `<span class="emoji">❤️</span>`. See https://github.com/thelounge/thelounge/issues/1784 // FIXME: Emoji in text should be `<span class="emoji">❤️</span>`. See https://github.com/thelounge/thelounge/issues/1784
expected: expected:
'<a href="https://i.❤️.thelounge.chat" target="_blank" rel="noopener">https://i.❤️.thelounge.chat</a>', '<a href="https://i.❤️.thelounge.chat" dir="auto" target="_blank" rel="noopener">https://i.❤️.thelounge.chat</a>',
}, },
{ {
name: "wrapped in channels", name: "wrapped in channels",
@ -511,7 +511,7 @@ describe("parse Handlebars helper", () => {
input: "like..http://example.com", input: "like..http://example.com",
expected: expected:
"like.." + "like.." +
'<a href="http://example.com" target="_blank" rel="noopener">' + '<a href="http://example.com" dir="auto" target="_blank" rel="noopener">' +
"http://example.com" + "http://example.com" +
"</a>", "</a>",
}, },
@ -519,7 +519,7 @@ describe("parse Handlebars helper", () => {
input: "like..HTTP://example.com", input: "like..HTTP://example.com",
expected: expected:
"like.." + "like.." +
'<a href="HTTP://example.com" target="_blank" rel="noopener">' + '<a href="HTTP://example.com" dir="auto" target="_blank" rel="noopener">' +
"HTTP://example.com" + "HTTP://example.com" +
"</a>", "</a>",
}, },
@ -536,7 +536,7 @@ describe("parse Handlebars helper", () => {
{ {
input: "http://example.com/#hash", input: "http://example.com/#hash",
expected: expected:
'<a href="http://example.com/#hash" target="_blank" rel="noopener">' + '<a href="http://example.com/#hash" dir="auto" target="_blank" rel="noopener">' +
"http://example.com/#hash" + "http://example.com/#hash" +
"</a>", "</a>",
}, },
@ -553,7 +553,7 @@ describe("parse Handlebars helper", () => {
const actual = getParsedMessageContents(input); const actual = getParsedMessageContents(input);
expect(actual).to.equal( expect(actual).to.equal(
'Url: <a href="http://example.com/path" target="_blank" rel="noopener">http://example.com/path</a> ' + 'Url: <a href="http://example.com/path" dir="auto" target="_blank" rel="noopener">http://example.com/path</a> ' +
'Channel: <span role="button" dir="auto" tabindex="0" data-chan="##channel" class="inline-channel">##channel</span>' 'Channel: <span role="button" dir="auto" tabindex="0" data-chan="##channel" class="inline-channel">##channel</span>'
); );
}); });

View File

@ -45,6 +45,7 @@ describe("Link plugin", function() {
head: "", head: "",
link: url, link: url,
thumb: "", thumb: "",
size: -1,
type: "loading", type: "loading",
shown: true, shown: true,
}, },
@ -278,6 +279,7 @@ describe("Link plugin", function() {
expect(data.preview.thumb).to.equal( expect(data.preview.thumb).to.equal(
"http://localhost:" + port + "/real-test-image.png" "http://localhost:" + port + "/real-test-image.png"
); );
expect(data.preview.size).to.equal(960);
done(); done();
}); });
}); });
@ -296,6 +298,7 @@ describe("Link plugin", function() {
head: "", head: "",
link: "http://localhost:" + port + "/one", link: "http://localhost:" + port + "/one",
thumb: "", thumb: "",
size: -1,
type: "loading", type: "loading",
shown: true, shown: true,
}, },
@ -304,6 +307,7 @@ describe("Link plugin", function() {
head: "", head: "",
link: "http://localhost:" + port + "/two", link: "http://localhost:" + port + "/two",
thumb: "", thumb: "",
size: -1,
type: "loading", type: "loading",
shown: true, shown: true,
}, },
@ -496,6 +500,7 @@ describe("Link plugin", function() {
head: "", head: "",
body: "", body: "",
thumb: "", thumb: "",
size: -1,
link: "http://localhost:" + port + "", link: "http://localhost:" + port + "",
shown: true, shown: true,
}, },