Move preview toggle buttons next to their respective URLs and switch from ellipsis to caret
This commit is contained in:
parent
64ebe0f437
commit
28200830ed
@ -205,6 +205,7 @@ kbd {
|
|||||||
#chat .whois .from:before,
|
#chat .whois .from:before,
|
||||||
#chat .nick .from:before,
|
#chat .nick .from:before,
|
||||||
#chat .action .from:before,
|
#chat .action .from:before,
|
||||||
|
#chat .toggle-button:after,
|
||||||
.context-menu-item:before,
|
.context-menu-item:before,
|
||||||
#nick button:before {
|
#nick button:before {
|
||||||
font: normal normal normal 14px/1 FontAwesome;
|
font: normal normal normal 14px/1 FontAwesome;
|
||||||
@ -293,6 +294,16 @@ kbd {
|
|||||||
content: "\f005"; /* http://fontawesome.io/icon/star/ */
|
content: "\f005"; /* http://fontawesome.io/icon/star/ */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#chat .toggle-button {
|
||||||
|
/* These 2 directives are loosely taken from .fa-fw */
|
||||||
|
width: 1.35em;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#chat .toggle-button:after {
|
||||||
|
content: "\f0da"; /* http://fontawesome.io/icon/caret-right/ */
|
||||||
|
}
|
||||||
|
|
||||||
#chat .count:before {
|
#chat .count:before {
|
||||||
color: #cfcfcf;
|
color: #cfcfcf;
|
||||||
content: "\f002"; /* http://fontawesome.io/icon/search/ */
|
content: "\f002"; /* http://fontawesome.io/icon/search/ */
|
||||||
@ -1097,17 +1108,18 @@ kbd {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#chat .toggle-button {
|
#chat .toggle-button {
|
||||||
background: #f5f5f5;
|
|
||||||
border-radius: 2px;
|
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
color: #666;
|
color: #666;
|
||||||
height: 1em;
|
transition: color .2s, transform .2s;
|
||||||
line-height: 0;
|
|
||||||
padding: 0 6px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#chat .toggle-button:after {
|
#chat .toggle-button.opened {
|
||||||
content: "···";
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
#chat .toggle-button:hover {
|
||||||
|
/* transform and opacity together glitch, so need to use RGBA transition */
|
||||||
|
color: rgba(102, 102, 102, .8); /* #666 x .8 opacity */
|
||||||
}
|
}
|
||||||
|
|
||||||
#chat .toggle-content {
|
#chat .toggle-content {
|
||||||
@ -1118,7 +1130,7 @@ kbd {
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
padding: 6px;
|
padding: 6px;
|
||||||
margin-top: 2px;
|
margin: 2px 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,6 +83,6 @@ module.exports = function parse(text) {
|
|||||||
return fragments;
|
return fragments;
|
||||||
}).join("") + linkParts.map((part) => {
|
}).join("") + linkParts.map((part) => {
|
||||||
const escapedLink = Handlebars.Utils.escapeExpression(part.link);
|
const escapedLink = Handlebars.Utils.escapeExpression(part.link);
|
||||||
return `<div data-url="${escapedLink}"></div>`;
|
return `<div class="preview" data-url="${escapedLink}"></div>`;
|
||||||
}).join("");
|
}).join("");
|
||||||
};
|
};
|
||||||
|
@ -16,7 +16,11 @@ function renderPreview(preview, msg) {
|
|||||||
bottom = container.isScrollBottom();
|
bottom = container.isScrollBottom();
|
||||||
}
|
}
|
||||||
|
|
||||||
msg.find(`[data-url="${preview.link}"]`)
|
msg.find(`.text a[href="${preview.link}"]`)
|
||||||
|
.first()
|
||||||
|
.after(templates.msg_preview_toggle({preview: preview}));
|
||||||
|
|
||||||
|
msg.find(`.preview[data-url="${preview.link}"]`)
|
||||||
.first()
|
.first()
|
||||||
.append(templates.msg_preview({preview: preview}));
|
.append(templates.msg_preview({preview: preview}));
|
||||||
|
|
||||||
@ -30,13 +34,15 @@ function renderPreview(preview, msg) {
|
|||||||
$("#chat").on("click", ".toggle-button", function() {
|
$("#chat").on("click", ".toggle-button", function() {
|
||||||
const self = $(this);
|
const self = $(this);
|
||||||
const container = self.closest(".chat");
|
const container = self.closest(".chat");
|
||||||
const content = self.parent().next(".toggle-content");
|
const content = self.closest(".text")
|
||||||
|
.find(`.preview[data-url="${self.data("url")}"] .toggle-content`);
|
||||||
const bottom = container.isScrollBottom();
|
const bottom = container.isScrollBottom();
|
||||||
|
|
||||||
if (bottom && !content.hasClass("show")) {
|
if (bottom && !content.hasClass("show")) {
|
||||||
handleImageInPreview(content, container);
|
handleImageInPreview(content, container);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.toggleClass("opened");
|
||||||
content.toggleClass("show");
|
content.toggleClass("show");
|
||||||
|
|
||||||
// If scrollbar was at the bottom before toggling the preview, keep it at the bottom
|
// If scrollbar was at the bottom before toggling the preview, keep it at the bottom
|
||||||
|
@ -26,6 +26,7 @@ module.exports = {
|
|||||||
msg: require("./msg.tpl"),
|
msg: require("./msg.tpl"),
|
||||||
msg_action: require("./msg_action.tpl"),
|
msg_action: require("./msg_action.tpl"),
|
||||||
msg_preview: require("./msg_preview.tpl"),
|
msg_preview: require("./msg_preview.tpl"),
|
||||||
|
msg_preview_toggle: require("./msg_preview_toggle.tpl"),
|
||||||
msg_unhandled: require("./msg_unhandled.tpl"),
|
msg_unhandled: require("./msg_unhandled.tpl"),
|
||||||
network: require("./network.tpl"),
|
network: require("./network.tpl"),
|
||||||
unread_marker: require("./unread_marker.tpl"),
|
unread_marker: require("./unread_marker.tpl"),
|
||||||
|
@ -1,7 +1,4 @@
|
|||||||
{{#preview}}
|
{{#preview}}
|
||||||
<div>
|
|
||||||
<button class="toggle-button" aria-label="Toggle prefetched media"></button>
|
|
||||||
</div>
|
|
||||||
<a href="{{link}}" target="_blank" rel="noopener" class="toggle-content toggle-type-{{type}}{{#if shown}} show{{/if}}">
|
<a href="{{link}}" target="_blank" rel="noopener" class="toggle-content toggle-type-{{type}}{{#if shown}} show{{/if}}">
|
||||||
{{#equal type "image"}}
|
{{#equal type "image"}}
|
||||||
<img src="{{link}}">
|
<img src="{{link}}">
|
||||||
|
10
client/views/msg_preview_toggle.tpl
Normal file
10
client/views/msg_preview_toggle.tpl
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{{#preview}}
|
||||||
|
<button class="toggle-button {{#if shown}} opened{{/if}}"
|
||||||
|
data-url="{{link}}"
|
||||||
|
{{#equal type "image"}}
|
||||||
|
aria-label="Toggle image preview"
|
||||||
|
{{else}}
|
||||||
|
aria-label="Toggle website preview"
|
||||||
|
{{/equal}}
|
||||||
|
></button>
|
||||||
|
{{/preview}}
|
@ -38,14 +38,14 @@ describe("parse Handlebars helper", () => {
|
|||||||
"<a href=\"irc://freenode.net/thelounge\" target=\"_blank\" rel=\"noopener\">" +
|
"<a href=\"irc://freenode.net/thelounge\" target=\"_blank\" rel=\"noopener\">" +
|
||||||
"irc://freenode.net/thelounge" +
|
"irc://freenode.net/thelounge" +
|
||||||
"</a>" +
|
"</a>" +
|
||||||
"<div data-url=\"irc://freenode.net/thelounge\"></div>"
|
"<div class=\"preview\" data-url=\"irc://freenode.net/thelounge\"></div>"
|
||||||
}, {
|
}, {
|
||||||
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\" target=\"_blank\" rel=\"noopener\">" +
|
||||||
"www.nooooooooooooooo.com" +
|
"www.nooooooooooooooo.com" +
|
||||||
"</a>" +
|
"</a>" +
|
||||||
"<div data-url=\"http://www.nooooooooooooooo.com\"></div>"
|
"<div class=\"preview\" data-url=\"http://www.nooooooooooooooo.com\"></div>"
|
||||||
}, {
|
}, {
|
||||||
input: "look at https://thelounge.github.io/ for more information",
|
input: "look at https://thelounge.github.io/ for more information",
|
||||||
expected:
|
expected:
|
||||||
@ -54,7 +54,7 @@ describe("parse Handlebars helper", () => {
|
|||||||
"https://thelounge.github.io/" +
|
"https://thelounge.github.io/" +
|
||||||
"</a>" +
|
"</a>" +
|
||||||
" for more information" +
|
" for more information" +
|
||||||
"<div data-url=\"https://thelounge.github.io/\"></div>"
|
"<div class=\"preview\" data-url=\"https://thelounge.github.io/\"></div>"
|
||||||
}, {
|
}, {
|
||||||
input: "use www.duckduckgo.com for privacy reasons",
|
input: "use www.duckduckgo.com for privacy reasons",
|
||||||
expected:
|
expected:
|
||||||
@ -63,14 +63,14 @@ describe("parse Handlebars helper", () => {
|
|||||||
"www.duckduckgo.com" +
|
"www.duckduckgo.com" +
|
||||||
"</a>" +
|
"</a>" +
|
||||||
" for privacy reasons" +
|
" for privacy reasons" +
|
||||||
"<div data-url=\"http://www.duckduckgo.com\"></div>"
|
"<div class=\"preview\" data-url=\"http://www.duckduckgo.com\"></div>"
|
||||||
}, {
|
}, {
|
||||||
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\" target=\"_blank\" rel=\"noopener\">" +
|
||||||
"svn+ssh://example.org" +
|
"svn+ssh://example.org" +
|
||||||
"</a>" +
|
"</a>" +
|
||||||
"<div data-url=\"svn+ssh://example.org\"></div>"
|
"<div class=\"preview\" data-url=\"svn+ssh://example.org\"></div>"
|
||||||
}, {
|
}, {
|
||||||
input: "https://example.com https://example.org",
|
input: "https://example.com https://example.org",
|
||||||
expected:
|
expected:
|
||||||
@ -80,8 +80,8 @@ describe("parse Handlebars helper", () => {
|
|||||||
"<a href=\"https://example.org\" target=\"_blank\" rel=\"noopener\">" +
|
"<a href=\"https://example.org\" target=\"_blank\" rel=\"noopener\">" +
|
||||||
"https://example.org" +
|
"https://example.org" +
|
||||||
"</a>" +
|
"</a>" +
|
||||||
"<div data-url=\"https://example.com\"></div>" +
|
"<div class=\"preview\" data-url=\"https://example.com\"></div>" +
|
||||||
"<div data-url=\"https://example.org\"></div>"
|
"<div class=\"preview\" data-url=\"https://example.org\"></div>"
|
||||||
}];
|
}];
|
||||||
|
|
||||||
const actual = testCases.map((testCase) => parse(testCase.input));
|
const actual = testCases.map((testCase) => parse(testCase.input));
|
||||||
@ -98,7 +98,7 @@ describe("parse Handlebars helper", () => {
|
|||||||
"<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\" 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>" +
|
||||||
"<div data-url=\"https://msdn.microsoft.com/en-us/library/windows/desktop/ms644989(v=vs.85).aspx\"></div>";
|
"<div class=\"preview\" data-url=\"https://msdn.microsoft.com/en-us/library/windows/desktop/ms644989(v=vs.85).aspx\"></div>";
|
||||||
|
|
||||||
const actual = parse(input);
|
const actual = parse(input);
|
||||||
|
|
||||||
@ -114,7 +114,7 @@ describe("parse Handlebars helper", () => {
|
|||||||
"https://theos.kyriasis.com/~kyrias/stats/archlinux.html" +
|
"https://theos.kyriasis.com/~kyrias/stats/archlinux.html" +
|
||||||
"</a>" +
|
"</a>" +
|
||||||
">" +
|
">" +
|
||||||
"<div data-url=\"https://theos.kyriasis.com/~kyrias/stats/archlinux.html\"></div>"
|
"<div class=\"preview\" data-url=\"https://theos.kyriasis.com/~kyrias/stats/archlinux.html\"></div>"
|
||||||
}, {
|
}, {
|
||||||
input: "abc (www.example.com)",
|
input: "abc (www.example.com)",
|
||||||
expected:
|
expected:
|
||||||
@ -123,21 +123,21 @@ describe("parse Handlebars helper", () => {
|
|||||||
"www.example.com" +
|
"www.example.com" +
|
||||||
"</a>" +
|
"</a>" +
|
||||||
")" +
|
")" +
|
||||||
"<div data-url=\"http://www.example.com\"></div>"
|
"<div class=\"preview\" data-url=\"http://www.example.com\"></div>"
|
||||||
}, {
|
}, {
|
||||||
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)\" target=\"_blank\" rel=\"noopener\">" +
|
||||||
"http://example.com/Test_(Page)" +
|
"http://example.com/Test_(Page)" +
|
||||||
"</a>" +
|
"</a>" +
|
||||||
"<div data-url=\"http://example.com/Test_(Page)\"></div>"
|
"<div class=\"preview\" data-url=\"http://example.com/Test_(Page)\"></div>"
|
||||||
}, {
|
}, {
|
||||||
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)\" target=\"_blank\" rel=\"noopener\">" +
|
||||||
"www.example.com/Test_(Page)" +
|
"www.example.com/Test_(Page)" +
|
||||||
"</a>" +
|
"</a>" +
|
||||||
"<div data-url=\"http://www.example.com/Test_(Page)\"></div>"
|
"<div class=\"preview\" data-url=\"http://www.example.com/Test_(Page)\"></div>"
|
||||||
}];
|
}];
|
||||||
|
|
||||||
const actual = testCases.map((testCase) => parse(testCase.input));
|
const actual = testCases.map((testCase) => parse(testCase.input));
|
||||||
@ -275,7 +275,7 @@ describe("parse Handlebars helper", () => {
|
|||||||
"/" +
|
"/" +
|
||||||
"<span class=\"irc-fg4 irc-bg8\">thelounge</span>" +
|
"<span class=\"irc-fg4 irc-bg8\">thelounge</span>" +
|
||||||
"</a>" +
|
"</a>" +
|
||||||
"<div data-url=\"irc://freenode.net/thelounge\"></div>"
|
"<div class=\"preview\" data-url=\"irc://freenode.net/thelounge\"></div>"
|
||||||
}, {
|
}, {
|
||||||
input: "\x02#\x038,9thelounge",
|
input: "\x02#\x038,9thelounge",
|
||||||
expected:
|
expected:
|
||||||
@ -315,7 +315,7 @@ describe("parse Handlebars helper", () => {
|
|||||||
"<a href=\"http://example.com\" target=\"_blank\" rel=\"noopener\">" +
|
"<a href=\"http://example.com\" target=\"_blank\" rel=\"noopener\">" +
|
||||||
"http://example.com" +
|
"http://example.com" +
|
||||||
"</a>" +
|
"</a>" +
|
||||||
"<div data-url=\"http://example.com\"></div>"
|
"<div class=\"preview\" data-url=\"http://example.com\"></div>"
|
||||||
}, {
|
}, {
|
||||||
input: "like..HTTP://example.com",
|
input: "like..HTTP://example.com",
|
||||||
expected:
|
expected:
|
||||||
@ -323,7 +323,7 @@ describe("parse Handlebars helper", () => {
|
|||||||
"<a href=\"HTTP://example.com\" target=\"_blank\" rel=\"noopener\">" +
|
"<a href=\"HTTP://example.com\" target=\"_blank\" rel=\"noopener\">" +
|
||||||
"HTTP://example.com" +
|
"HTTP://example.com" +
|
||||||
"</a>" +
|
"</a>" +
|
||||||
"<div data-url=\"HTTP://example.com\"></div>"
|
"<div class=\"preview\" data-url=\"HTTP://example.com\"></div>"
|
||||||
}];
|
}];
|
||||||
|
|
||||||
const actual = testCases.map((testCase) => parse(testCase.input));
|
const actual = testCases.map((testCase) => parse(testCase.input));
|
||||||
@ -340,7 +340,7 @@ describe("parse Handlebars helper", () => {
|
|||||||
"<a href=\"http://example.com/#hash\" target=\"_blank\" rel=\"noopener\">" +
|
"<a href=\"http://example.com/#hash\" target=\"_blank\" rel=\"noopener\">" +
|
||||||
"http://example.com/#hash" +
|
"http://example.com/#hash" +
|
||||||
"</a>" +
|
"</a>" +
|
||||||
"<div data-url=\"http://example.com/#hash\"></div>"
|
"<div class=\"preview\" data-url=\"http://example.com/#hash\"></div>"
|
||||||
}];
|
}];
|
||||||
|
|
||||||
const actual = testCases.map((testCase) => parse(testCase.input));
|
const actual = testCases.map((testCase) => parse(testCase.input));
|
||||||
@ -356,7 +356,7 @@ describe("parse Handlebars helper", () => {
|
|||||||
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\" target=\"_blank\" rel=\"noopener\">http://example.com/path</a> " +
|
||||||
"Channel: <span class=\"inline-channel\" role=\"button\" tabindex=\"0\" data-chan=\"##channel\">##channel</span>" +
|
"Channel: <span class=\"inline-channel\" role=\"button\" tabindex=\"0\" data-chan=\"##channel\">##channel</span>" +
|
||||||
"<div data-url=\"http://example.com/path\"></div>"
|
"<div class=\"preview\" data-url=\"http://example.com/path\"></div>"
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user