diff --git a/client/css/style.css b/client/css/style.css index dee0ab4a..ca90ef12 100644 --- a/client/css/style.css +++ b/client/css/style.css @@ -679,6 +679,7 @@ button { #chat .show-more { display: none; padding: 10px; + padding-bottom: 0; width: 100%; } @@ -700,15 +701,40 @@ button { } #chat .messages { - display: table; - table-layout: fixed; width: 100%; padding: 10px 0; + overflow-wrap: break-word; + word-wrap: break-word; + word-break: break-word; } -#chat .msg { - display: table-row; - word-wrap: break-word; +#chat .unread-marker { + position: relative; + text-align: center; + opacity: .5; + margin: 0 10px; +} + +#chat .unread-marker:before { + position: absolute; + z-index: -1; + content: ""; + left: 0; + right: 0; + top: 50%; + border-top: 1px solid #e74c3c; +} + +#chat .unread-marker-text:before { + content: "New messages"; + background-color: white; + color: #e74c3c; + padding: 0 10px; + font: bold 12px Lato; +} + +#chat .unread-marker:last-child { + display: none; } .inline-channel { @@ -739,7 +765,7 @@ button { color: #b1c3ce; padding-right: 10px; text-align: right; - width: 134px; + max-width: 134px; min-width: 134px; } @@ -1629,10 +1655,6 @@ button { padding: 2px 0; } - #chat .msg:last-child { - height: auto; - } - #chat .time, #chat .from, #chat .text { @@ -1640,6 +1662,10 @@ button { display: inline; padding: 0; } + + #chat .unread-marker { + margin: 0; + } } ::-webkit-scrollbar { diff --git a/client/js/lounge.js b/client/js/lounge.js index 6c1e0f1d..7fc1c1a0 100644 --- a/client/js/lounge.js +++ b/client/js/lounge.js @@ -287,7 +287,20 @@ $(function() { function renderChannelMessages(data) { var documentFragment = buildChannelMessages(data.id, data.messages); - chat.find("#chan-" + data.id + " .messages").append(documentFragment); + var channel = chat.find("#chan-" + data.id + " .messages").append(documentFragment); + + if (data.firstUnread > 0) { + var first = channel.find("#msg-" + data.firstUnread); + + // TODO: If the message is far off in the history, we still need to append the marker into DOM + if (!first.length) { + channel.prepend(render("unread_marker")); + } else { + first.before(render("unread_marker")); + } + } else { + channel.append(render("unread_marker")); + } } function renderChannelUsers(data) { @@ -315,12 +328,20 @@ $(function() { socket.on("msg", function(data) { var msg = buildChatMessage(data); var target = "#chan-" + data.chan; - chat.find(target + " .messages") + var container = chat.find(target + " .messages"); + + container .append(msg) .trigger("msg", [ target, data.msg ]); + + if (data.msg.self) { + container + .find(".unread-marker") + .appendTo(container); + } }); socket.on("more", function(data) { @@ -753,11 +774,17 @@ $(function() { } viewport.removeClass("lt"); - $("#windows .active") + var lastActive = $("#windows .active"); + + lastActive .removeClass("active") .find(".chat") .unsticky(); + lastActive + .find(".unread-marker") + .appendTo(lastActive.find(".messages")); + var chan = $(target) .addClass("active") .trigger("show") @@ -1031,14 +1058,14 @@ $(function() { setInterval(function() { chat.find(".chan:not(.active)").each(function() { var chan = $(this); - if (chan.find(".messages").children().slice(0, -100).remove().length) { + if (chan.find(".messages .msg:not(.unread-marker)").slice(0, -100).remove().length) { chan.find(".show-more").addClass("show"); } }); }, 1000 * 10); function clear() { - chat.find(".active .messages").empty(); + chat.find(".active .messages .msg:not(.unread-marker)").remove(); chat.find(".active .show-more").addClass("show"); } diff --git a/client/themes/crypto.css b/client/themes/crypto.css index e1a57b0f..28b1007b 100644 --- a/client/themes/crypto.css +++ b/client/themes/crypto.css @@ -117,6 +117,10 @@ a:hover, font-weight: bold; } +#chat .unread-marker-text:before { + font: bold 12px Inconsolata-g, monospace; +} + #form .input { font: 12px Inconsolata-g, monospace; } diff --git a/client/themes/morning.css b/client/themes/morning.css index bdd5755a..71d84f23 100644 --- a/client/themes/morning.css +++ b/client/themes/morning.css @@ -175,6 +175,14 @@ body { color: #99a2b4; } +#chat .unread-marker { + opacity: 1; +} + +#chat .unread-marker-text:before { + background-color: #333c4a; +} + /* Setup text colors */ #chat .msg { color: #f3f3f3; diff --git a/client/themes/zenburn.css b/client/themes/zenburn.css index abf94d9b..2484fe10 100644 --- a/client/themes/zenburn.css +++ b/client/themes/zenburn.css @@ -202,6 +202,14 @@ body { color: #d2d39b; } +#chat .unread-marker { + opacity: 1; +} + +#chat .unread-marker-text:before { + background-color: #3f3f3f; +} + /* Setup text colors */ #chat .msg { color: #ffcfaf; diff --git a/client/views/msg.tpl b/client/views/msg.tpl index 10c79e24..65737198 100644 --- a/client/views/msg.tpl +++ b/client/views/msg.tpl @@ -1,4 +1,4 @@ -
+
{{tz time}} diff --git a/client/views/msg_action.tpl b/client/views/msg_action.tpl index 2eb1fe85..9b56fdad 100644 --- a/client/views/msg_action.tpl +++ b/client/views/msg_action.tpl @@ -1,4 +1,4 @@ -
+
{{tz time}} diff --git a/client/views/unread_marker.tpl b/client/views/unread_marker.tpl new file mode 100644 index 00000000..cb952947 --- /dev/null +++ b/client/views/unread_marker.tpl @@ -0,0 +1,3 @@ +
+ +
diff --git a/src/client.js b/src/client.js index 6eed583b..e682dfad 100644 --- a/src/client.js +++ b/src/client.js @@ -362,6 +362,7 @@ Client.prototype.more = function(data) { Client.prototype.open = function(data) { var target = this.find(data); if (target) { + target.chan.firstUnread = 0; target.chan.unread = 0; target.chan.highlight = false; this.activeChannel = target.chan.id; diff --git a/src/models/chan.js b/src/models/chan.js index f5481141..e64ac8ac 100644 --- a/src/models/chan.js +++ b/src/models/chan.js @@ -18,6 +18,7 @@ function Chan(attr) { name: "", topic: "", type: Chan.Type.CHANNEL, + firstUnread: 0, unread: 0, highlight: false, users: [] @@ -41,6 +42,16 @@ Chan.prototype.pushMessage = function(client, msg) { if (Helper.config.maxHistory >= 0 && this.messages.length > Helper.config.maxHistory) { this.messages.splice(0, this.messages.length - Helper.config.maxHistory); } + + if (!msg.self && this.id !== client.activeChannel) { + if (!this.firstUnread) { + this.firstUnread = msg.id; + } + + if (msg.highlight) { + this.highlight = true; + } + } }; Chan.prototype.sortUsers = function(irc) { diff --git a/src/plugins/irc-events/message.js b/src/plugins/irc-events/message.js index 98c7c52a..bd1b5291 100644 --- a/src/plugins/irc-events/message.js +++ b/src/plugins/irc-events/message.js @@ -72,10 +72,6 @@ module.exports = function(irc, network) { if (!self && chan.id !== client.activeChannel) { chan.unread++; - - if (highlight) { - chan.highlight = true; - } } var msg = new Msg({