From 11257a272ee679502e790b4474cdbb48bed19e08 Mon Sep 17 00:00:00 2001 From: Attila Kerekes <439392+keriati@users.noreply.github.com> Date: Mon, 5 Dec 2022 15:29:06 +0000 Subject: [PATCH] feat: Introduce queue based live stat refresh (#1059) --- public/js/app.js | 2 +- public/mix-manifest.json | 2 +- resources/assets/js/app.js | 82 -------------------- resources/assets/js/liveStatRefresh.js | 100 +++++++++++++++++++++++++ webpack.mix.js | 1 + 5 files changed, 103 insertions(+), 84 deletions(-) create mode 100644 resources/assets/js/liveStatRefresh.js diff --git a/public/js/app.js b/public/js/app.js index 8c600c8f..6555843d 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -1 +1 @@ -function _typeof(t){return _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},_typeof(t)}!function(t,e){"function"==typeof define&&define.amd?define("ev-emitter/ev-emitter",e):"object"==("undefined"==typeof module?"undefined":_typeof(module))&&module.exports?module.exports=e():t.EvEmitter=e()}("undefined"!=typeof window?window:this,(function(){function t(){}var e=t.prototype;return e.on=function(t,e){if(t&&e){var n=this._events=this._events||{},i=n[t]=n[t]||[];return-1==i.indexOf(e)&&i.push(e),this}},e.once=function(t,e){if(t&&e){this.on(t,e);var n=this._onceEvents=this._onceEvents||{};return(n[t]=n[t]||{})[e]=!0,this}},e.off=function(t,e){var n=this._events&&this._events[t];if(n&&n.length){var i=n.indexOf(e);return-1!=i&&n.splice(i,1),this}},e.emitEvent=function(t,e){var n=this._events&&this._events[t];if(n&&n.length){var i=0,o=n[i];e=e||[];for(var s=this._onceEvents&&this._onceEvents[t];o;){var r=s&&s[o];r&&(this.off(t,o),delete s[o]),o.apply(this,e),o=n[i+=r?0:1]}return this}},t})),function(t,e){"function"==typeof define&&define.amd?define("unipointer/unipointer",["ev-emitter/ev-emitter"],(function(n){return e(t,n)})):"object"==("undefined"==typeof module?"undefined":_typeof(module))&&module.exports?module.exports=e(t,require("ev-emitter")):t.Unipointer=e(t,t.EvEmitter)}(window,(function(t,e){function n(){}var i=n.prototype=Object.create(e.prototype);i.bindStartEvent=function(t){this._bindStartEvent(t,!0)},i.unbindStartEvent=function(t){this._bindStartEvent(t,!1)},i._bindStartEvent=function(e,n){var i=(n=void 0===n||!!n)?"addEventListener":"removeEventListener";t.navigator.pointerEnabled?e[i]("pointerdown",this):t.navigator.msPointerEnabled?e[i]("MSPointerDown",this):(e[i]("mousedown",this),e[i]("touchstart",this))},i.handleEvent=function(t){var e="on"+t.type;this[e]&&this[e](t)},i.getTouch=function(t){for(var e=0;e.5;var o=this.colorGrid[e.toUpperCase()];this.updateCursor(o),this.setTexts(),this.setBackgrounds(),n||this.emitEvent("change",[e,t.hue,t.sat,t.lum])}},h.setTexts=function(){if(this.setTextElems)for(var t=0;t0&&s.attr("value",o)}$(".message-container").length&&setTimeout((function(){$(".message-container").fadeOut()}),3500),void 0!==document.hidden?(t="hidden",e="visibilitychange"):void 0!==document.msHidden?(t="msHidden",e="msvisibilitychange"):void 0!==document.webkitHidden&&(t="webkitHidden",e="webkitvisibilitychange");var r=[],a=[],c=$(".livestats-container");c.length>0&&(void 0===document.addEventListener||void 0===t?console.log("This browser does not support visibilityChange"):document.addEventListener(e,(function(){document[t]?r.forEach((function(t){window.clearTimeout(t)})):a.forEach((function(t){t()}))}),!1),c.each((function(t){var e=$(this).data("id"),i=1===$(this).data("dataonly")?2e4:1e3,o=$(this),s=5e3,c=function a(){$.ajax({url:"".concat(n,"get_stats/").concat(e),dataType:"json",success:function(t){o.html(t.html),"active"===t.status?s=i:s<3e4&&(s+=2e3)},complete:function(e){e.status>299||(r[t]=window.setTimeout(a,s))}})};a[t]=c,c()}))),$("#upload").change((function(){!function(t){if(t.files&&t.files[0]){var e=new FileReader;e.onload=function(t){$("#appimage img").attr("src",t.target.result)},e.readAsDataURL(t.files[0])}}(this)})),$("#sortable").sortable({stop:function(){var t=$("#sortable").sortable("toArray",{attribute:"data-id"});$.post("".concat(n,"order"),{order:t})}}),$("#sortable").sortable("disable"),$("#main").on("mouseenter","#sortable.ui-sortable-disabled .item",(function(){$(this).siblings(".tooltip").addClass("active"),$(".refresh",this).addClass("active")})).on("mouseleave",".item",(function(){$(this).siblings(".tooltip").removeClass("active"),$(".refresh",this).removeClass("active")})),$("#config-buttons").on("mouseenter","a",(function(){$(".tooltip",this).addClass("active")})).on("mouseleave","a",(function(){$(".tooltip",this).removeClass("active")})),$(".searchform > form").on("submit",(function(t){"tiles"===$("#search-container select[name=provider]").val()&&t.preventDefault()})),$("#search-container").on("input","input[name=q]",(function(){var t=this.value,e=$("#sortable").children(".item-container");"tiles"===$("#search-container select[name=provider]").val()&&t.length>0?(e.hide(),e.filter((function(){return $(this).data("name").toLowerCase().includes(t.toLowerCase())})).show()):e.show()})).on("change","select[name=provider]",(function(){var t=$("#sortable").children(".item-container");if("tiles"===$(this).val()){$("#search-container button").hide();var e=$("#search-container input[name=q]").val();e.length>0?(t.hide(),t.filter((function(){return $(this).data("name").toLowerCase().includes(e.toLowerCase())})).show()):t.show()}else $("#search-container button").show(),t.show()})),$("#app").on("click","#config-button",(function(t){t.preventDefault();var e=$("#app"),n=e.hasClass("header");e.toggleClass("header"),n?($(".add-item").hide(),$(".item-edit").hide(),$("#app").removeClass("sidebar"),$("#sortable .tooltip").css("display",""),$("#sortable").sortable("disable")):($("#sortable .tooltip").css("display","none"),$("#sortable").sortable("enable"),setTimeout((function(){$(".add-item").fadeIn(),$(".item-edit").fadeIn()}),350))})).on("click","#add-item, #pin-item",(function(t){t.preventDefault(),$("#app").toggleClass("sidebar")})).on("click",".close-sidenav",(function(t){t.preventDefault(),$("#app").removeClass("sidebar")})).on("click","#test_config",(function(t){t.preventDefault();var e=$("#create input[name=url]").val(),i=$('#sapconfig input[name="config[override_url]"]').val();i.length&&""!==i&&(e=i);var s={};s.url=e,$(".config-item").each((function(){var t=$(this).data("config");s[t]=$(this).val()})),s.id=$("form[data-item-id]").data("item-id"),s.password&&s.password===o&&(s.password=""),$.post("".concat(n,"test_config"),{data:s},(function(t){alert(t)}))})),$("#pinlist").on("click","a",(function(t){t.preventDefault();var e=$(this),i=e.data("id"),o=e.data("tag");$.get("".concat(n,"items/pintoggle/").concat(i,"/true/").concat(o),(function(t){var n=$(t).filter("#sortable").html();$("#sortable").html(n),e.toggleClass("active")}))})),$("#itemform").on("submit",(function(){var t=$('input[name="config[password]"]').first();t.length>0&&t.attr("value")===o&&t.attr("value","")}))}));var focusSearch=function(t){var e=document.querySelector('input[name="q"]');e&&(t.preventDefault(),e.focus())},openFirstNonHiddenItem=function(t){if(t.target===document.querySelector('input[name="q"]')&&"tiles"===document.querySelector("#search-container select[name=provider]").value){var e=document.querySelector('#sortable section.item-container:not([style="display: none;"]) a');"href"in e&&(t.preventDefault(),window.open(e.href))}},KEY_BINDINGS={"/":focusSearch,Enter:openFirstNonHiddenItem};document.addEventListener("keydown",(function(t){try{t.key in KEY_BINDINGS&&KEY_BINDINGS[t.key](t)}catch(t){}}));var EXPORT_FILE_NAME="HeimdallExport.json",EXPORT_API_URL="api/item";function triggerFileDownload(t,e){var n=document.createElement("a"),i=new Blob([e],{type:"text/plain"});n.href=URL.createObjectURL(i),n.download=EXPORT_FILE_NAME,n.click()}var exportItems=function(t){t.preventDefault(),fetch(EXPORT_API_URL).then((function(t){return 200!==t.status&&window.alert("An error occurred while exporting..."),t.json()})).then((function(t){var e=JSON.stringify(t,null,2);triggerFileDownload(EXPORT_FILE_NAME,e)}))},exportButton=document.querySelector("#item-export");exportButton&&exportButton.addEventListener("click",exportItems);var IMPORT_API_URL="api/item",APP_LOAD_URL="appload",updateStatus=function(t){var e,n=t.item,i=t.errors;console.log(n,i),e=0===i.length?'
  • Imported: '.concat(n.title,"
  • "):'
  • Failed: '.concat(n.title," - ").concat(i[0],"
  • "),document.querySelector(".import-status").innerHTML+=e};function clearStatus(){document.querySelector(".import-status").innerHTML=""}var postToApi=function(t,e){return fetch(IMPORT_API_URL,{method:"POST",cache:"no-cache",redirect:"follow",headers:{"Content-Type":"application/json","X-CSRF-TOKEN":e},body:JSON.stringify(t)})},getCSRFToken=function(){return document.querySelector('input[name="_token"]').value},mergeItemWithAppDetails=function(t,e){return{pinned:1,tags:[0],appid:t.appid,title:t.title,colour:t.colour,url:t.url,appdescription:t.appdescription?t.appdescription:e.description,website:e.website,icon:e.iconview,config:t.description?JSON.parse(t.description):null}},fetchAppDetails=function(t){return null===t||"null"===t?Promise.resolve({}):fetch(APP_LOAD_URL,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({app:t})}).then((function(t){return t.json()}))},importItems=function(t){t.forEach((function(t){var e=[];fetchAppDetails(t.appid).catch((function(){return e.push(new Error("Failed to find app id: ".concat(t.appid)))})).then((function(e){var n=mergeItemWithAppDetails(t,e),i=getCSRFToken();return postToApi(n,i)})).catch((function(){return e.push(new Error("Failed to create item: ".concat(t.title)))})).finally((function(){updateStatus({item:t,errors:e})}))}))},readJSON=function(t){return new Promise((function(e,n){try{var i=new FileReader;i.onload=function(t){var n=t.target.result;e(JSON.parse(n))},i.readAsText(t)}catch(t){n(new Error("Unable to read file"))}}))},openFileForImport=function(t){return clearStatus(),readJSON(t).catch((function(t){console.error(t)})).then(importItems)},fileInput=document.querySelector("input[name='import']"),importButton=document.querySelectorAll(".import-button");fileInput&&importButton&&(importButton.forEach((function(t){t.addEventListener("click",(function(){var t=fileInput.files[0];t&&openFileForImport(t)}))})),fileInput.addEventListener("change",openFileForImport,!1)); +function _typeof(t){return _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},_typeof(t)}!function(t,e){"function"==typeof define&&define.amd?define("ev-emitter/ev-emitter",e):"object"==("undefined"==typeof module?"undefined":_typeof(module))&&module.exports?module.exports=e():t.EvEmitter=e()}("undefined"!=typeof window?window:this,(function(){function t(){}var e=t.prototype;return e.on=function(t,e){if(t&&e){var n=this._events=this._events||{},i=n[t]=n[t]||[];return-1==i.indexOf(e)&&i.push(e),this}},e.once=function(t,e){if(t&&e){this.on(t,e);var n=this._onceEvents=this._onceEvents||{};return(n[t]=n[t]||{})[e]=!0,this}},e.off=function(t,e){var n=this._events&&this._events[t];if(n&&n.length){var i=n.indexOf(e);return-1!=i&&n.splice(i,1),this}},e.emitEvent=function(t,e){var n=this._events&&this._events[t];if(n&&n.length){var i=0,o=n[i];e=e||[];for(var s=this._onceEvents&&this._onceEvents[t];o;){var r=s&&s[o];r&&(this.off(t,o),delete s[o]),o.apply(this,e),o=n[i+=r?0:1]}return this}},t})),function(t,e){"function"==typeof define&&define.amd?define("unipointer/unipointer",["ev-emitter/ev-emitter"],(function(n){return e(t,n)})):"object"==("undefined"==typeof module?"undefined":_typeof(module))&&module.exports?module.exports=e(t,require("ev-emitter")):t.Unipointer=e(t,t.EvEmitter)}(window,(function(t,e){function n(){}var i=n.prototype=Object.create(e.prototype);i.bindStartEvent=function(t){this._bindStartEvent(t,!0)},i.unbindStartEvent=function(t){this._bindStartEvent(t,!1)},i._bindStartEvent=function(e,n){var i=(n=void 0===n||!!n)?"addEventListener":"removeEventListener";t.navigator.pointerEnabled?e[i]("pointerdown",this):t.navigator.msPointerEnabled?e[i]("MSPointerDown",this):(e[i]("mousedown",this),e[i]("touchstart",this))},i.handleEvent=function(t){var e="on"+t.type;this[e]&&this[e](t)},i.getTouch=function(t){for(var e=0;e.5;var o=this.colorGrid[e.toUpperCase()];this.updateCursor(o),this.setTexts(),this.setBackgrounds(),n||this.emitEvent("change",[e,t.hue,t.sat,t.lum])}},u.setTexts=function(){if(this.setTextElems)for(var t=0;t0&&i.attr("value",n)}$(".message-container").length&&setTimeout((function(){$(".message-container").fadeOut()}),3500),$("#upload").change((function(){!function(t){if(t.files&&t.files[0]){var e=new FileReader;e.onload=function(t){$("#appimage img").attr("src",t.target.result)},e.readAsDataURL(t.files[0])}}(this)})),$("#sortable").sortable({stop:function(){var e=$("#sortable").sortable("toArray",{attribute:"data-id"});$.post("".concat(t,"order"),{order:e})}}),$("#sortable").sortable("disable"),$("#main").on("mouseenter","#sortable.ui-sortable-disabled .item",(function(){$(this).siblings(".tooltip").addClass("active"),$(".refresh",this).addClass("active")})).on("mouseleave",".item",(function(){$(this).siblings(".tooltip").removeClass("active"),$(".refresh",this).removeClass("active")})),$("#config-buttons").on("mouseenter","a",(function(){$(".tooltip",this).addClass("active")})).on("mouseleave","a",(function(){$(".tooltip",this).removeClass("active")})),$(".searchform > form").on("submit",(function(t){"tiles"===$("#search-container select[name=provider]").val()&&t.preventDefault()})),$("#search-container").on("input","input[name=q]",(function(){var t=this.value,e=$("#sortable").children(".item-container");"tiles"===$("#search-container select[name=provider]").val()&&t.length>0?(e.hide(),e.filter((function(){return $(this).data("name").toLowerCase().includes(t.toLowerCase())})).show()):e.show()})).on("change","select[name=provider]",(function(){var t=$("#sortable").children(".item-container");if("tiles"===$(this).val()){$("#search-container button").hide();var e=$("#search-container input[name=q]").val();e.length>0?(t.hide(),t.filter((function(){return $(this).data("name").toLowerCase().includes(e.toLowerCase())})).show()):t.show()}else $("#search-container button").show(),t.show()})),$("#app").on("click","#config-button",(function(t){t.preventDefault();var e=$("#app"),n=e.hasClass("header");e.toggleClass("header"),n?($(".add-item").hide(),$(".item-edit").hide(),$("#app").removeClass("sidebar"),$("#sortable .tooltip").css("display",""),$("#sortable").sortable("disable")):($("#sortable .tooltip").css("display","none"),$("#sortable").sortable("enable"),setTimeout((function(){$(".add-item").fadeIn(),$(".item-edit").fadeIn()}),350))})).on("click","#add-item, #pin-item",(function(t){t.preventDefault(),$("#app").toggleClass("sidebar")})).on("click",".close-sidenav",(function(t){t.preventDefault(),$("#app").removeClass("sidebar")})).on("click","#test_config",(function(e){e.preventDefault();var i=$("#create input[name=url]").val(),o=$('#sapconfig input[name="config[override_url]"]').val();o.length&&""!==o&&(i=o);var s={};s.url=i,$(".config-item").each((function(){var t=$(this).data("config");s[t]=$(this).val()})),s.id=$("form[data-item-id]").data("item-id"),s.password&&s.password===n&&(s.password=""),$.post("".concat(t,"test_config"),{data:s},(function(t){alert(t)}))})),$("#pinlist").on("click","a",(function(e){e.preventDefault();var n=$(this),i=n.data("id"),o=n.data("tag");$.get("".concat(t,"items/pintoggle/").concat(i,"/true/").concat(o),(function(t){var e=$(t).filter("#sortable").html();$("#sortable").html(e),n.toggleClass("active")}))})),$("#itemform").on("submit",(function(){var t=$('input[name="config[password]"]').first();t.length>0&&t.attr("value")===n&&t.attr("value","")}))}));var focusSearch=function(t){var e=document.querySelector('input[name="q"]');e&&(t.preventDefault(),e.focus())},openFirstNonHiddenItem=function(t){if(t.target===document.querySelector('input[name="q"]')&&"tiles"===document.querySelector("#search-container select[name=provider]").value){var e=document.querySelector('#sortable section.item-container:not([style="display: none;"]) a');"href"in e&&(t.preventDefault(),window.open(e.href))}},KEY_BINDINGS={"/":focusSearch,Enter:openFirstNonHiddenItem};document.addEventListener("keydown",(function(t){try{t.key in KEY_BINDINGS&&KEY_BINDINGS[t.key](t)}catch(t){}}));var EXPORT_FILE_NAME="HeimdallExport.json",EXPORT_API_URL="api/item";function triggerFileDownload(t,e){var n=document.createElement("a"),i=new Blob([e],{type:"text/plain"});n.href=URL.createObjectURL(i),n.download=EXPORT_FILE_NAME,n.click()}var exportItems=function(t){t.preventDefault(),fetch(EXPORT_API_URL).then((function(t){return 200!==t.status&&window.alert("An error occurred while exporting..."),t.json()})).then((function(t){var e=JSON.stringify(t,null,2);triggerFileDownload(EXPORT_FILE_NAME,e)}))},exportButton=document.querySelector("#item-export");exportButton&&exportButton.addEventListener("click",exportItems);var IMPORT_API_URL="api/item",APP_LOAD_URL="appload",updateStatus=function(t){var e,n=t.item,i=t.errors;console.log(n,i),e=0===i.length?'
  • Imported: '.concat(n.title,"
  • "):'
  • Failed: '.concat(n.title," - ").concat(i[0],"
  • "),document.querySelector(".import-status").innerHTML+=e};function clearStatus(){document.querySelector(".import-status").innerHTML=""}var postToApi=function(t,e){return fetch(IMPORT_API_URL,{method:"POST",cache:"no-cache",redirect:"follow",headers:{"Content-Type":"application/json","X-CSRF-TOKEN":e},body:JSON.stringify(t)})},getCSRFToken=function(){return document.querySelector('input[name="_token"]').value},mergeItemWithAppDetails=function(t,e){return{pinned:1,tags:[0],appid:t.appid,title:t.title,colour:t.colour,url:t.url,appdescription:t.appdescription?t.appdescription:e.description,website:e.website,icon:e.iconview,config:t.description?JSON.parse(t.description):null}},fetchAppDetails=function(t){return null===t||"null"===t?Promise.resolve({}):fetch(APP_LOAD_URL,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({app:t})}).then((function(t){return t.json()}))},importItems=function(t){t.forEach((function(t){var e=[];fetchAppDetails(t.appid).catch((function(){return e.push(new Error("Failed to find app id: ".concat(t.appid)))})).then((function(e){var n=mergeItemWithAppDetails(t,e),i=getCSRFToken();return postToApi(n,i)})).catch((function(){return e.push(new Error("Failed to create item: ".concat(t.title)))})).finally((function(){updateStatus({item:t,errors:e})}))}))},readJSON=function(t){return new Promise((function(e,n){try{var i=new FileReader;i.onload=function(t){var n=t.target.result;e(JSON.parse(n))},i.readAsText(t)}catch(t){n(new Error("Unable to read file"))}}))},openFileForImport=function(t){return clearStatus(),readJSON(t).catch((function(t){console.error(t)})).then(importItems)},fileInput=document.querySelector("input[name='import']"),importButton=document.querySelectorAll(".import-button");fileInput&&importButton&&(importButton.forEach((function(t){t.addEventListener("click",(function(){var t=fileInput.files[0];t&&openFileForImport(t)}))})),fileInput.addEventListener("change",openFileForImport,!1));var REFRESH_INTERVAL_SMALL=5e3,REFRESH_INTERVAL_BIG=3e4,QUEUE_PROCESSING_INTERVAL=1e3,CONTAINER_SELECTOR=".livestats-container";function createQueue(){var t=[],e=!1;return document.addEventListener("visibilitychange",(function(){e=document.hidden})),setInterval((function(){0!==t.length&&!0!==e&&t.shift()()}),QUEUE_PROCESSING_INTERVAL),t}function getContainers(){return document.querySelectorAll(CONTAINER_SELECTOR)}function getQueueInterval(t,e){return t?REFRESH_INTERVAL_BIG:e?REFRESH_INTERVAL_SMALL:REFRESH_INTERVAL_BIG}function createUpdateJob(t,e){var n=t.getAttribute("data-id"),i="1"===t.getAttribute("data-dataonly");return function(){return fetch("get_stats/".concat(n)).then((function(t){if(t.ok)return t.json();throw new Error("Network response was not ok: ".concat(t.status))})).then((function(n){t.innerHTML=n.html;var o="active"===n.status;e&&setTimeout((function(){e.push(createUpdateJob(t,e))}),getQueueInterval(i,o))})).catch((function(t){console.error(t)}))}}var livestatContainers=getContainers();if(livestatContainers.length>0){var myQueue=createQueue();livestatContainers.forEach((function(t){createUpdateJob(t,myQueue)()}))} diff --git a/public/mix-manifest.json b/public/mix-manifest.json index 091c2514..6428d1b6 100644 --- a/public/mix-manifest.json +++ b/public/mix-manifest.json @@ -1,4 +1,4 @@ { "/css/app.css": "/css/app.css?id=910562b0b11f9731ff1cdded5e57f7b5", - "/js/app.js": "/js/app.js?id=455ff98b9cf4ee09f73e8521270cea96" + "/js/app.js": "/js/app.js?id=86f896ef6c2066036a4e2b946e07750d" } diff --git a/resources/assets/js/app.js b/resources/assets/js/app.js index 120dbb7e..5c91318d 100644 --- a/resources/assets/js/app.js +++ b/resources/assets/js/app.js @@ -19,88 +19,6 @@ $.when($.ready).then(() => { }, 3500); } - // from https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API - // Set the name of the hidden property and the change event for visibility - let hidden; - let visibilityChange; - if (typeof document.hidden !== "undefined") { - // Opera 12.10 and Firefox 18 and later support - hidden = "hidden"; - visibilityChange = "visibilitychange"; - } else if (typeof document.msHidden !== "undefined") { - hidden = "msHidden"; - visibilityChange = "msvisibilitychange"; - } else if (typeof document.webkitHidden !== "undefined") { - hidden = "webkitHidden"; - visibilityChange = "webkitvisibilitychange"; - } - - const livestatsRefreshTimeouts = []; - const livestatsFuncs = []; - const livestatsContainers = $(".livestats-container"); - function stopLivestatsRefresh() { - livestatsRefreshTimeouts.forEach((timeoutId) => { - window.clearTimeout(timeoutId); - }); - } - function startLivestatsRefresh() { - livestatsFuncs.forEach((fun) => { - fun(); - }); - } - - if (livestatsContainers.length > 0) { - if ( - typeof document.addEventListener === "undefined" || - hidden === undefined - ) { - console.log("This browser does not support visibilityChange"); - } else { - document.addEventListener( - visibilityChange, - () => { - if (document[hidden]) { - stopLivestatsRefresh(); - } else { - startLivestatsRefresh(); - } - }, - false - ); - } - - livestatsContainers.each(function (index) { - const id = $(this).data("id"); - const dataonly = $(this).data("dataonly"); - const increaseby = dataonly === 1 ? 20000 : 1000; - const container = $(this); - const maxTimer = 30000; - let timer = 5000; - const fun = function worker() { - $.ajax({ - url: `${base}get_stats/${id}`, - dataType: "json", - success(data) { - container.html(data.html); - if (data.status === "active") timer = increaseby; - else if (timer < maxTimer) timer += 2000; - }, - complete(jqXHR) { - if (jqXHR.status > 299) { - // Stop polling when we get errors - return; - } - - // Schedule the next request when the current one's complete - livestatsRefreshTimeouts[index] = window.setTimeout(worker, timer); - }, - }); - }; - livestatsFuncs[index] = fun; - fun(); - }); - } - function readURL(input) { if (input.files && input.files[0]) { const reader = new FileReader(); diff --git a/resources/assets/js/liveStatRefresh.js b/resources/assets/js/liveStatRefresh.js new file mode 100644 index 00000000..71706935 --- /dev/null +++ b/resources/assets/js/liveStatRefresh.js @@ -0,0 +1,100 @@ +const REFRESH_INTERVAL_SMALL = 5000; +const REFRESH_INTERVAL_BIG = 30000; +const QUEUE_PROCESSING_INTERVAL = 1000; +const CONTAINER_SELECTOR = ".livestats-container"; + +/** + * @returns {*[]} + */ +function createQueue() { + const queue = []; + let suspended = false; + + function processQueue() { + if (queue.length === 0 || suspended === true) { + return; + } + + const next = queue.shift(); + next(); + } + + document.addEventListener("visibilitychange", () => { + suspended = document.hidden; + }); + + setInterval(processQueue, QUEUE_PROCESSING_INTERVAL); + + return queue; +} + +/** + * @returns {NodeListOf} + */ +function getContainers() { + return document.querySelectorAll(CONTAINER_SELECTOR); +} + +/** + * + * @param {boolean} dataOnly + * @param {boolean} active + * @returns {number} + */ +function getQueueInterval(dataOnly, active) { + if (dataOnly) { + return REFRESH_INTERVAL_BIG; + } + + if (active) { + return REFRESH_INTERVAL_SMALL; + } + + return REFRESH_INTERVAL_BIG; +} + +/** + * @param {HTMLElement} container + * @param {array} queue + * @returns {function(): Promise} + */ +function createUpdateJob(container, queue) { + const id = container.getAttribute("data-id"); + // Data only attribute seems to indicate that the item should not be updated that often + const isDataOnly = container.getAttribute("data-dataonly") === "1"; + + return () => + fetch(`get_stats/${id}`) + .then((response) => { + if (response.ok) { + return response.json(); + } + + throw new Error(`Network response was not ok: ${response.status}`); + }) + .then((data) => { + // eslint-disable-next-line no-param-reassign + container.innerHTML = data.html; + + const isActive = data.status === "active"; + + if (queue) { + setTimeout(() => { + queue.push(createUpdateJob(container, queue)); + }, getQueueInterval(isDataOnly, isActive)); + } + }) + .catch((error) => { + console.error(error); + }); +} + +const livestatContainers = getContainers(); + +if (livestatContainers.length > 0) { + const myQueue = createQueue(); + + livestatContainers.forEach((container) => { + createUpdateJob(container, myQueue)(); + }); +} diff --git a/webpack.mix.js b/webpack.mix.js index 6fa6828d..5adaf892 100644 --- a/webpack.mix.js +++ b/webpack.mix.js @@ -20,6 +20,7 @@ mix "resources/assets/js/keyBindings.js", "resources/assets/js/itemExport.js", "resources/assets/js/itemImport.js", + "resources/assets/js/liveStatRefresh.js", ], "public/js/app.js" )