aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRblSb <msrblsb@gmail.com>2023-06-20 23:33:13 +0300
committerRblSb <msrblsb@gmail.com>2023-06-20 23:33:13 +0300
commitc476a16ad982e778580d74b8e4120ed29118129a (patch)
treec326895bc9eb57cf50123eadb049ec73b3a201f2
parentcdf7f00f613d636e587b7840ec8b263017513486 (diff)
Scroll to chat end button
-rw-r--r--res/client.js88
-rw-r--r--res/css/des.css20
-rw-r--r--res/index.html45
-rw-r--r--src/client/Buttons.hx19
-rw-r--r--src/client/Main.hx28
-rw-r--r--src/client/Utils.hx9
-rw-r--r--test/tests/TestTimer.hx6
7 files changed, 161 insertions, 54 deletions
diff --git a/res/client.js b/res/client.js
index 3f1bfd4..830c25c 100644
--- a/res/client.js
+++ b/res/client.js
@@ -1,4 +1,4 @@
-// Generated by Haxe 4.3.0
+// Generated by Haxe 4.3.1
(function ($hx_exports, $global) { "use strict";
$hx_exports["client"] = $hx_exports["client"] || {};
$hx_exports["client"]["JsApi"] = $hx_exports["client"]["JsApi"] || {};
@@ -536,6 +536,27 @@ client_Buttons.init = function(main) {
child.removeAttribute("data-src");
}
};
+ var scrollToChatEndBtn = window.document.querySelector("#scroll-to-chat-end");
+ var scrollToChatEndBtnAnim = function() {
+ if(scrollToChatEndBtn.style.opacity == "0") {
+ return;
+ }
+ scrollToChatEndBtn.style.opacity = "0";
+ scrollToChatEndBtn.addEventListener("transitionend",function(e) {
+ return scrollToChatEndBtn.style.display = "none";
+ },{ once : true});
+ };
+ scrollToChatEndBtn.onclick = function(e) {
+ main.scrollChatToEnd();
+ scrollToChatEndBtnAnim();
+ };
+ var msgBuf = window.document.querySelector("#messagebuffer");
+ msgBuf.onscroll = function(e) {
+ if(msgBuf.offsetHeight + msgBuf.scrollTop < msgBuf.scrollHeight - 1) {
+ return;
+ }
+ scrollToChatEndBtnAnim();
+ };
window.document.querySelector("#clearchatbtn").onclick = function(e) {
if((main.personal.group & 8) != 0) {
main.send({ type : "ClearChat"});
@@ -1178,6 +1199,7 @@ var client_Main = function() {
this.forceSyncNextTick = false;
this.isSyncActive = true;
var _gthis = this;
+ haxe_Log.trace = client_Utils.nativeTrace;
this.player = new client_Player(this);
this.host = $global.location.hostname;
if(this.host == "") {
@@ -1206,22 +1228,6 @@ client_Main.__name__ = true;
client_Main.main = function() {
new client_Main();
};
-client_Main.chatMessageConnected = function() {
- var div = window.document.createElement("div");
- div.className = "server-msg-reconnect";
- div.textContent = Lang.get("msgConnected");
- var msgBuf = window.document.querySelector("#messagebuffer");
- msgBuf.appendChild(div);
- msgBuf.scrollTop = msgBuf.scrollHeight;
-};
-client_Main.chatMessageDisconnected = function() {
- var div = window.document.createElement("div");
- div.className = "server-msg-disconnect";
- div.textContent = Lang.get("msgDisconnected");
- var msgBuf = window.document.querySelector("#messagebuffer");
- msgBuf.appendChild(div);
- msgBuf.scrollTop = msgBuf.scrollHeight;
-};
client_Main.serverMessage = function(text,isText,withTimestamp) {
if(withTimestamp == null) {
withTimestamp = true;
@@ -1283,12 +1289,12 @@ client_Main.prototype = {
this.ws = new WebSocket("" + protocol + "//" + this.host + colonPort + path);
this.ws.onmessage = $bind(this,this.onMessage);
this.ws.onopen = function() {
- client_Main.chatMessageConnected();
+ _gthis.chatMessageConnected();
return _gthis.isConnected = true;
};
this.ws.onclose = function() {
if(_gthis.isConnected) {
- client_Main.chatMessageDisconnected();
+ _gthis.chatMessageDisconnected();
}
_gthis.isConnected = false;
_gthis.player.pause();
@@ -1515,7 +1521,7 @@ client_Main.prototype = {
var data = JSON.parse(e.data);
if(this.config != null && this.config.isVerbose) {
var t = data.type;
- haxe_Log.trace("Event: " + data.type,{ fileName : "src/client/Main.hx", lineNumber : 397, className : "client.Main", methodName : "onMessage", customParams : [Reflect.field(data,t.charAt(0).toLowerCase() + HxOverrides.substr(t,1,null))]});
+ haxe_Log.trace("Event: " + data.type,{ fileName : "src/client/Main.hx", lineNumber : 398, className : "client.Main", methodName : "onMessage", customParams : [Reflect.field(data,t.charAt(0).toLowerCase() + HxOverrides.substr(t,1,null))]});
}
client_JsApi.fireOnceEvent(data);
switch(data.type) {
@@ -1732,7 +1738,7 @@ client_Main.prototype = {
this.setLeaderButton((this.personal.group & 4) != 0);
this.setPlaylistLock(connected.isPlaylistOpen);
this.clearChat();
- client_Main.chatMessageConnected();
+ this.chatMessageConnected();
var _g = 0;
var _g1 = connected.history;
while(_g < _g1.length) {
@@ -1948,6 +1954,20 @@ client_Main.prototype = {
}
this.ws.send(JSON.stringify(data));
}
+ ,chatMessageConnected: function() {
+ var div = window.document.createElement("div");
+ div.className = "server-msg-reconnect";
+ div.textContent = Lang.get("msgConnected");
+ window.document.querySelector("#messagebuffer").appendChild(div);
+ this.scrollChatToEnd();
+ }
+ ,chatMessageDisconnected: function() {
+ var div = window.document.createElement("div");
+ div.className = "server-msg-disconnect";
+ div.textContent = Lang.get("msgDisconnected");
+ window.document.querySelector("#messagebuffer").appendChild(div);
+ this.scrollChatToEnd();
+ }
,updateUserList: function() {
window.document.querySelector("#usercount").textContent = this.clients.length + " " + Lang.get("online");
window.document.title = this.getPageTitle();
@@ -2009,7 +2029,7 @@ client_Main.prototype = {
text = text.replace(filter.regex.r,filter.replace);
}
textDiv.innerHTML = text;
- var isInChatEnd = msgBuf.scrollTop + msgBuf.clientHeight >= msgBuf.scrollHeight - 1;
+ var isInChatEnd = msgBuf.scrollTop + msgBuf.clientHeight >= msgBuf.scrollHeight - 50;
if(isInChatEnd) {
var _g = 0;
var _g1 = textDiv.getElementsByTagName("img");
@@ -2025,18 +2045,29 @@ client_Main.prototype = {
msgBuf.appendChild(userDiv);
if(isInChatEnd) {
while(msgBuf.children.length > 200) msgBuf.removeChild(msgBuf.firstChild);
- msgBuf.scrollTop = msgBuf.scrollHeight;
}
- if(name == this.personal.name) {
- msgBuf.scrollTop = msgBuf.scrollHeight;
+ if(isInChatEnd || name == this.personal.name) {
+ this.scrollChatToEnd();
+ } else {
+ this.showScrollToChatEndBtn();
}
if(this.onBlinkTab == null) {
this.blinkTabWithTitle("*Chat*");
}
}
+ ,showScrollToChatEndBtn: function() {
+ var btn = window.document.querySelector("#scroll-to-chat-end");
+ btn.style.display = "block";
+ haxe_Timer.delay(function() {
+ btn.style.opacity = "1";
+ },0);
+ }
,onChatImageLoaded: function(e) {
this.scrollChatToEnd();
e.target.onload = null;
+ var btn = window.document.querySelector("#scroll-to-chat-end");
+ btn.style.opacity = "0";
+ btn.style.display = "none";
}
,onChatVideoLoaded: function(e) {
var el = e.target;
@@ -2757,6 +2788,13 @@ client_Settings.write = function(data) {
};
var client_Utils = function() { };
client_Utils.__name__ = true;
+client_Utils.nativeTrace = function(msg,infos) {
+ var args = ["" + infos.fileName + ":" + infos.lineNumber,msg];
+ if(infos.customParams != null) {
+ args = args.concat(infos.customParams);
+ }
+ ($_=window.console,$_.log.apply($_,args));
+};
client_Utils.isTouch = function() {
return 'ontouchstart' in window;
};
diff --git a/res/css/des.css b/res/css/des.css
index 968ad39..89ab857 100644
--- a/res/css/des.css
+++ b/res/css/des.css
@@ -7,6 +7,7 @@
:root {
--background-video: #000;
--background-chat: #111;
+ --scroll-to-end-bg: #fff;
--midground: #888;
--foreground: #bbb;
--accent: #0055ff;
@@ -646,8 +647,27 @@ footer#footer {
font-style: italic;
}
+#scroll-to-chat-end {
+ transition: opacity 200ms;
+ position: absolute;
+ margin-left: auto;
+ top: -4em;
+ right: 1em;
+ padding: 0.8em;
+ border-radius: 50%;
+ background-color: var(--scroll-to-end-bg);
+}
+
+#scroll-to-chat-end ion-icon {
+ color: var(--midground);
+}
+
/* Chat input */
+#chat-inputs-wrapper {
+ position: relative;
+}
+
#chatbox {
padding-top: 1rem;
border-top: .063rem solid;
diff --git a/res/index.html b/res/index.html
index 6310f8b..9ab9d03 100644
--- a/res/index.html
+++ b/res/index.html
@@ -185,29 +185,34 @@
</ul>
<!-- Messages -->
<div id="messagebuffer"></div>
- <!-- Message input -->
- <div id="chatbox">
- <input id="chatline" type="text" placeholder="${chatlinePlaceholder}">
- <button id="smilesbtn" title="${emotes}">
- <ion-icon name="happy"></ion-icon>
+ <div id="chat-inputs-wrapper">
+ <button id="scroll-to-chat-end" style="display: none; opacity: 0;" class="active">
+ <ion-icon name="arrow-down" role="img" class="md hydrated" aria-label="arrow down"></ion-icon>
</button>
- </div>
- <div id="smiles-wrap" class="collapsible">
- <div id="smiles-list"></div>
- </div>
- <!-- Guest login -->
- <div id="guestlogin" style="display: none;">
- <label>${enterAsGuest}</label>
- <input id="guestname" type="text" placeholder="${yourName}">
- </div>
- <div id="guestpassword" style="display: none;">
- <label>${enterUserPassword}</label>
- <div id="passwordbox">
- <input id="guestpass" type="text" placeholder="${yourPassword}">
- <button id="guestpass_icon">
- <ion-icon name="eye"></ion-icon>
+ <!-- Message input -->
+ <div id="chatbox">
+ <input id="chatline" type="text" placeholder="${chatlinePlaceholder}">
+ <button id="smilesbtn" title="${emotes}">
+ <ion-icon name="happy"></ion-icon>
</button>
</div>
+ <div id="smiles-wrap" class="collapsible">
+ <div id="smiles-list"></div>
+ </div>
+ <!-- Guest login -->
+ <div id="guestlogin" style="display: none;">
+ <label>${enterAsGuest}</label>
+ <input id="guestname" type="text" placeholder="${yourName}">
+ </div>
+ <div id="guestpassword" style="display: none;">
+ <label>${enterUserPassword}</label>
+ <div id="passwordbox">
+ <input id="guestpass" type="text" placeholder="${yourPassword}">
+ <button id="guestpass_icon">
+ <ion-icon name="eye"></ion-icon>
+ </button>
+ </div>
+ </div>
</div>
</aside>
diff --git a/src/client/Buttons.hx b/src/client/Buttons.hx
index aa7c1b2..7152a31 100644
--- a/src/client/Buttons.hx
+++ b/src/client/Buttons.hx
@@ -60,6 +60,25 @@ class Buttons {
}
}
+ final scrollToChatEndBtn = ge("#scroll-to-chat-end");
+ function scrollToChatEndBtnAnim():Void {
+ if (scrollToChatEndBtn.style.opacity == "0") return;
+ scrollToChatEndBtn.style.opacity = "0";
+ scrollToChatEndBtn.addEventListener("transitionend", e -> {
+ scrollToChatEndBtn.style.display = "none";
+ }, {once: true});
+ }
+ scrollToChatEndBtn.onclick = e -> {
+ main.scrollChatToEnd();
+ scrollToChatEndBtnAnim();
+ }
+ // hide scroll button when chat is scrolled to the end
+ final msgBuf = ge("#messagebuffer");
+ msgBuf.onscroll = e -> {
+ if (msgBuf.offsetHeight + msgBuf.scrollTop < msgBuf.scrollHeight - 1) return;
+ scrollToChatEndBtnAnim();
+ }
+
ge("#clearchatbtn").onclick = e -> {
if (main.isAdmin()) main.send({type: ClearChat});
}
diff --git a/src/client/Main.hx b/src/client/Main.hx
index a7417fb..69450d9 100644
--- a/src/client/Main.hx
+++ b/src/client/Main.hx
@@ -52,6 +52,7 @@ class Main {
}
function new() {
+ haxe.Log.trace = Utils.nativeTrace;
player = new Player(this);
host = Browser.location.hostname;
if (host == "") host = "localhost";
@@ -790,22 +791,22 @@ class Main {
ws.send(Json.stringify(data));
}
- static function chatMessageConnected():Void {
+ function chatMessageConnected():Void {
final div = document.createDivElement();
div.className = "server-msg-reconnect";
div.textContent = Lang.get("msgConnected");
final msgBuf = ge("#messagebuffer");
msgBuf.appendChild(div);
- msgBuf.scrollTop = msgBuf.scrollHeight;
+ scrollChatToEnd();
}
- static function chatMessageDisconnected():Void {
+ function chatMessageDisconnected():Void {
final div = document.createDivElement();
div.className = "server-msg-disconnect";
div.textContent = Lang.get("msgDisconnected");
final msgBuf = ge("#messagebuffer");
msgBuf.appendChild(div);
- msgBuf.scrollTop = msgBuf.scrollHeight;
+ scrollChatToEnd();
}
public static function serverMessage(text:String, isText = true, withTimestamp = true):Void {
@@ -897,7 +898,8 @@ class Main {
text = filter.regex.replace(text, filter.replace);
}
textDiv.innerHTML = text;
- final isInChatEnd = msgBuf.scrollTop + msgBuf.clientHeight >= msgBuf.scrollHeight - 1;
+ final isInChatEnd = msgBuf.scrollTop
+ + msgBuf.clientHeight >= msgBuf.scrollHeight - 50;
if (isInChatEnd) { // scroll chat to end after images loaded
for (img in textDiv.getElementsByTagName("img")) {
@@ -917,17 +919,27 @@ class Main {
while (msgBuf.children.length > 200) {
msgBuf.removeChild(msgBuf.firstChild);
}
- msgBuf.scrollTop = msgBuf.scrollHeight;
}
- if (name == personal.name) {
- msgBuf.scrollTop = msgBuf.scrollHeight;
+ if (isInChatEnd || name == personal.name) {
+ scrollChatToEnd();
+ } else {
+ showScrollToChatEndBtn();
}
if (onBlinkTab == null) blinkTabWithTitle("*Chat*");
}
+ function showScrollToChatEndBtn() {
+ final btn = ge("#scroll-to-chat-end");
+ btn.style.display = "block";
+ Timer.delay(() -> btn.style.opacity = "1", 0);
+ }
+
function onChatImageLoaded(e:Event):Void {
scrollChatToEnd();
(cast e.target : Element).onload = null;
+ final btn = ge("#scroll-to-chat-end");
+ btn.style.opacity = "0";
+ btn.style.display = "none";
}
var emoteMaxSize:Null<Int>;
diff --git a/src/client/Utils.hx b/src/client/Utils.hx
index cdf9f21..a0e19f7 100644
--- a/src/client/Utils.hx
+++ b/src/client/Utils.hx
@@ -8,6 +8,15 @@ import js.html.Element;
import js.html.URL;
class Utils {
+ public static function nativeTrace(msg:Dynamic, ?infos:haxe.PosInfos):Void {
+ final fileData = '${infos.fileName}:${infos.lineNumber}';
+ var args:Array<Dynamic> = [fileData, msg];
+ if (infos.customParams != null) args = args.concat(infos.customParams);
+ js.Browser.window.console.log(
+ ...haxe.Rest.of(args)
+ );
+ }
+
public static function isTouch():Bool {
return js.Syntax.code("'ontouchstart' in window");
}
diff --git a/test/tests/TestTimer.hx b/test/tests/TestTimer.hx
index 8a22cc9..1261553 100644
--- a/test/tests/TestTimer.hx
+++ b/test/tests/TestTimer.hx
@@ -165,7 +165,7 @@ class TestTimer extends Test {
}
function almostEq(a:Float, b:Float, ?p:PosInfos):Void {
- if (isMacCI()) {
+ if (isMacCI() || isWindowsCI()) {
Assert.isTrue(Math.abs(a - b) < 0.5);
return;
}
@@ -175,4 +175,8 @@ class TestTimer extends Test {
function isMacCI():Bool {
return Sys.systemName() == "Mac" && Sys.environment()["CI"] == "true";
}
+
+ function isWindowsCI():Bool {
+ return Sys.systemName() == "Windows" && Sys.environment()["CI"] == "true";
+ }
}
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage