From 17a9d723f18e91a73355c4d3b5691b0975ae0352 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Diemer?= Date: Fri, 1 Mar 2024 13:53:25 +0100 Subject: [PATCH] Add an argument to the callback in PollingManager to stop the polling | refs #35772 --- dist/jsu.min.js | 2 +- dist/jsu.min.mjs | 2 +- src/lib/polling-manager.js | 8 +++++--- tests/test_polling.spec.js | 32 ++++++++++++++++++++++++++------ 4 files changed, 33 insertions(+), 11 deletions(-) diff --git a/dist/jsu.min.js b/dist/jsu.min.js index c0e246c..786c615 100644 --- a/dist/jsu.min.js +++ b/dist/jsu.min.js @@ -1 +1 @@ -class JavaScriptUtilities{constructor(){this.version=11,this.ignoreUntilFocusChanges=!1,this.userAgent=window.navigator&&window.navigator.userAgent?window.navigator.userAgent.toLowerCase():"unknown",this.userAgentData=null,this.osName="",this.osVersion="",this.browserName="",this.browserVersion="",this.isTactile=!1,this.isMobile=!1,this._translations={en:{}},this._currentLang="en",this._currentCatalog=this._translations.en,this._getOSInfo(),this._getBrowserInfo(),this._overrideHttpRequest(),window.jsu?this.version!=window.jsu.version&&(console.warn('Another version of jsu.js was already imported, jsu will be replaced by most recent version. Version: "'+this.version+'", other version: "'+window.jsu.version+'".'),window.jsu.version0){let t=document.cookie.indexOf(e+"=");if(-1!=t){t=t+e.length+1;let s=document.cookie.indexOf(";",t);return-1==s&&(s=document.cookie.length),window.decodeURIComponent(document.cookie.substring(t,s))}}return t}setCookie(e,t,s=360){const n=new Date;n.setDate(n.getDate()+s);const i=0===window.location.href.indexOf("https://")?"; secure; samesite=none":"";document.cookie=e+"="+window.decodeURIComponent(t)+"; expires="+n.toUTCString()+"; path=/"+i}strip(e,t=""){if(!e)return e;const s=""!==t?t:" \n\r\t ";let n=0;for(;n=0&&-1!=s.indexOf(e[i]);)i--;return e.substring(n,i+1)}slugify(e){return e.toString().toLowerCase().replace(/\s+/g,"-").replace(/[^-\w]+/g,"").replace(/-+/g,"-").replace(/^-+/,"").replace(/-+$/,"")}stripHTML(e){if(!e)return e;const t=document.createElement("div");return t.innerHTML=e,t.textContent}decodeHTML(e){if(!e)return"";const t=document.createElement("div");return t.innerHTML=e,0===t.childNodes.length?"":t.childNodes[0].nodeValue}escapeHTML(e){if(!e)return e;let t=e.toString();return t=(t=(t=(t=t.replace(/(&)/g,"&")).replace(/(<)/g,"<")).replace(/(>)/g,">")).replace(/(\n)/g,"
")}escapeAttribute(e){if(!e)return e;let t=e.toString();return t=(t=(t=t.replace(/(")/g,""")).replace(/(')/g,"'")).replace(/(\n)/g," ")}getClickPosition(e,t){let s=t,n=0,i=0;for(;null!=s;)n+=s.offsetLeft,i+=s.offsetTop,s=s.offsetParent;return{x:e.pageX-n,y:e.pageY-i}}onDOMLoad(e){"complete"===document.readyState||"interactive"===document.readyState?setTimeout(e,1):document.addEventListener("DOMContentLoaded",e)}httpRequest(e){const t=e.params?e.params:{};e.cache||(t._=(new Date).getTime());const s=e.method?e.method.toUpperCase():"GET";let n=e.url?e.url:"";const i=e.headers?e.headers:{};if(!/^(GET|HEAD|OPTIONS|TRACE)$/.test(s)){const e=this.getCookie("csrftoken");e&&(i["X-CSRFToken"]=e)}const r=[];for(const e in t)if(t[e]instanceof Array)for(const s of t[e])r.push(encodeURIComponent(e)+"="+encodeURIComponent(s));else r.push(encodeURIComponent(e)+"="+encodeURIComponent(t[e]));let o;if(r.length>0&&(n+=(-1===n.indexOf("?")?"?":"&")+r.join("&")),e.jsonData)i["Content-Type"]="application/json; charset=UTF-8",o=e.data;else if(e.data instanceof FormData)o=e.data;else if(e.data){o=new FormData;for(const t in e.data)if(e.data[t]instanceof Array)for(const s of e.data[t])o.append(t+"[]",s);else o.append(t,e.data[t])}else o=null;const a=new XMLHttpRequest;e.progress&&a.upload&&a.upload.addEventListener("progress",e.progress,!1),e.callback&&(a.addEventListener("readystatechange",function(){if(this.readyState!==XMLHttpRequest.DONE)return;if(a._callbackCalled)return;let t;if(a._callbackCalled=!0,e.json)if(""===this.responseText)t={error:"No response.",empty:!0,raw:this.responseText};else try{t=JSON.parse(this.responseText)}catch(e){t={error:"Failed to parse json response: "+e,raw:this.responseText}}else t=this.responseText;e.callback(this,t)}),a.addEventListener("error",function(t){if(a._callbackCalled)return;a._callbackCalled=!0;const s=t.error||t.message||(t.detail?t.detail.error||t.detail.message:"Unknown error");e.callback(this,{error:s})})),a.open(s,n,!e.synchronous);for(const e in i)if(i[e]instanceof Array)for(const t of i[e])a.setRequestHeader(e,t);else a.setRequestHeader(e,i[e]);return a.send(o),a}compareVersions(e,t,s){t="="==t?"==":t;const n=e.split("."),i=s.split("."),r=Math.max(n.length,i.length);for(let e=0;es)return-1}return 0}setObjectAttributes(e,t,s=null){if(t){"translations"in t&&(this.addTranslations(t.translations),delete t.translations);for(const n in t)s&&-1==s.indexOf(n)||(e[n]=t[n])}}getWebglContext(e,t={},s=""){if(window.WebGLRenderingContext)try{let n;return(n="safari"===s?e.getContext("webgl",t)||e.getContext("experimental-webgl",t):e.getContext("webgl2",t)||e.getContext("webgl",t)||e.getContext("experimental-webgl",t))||(console.log("Failed to initialize WebGL context. Your browser does not support Webgl context."),null)}catch(e){return console.log("WebGL context is supported but may be disable, please check your browser configuration."),null}return console.log("Your browser does not support Webgl context"),null}isInIframe(){return!(!window.frameElement||"IFRAME"!=window.frameElement.nodeName)}attemptFocus(e){if(!this.isFocusable(e))return!1;this.ignoreUntilFocusChanges=!0;try{e.focus()}catch(t){console.log("Failed to focus element.",e,t)}return this.ignoreUntilFocusChanges=!1,document.activeElement===e}isFocusable(e){if(e.tabIndex>0||0===e.tabIndex&&null!==e.getAttribute("tabIndex"))return!0;if(e.disabled)return!1;switch(e.nodeName){case"A":return!!e.href&&"ignore"!=e.rel;case"INPUT":return"hidden"!=e.type&&"file"!=e.type;case"BUTTON":case"SELECT":case"TEXTAREA":return!0;default:return!1}}focusFirstDescendant(e){for(let t=0;t=0;t--){const s=e.childNodes[t];if(this.attemptFocus(s)||this.focusLastDescendant(s))return!0}return!1}_getOSInfo(){let e,t;if(!e&&window.navigator&&window.navigator.platform){const s=window.navigator.platform.toLowerCase();-1==s.indexOf("ipad")&&-1==s.indexOf("iphone")&&-1==s.indexOf("ipod")||(e="ios",t=parseFloat((""+(/CPU.*OS ([0-9_]{1,5})|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent)||[0,""])[1]).replace("undefined","3_2").replace("_",".").replace("_",""))||!1)}if(!e&&window.navigator&&window.navigator.appVersion){const t=window.navigator.appVersion.toLowerCase();-1!=t.indexOf("win")?e="windows":-1!=t.indexOf("mac")?e="macos":-1==t.indexOf("x11")&&-1==t.indexOf("linux")||(e="linux")}this.osName=e||"unknown",this.osVersion=t||0}_getBrowserInfo(){let e,t=0;if(window.navigator&&window.navigator.userAgentData&&window.navigator.userAgentData.brands)for(let s=0;s=45,t=("chrome"===this.browserName||"chromium"===this.browserName)&&this.browserVersion>=57,s="safari"===this.browserName&&this.browserVersion>=16,n="edge"===this.browserName&&this.browserVersion>=79;return e||t||n||s}isLivestreamingAvailable(){const e=("chrome"===this.browserName||"chromium"===this.browserName)&&this.browserVersion>=57,t="edge"===this.browserName&&this.browserVersion>=79,s="safari"===this.browserName&&this.browserVersion>=16;return e||t||s}useLang(e){this._currentLang=e,this._translations[e]||(this._translations[e]={}),this._currentCatalog=this._translations[e]}getCurrentLang(){return this._currentLang}getCurrentCatalog(){return this._currentCatalog}addTranslations(e,t=""){let s;t?(this._translations[t]||(this._translations[t]={}),s=this._translations[t]):s=this._currentCatalog;for(const t of Object.keys(e))e[t]&&(s[t]=e[t])}translate(e,t=""){const s=(t?t+"":"")+e;return s in this._currentCatalog?this._currentCatalog[s]:"en"!=this._currentLang&&s in this._translations.en?this._translations.en[s]:e}translateHTML(e,t=""){const s=this.translate(e,t);return this.escapeHTML(s)}translateAttribute(e,t=""){const s=this.translate(e,t);return this.escapeAttribute(s)}getDateDisplay(e){if(!e)return"";const t=/^(\d+)-(\d+)-(\d+)(?: |T)(\d+):(\d+):(\d+)$/.exec(e);if(!t)return e;const s=t[1];let n=null;switch(t[2]){case"01":n=this.translate("January");break;case"02":n=this.translate("February");break;case"03":n=this.translate("March");break;case"04":n=this.translate("April");break;case"05":n=this.translate("May");break;case"06":n=this.translate("June");break;case"07":n=this.translate("July");break;case"08":n=this.translate("August");break;case"09":n=this.translate("September");break;case"10":n=this.translate("October");break;case"11":n=this.translate("November");break;case"12":n=this.translate("December")}const i=t[3];let r,o=parseInt(t[4],10),a=parseInt(t[5],10);if(!n||isNaN(o)||isNaN(a))return e;if(a<10&&(a="0"+a),"en"!==this._currentLang)o<10&&(o="0"+o),r=o+":"+a;else{let e;o<12?(e="AM",o||(o=12)):(e="PM",o>12&&(o-=12)),r=o+":"+a+" "+e}return i+" "+n+" "+s+" "+this.translate("at")+" "+r}getSizeDisplay(e){if(!e||isNaN(e))return"0 "+this.translate("B");let t="";return e>1e3&&(t="k",(e/=1e3)>1e3&&(t="M",(e/=1e3)>1e3&&(t="G",(e/=1e3)>1e3&&(e/=1e3,t="T")))),e.toFixed(1)+" "+t+this.translate("B")}getHashFromRequest(e,t,s,n={}){let i=e+t;if(i&&i.includes("_=")&&((i=i.replace(/_=[0-9]+&?/g,"")).endsWith("?")||i.endsWith("&"))&&(i=i.substring(0,i.length-1)),s instanceof FormData||s instanceof URLSearchParams)i+=JSON.stringify(Object.fromEntries(s));else if(s instanceof Blob)i+="blob-"+s.size;else if(s instanceof ArrayBuffer)i+="arraybuffer-"+s.byteLength;else if(s)try{i+=JSON.stringify(s)}catch(e){i+=JSON.stringify(new Date)}return Object.keys(n).length&&(i+=JSON.stringify(n)),i}_overrideHttpRequest(){window.xhrOverride=!0;const e=[];XMLHttpRequest.noIntercept=!1;const t=XMLHttpRequest.prototype.open;XMLHttpRequest.prototype.open=function(e,s){return this._method=e,this._url=s,t.apply(this,arguments)};const s=XMLHttpRequest.prototype.setRequestHeader;XMLHttpRequest.prototype.setRequestHeader=function(e,t){const n=s.apply(this,arguments);return this._headers||(this._headers={}),this._headers[e]||(this._headers[e]=[]),this._headers[e].push(t),n};const n=XMLHttpRequest.prototype.send;XMLHttpRequest.prototype.send=function(t){const s=window.jsu.getHashFromRequest(this._method,this._url,t,this._headers);if(e.includes(s)){const e="Duplicated request aborted";return Object.defineProperty(this,"statusText",{value:e,writable:!1}),this.dispatchEvent(new CustomEvent("error",{detail:{error:e,message:e}}))}return e.push(s),this.noIntercept||this.addEventListener&&this.addEventListener("readystatechange",function(){this.readyState===XMLHttpRequest.DONE&&e.splice(e.indexOf(s),1)},!1),n.apply(this,arguments)}}}class ChunkedUpload{constructor(e){const t=["file","uploadURL","completeURL"],s={debugMode:null,extraHeaders:{},extraData:{},maxRetry:30,retryDelay:1e4,chunkSize:2e7,fileNameSuffix:"",progressCallback:null,retryCallback:null,successCallback:null,failureCallback:null,inTest:!1};for(const s of t){if(!e[s])throw new Error('A mandatory argument is missing: "'+s+'".');this[s]=e[s]}for(const t in s)this[t]=void 0!==e[t]?e[t]:s[t];null===this.debugMode&&-1!==window.location.hash.indexOf("debug")&&(this.debugMode=!0),this.sendFile()}logDebug(){this.debugMode&&!this.inTest&&console.log.apply(null,arguments)}logError(){this.inTest||console.error.apply(null,arguments)}logWarn(){this.inTest||console.warn.apply(null,arguments)}onProgress(e){this.progressCallback&&this.progressCallback(e)}onRetry(e,t){let s;if(this.retryCallback&&(s=this.retryCallback(e)),void 0===s){const e=this;s=new Promise(function(t){e.logDebug("Retrying in "+e.retryDelay+" ms..."),setTimeout(t,e.retryDelay)})}s.then(t)}onSuccess(){this.successCallback&&this.successCallback(this.uploadId)}onFailure(e){this.failureCallback&&this.failureCallback(e)}sendFile(){if(this.onProgress(0),this.uploadId=null,this.fileName=this.file.name,this.fileNameSuffix){const e=this.fileName.lastIndexOf(".");this.fileName=e>0?this.fileName.substring(0,e)+this.fileNameSuffix+this.fileName.substring(e):"file"+this.fileNameSuffix+".tmp"}this.logDebug("Number of chunk to send:",Math.ceil(this.file.size/this.chunkSize),this.chunkSize,this.file.size),this.sendNextChunk(0,0)}sendNextChunk(e,t){this.logDebug("Sending chunk:","start:",e,"total size:",this.file.size,"retries:",t);const s=Math.min(e+this.chunkSize,this.file.size),n=new FormData;n.append("file",this.file.slice(e,s),this.fileName),n.append("retries",t),this.uploadId&&n.append("upload_id",this.uploadId);for(const e in this.extraData)n.append(e,this.extraData[e]);const i=(s-e)/this.file.size,r=Object.assign(this.extraHeaders,{"Content-Range":"bytes "+e+"-"+(s-1)+"/"+this.file.size});this.logDebug("Content-Range",r["Content-Range"]);const o=this;jsu.httpRequest({method:"POST",url:this.uploadURL,headers:r,data:n,json:!0,progress:function(t){if(t.lengthComputable){let s=e/o.file.size;t.total&&(s+=i*(t.loaded/t.total)),s=Math.floor(95*s),o.logDebug("Progress:",s,i,t.loaded,t.total),o.onProgress(s)}},callback:function(n,i){if(200==n.status&&i.upload_id){o.logDebug("Chunk sent",i),o.uploadId=i.upload_id;const e=s;e>=o.file.size?o.completeUpload(0):o.sendNextChunk(e,0)}else o.logError("Failed to send chunk:",i),t0){let t=document.cookie.indexOf(e+"=");if(-1!=t){t=t+e.length+1;let s=document.cookie.indexOf(";",t);return-1==s&&(s=document.cookie.length),window.decodeURIComponent(document.cookie.substring(t,s))}}return t}setCookie(e,t,s=360){const n=new Date;n.setDate(n.getDate()+s);const i=0===window.location.href.indexOf("https://")?"; secure; samesite=none":"";document.cookie=e+"="+window.decodeURIComponent(t)+"; expires="+n.toUTCString()+"; path=/"+i}strip(e,t=""){if(!e)return e;const s=""!==t?t:" \n\r\t ";let n=0;for(;n=0&&-1!=s.indexOf(e[i]);)i--;return e.substring(n,i+1)}slugify(e){return e.toString().toLowerCase().replace(/\s+/g,"-").replace(/[^-\w]+/g,"").replace(/-+/g,"-").replace(/^-+/,"").replace(/-+$/,"")}stripHTML(e){if(!e)return e;const t=document.createElement("div");return t.innerHTML=e,t.textContent}decodeHTML(e){if(!e)return"";const t=document.createElement("div");return t.innerHTML=e,0===t.childNodes.length?"":t.childNodes[0].nodeValue}escapeHTML(e){if(!e)return e;let t=e.toString();return t=(t=(t=(t=t.replace(/(&)/g,"&")).replace(/(<)/g,"<")).replace(/(>)/g,">")).replace(/(\n)/g,"
")}escapeAttribute(e){if(!e)return e;let t=e.toString();return t=(t=(t=t.replace(/(")/g,""")).replace(/(')/g,"'")).replace(/(\n)/g," ")}getClickPosition(e,t){let s=t,n=0,i=0;for(;null!=s;)n+=s.offsetLeft,i+=s.offsetTop,s=s.offsetParent;return{x:e.pageX-n,y:e.pageY-i}}onDOMLoad(e){"complete"===document.readyState||"interactive"===document.readyState?setTimeout(e,1):document.addEventListener("DOMContentLoaded",e)}httpRequest(e){const t=e.params?e.params:{};e.cache||(t._=(new Date).getTime());const s=e.method?e.method.toUpperCase():"GET";let n=e.url?e.url:"";const i=e.headers?e.headers:{};if(!/^(GET|HEAD|OPTIONS|TRACE)$/.test(s)){const e=this.getCookie("csrftoken");e&&(i["X-CSRFToken"]=e)}const r=[];for(const e in t)if(t[e]instanceof Array)for(const s of t[e])r.push(encodeURIComponent(e)+"="+encodeURIComponent(s));else r.push(encodeURIComponent(e)+"="+encodeURIComponent(t[e]));let o;if(r.length>0&&(n+=(-1===n.indexOf("?")?"?":"&")+r.join("&")),e.jsonData)i["Content-Type"]="application/json; charset=UTF-8",o=e.data;else if(e.data instanceof FormData)o=e.data;else if(e.data){o=new FormData;for(const t in e.data)if(e.data[t]instanceof Array)for(const s of e.data[t])o.append(t+"[]",s);else o.append(t,e.data[t])}else o=null;const a=new XMLHttpRequest;e.progress&&a.upload&&a.upload.addEventListener("progress",e.progress,!1),e.callback&&(a.addEventListener("readystatechange",function(){if(this.readyState!==XMLHttpRequest.DONE)return;if(a._callbackCalled)return;let t;if(a._callbackCalled=!0,e.json)if(""===this.responseText)t={error:"No response.",empty:!0,raw:this.responseText};else try{t=JSON.parse(this.responseText)}catch(e){t={error:"Failed to parse json response: "+e,raw:this.responseText}}else t=this.responseText;e.callback(this,t)}),a.addEventListener("error",function(t){if(a._callbackCalled)return;a._callbackCalled=!0;const s=t.error||t.message||(t.detail?t.detail.error||t.detail.message:"Unknown error");e.callback(this,{error:s})})),a.open(s,n,!e.synchronous);for(const e in i)if(i[e]instanceof Array)for(const t of i[e])a.setRequestHeader(e,t);else a.setRequestHeader(e,i[e]);return a.send(o),a}compareVersions(e,t,s){t="="==t?"==":t;const n=e.split("."),i=s.split("."),r=Math.max(n.length,i.length);for(let e=0;es)return-1}return 0}setObjectAttributes(e,t,s=null){if(t){"translations"in t&&(this.addTranslations(t.translations),delete t.translations);for(const n in t)s&&-1==s.indexOf(n)||(e[n]=t[n])}}getWebglContext(e,t={},s=""){if(window.WebGLRenderingContext)try{let n;return(n="safari"===s?e.getContext("webgl",t)||e.getContext("experimental-webgl",t):e.getContext("webgl2",t)||e.getContext("webgl",t)||e.getContext("experimental-webgl",t))||(console.log("Failed to initialize WebGL context. Your browser does not support Webgl context."),null)}catch(e){return console.log("WebGL context is supported but may be disable, please check your browser configuration."),null}return console.log("Your browser does not support Webgl context"),null}isInIframe(){return!(!window.frameElement||"IFRAME"!=window.frameElement.nodeName)}attemptFocus(e){if(!this.isFocusable(e))return!1;this.ignoreUntilFocusChanges=!0;try{e.focus()}catch(t){console.log("Failed to focus element.",e,t)}return this.ignoreUntilFocusChanges=!1,document.activeElement===e}isFocusable(e){if(e.tabIndex>0||0===e.tabIndex&&null!==e.getAttribute("tabIndex"))return!0;if(e.disabled)return!1;switch(e.nodeName){case"A":return!!e.href&&"ignore"!=e.rel;case"INPUT":return"hidden"!=e.type&&"file"!=e.type;case"BUTTON":case"SELECT":case"TEXTAREA":return!0;default:return!1}}focusFirstDescendant(e){for(let t=0;t=0;t--){const s=e.childNodes[t];if(this.attemptFocus(s)||this.focusLastDescendant(s))return!0}return!1}_getOSInfo(){let e,t;if(!e&&window.navigator&&window.navigator.platform){const s=window.navigator.platform.toLowerCase();-1==s.indexOf("ipad")&&-1==s.indexOf("iphone")&&-1==s.indexOf("ipod")||(e="ios",t=parseFloat((""+(/CPU.*OS ([0-9_]{1,5})|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent)||[0,""])[1]).replace("undefined","3_2").replace("_",".").replace("_",""))||!1)}if(!e&&window.navigator&&window.navigator.appVersion){const t=window.navigator.appVersion.toLowerCase();-1!=t.indexOf("win")?e="windows":-1!=t.indexOf("mac")?e="macos":-1==t.indexOf("x11")&&-1==t.indexOf("linux")||(e="linux")}this.osName=e||"unknown",this.osVersion=t||0}_getBrowserInfo(){let e,t=0;if(window.navigator&&window.navigator.userAgentData&&window.navigator.userAgentData.brands)for(let s=0;s=45,t=("chrome"===this.browserName||"chromium"===this.browserName)&&this.browserVersion>=57,s="safari"===this.browserName&&this.browserVersion>=16,n="edge"===this.browserName&&this.browserVersion>=79;return e||t||n||s}isLivestreamingAvailable(){const e=("chrome"===this.browserName||"chromium"===this.browserName)&&this.browserVersion>=57,t="edge"===this.browserName&&this.browserVersion>=79,s="safari"===this.browserName&&this.browserVersion>=16;return e||t||s}useLang(e){this._currentLang=e,this._translations[e]||(this._translations[e]={}),this._currentCatalog=this._translations[e]}getCurrentLang(){return this._currentLang}getCurrentCatalog(){return this._currentCatalog}addTranslations(e,t=""){let s;t?(this._translations[t]||(this._translations[t]={}),s=this._translations[t]):s=this._currentCatalog;for(const t of Object.keys(e))e[t]&&(s[t]=e[t])}translate(e,t=""){const s=(t?t+"":"")+e;return s in this._currentCatalog?this._currentCatalog[s]:"en"!=this._currentLang&&s in this._translations.en?this._translations.en[s]:e}translateHTML(e,t=""){const s=this.translate(e,t);return this.escapeHTML(s)}translateAttribute(e,t=""){const s=this.translate(e,t);return this.escapeAttribute(s)}getDateDisplay(e){if(!e)return"";const t=/^(\d+)-(\d+)-(\d+)(?: |T)(\d+):(\d+):(\d+)$/.exec(e);if(!t)return e;const s=t[1];let n=null;switch(t[2]){case"01":n=this.translate("January");break;case"02":n=this.translate("February");break;case"03":n=this.translate("March");break;case"04":n=this.translate("April");break;case"05":n=this.translate("May");break;case"06":n=this.translate("June");break;case"07":n=this.translate("July");break;case"08":n=this.translate("August");break;case"09":n=this.translate("September");break;case"10":n=this.translate("October");break;case"11":n=this.translate("November");break;case"12":n=this.translate("December")}const i=t[3];let r,o=parseInt(t[4],10),a=parseInt(t[5],10);if(!n||isNaN(o)||isNaN(a))return e;if(a<10&&(a="0"+a),"en"!==this._currentLang)o<10&&(o="0"+o),r=o+":"+a;else{let e;o<12?(e="AM",o||(o=12)):(e="PM",o>12&&(o-=12)),r=o+":"+a+" "+e}return i+" "+n+" "+s+" "+this.translate("at")+" "+r}getSizeDisplay(e){if(!e||isNaN(e))return"0 "+this.translate("B");let t="";return e>1e3&&(t="k",(e/=1e3)>1e3&&(t="M",(e/=1e3)>1e3&&(t="G",(e/=1e3)>1e3&&(e/=1e3,t="T")))),e.toFixed(1)+" "+t+this.translate("B")}getHashFromRequest(e,t,s,n={}){let i=e+t;if(i&&i.includes("_=")&&((i=i.replace(/_=[0-9]+&?/g,"")).endsWith("?")||i.endsWith("&"))&&(i=i.substring(0,i.length-1)),s instanceof FormData||s instanceof URLSearchParams)i+=JSON.stringify(Object.fromEntries(s));else if(s instanceof Blob)i+="blob-"+s.size;else if(s instanceof ArrayBuffer)i+="arraybuffer-"+s.byteLength;else if(s)try{i+=JSON.stringify(s)}catch(e){i+=JSON.stringify(new Date)}return Object.keys(n).length&&(i+=JSON.stringify(n)),i}_overrideHttpRequest(){window.xhrOverride=!0;const e=[];XMLHttpRequest.noIntercept=!1;const t=XMLHttpRequest.prototype.open;XMLHttpRequest.prototype.open=function(e,s){return this._method=e,this._url=s,t.apply(this,arguments)};const s=XMLHttpRequest.prototype.setRequestHeader;XMLHttpRequest.prototype.setRequestHeader=function(e,t){const n=s.apply(this,arguments);return this._headers||(this._headers={}),this._headers[e]||(this._headers[e]=[]),this._headers[e].push(t),n};const n=XMLHttpRequest.prototype.send;XMLHttpRequest.prototype.send=function(t){const s=window.jsu.getHashFromRequest(this._method,this._url,t,this._headers);if(e.includes(s)){const e="Duplicated request aborted";return Object.defineProperty(this,"statusText",{value:e,writable:!1}),this.dispatchEvent(new CustomEvent("error",{detail:{error:e,message:e}}))}return e.push(s),this.noIntercept||this.addEventListener&&this.addEventListener("readystatechange",function(){this.readyState===XMLHttpRequest.DONE&&e.splice(e.indexOf(s),1)},!1),n.apply(this,arguments)}}}class ChunkedUpload{constructor(e){const t=["file","uploadURL","completeURL"],s={debugMode:null,extraHeaders:{},extraData:{},maxRetry:30,retryDelay:1e4,chunkSize:2e7,fileNameSuffix:"",progressCallback:null,retryCallback:null,successCallback:null,failureCallback:null,inTest:!1};for(const s of t){if(!e[s])throw new Error('A mandatory argument is missing: "'+s+'".');this[s]=e[s]}for(const t in s)this[t]=void 0!==e[t]?e[t]:s[t];null===this.debugMode&&-1!==window.location.hash.indexOf("debug")&&(this.debugMode=!0),this.sendFile()}logDebug(){this.debugMode&&!this.inTest&&console.log.apply(null,arguments)}logError(){this.inTest||console.error.apply(null,arguments)}logWarn(){this.inTest||console.warn.apply(null,arguments)}onProgress(e){this.progressCallback&&this.progressCallback(e)}onRetry(e,t){let s;if(this.retryCallback&&(s=this.retryCallback(e)),void 0===s){const e=this;s=new Promise(function(t){e.logDebug("Retrying in "+e.retryDelay+" ms..."),setTimeout(t,e.retryDelay)})}s.then(t)}onSuccess(){this.successCallback&&this.successCallback(this.uploadId)}onFailure(e){this.failureCallback&&this.failureCallback(e)}sendFile(){if(this.onProgress(0),this.uploadId=null,this.fileName=this.file.name,this.fileNameSuffix){const e=this.fileName.lastIndexOf(".");this.fileName=e>0?this.fileName.substring(0,e)+this.fileNameSuffix+this.fileName.substring(e):"file"+this.fileNameSuffix+".tmp"}this.logDebug("Number of chunk to send:",Math.ceil(this.file.size/this.chunkSize),this.chunkSize,this.file.size),this.sendNextChunk(0,0)}sendNextChunk(e,t){this.logDebug("Sending chunk:","start:",e,"total size:",this.file.size,"retries:",t);const s=Math.min(e+this.chunkSize,this.file.size),n=new FormData;n.append("file",this.file.slice(e,s),this.fileName),n.append("retries",t),this.uploadId&&n.append("upload_id",this.uploadId);for(const e in this.extraData)n.append(e,this.extraData[e]);const i=(s-e)/this.file.size,r=Object.assign(this.extraHeaders,{"Content-Range":"bytes "+e+"-"+(s-1)+"/"+this.file.size});this.logDebug("Content-Range",r["Content-Range"]);const o=this;jsu.httpRequest({method:"POST",url:this.uploadURL,headers:r,data:n,json:!0,progress:function(t){if(t.lengthComputable){let s=e/o.file.size;t.total&&(s+=i*(t.loaded/t.total)),s=Math.floor(95*s),o.logDebug("Progress:",s,i,t.loaded,t.total),o.onProgress(s)}},callback:function(n,i){if(200==n.status&&i.upload_id){o.logDebug("Chunk sent",i),o.uploadId=i.upload_id;const e=s;e>=o.file.size?o.completeUpload(0):o.sendNextChunk(e,0)}else o.logError("Failed to send chunk:",i),t0){let t=document.cookie.indexOf(e+"=");if(-1!=t){t=t+e.length+1;let s=document.cookie.indexOf(";",t);return-1==s&&(s=document.cookie.length),window.decodeURIComponent(document.cookie.substring(t,s))}}return t}setCookie(e,t,s=360){const n=new Date;n.setDate(n.getDate()+s);const i=0===window.location.href.indexOf("https://")?"; secure; samesite=none":"";document.cookie=e+"="+window.decodeURIComponent(t)+"; expires="+n.toUTCString()+"; path=/"+i}strip(e,t=""){if(!e)return e;const s=""!==t?t:" \n\r\t ";let n=0;for(;n=0&&-1!=s.indexOf(e[i]);)i--;return e.substring(n,i+1)}slugify(e){return e.toString().toLowerCase().replace(/\s+/g,"-").replace(/[^-\w]+/g,"").replace(/-+/g,"-").replace(/^-+/,"").replace(/-+$/,"")}stripHTML(e){if(!e)return e;const t=document.createElement("div");return t.innerHTML=e,t.textContent}decodeHTML(e){if(!e)return"";const t=document.createElement("div");return t.innerHTML=e,0===t.childNodes.length?"":t.childNodes[0].nodeValue}escapeHTML(e){if(!e)return e;let t=e.toString();return t=(t=(t=(t=t.replace(/(&)/g,"&")).replace(/(<)/g,"<")).replace(/(>)/g,">")).replace(/(\n)/g,"
")}escapeAttribute(e){if(!e)return e;let t=e.toString();return t=(t=(t=t.replace(/(")/g,""")).replace(/(')/g,"'")).replace(/(\n)/g," ")}getClickPosition(e,t){let s=t,n=0,i=0;for(;null!=s;)n+=s.offsetLeft,i+=s.offsetTop,s=s.offsetParent;return{x:e.pageX-n,y:e.pageY-i}}onDOMLoad(e){"complete"===document.readyState||"interactive"===document.readyState?setTimeout(e,1):document.addEventListener("DOMContentLoaded",e)}httpRequest(e){const t=e.params?e.params:{};e.cache||(t._=(new Date).getTime());const s=e.method?e.method.toUpperCase():"GET";let n=e.url?e.url:"";const i=e.headers?e.headers:{};if(!/^(GET|HEAD|OPTIONS|TRACE)$/.test(s)){const e=this.getCookie("csrftoken");e&&(i["X-CSRFToken"]=e)}const r=[];for(const e in t)if(t[e]instanceof Array)for(const s of t[e])r.push(encodeURIComponent(e)+"="+encodeURIComponent(s));else r.push(encodeURIComponent(e)+"="+encodeURIComponent(t[e]));let o;if(r.length>0&&(n+=(-1===n.indexOf("?")?"?":"&")+r.join("&")),e.jsonData)i["Content-Type"]="application/json; charset=UTF-8",o=e.data;else if(e.data instanceof FormData)o=e.data;else if(e.data){o=new FormData;for(const t in e.data)if(e.data[t]instanceof Array)for(const s of e.data[t])o.append(t+"[]",s);else o.append(t,e.data[t])}else o=null;const a=new XMLHttpRequest;e.progress&&a.upload&&a.upload.addEventListener("progress",e.progress,!1),e.callback&&(a.addEventListener("readystatechange",function(){if(this.readyState!==XMLHttpRequest.DONE)return;if(a._callbackCalled)return;let t;if(a._callbackCalled=!0,e.json)if(""===this.responseText)t={error:"No response.",empty:!0,raw:this.responseText};else try{t=JSON.parse(this.responseText)}catch(e){t={error:"Failed to parse json response: "+e,raw:this.responseText}}else t=this.responseText;e.callback(this,t)}),a.addEventListener("error",function(t){if(a._callbackCalled)return;a._callbackCalled=!0;const s=t.error||t.message||(t.detail?t.detail.error||t.detail.message:"Unknown error");e.callback(this,{error:s})})),a.open(s,n,!e.synchronous);for(const e in i)if(i[e]instanceof Array)for(const t of i[e])a.setRequestHeader(e,t);else a.setRequestHeader(e,i[e]);return a.send(o),a}compareVersions(e,t,s){t="="==t?"==":t;const n=e.split("."),i=s.split("."),r=Math.max(n.length,i.length);for(let e=0;es)return-1}return 0}setObjectAttributes(e,t,s=null){if(t){"translations"in t&&(this.addTranslations(t.translations),delete t.translations);for(const n in t)s&&-1==s.indexOf(n)||(e[n]=t[n])}}getWebglContext(e,t={},s=""){if(window.WebGLRenderingContext)try{let n;return(n="safari"===s?e.getContext("webgl",t)||e.getContext("experimental-webgl",t):e.getContext("webgl2",t)||e.getContext("webgl",t)||e.getContext("experimental-webgl",t))||(console.log("Failed to initialize WebGL context. Your browser does not support Webgl context."),null)}catch(e){return console.log("WebGL context is supported but may be disable, please check your browser configuration."),null}return console.log("Your browser does not support Webgl context"),null}isInIframe(){return!(!window.frameElement||"IFRAME"!=window.frameElement.nodeName)}attemptFocus(e){if(!this.isFocusable(e))return!1;this.ignoreUntilFocusChanges=!0;try{e.focus()}catch(t){console.log("Failed to focus element.",e,t)}return this.ignoreUntilFocusChanges=!1,document.activeElement===e}isFocusable(e){if(e.tabIndex>0||0===e.tabIndex&&null!==e.getAttribute("tabIndex"))return!0;if(e.disabled)return!1;switch(e.nodeName){case"A":return!!e.href&&"ignore"!=e.rel;case"INPUT":return"hidden"!=e.type&&"file"!=e.type;case"BUTTON":case"SELECT":case"TEXTAREA":return!0;default:return!1}}focusFirstDescendant(e){for(let t=0;t=0;t--){const s=e.childNodes[t];if(this.attemptFocus(s)||this.focusLastDescendant(s))return!0}return!1}_getOSInfo(){let e,t;if(!e&&window.navigator&&window.navigator.platform){const s=window.navigator.platform.toLowerCase();-1==s.indexOf("ipad")&&-1==s.indexOf("iphone")&&-1==s.indexOf("ipod")||(e="ios",t=parseFloat((""+(/CPU.*OS ([0-9_]{1,5})|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent)||[0,""])[1]).replace("undefined","3_2").replace("_",".").replace("_",""))||!1)}if(!e&&window.navigator&&window.navigator.appVersion){const t=window.navigator.appVersion.toLowerCase();-1!=t.indexOf("win")?e="windows":-1!=t.indexOf("mac")?e="macos":-1==t.indexOf("x11")&&-1==t.indexOf("linux")||(e="linux")}this.osName=e||"unknown",this.osVersion=t||0}_getBrowserInfo(){let e,t=0;if(window.navigator&&window.navigator.userAgentData&&window.navigator.userAgentData.brands)for(let s=0;s=45,t=("chrome"===this.browserName||"chromium"===this.browserName)&&this.browserVersion>=57,s="safari"===this.browserName&&this.browserVersion>=16,n="edge"===this.browserName&&this.browserVersion>=79;return e||t||n||s}isLivestreamingAvailable(){const e=("chrome"===this.browserName||"chromium"===this.browserName)&&this.browserVersion>=57,t="edge"===this.browserName&&this.browserVersion>=79,s="safari"===this.browserName&&this.browserVersion>=16;return e||t||s}useLang(e){this._currentLang=e,this._translations[e]||(this._translations[e]={}),this._currentCatalog=this._translations[e]}getCurrentLang(){return this._currentLang}getCurrentCatalog(){return this._currentCatalog}addTranslations(e,t=""){let s;t?(this._translations[t]||(this._translations[t]={}),s=this._translations[t]):s=this._currentCatalog;for(const t of Object.keys(e))e[t]&&(s[t]=e[t])}translate(e,t=""){const s=(t?t+"":"")+e;return s in this._currentCatalog?this._currentCatalog[s]:"en"!=this._currentLang&&s in this._translations.en?this._translations.en[s]:e}translateHTML(e,t=""){const s=this.translate(e,t);return this.escapeHTML(s)}translateAttribute(e,t=""){const s=this.translate(e,t);return this.escapeAttribute(s)}getDateDisplay(e){if(!e)return"";const t=/^(\d+)-(\d+)-(\d+)(?: |T)(\d+):(\d+):(\d+)$/.exec(e);if(!t)return e;const s=t[1];let n=null;switch(t[2]){case"01":n=this.translate("January");break;case"02":n=this.translate("February");break;case"03":n=this.translate("March");break;case"04":n=this.translate("April");break;case"05":n=this.translate("May");break;case"06":n=this.translate("June");break;case"07":n=this.translate("July");break;case"08":n=this.translate("August");break;case"09":n=this.translate("September");break;case"10":n=this.translate("October");break;case"11":n=this.translate("November");break;case"12":n=this.translate("December")}const i=t[3];let r,o=parseInt(t[4],10),a=parseInt(t[5],10);if(!n||isNaN(o)||isNaN(a))return e;if(a<10&&(a="0"+a),"en"!==this._currentLang)o<10&&(o="0"+o),r=o+":"+a;else{let e;o<12?(e="AM",o||(o=12)):(e="PM",o>12&&(o-=12)),r=o+":"+a+" "+e}return i+" "+n+" "+s+" "+this.translate("at")+" "+r}getSizeDisplay(e){if(!e||isNaN(e))return"0 "+this.translate("B");let t="";return e>1e3&&(t="k",(e/=1e3)>1e3&&(t="M",(e/=1e3)>1e3&&(t="G",(e/=1e3)>1e3&&(e/=1e3,t="T")))),e.toFixed(1)+" "+t+this.translate("B")}getHashFromRequest(e,t,s,n={}){let i=e+t;if(i&&i.includes("_=")&&((i=i.replace(/_=[0-9]+&?/g,"")).endsWith("?")||i.endsWith("&"))&&(i=i.substring(0,i.length-1)),s instanceof FormData||s instanceof URLSearchParams)i+=JSON.stringify(Object.fromEntries(s));else if(s instanceof Blob)i+="blob-"+s.size;else if(s instanceof ArrayBuffer)i+="arraybuffer-"+s.byteLength;else if(s)try{i+=JSON.stringify(s)}catch(e){i+=JSON.stringify(new Date)}return Object.keys(n).length&&(i+=JSON.stringify(n)),i}_overrideHttpRequest(){window.xhrOverride=!0;const e=[];XMLHttpRequest.noIntercept=!1;const t=XMLHttpRequest.prototype.open;XMLHttpRequest.prototype.open=function(e,s){return this._method=e,this._url=s,t.apply(this,arguments)};const s=XMLHttpRequest.prototype.setRequestHeader;XMLHttpRequest.prototype.setRequestHeader=function(e,t){const n=s.apply(this,arguments);return this._headers||(this._headers={}),this._headers[e]||(this._headers[e]=[]),this._headers[e].push(t),n};const n=XMLHttpRequest.prototype.send;XMLHttpRequest.prototype.send=function(t){const s=window.jsu.getHashFromRequest(this._method,this._url,t,this._headers);if(e.includes(s)){const e="Duplicated request aborted";return Object.defineProperty(this,"statusText",{value:e,writable:!1}),this.dispatchEvent(new CustomEvent("error",{detail:{error:e,message:e}}))}return e.push(s),this.noIntercept||this.addEventListener&&this.addEventListener("readystatechange",function(){this.readyState===XMLHttpRequest.DONE&&e.splice(e.indexOf(s),1)},!1),n.apply(this,arguments)}}}export class ChunkedUpload{constructor(e){const t=["file","uploadURL","completeURL"],s={debugMode:null,extraHeaders:{},extraData:{},maxRetry:30,retryDelay:1e4,chunkSize:2e7,fileNameSuffix:"",progressCallback:null,retryCallback:null,successCallback:null,failureCallback:null,inTest:!1};for(const s of t){if(!e[s])throw new Error('A mandatory argument is missing: "'+s+'".');this[s]=e[s]}for(const t in s)this[t]=void 0!==e[t]?e[t]:s[t];null===this.debugMode&&-1!==window.location.hash.indexOf("debug")&&(this.debugMode=!0),this.sendFile()}logDebug(){this.debugMode&&!this.inTest&&console.log.apply(null,arguments)}logError(){this.inTest||console.error.apply(null,arguments)}logWarn(){this.inTest||console.warn.apply(null,arguments)}onProgress(e){this.progressCallback&&this.progressCallback(e)}onRetry(e,t){let s;if(this.retryCallback&&(s=this.retryCallback(e)),void 0===s){const e=this;s=new Promise(function(t){e.logDebug("Retrying in "+e.retryDelay+" ms..."),setTimeout(t,e.retryDelay)})}s.then(t)}onSuccess(){this.successCallback&&this.successCallback(this.uploadId)}onFailure(e){this.failureCallback&&this.failureCallback(e)}sendFile(){if(this.onProgress(0),this.uploadId=null,this.fileName=this.file.name,this.fileNameSuffix){const e=this.fileName.lastIndexOf(".");this.fileName=e>0?this.fileName.substring(0,e)+this.fileNameSuffix+this.fileName.substring(e):"file"+this.fileNameSuffix+".tmp"}this.logDebug("Number of chunk to send:",Math.ceil(this.file.size/this.chunkSize),this.chunkSize,this.file.size),this.sendNextChunk(0,0)}sendNextChunk(e,t){this.logDebug("Sending chunk:","start:",e,"total size:",this.file.size,"retries:",t);const s=Math.min(e+this.chunkSize,this.file.size),n=new FormData;n.append("file",this.file.slice(e,s),this.fileName),n.append("retries",t),this.uploadId&&n.append("upload_id",this.uploadId);for(const e in this.extraData)n.append(e,this.extraData[e]);const i=(s-e)/this.file.size,r=Object.assign(this.extraHeaders,{"Content-Range":"bytes "+e+"-"+(s-1)+"/"+this.file.size});this.logDebug("Content-Range",r["Content-Range"]);const o=this;jsu.httpRequest({method:"POST",url:this.uploadURL,headers:r,data:n,json:!0,progress:function(t){if(t.lengthComputable){let s=e/o.file.size;t.total&&(s+=i*(t.loaded/t.total)),s=Math.floor(95*s),o.logDebug("Progress:",s,i,t.loaded,t.total),o.onProgress(s)}},callback:function(n,i){if(200==n.status&&i.upload_id){o.logDebug("Chunk sent",i),o.uploadId=i.upload_id;const e=s;e>=o.file.size?o.completeUpload(0):o.sendNextChunk(e,0)}else o.logError("Failed to send chunk:",i),t0){let t=document.cookie.indexOf(e+"=");if(-1!=t){t=t+e.length+1;let s=document.cookie.indexOf(";",t);return-1==s&&(s=document.cookie.length),window.decodeURIComponent(document.cookie.substring(t,s))}}return t}setCookie(e,t,s=360){const n=new Date;n.setDate(n.getDate()+s);const i=0===window.location.href.indexOf("https://")?"; secure; samesite=none":"";document.cookie=e+"="+window.decodeURIComponent(t)+"; expires="+n.toUTCString()+"; path=/"+i}strip(e,t=""){if(!e)return e;const s=""!==t?t:" \n\r\t ";let n=0;for(;n=0&&-1!=s.indexOf(e[i]);)i--;return e.substring(n,i+1)}slugify(e){return e.toString().toLowerCase().replace(/\s+/g,"-").replace(/[^-\w]+/g,"").replace(/-+/g,"-").replace(/^-+/,"").replace(/-+$/,"")}stripHTML(e){if(!e)return e;const t=document.createElement("div");return t.innerHTML=e,t.textContent}decodeHTML(e){if(!e)return"";const t=document.createElement("div");return t.innerHTML=e,0===t.childNodes.length?"":t.childNodes[0].nodeValue}escapeHTML(e){if(!e)return e;let t=e.toString();return t=(t=(t=(t=t.replace(/(&)/g,"&")).replace(/(<)/g,"<")).replace(/(>)/g,">")).replace(/(\n)/g,"
")}escapeAttribute(e){if(!e)return e;let t=e.toString();return t=(t=(t=t.replace(/(")/g,""")).replace(/(')/g,"'")).replace(/(\n)/g," ")}getClickPosition(e,t){let s=t,n=0,i=0;for(;null!=s;)n+=s.offsetLeft,i+=s.offsetTop,s=s.offsetParent;return{x:e.pageX-n,y:e.pageY-i}}onDOMLoad(e){"complete"===document.readyState||"interactive"===document.readyState?setTimeout(e,1):document.addEventListener("DOMContentLoaded",e)}httpRequest(e){const t=e.params?e.params:{};e.cache||(t._=(new Date).getTime());const s=e.method?e.method.toUpperCase():"GET";let n=e.url?e.url:"";const i=e.headers?e.headers:{};if(!/^(GET|HEAD|OPTIONS|TRACE)$/.test(s)){const e=this.getCookie("csrftoken");e&&(i["X-CSRFToken"]=e)}const r=[];for(const e in t)if(t[e]instanceof Array)for(const s of t[e])r.push(encodeURIComponent(e)+"="+encodeURIComponent(s));else r.push(encodeURIComponent(e)+"="+encodeURIComponent(t[e]));let o;if(r.length>0&&(n+=(-1===n.indexOf("?")?"?":"&")+r.join("&")),e.jsonData)i["Content-Type"]="application/json; charset=UTF-8",o=e.data;else if(e.data instanceof FormData)o=e.data;else if(e.data){o=new FormData;for(const t in e.data)if(e.data[t]instanceof Array)for(const s of e.data[t])o.append(t+"[]",s);else o.append(t,e.data[t])}else o=null;const a=new XMLHttpRequest;e.progress&&a.upload&&a.upload.addEventListener("progress",e.progress,!1),e.callback&&(a.addEventListener("readystatechange",function(){if(this.readyState!==XMLHttpRequest.DONE)return;if(a._callbackCalled)return;let t;if(a._callbackCalled=!0,e.json)if(""===this.responseText)t={error:"No response.",empty:!0,raw:this.responseText};else try{t=JSON.parse(this.responseText)}catch(e){t={error:"Failed to parse json response: "+e,raw:this.responseText}}else t=this.responseText;e.callback(this,t)}),a.addEventListener("error",function(t){if(a._callbackCalled)return;a._callbackCalled=!0;const s=t.error||t.message||(t.detail?t.detail.error||t.detail.message:"Unknown error");e.callback(this,{error:s})})),a.open(s,n,!e.synchronous);for(const e in i)if(i[e]instanceof Array)for(const t of i[e])a.setRequestHeader(e,t);else a.setRequestHeader(e,i[e]);return a.send(o),a}compareVersions(e,t,s){t="="==t?"==":t;const n=e.split("."),i=s.split("."),r=Math.max(n.length,i.length);for(let e=0;es)return-1}return 0}setObjectAttributes(e,t,s=null){if(t){"translations"in t&&(this.addTranslations(t.translations),delete t.translations);for(const n in t)s&&-1==s.indexOf(n)||(e[n]=t[n])}}getWebglContext(e,t={},s=""){if(window.WebGLRenderingContext)try{let n;return(n="safari"===s?e.getContext("webgl",t)||e.getContext("experimental-webgl",t):e.getContext("webgl2",t)||e.getContext("webgl",t)||e.getContext("experimental-webgl",t))||(console.log("Failed to initialize WebGL context. Your browser does not support Webgl context."),null)}catch(e){return console.log("WebGL context is supported but may be disable, please check your browser configuration."),null}return console.log("Your browser does not support Webgl context"),null}isInIframe(){return!(!window.frameElement||"IFRAME"!=window.frameElement.nodeName)}attemptFocus(e){if(!this.isFocusable(e))return!1;this.ignoreUntilFocusChanges=!0;try{e.focus()}catch(t){console.log("Failed to focus element.",e,t)}return this.ignoreUntilFocusChanges=!1,document.activeElement===e}isFocusable(e){if(e.tabIndex>0||0===e.tabIndex&&null!==e.getAttribute("tabIndex"))return!0;if(e.disabled)return!1;switch(e.nodeName){case"A":return!!e.href&&"ignore"!=e.rel;case"INPUT":return"hidden"!=e.type&&"file"!=e.type;case"BUTTON":case"SELECT":case"TEXTAREA":return!0;default:return!1}}focusFirstDescendant(e){for(let t=0;t=0;t--){const s=e.childNodes[t];if(this.attemptFocus(s)||this.focusLastDescendant(s))return!0}return!1}_getOSInfo(){let e,t;if(!e&&window.navigator&&window.navigator.platform){const s=window.navigator.platform.toLowerCase();-1==s.indexOf("ipad")&&-1==s.indexOf("iphone")&&-1==s.indexOf("ipod")||(e="ios",t=parseFloat((""+(/CPU.*OS ([0-9_]{1,5})|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent)||[0,""])[1]).replace("undefined","3_2").replace("_",".").replace("_",""))||!1)}if(!e&&window.navigator&&window.navigator.appVersion){const t=window.navigator.appVersion.toLowerCase();-1!=t.indexOf("win")?e="windows":-1!=t.indexOf("mac")?e="macos":-1==t.indexOf("x11")&&-1==t.indexOf("linux")||(e="linux")}this.osName=e||"unknown",this.osVersion=t||0}_getBrowserInfo(){let e,t=0;if(window.navigator&&window.navigator.userAgentData&&window.navigator.userAgentData.brands)for(let s=0;s=45,t=("chrome"===this.browserName||"chromium"===this.browserName)&&this.browserVersion>=57,s="safari"===this.browserName&&this.browserVersion>=16,n="edge"===this.browserName&&this.browserVersion>=79;return e||t||n||s}isLivestreamingAvailable(){const e=("chrome"===this.browserName||"chromium"===this.browserName)&&this.browserVersion>=57,t="edge"===this.browserName&&this.browserVersion>=79,s="safari"===this.browserName&&this.browserVersion>=16;return e||t||s}useLang(e){this._currentLang=e,this._translations[e]||(this._translations[e]={}),this._currentCatalog=this._translations[e]}getCurrentLang(){return this._currentLang}getCurrentCatalog(){return this._currentCatalog}addTranslations(e,t=""){let s;t?(this._translations[t]||(this._translations[t]={}),s=this._translations[t]):s=this._currentCatalog;for(const t of Object.keys(e))e[t]&&(s[t]=e[t])}translate(e,t=""){const s=(t?t+"":"")+e;return s in this._currentCatalog?this._currentCatalog[s]:"en"!=this._currentLang&&s in this._translations.en?this._translations.en[s]:e}translateHTML(e,t=""){const s=this.translate(e,t);return this.escapeHTML(s)}translateAttribute(e,t=""){const s=this.translate(e,t);return this.escapeAttribute(s)}getDateDisplay(e){if(!e)return"";const t=/^(\d+)-(\d+)-(\d+)(?: |T)(\d+):(\d+):(\d+)$/.exec(e);if(!t)return e;const s=t[1];let n=null;switch(t[2]){case"01":n=this.translate("January");break;case"02":n=this.translate("February");break;case"03":n=this.translate("March");break;case"04":n=this.translate("April");break;case"05":n=this.translate("May");break;case"06":n=this.translate("June");break;case"07":n=this.translate("July");break;case"08":n=this.translate("August");break;case"09":n=this.translate("September");break;case"10":n=this.translate("October");break;case"11":n=this.translate("November");break;case"12":n=this.translate("December")}const i=t[3];let r,o=parseInt(t[4],10),a=parseInt(t[5],10);if(!n||isNaN(o)||isNaN(a))return e;if(a<10&&(a="0"+a),"en"!==this._currentLang)o<10&&(o="0"+o),r=o+":"+a;else{let e;o<12?(e="AM",o||(o=12)):(e="PM",o>12&&(o-=12)),r=o+":"+a+" "+e}return i+" "+n+" "+s+" "+this.translate("at")+" "+r}getSizeDisplay(e){if(!e||isNaN(e))return"0 "+this.translate("B");let t="";return e>1e3&&(t="k",(e/=1e3)>1e3&&(t="M",(e/=1e3)>1e3&&(t="G",(e/=1e3)>1e3&&(e/=1e3,t="T")))),e.toFixed(1)+" "+t+this.translate("B")}getHashFromRequest(e,t,s,n={}){let i=e+t;if(i&&i.includes("_=")&&((i=i.replace(/_=[0-9]+&?/g,"")).endsWith("?")||i.endsWith("&"))&&(i=i.substring(0,i.length-1)),s instanceof FormData||s instanceof URLSearchParams)i+=JSON.stringify(Object.fromEntries(s));else if(s instanceof Blob)i+="blob-"+s.size;else if(s instanceof ArrayBuffer)i+="arraybuffer-"+s.byteLength;else if(s)try{i+=JSON.stringify(s)}catch(e){i+=JSON.stringify(new Date)}return Object.keys(n).length&&(i+=JSON.stringify(n)),i}_overrideHttpRequest(){window.xhrOverride=!0;const e=[];XMLHttpRequest.noIntercept=!1;const t=XMLHttpRequest.prototype.open;XMLHttpRequest.prototype.open=function(e,s){return this._method=e,this._url=s,t.apply(this,arguments)};const s=XMLHttpRequest.prototype.setRequestHeader;XMLHttpRequest.prototype.setRequestHeader=function(e,t){const n=s.apply(this,arguments);return this._headers||(this._headers={}),this._headers[e]||(this._headers[e]=[]),this._headers[e].push(t),n};const n=XMLHttpRequest.prototype.send;XMLHttpRequest.prototype.send=function(t){const s=window.jsu.getHashFromRequest(this._method,this._url,t,this._headers);if(e.includes(s)){const e="Duplicated request aborted";return Object.defineProperty(this,"statusText",{value:e,writable:!1}),this.dispatchEvent(new CustomEvent("error",{detail:{error:e,message:e}}))}return e.push(s),this.noIntercept||this.addEventListener&&this.addEventListener("readystatechange",function(){this.readyState===XMLHttpRequest.DONE&&e.splice(e.indexOf(s),1)},!1),n.apply(this,arguments)}}}export class ChunkedUpload{constructor(e){const t=["file","uploadURL","completeURL"],s={debugMode:null,extraHeaders:{},extraData:{},maxRetry:30,retryDelay:1e4,chunkSize:2e7,fileNameSuffix:"",progressCallback:null,retryCallback:null,successCallback:null,failureCallback:null,inTest:!1};for(const s of t){if(!e[s])throw new Error('A mandatory argument is missing: "'+s+'".');this[s]=e[s]}for(const t in s)this[t]=void 0!==e[t]?e[t]:s[t];null===this.debugMode&&-1!==window.location.hash.indexOf("debug")&&(this.debugMode=!0),this.sendFile()}logDebug(){this.debugMode&&!this.inTest&&console.log.apply(null,arguments)}logError(){this.inTest||console.error.apply(null,arguments)}logWarn(){this.inTest||console.warn.apply(null,arguments)}onProgress(e){this.progressCallback&&this.progressCallback(e)}onRetry(e,t){let s;if(this.retryCallback&&(s=this.retryCallback(e)),void 0===s){const e=this;s=new Promise(function(t){e.logDebug("Retrying in "+e.retryDelay+" ms..."),setTimeout(t,e.retryDelay)})}s.then(t)}onSuccess(){this.successCallback&&this.successCallback(this.uploadId)}onFailure(e){this.failureCallback&&this.failureCallback(e)}sendFile(){if(this.onProgress(0),this.uploadId=null,this.fileName=this.file.name,this.fileNameSuffix){const e=this.fileName.lastIndexOf(".");this.fileName=e>0?this.fileName.substring(0,e)+this.fileNameSuffix+this.fileName.substring(e):"file"+this.fileNameSuffix+".tmp"}this.logDebug("Number of chunk to send:",Math.ceil(this.file.size/this.chunkSize),this.chunkSize,this.file.size),this.sendNextChunk(0,0)}sendNextChunk(e,t){this.logDebug("Sending chunk:","start:",e,"total size:",this.file.size,"retries:",t);const s=Math.min(e+this.chunkSize,this.file.size),n=new FormData;n.append("file",this.file.slice(e,s),this.fileName),n.append("retries",t),this.uploadId&&n.append("upload_id",this.uploadId);for(const e in this.extraData)n.append(e,this.extraData[e]);const i=(s-e)/this.file.size,r=Object.assign(this.extraHeaders,{"Content-Range":"bytes "+e+"-"+(s-1)+"/"+this.file.size});this.logDebug("Content-Range",r["Content-Range"]);const o=this;jsu.httpRequest({method:"POST",url:this.uploadURL,headers:r,data:n,json:!0,progress:function(t){if(t.lengthComputable){let s=e/o.file.size;t.total&&(s+=i*(t.loaded/t.total)),s=Math.floor(95*s),o.logDebug("Progress:",s,i,t.loaded,t.total),o.onProgress(s)}},callback:function(n,i){if(200==n.status&&i.upload_id){o.logDebug("Chunk sent",i),o.uploadId=i.upload_id;const e=s;e>=o.file.size?o.completeUpload(0):o.sendNextChunk(e,0)}else o.logError("Failed to send chunk:",i),t { + return new Promise((resolve) => { + setTimeout(resolve, time); + }); +}; + describe('PollingManager', () => { it('should handle polling function', async () => { - const sleep = (time) => { - return new Promise((resolve) => { - setTimeout(resolve, time); - }); - }; - const start = new Date().getTime(); const calls = []; const polling = new PollingManager(function (callback) { @@ -47,4 +47,24 @@ describe('PollingManager', () => { // Cleanup test polling.disable(); }).timeout(5000); + it('should handle planNext in callback', async () => { + const start = new Date().getTime(); + const calls = []; + const polling = new PollingManager(function (callback) { + calls.push(new Date().getTime() - start); + callback(false); + }, 1000); + + // Test call after init + await sleep(500); + assert(calls.length == 1); + assert(calls[0] < 100, `${calls[0]} ~= 0`); + + // Test no call after first run because planNext=false + await sleep(1000); + assert(calls.length == 1); + + // Cleanup test + polling.disable(); + }).timeout(2000); });