diff options
| author | RblSb <msrblsb@gmail.com> | 2020-04-26 06:14:07 +0300 |
|---|---|---|
| committer | RblSb <msrblsb@gmail.com> | 2020-04-26 11:00:30 +0300 |
| commit | e0f2520fb03ed07a38e96c012c0f599b2fbe7f04 (patch) | |
| tree | 3b990453720b8193350ab5557abd410119160dd6 | |
| parent | 3c5fda212a8b895027c3853d9979b12a8f6c5798 (diff) | |
Fix autoscroll with unloaded images
| -rw-r--r-- | res/client.js | 44 | ||||
| -rw-r--r-- | res/css/cytube.css | 7 | ||||
| -rw-r--r-- | src/client/Buttons.hx | 2 | ||||
| -rw-r--r-- | src/client/Main.hx | 31 | ||||
| -rw-r--r-- | src/client/Player.hx | 9 | ||||
| -rw-r--r-- | src/client/Utils.hx | 6 | ||||
| -rw-r--r-- | src/client/players/Raw.hx | 2 |
7 files changed, 80 insertions, 21 deletions
diff --git a/res/client.js b/res/client.js index 8161f26..715fe24 100644 --- a/res/client.js +++ b/res/client.js @@ -530,7 +530,9 @@ client_Buttons.init = function(main) { client_Buttons.split.setSizes(sizes); client_Buttons.settings.isExtendedPlayer = isExtended; client_Buttons.writeSplitSize(); - return window.dispatchEvent(new Event("resize")); + window.dispatchEvent(new Event("resize")); + main.scrollChatToEnd(); + return; }; if(client_Buttons.settings.isExtendedPlayer) { extendPlayer.onclick(); @@ -749,6 +751,7 @@ client_Buttons.initNavBar = function(main) { client_Buttons.initSplit(); swapLayoutBtn.blur(); client_Buttons.hideMenus(); + main.scrollChatToEnd(); return; }; if(client_Buttons.settings.isSwapped) { @@ -1389,7 +1392,7 @@ client_Main.prototype = { while(_g2 < _g3.length) { var emote = _g3[_g2]; ++_g2; - var tag = StringTools.endsWith(emote.image,"mp4") ? "video autoplay=\"\" loop=\"\"" : "img"; + var tag = StringTools.endsWith(emote.image,"mp4") ? "video autoplay=\"\" loop=\"\" muted=\"\"" : "img"; this.filters.push({ regex : new EReg("(^| )" + this.escapeRegExp(emote.name) + "(?!\\S)","g"), replace : "$1<" + tag + " class=\"channel-emote\" src=\"" + emote.image + "\" title=\"" + emote.name + "\"/>"}); } window.document.querySelector("#smilesbtn").classList.remove("active"); @@ -1549,6 +1552,14 @@ client_Main.prototype = { } textDiv.innerHTML = text; var isInChatEnd = msgBuf.scrollTop + msgBuf.clientHeight >= msgBuf.scrollHeight - 1; + if(isInChatEnd) { + var _g2 = 0; + var _g11 = textDiv.getElementsByTagName("img"); + while(_g2 < _g11.length) _g11[_g2++].onload = $bind(this,this.onChatImageLoaded); + var _g21 = 0; + var _g3 = textDiv.getElementsByTagName("video"); + while(_g21 < _g3.length) _g3[_g21++].onloadedmetadata = $bind(this,this.onChatVideoLoaded); + } userDiv.appendChild(tstamp); userDiv.appendChild(nameDiv); userDiv.appendChild(textDiv); @@ -1572,6 +1583,21 @@ client_Main.prototype = { this.onBlinkTab.run(); } } + ,onChatImageLoaded: function(e) { + this.scrollChatToEnd(); + e.target.onload = null; + } + ,onChatVideoLoaded: function(e) { + var _gthis = this; + haxe_Timer.delay(function() { + _gthis.scrollChatToEnd(); + return e.target.onloadedmetadata = null; + },100); + } + ,scrollChatToEnd: function() { + var msgBuf = window.document.querySelector("#messagebuffer"); + msgBuf.scrollTop = msgBuf.scrollHeight; + } ,handleCommands: function(text) { if(text == "clear") { if((this.personal.group & 4) != 0) { @@ -1782,7 +1808,7 @@ client_Player.prototype = { } ,addVideoItem: function(item,atEnd) { var url = StringTools.htmlEscape(item.url,true); - var itemEl = this.nodeFromString("<li class=\"queue_entry pluid-0\" title=\"" + Lang.get("addedBy") + ": " + item.author + "\">\n\t\t\t\t<a class=\"qe_title\" href=\"" + url + "\" target=\"_blank\">" + StringTools.htmlEscape(item.title) + "</a>\n\t\t\t\t<span class=\"qe_time\">" + this.duration(item.duration) + "</span>\n\t\t\t\t<div class=\"qe_clear\"></div>\n\t\t\t\t<div class=\"btn-group\">\n\t\t\t\t\t<button class=\"btn btn-xs btn-default qbtn-play\">\n\t\t\t\t\t\t<span class=\"glyphicon glyphicon-play\"></span>" + Lang.get("play") + "\n\t\t\t\t\t</button>\n\t\t\t\t\t<button class=\"btn btn-xs btn-default qbtn-next\">\n\t\t\t\t\t\t<span class=\"glyphicon glyphicon-share-alt\"></span>" + Lang.get("setNext") + "\n\t\t\t\t\t</button>\n\t\t\t\t\t<button class=\"btn btn-xs btn-default qbtn-tmp\">\n\t\t\t\t\t\t<span class=\"glyphicon glyphicon-flag\"></span>\n\t\t\t\t\t</button>\n\t\t\t\t\t<button class=\"btn btn-xs btn-default qbtn-delete\">\n\t\t\t\t\t\t<span class=\"glyphicon glyphicon-trash\"></span>" + Lang.get("delete") + "\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t</li>"); + var itemEl = client_Utils.nodeFromString("<li class=\"queue_entry pluid-0\" title=\"" + Lang.get("addedBy") + ": " + item.author + "\">\n\t\t\t\t<a class=\"qe_title\" href=\"" + url + "\" target=\"_blank\">" + StringTools.htmlEscape(item.title) + "</a>\n\t\t\t\t<span class=\"qe_time\">" + this.duration(item.duration) + "</span>\n\t\t\t\t<div class=\"qe_clear\"></div>\n\t\t\t\t<div class=\"btn-group\">\n\t\t\t\t\t<button class=\"btn btn-xs btn-default qbtn-play\">\n\t\t\t\t\t\t<span class=\"glyphicon glyphicon-play\"></span>" + Lang.get("play") + "\n\t\t\t\t\t</button>\n\t\t\t\t\t<button class=\"btn btn-xs btn-default qbtn-next\">\n\t\t\t\t\t\t<span class=\"glyphicon glyphicon-share-alt\"></span>" + Lang.get("setNext") + "\n\t\t\t\t\t</button>\n\t\t\t\t\t<button class=\"btn btn-xs btn-default qbtn-tmp\">\n\t\t\t\t\t\t<span class=\"glyphicon glyphicon-flag\"></span>\n\t\t\t\t\t</button>\n\t\t\t\t\t<button class=\"btn btn-xs btn-default qbtn-delete\">\n\t\t\t\t\t\t<span class=\"glyphicon glyphicon-trash\"></span>" + Lang.get("delete") + "\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t</li>"); _$VideoList_VideoList_$Impl_$.addItem(this.items,item,atEnd,this.itemPos); this.setItemElementType(itemEl,item.isTemp); if(atEnd) { @@ -1907,11 +1933,6 @@ client_Player.prototype = { while(_g < _g1.length) time += _g1[_g++].duration; return this.duration(time); } - ,nodeFromString: function(div) { - var wrapper = window.document.createElement("div"); - wrapper.innerHTML = div; - return wrapper.firstElementChild; - } ,isListEmpty: function() { return this.items.length == 0; } @@ -2053,6 +2074,11 @@ client_Utils.__name__ = true; client_Utils.isTouch = function() { return 'ontouchstart' in window; }; +client_Utils.nodeFromString = function(div) { + var wrapper = window.document.createElement("div"); + wrapper.innerHTML = div; + return wrapper.firstElementChild; +}; client_Utils.prepend = function(parent,child) { if(parent.firstChild == null) { parent.appendChild(child); @@ -2235,10 +2261,10 @@ client_players_Raw.prototype = { } ,restartControlsHider: function() { var _gthis = this; + this.video.controls = true; if(client_Utils.isTouch()) { return; } - this.video.controls = true; if(this.controlsHider != null) { this.controlsHider.stop(); } diff --git a/res/css/cytube.css b/res/css/cytube.css index b080f91..55e832c 100644 --- a/res/css/cytube.css +++ b/res/css/cytube.css @@ -101,11 +101,16 @@ max-height: 75px; cursor: pointer; } -.channel-emote, .chat-img { +.channel-emote { max-width: 150px; max-height: 150px; } +.chat-img { + max-width: 200px; + max-height: 200px; +} video.channel-emote, video.chat-img { + background-color: transparent; /* Fixes default video tag size in chat when tab unloads videos in background */ /* (some browsers optimization i guess) */ height: 150px; diff --git a/src/client/Buttons.hx b/src/client/Buttons.hx index a7dd4e1..d4533bf 100644 --- a/src/client/Buttons.hx +++ b/src/client/Buttons.hx @@ -90,6 +90,7 @@ class Buttons { settings.isExtendedPlayer = isExtended; writeSplitSize(); window.dispatchEvent(new Event("resize")); + main.scrollChatToEnd(); } if (settings.isExtendedPlayer) extendPlayer.onclick(); @@ -281,6 +282,7 @@ class Buttons { initSplit(); swapLayoutBtn.blur(); hideMenus(); + main.scrollChatToEnd(); } if (settings.isSwapped) swapLayoutBtn.onclick(); final removeBtn = ge("#removeVideoBtn"); diff --git a/src/client/Main.hx b/src/client/Main.hx index 5ee14d6..fda93c7 100644 --- a/src/client/Main.hx +++ b/src/client/Main.hx @@ -510,7 +510,7 @@ class Main { }); } for (emote in config.emotes) { - final tag = emote.image.endsWith("mp4") ? 'video autoplay="" loop=""' : "img"; + final tag = emote.image.endsWith("mp4") ? 'video autoplay="" loop="" muted=""' : "img"; filters.push({ regex: new EReg("(^| )" + escapeRegExp(emote.name) + "(?!\\S)", "g"), replace: '$1<$tag class="channel-emote" src="${emote.image}" title="${emote.name}"/>' @@ -656,8 +656,17 @@ class Main { } } textDiv.innerHTML = text; - final isInChatEnd = msgBuf.scrollTop + msgBuf.clientHeight >= msgBuf.scrollHeight - 1; + + if (isInChatEnd) { // scroll chat to end after images loaded + for (img in textDiv.getElementsByTagName("img")) { + img.onload = onChatImageLoaded; + } + for (video in textDiv.getElementsByTagName("video")) { + video.onloadedmetadata = onChatVideoLoaded; + } + } + userDiv.appendChild(tstamp); userDiv.appendChild(nameDiv); userDiv.appendChild(textDiv); @@ -680,6 +689,24 @@ class Main { } } + function onChatImageLoaded(e:Event):Void { + scrollChatToEnd(); + (cast e.target : Element).onload = null; + } + + function onChatVideoLoaded(e:Event):Void { + // for some time default video size is 300x150px + Timer.delay(() -> { + scrollChatToEnd(); + (cast e.target : Element).onloadedmetadata = null; + }, 100); + } + + public function scrollChatToEnd():Void { + final msgBuf = ge("#messagebuffer"); + msgBuf.scrollTop = msgBuf.scrollHeight; + } + final matchNumbers = ~/^-?[0-9]+$/; function handleCommands(text:String):Void { diff --git a/src/client/Player.hx b/src/client/Player.hx index c853464..28b5c09 100644 --- a/src/client/Player.hx +++ b/src/client/Player.hx @@ -1,7 +1,6 @@ package client; import js.html.Element; -import js.Browser.document; import client.Main.ge; import client.players.Raw; import client.players.Youtube; @@ -180,7 +179,7 @@ class Player { public function addVideoItem(item:VideoItem, atEnd:Bool):Void { final url = item.url.htmlEscape(true); - final itemEl = nodeFromString( + final itemEl = Utils.nodeFromString( '<li class="queue_entry pluid-0" title="${Lang.get("addedBy")}: ${item.author}"> <a class="qe_title" href="$url" target="_blank">${item.title.htmlEscape()}</a> <span class="qe_time">${duration(item.duration)}</span> @@ -297,12 +296,6 @@ class Player { return duration(time); } - function nodeFromString(div:String):Element { - final wrapper = document.createDivElement(); - wrapper.innerHTML = div; - return wrapper.firstElementChild; - } - public function isListEmpty():Bool { return items.length == 0; } diff --git a/src/client/Utils.hx b/src/client/Utils.hx index 3ac9953..e9d5ff8 100644 --- a/src/client/Utils.hx +++ b/src/client/Utils.hx @@ -10,6 +10,12 @@ class Utils { return js.Syntax.code("'ontouchstart' in window"); } + public static function nodeFromString(div:String):Element { + final wrapper = document.createDivElement(); + wrapper.innerHTML = div; + return wrapper.firstElementChild; + } + public static function prepend(parent:Element, child:Element):Void { if (parent.firstChild == null) parent.appendChild(child); else parent.insertBefore(child, parent.firstChild); diff --git a/src/client/players/Raw.hx b/src/client/players/Raw.hx index 4fa000b..266f0a2 100644 --- a/src/client/players/Raw.hx +++ b/src/client/players/Raw.hx @@ -71,8 +71,8 @@ class Raw implements IPlayer { } function restartControlsHider():Void { - if (Utils.isTouch()) return; video.controls = true; + if (Utils.isTouch()) return; if (controlsHider != null) controlsHider.stop(); controlsHider = Timer.delay(() -> { video.controls = false; |
