diff --git a/package.json b/package.json index f2d88bd0..85326d76 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,8 @@ "build:dev": "webpack --config webpack.dev.js", "test": "jest --config=jest.config.js", "profile": "webpack --profile --json > stats.json --config webpack.prod.js", - "profile:dev": "webpack --profile --json > stats.json --config webpack.dev.js" + "profile:dev": "webpack --profile --json > stats.json --config webpack.dev.js", + "whybundled": "npm run profile; whybundled stats.json" }, "author": "", "license": "ISC", diff --git a/rlottie_with_printf/rlottie-wasm.js b/rlottie_with_printf/rlottie-wasm.js new file mode 100644 index 00000000..e1b36d85 --- /dev/null +++ b/rlottie_with_printf/rlottie-wasm.js @@ -0,0 +1 @@ +var Module=typeof Module!=="undefined"?Module:{};var moduleOverrides={};var key;for(key in Module){if(Module.hasOwnProperty(key)){moduleOverrides[key]=Module[key]}}var arguments_=[];var thisProgram="./this.program";var quit_=function(status,toThrow){throw toThrow};var ENVIRONMENT_IS_WEB=false;var ENVIRONMENT_IS_WORKER=false;var ENVIRONMENT_IS_NODE=false;var ENVIRONMENT_IS_SHELL=false;ENVIRONMENT_IS_WEB=typeof window==="object";ENVIRONMENT_IS_WORKER=typeof importScripts==="function";ENVIRONMENT_IS_NODE=typeof process==="object"&&typeof process.versions==="object"&&typeof process.versions.node==="string";ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER;var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var read_,readAsync,readBinary,setWindowTitle;var nodeFS;var nodePath;if(ENVIRONMENT_IS_NODE){if(ENVIRONMENT_IS_WORKER){scriptDirectory=require("path").dirname(scriptDirectory)+"/"}else{scriptDirectory=__dirname+"/"}read_=function shell_read(filename,binary){if(!nodeFS)nodeFS=require("fs");if(!nodePath)nodePath=require("path");filename=nodePath["normalize"](filename);return nodeFS["readFileSync"](filename,binary?null:"utf8")};readBinary=function readBinary(filename){var ret=read_(filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}assert(ret.buffer);return ret};if(process["argv"].length>1){thisProgram=process["argv"][1].replace(/\\/g,"/")}arguments_=process["argv"].slice(2);if(typeof module!=="undefined"){module["exports"]=Module}process["on"]("uncaughtException",function(ex){if(!(ex instanceof ExitStatus)){throw ex}});process["on"]("unhandledRejection",abort);quit_=function(status){process["exit"](status)};Module["inspect"]=function(){return"[Emscripten Module object]"}}else if(ENVIRONMENT_IS_SHELL){if(typeof read!="undefined"){read_=function shell_read(f){return read(f)}}readBinary=function readBinary(f){var data;if(typeof readbuffer==="function"){return new Uint8Array(readbuffer(f))}data=read(f,"binary");assert(typeof data==="object");return data};if(typeof scriptArgs!="undefined"){arguments_=scriptArgs}else if(typeof arguments!="undefined"){arguments_=arguments}if(typeof quit==="function"){quit_=function(status){quit(status)}}if(typeof print!=="undefined"){if(typeof console==="undefined")console={};console.log=print;console.warn=console.error=typeof printErr!=="undefined"?printErr:print}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(document.currentScript){scriptDirectory=document.currentScript.src}if(scriptDirectory.indexOf("blob:")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.lastIndexOf("/")+1)}else{scriptDirectory=""}{read_=function shell_read(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){readBinary=function readBinary(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=function readAsync(url,onload,onerror){var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=function xhr_onload(){if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null)}}setWindowTitle=function(title){document.title=title}}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.warn.bind(console);for(key in moduleOverrides){if(moduleOverrides.hasOwnProperty(key)){Module[key]=moduleOverrides[key]}}moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["quit"])quit_=Module["quit"];function dynamicAlloc(size){var ret=HEAP32[DYNAMICTOP_PTR>>2];var end=ret+size+15&-16;HEAP32[DYNAMICTOP_PTR>>2]=end;return ret}function getNativeTypeSize(type){switch(type){case"i1":case"i8":return 1;case"i16":return 2;case"i32":return 4;case"i64":return 8;case"float":return 4;case"double":return 8;default:{if(type[type.length-1]==="*"){return 4}else if(type[0]==="i"){var bits=Number(type.substr(1));assert(bits%8===0,"getNativeTypeSize invalid bits "+bits+", type "+type);return bits/8}else{return 0}}}}var tempRet0=0;var setTempRet0=function(value){tempRet0=value};var getTempRet0=function(){return tempRet0};var wasmBinary;if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];var noExitRuntime;if(Module["noExitRuntime"])noExitRuntime=Module["noExitRuntime"];if(typeof WebAssembly!=="object"){err("no native wasm support detected")}function setValue(ptr,value,type,noSafe){type=type||"i8";if(type.charAt(type.length-1)==="*")type="i32";switch(type){case"i1":HEAP8[ptr>>0]=value;break;case"i8":HEAP8[ptr>>0]=value;break;case"i16":HEAP16[ptr>>1]=value;break;case"i32":HEAP32[ptr>>2]=value;break;case"i64":tempI64=[value>>>0,(tempDouble=value,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[ptr>>2]=tempI64[0],HEAP32[ptr+4>>2]=tempI64[1];break;case"float":HEAPF32[ptr>>2]=value;break;case"double":HEAPF64[ptr>>3]=value;break;default:abort("invalid type for setValue: "+type)}}var wasmMemory;var wasmTable=new WebAssembly.Table({"initial":524,"maximum":524+0,"element":"anyfunc"});var ABORT=false;var EXITSTATUS=0;function assert(condition,text){if(!condition){abort("Assertion failed: "+text)}}function getCFunc(ident){var func=Module["_"+ident];assert(func,"Cannot call unknown function "+ident+", make sure it is exported");return func}function ccall(ident,returnType,argTypes,args,opts){var toC={"string":function(str){var ret=0;if(str!==null&&str!==undefined&&str!==0){var len=(str.length<<2)+1;ret=stackAlloc(len);stringToUTF8(str,ret,len)}return ret},"array":function(arr){var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}};function convertReturnValue(ret){if(returnType==="string")return UTF8ToString(ret);if(returnType==="boolean")return Boolean(ret);return ret}var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i>2]=0}stop=ret+size;while(ptr>0]=0}return ret}if(singleType==="i8"){if(slab.subarray||slab.slice){HEAPU8.set(slab,ret)}else{HEAPU8.set(new Uint8Array(slab),ret)}return ret}var i=0,type,typeSize,previousType;while(i=endIdx))++endPtr;if(endPtr-idx>16&&heap.subarray&&UTF8Decoder){return UTF8Decoder.decode(heap.subarray(idx,endPtr))}else{var str="";while(idx>10,56320|ch&1023)}}}return str}function UTF8ToString(ptr,maxBytesToRead){return ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):""}function stringToUTF8Array(str,heap,outIdx,maxBytesToWrite){if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}}heap[outIdx]=0;return outIdx-startIdx}function stringToUTF8(str,outPtr,maxBytesToWrite){return stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite)}function lengthBytesUTF8(str){var len=0;for(var i=0;i=55296&&u<=57343)u=65536+((u&1023)<<10)|str.charCodeAt(++i)&1023;if(u<=127)++len;else if(u<=2047)len+=2;else if(u<=65535)len+=3;else len+=4}return len}function writeArrayToMemory(array,buffer){HEAP8.set(array,buffer)}function writeAsciiToMemory(str,buffer,dontAddNull){for(var i=0;i>0]=str.charCodeAt(i)}if(!dontAddNull)HEAP8[buffer>>0]=0}var WASM_PAGE_SIZE=65536;function alignUp(x,multiple){if(x%multiple>0){x+=multiple-x%multiple}return x}var buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBufferAndViews(buf){buffer=buf;Module["HEAP8"]=HEAP8=new Int8Array(buf);Module["HEAP16"]=HEAP16=new Int16Array(buf);Module["HEAP32"]=HEAP32=new Int32Array(buf);Module["HEAPU8"]=HEAPU8=new Uint8Array(buf);Module["HEAPU16"]=HEAPU16=new Uint16Array(buf);Module["HEAPU32"]=HEAPU32=new Uint32Array(buf);Module["HEAPF32"]=HEAPF32=new Float32Array(buf);Module["HEAPF64"]=HEAPF64=new Float64Array(buf)}var DYNAMIC_BASE=5276688,DYNAMICTOP_PTR=33648;var INITIAL_INITIAL_MEMORY=Module["INITIAL_MEMORY"]||16777216;if(Module["wasmMemory"]){wasmMemory=Module["wasmMemory"]}else{wasmMemory=new WebAssembly.Memory({"initial":INITIAL_INITIAL_MEMORY/WASM_PAGE_SIZE,"maximum":2147483648/WASM_PAGE_SIZE})}if(wasmMemory){buffer=wasmMemory.buffer}INITIAL_INITIAL_MEMORY=buffer.byteLength;updateGlobalBufferAndViews(buffer);HEAP32[DYNAMICTOP_PTR>>2]=DYNAMIC_BASE;function callRuntimeCallbacks(callbacks){while(callbacks.length>0){var callback=callbacks.shift();if(typeof callback=="function"){callback(Module);continue}var func=callback.func;if(typeof func==="number"){if(callback.arg===undefined){Module["dynCall_v"](func)}else{Module["dynCall_vi"](func,callback.arg)}}else{func(callback.arg===undefined?null:callback.arg)}}}var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){runtimeInitialized=true;if(!Module["noFSInit"]&&!FS.init.initialized)FS.init();TTY.init();callRuntimeCallbacks(__ATINIT__)}function preMain(){FS.ignorePermissions=false;callRuntimeCallbacks(__ATMAIN__)}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var Math_abs=Math.abs;var Math_ceil=Math.ceil;var Math_floor=Math.floor;var Math_min=Math.min;var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function getUniqueRunDependency(id){return id}function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}}function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}Module["preloadedImages"]={};Module["preloadedAudios"]={};function abort(what){if(Module["onAbort"]){Module["onAbort"](what)}what+="";out(what);err(what);ABORT=true;EXITSTATUS=1;what="abort("+what+"). Build with -s ASSERTIONS=1 for more info.";throw new WebAssembly.RuntimeError(what)}function hasPrefix(str,prefix){return String.prototype.startsWith?str.startsWith(prefix):str.indexOf(prefix)===0}var dataURIPrefix="data:application/octet-stream;base64,";function isDataURI(filename){return hasPrefix(filename,dataURIPrefix)}var fileURIPrefix="file://";function isFileURI(filename){return hasPrefix(filename,fileURIPrefix)}var wasmBinaryFile="rlottie-wasm.wasm";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}function getBinary(){try{if(wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(wasmBinaryFile)}else{throw"both async and sync fetching of the wasm failed"}}catch(err){abort(err)}}function getBinaryPromise(){if(!wasmBinary&&(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER)&&typeof fetch==="function"&&!isFileURI(wasmBinaryFile)){return fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){if(!response["ok"]){throw"failed to load wasm binary file at '"+wasmBinaryFile+"'"}return response["arrayBuffer"]()}).catch(function(){return getBinary()})}return new Promise(function(resolve,reject){resolve(getBinary())})}function createWasm(){var info={"a":asmLibraryArg};function receiveInstance(instance,module){var exports=instance.exports;Module["asm"]=exports;removeRunDependency("wasm-instantiate")}addRunDependency("wasm-instantiate");function receiveInstantiatedSource(output){receiveInstance(output["instance"])}function instantiateArrayBuffer(receiver){return getBinaryPromise().then(function(binary){return WebAssembly.instantiate(binary,info)}).then(receiver,function(reason){err("failed to asynchronously prepare wasm: "+reason);abort(reason)})}function instantiateAsync(){if(!wasmBinary&&typeof WebAssembly.instantiateStreaming==="function"&&!isDataURI(wasmBinaryFile)&&!isFileURI(wasmBinaryFile)&&typeof fetch==="function"){fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){var result=WebAssembly.instantiateStreaming(response,info);return result.then(receiveInstantiatedSource,function(reason){err("wasm streaming compile failed: "+reason);err("falling back to ArrayBuffer instantiation");instantiateArrayBuffer(receiveInstantiatedSource)})})}else{return instantiateArrayBuffer(receiveInstantiatedSource)}}if(Module["instantiateWasm"]){try{var exports=Module["instantiateWasm"](info,receiveInstance);return exports}catch(e){err("Module.instantiateWasm callback failed with error: "+e);return false}}instantiateAsync();return{}}var tempDouble;var tempI64;__ATINIT__.push({func:function(){___wasm_call_ctors()}});function demangle(func){return func}function demangleAll(text){var regex=/\b_Z[\w\d_]+/g;return text.replace(regex,function(x){var y=demangle(x);return x===y?x:y+" ["+x+"]"})}function jsStackTrace(){var err=new Error;if(!err.stack){try{throw new Error}catch(e){err=e}if(!err.stack){return"(no stack trace available)"}}return err.stack.toString()}function stackTrace(){var js=jsStackTrace();if(Module["extraStackTrace"])js+="\n"+Module["extraStackTrace"]();return demangleAll(js)}function __ZN7VRegionC1ERK5VRect(){err("missing function: _ZN7VRegionC1ERK5VRect");abort(-1)}function __ZN7VRegionD1Ev(){err("missing function: _ZN7VRegionD1Ev");abort(-1)}function __ZN7VRegionpLERK5VRect(){err("missing function: _ZN7VRegionpLERK5VRect");abort(-1)}function __ZNK7VRegion12boundingRectEv(){err("missing function: _ZNK7VRegion12boundingRectEv");abort(-1)}function ___assert_fail(condition,filename,line,func){abort("Assertion failed: "+UTF8ToString(condition)+", at: "+[filename?UTF8ToString(filename):"unknown filename",line,func?UTF8ToString(func):"unknown function"])}function setErrNo(value){HEAP32[___errno_location()>>2]=value;return value}function ___map_file(pathname,size){setErrNo(63);return-1}var PATH={splitPath:function(filename){var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:function(parts,allowAboveRoot){var up=0;for(var i=parts.length-1;i>=0;i--){var last=parts[i];if(last==="."){parts.splice(i,1)}else if(last===".."){parts.splice(i,1);up++}else if(up){parts.splice(i,1);up--}}if(allowAboveRoot){for(;up;up--){parts.unshift("..")}}return parts},normalize:function(path){var isAbsolute=path.charAt(0)==="/",trailingSlash=path.substr(-1)==="/";path=PATH.normalizeArray(path.split("/").filter(function(p){return!!p}),!isAbsolute).join("/");if(!path&&!isAbsolute){path="."}if(path&&trailingSlash){path+="/"}return(isAbsolute?"/":"")+path},dirname:function(path){var result=PATH.splitPath(path),root=result[0],dir=result[1];if(!root&&!dir){return"."}if(dir){dir=dir.substr(0,dir.length-1)}return root+dir},basename:function(path){if(path==="/")return"/";var lastSlash=path.lastIndexOf("/");if(lastSlash===-1)return path;return path.substr(lastSlash+1)},extname:function(path){return PATH.splitPath(path)[3]},join:function(){var paths=Array.prototype.slice.call(arguments,0);return PATH.normalize(paths.join("/"))},join2:function(l,r){return PATH.normalize(l+"/"+r)}};var PATH_FS={resolve:function(){var resolvedPath="",resolvedAbsolute=false;for(var i=arguments.length-1;i>=-1&&!resolvedAbsolute;i--){var path=i>=0?arguments[i]:FS.cwd();if(typeof path!=="string"){throw new TypeError("Arguments to path.resolve must be strings")}else if(!path){return""}resolvedPath=path+"/"+resolvedPath;resolvedAbsolute=path.charAt(0)==="/"}resolvedPath=PATH.normalizeArray(resolvedPath.split("/").filter(function(p){return!!p}),!resolvedAbsolute).join("/");return(resolvedAbsolute?"/":"")+resolvedPath||"."},relative:function(from,to){from=PATH_FS.resolve(from).substr(1);to=PATH_FS.resolve(to).substr(1);function trim(arr){var start=0;for(;start=0;end--){if(arr[end]!=="")break}if(start>end)return[];return arr.slice(start,end-start+1)}var fromParts=trim(from.split("/"));var toParts=trim(to.split("/"));var length=Math.min(fromParts.length,toParts.length);var samePartsLength=length;for(var i=0;i0){result=buf.slice(0,bytesRead).toString("utf-8")}else{result=null}}else if(typeof window!="undefined"&&typeof window.prompt=="function"){result=window.prompt("Input: ");if(result!==null){result+="\n"}}else if(typeof readline=="function"){result=readline();if(result!==null){result+="\n"}}if(!result){return null}tty.input=intArrayFromString(result,true)}return tty.input.shift()},put_char:function(tty,val){if(val===null||val===10){out(UTF8ArrayToString(tty.output,0));tty.output=[]}else{if(val!=0)tty.output.push(val)}},flush:function(tty){if(tty.output&&tty.output.length>0){out(UTF8ArrayToString(tty.output,0));tty.output=[]}}},default_tty1_ops:{put_char:function(tty,val){if(val===null||val===10){err(UTF8ArrayToString(tty.output,0));tty.output=[]}else{if(val!=0)tty.output.push(val)}},flush:function(tty){if(tty.output&&tty.output.length>0){err(UTF8ArrayToString(tty.output,0));tty.output=[]}}}};var MEMFS={ops_table:null,mount:function(mount){return MEMFS.createNode(null,"/",16384|511,0)},createNode:function(parent,name,mode,dev){if(FS.isBlkdev(mode)||FS.isFIFO(mode)){throw new FS.ErrnoError(63)}if(!MEMFS.ops_table){MEMFS.ops_table={dir:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,lookup:MEMFS.node_ops.lookup,mknod:MEMFS.node_ops.mknod,rename:MEMFS.node_ops.rename,unlink:MEMFS.node_ops.unlink,rmdir:MEMFS.node_ops.rmdir,readdir:MEMFS.node_ops.readdir,symlink:MEMFS.node_ops.symlink},stream:{llseek:MEMFS.stream_ops.llseek}},file:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:{llseek:MEMFS.stream_ops.llseek,read:MEMFS.stream_ops.read,write:MEMFS.stream_ops.write,allocate:MEMFS.stream_ops.allocate,mmap:MEMFS.stream_ops.mmap,msync:MEMFS.stream_ops.msync}},link:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,readlink:MEMFS.node_ops.readlink},stream:{}},chrdev:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:FS.chrdev_stream_ops}}}var node=FS.createNode(parent,name,mode,dev);if(FS.isDir(node.mode)){node.node_ops=MEMFS.ops_table.dir.node;node.stream_ops=MEMFS.ops_table.dir.stream;node.contents={}}else if(FS.isFile(node.mode)){node.node_ops=MEMFS.ops_table.file.node;node.stream_ops=MEMFS.ops_table.file.stream;node.usedBytes=0;node.contents=null}else if(FS.isLink(node.mode)){node.node_ops=MEMFS.ops_table.link.node;node.stream_ops=MEMFS.ops_table.link.stream}else if(FS.isChrdev(node.mode)){node.node_ops=MEMFS.ops_table.chrdev.node;node.stream_ops=MEMFS.ops_table.chrdev.stream}node.timestamp=Date.now();if(parent){parent.contents[name]=node}return node},getFileDataAsRegularArray:function(node){if(node.contents&&node.contents.subarray){var arr=[];for(var i=0;i=newCapacity)return;var CAPACITY_DOUBLING_MAX=1024*1024;newCapacity=Math.max(newCapacity,prevCapacity*(prevCapacity>>0);if(prevCapacity!=0)newCapacity=Math.max(newCapacity,256);var oldContents=node.contents;node.contents=new Uint8Array(newCapacity);if(node.usedBytes>0)node.contents.set(oldContents.subarray(0,node.usedBytes),0);return},resizeFileStorage:function(node,newSize){if(node.usedBytes==newSize)return;if(newSize==0){node.contents=null;node.usedBytes=0;return}if(!node.contents||node.contents.subarray){var oldContents=node.contents;node.contents=new Uint8Array(newSize);if(oldContents){node.contents.set(oldContents.subarray(0,Math.min(newSize,node.usedBytes)))}node.usedBytes=newSize;return}if(!node.contents)node.contents=[];if(node.contents.length>newSize)node.contents.length=newSize;else while(node.contents.length=stream.node.usedBytes)return 0;var size=Math.min(stream.node.usedBytes-position,length);if(size>8&&contents.subarray){buffer.set(contents.subarray(position,position+size),offset)}else{for(var i=0;i0||position+length8){throw new FS.ErrnoError(32)}var parts=PATH.normalizeArray(path.split("/").filter(function(p){return!!p}),false);var current=FS.root;var current_path="/";for(var i=0;i40){throw new FS.ErrnoError(32)}}}}return{path:current_path,node:current}},getPath:function(node){var path;while(true){if(FS.isRoot(node)){var mount=node.mount.mountpoint;if(!path)return mount;return mount[mount.length-1]!=="/"?mount+"/"+path:mount+path}path=path?node.name+"/"+path:node.name;node=node.parent}},hashName:function(parentid,name){var hash=0;for(var i=0;i>>0)%FS.nameTable.length},hashAddNode:function(node){var hash=FS.hashName(node.parent.id,node.name);node.name_next=FS.nameTable[hash];FS.nameTable[hash]=node},hashRemoveNode:function(node){var hash=FS.hashName(node.parent.id,node.name);if(FS.nameTable[hash]===node){FS.nameTable[hash]=node.name_next}else{var current=FS.nameTable[hash];while(current){if(current.name_next===node){current.name_next=node.name_next;break}current=current.name_next}}},lookupNode:function(parent,name){var errCode=FS.mayLookup(parent);if(errCode){throw new FS.ErrnoError(errCode,parent)}var hash=FS.hashName(parent.id,name);for(var node=FS.nameTable[hash];node;node=node.name_next){var nodeName=node.name;if(node.parent.id===parent.id&&nodeName===name){return node}}return FS.lookup(parent,name)},createNode:function(parent,name,mode,rdev){var node=new FS.FSNode(parent,name,mode,rdev);FS.hashAddNode(node);return node},destroyNode:function(node){FS.hashRemoveNode(node)},isRoot:function(node){return node===node.parent},isMountpoint:function(node){return!!node.mounted},isFile:function(mode){return(mode&61440)===32768},isDir:function(mode){return(mode&61440)===16384},isLink:function(mode){return(mode&61440)===40960},isChrdev:function(mode){return(mode&61440)===8192},isBlkdev:function(mode){return(mode&61440)===24576},isFIFO:function(mode){return(mode&61440)===4096},isSocket:function(mode){return(mode&49152)===49152},flagModes:{"r":0,"rs":1052672,"r+":2,"w":577,"wx":705,"xw":705,"w+":578,"wx+":706,"xw+":706,"a":1089,"ax":1217,"xa":1217,"a+":1090,"ax+":1218,"xa+":1218},modeStringToFlags:function(str){var flags=FS.flagModes[str];if(typeof flags==="undefined"){throw new Error("Unknown file open mode: "+str)}return flags},flagsToPermissionString:function(flag){var perms=["r","w","rw"][flag&3];if(flag&512){perms+="w"}return perms},nodePermissions:function(node,perms){if(FS.ignorePermissions){return 0}if(perms.indexOf("r")!==-1&&!(node.mode&292)){return 2}else if(perms.indexOf("w")!==-1&&!(node.mode&146)){return 2}else if(perms.indexOf("x")!==-1&&!(node.mode&73)){return 2}return 0},mayLookup:function(dir){var errCode=FS.nodePermissions(dir,"x");if(errCode)return errCode;if(!dir.node_ops.lookup)return 2;return 0},mayCreate:function(dir,name){try{var node=FS.lookupNode(dir,name);return 20}catch(e){}return FS.nodePermissions(dir,"wx")},mayDelete:function(dir,name,isdir){var node;try{node=FS.lookupNode(dir,name)}catch(e){return e.errno}var errCode=FS.nodePermissions(dir,"wx");if(errCode){return errCode}if(isdir){if(!FS.isDir(node.mode)){return 54}if(FS.isRoot(node)||FS.getPath(node)===FS.cwd()){return 10}}else{if(FS.isDir(node.mode)){return 31}}return 0},mayOpen:function(node,flags){if(!node){return 44}if(FS.isLink(node.mode)){return 32}else if(FS.isDir(node.mode)){if(FS.flagsToPermissionString(flags)!=="r"||flags&512){return 31}}return FS.nodePermissions(node,FS.flagsToPermissionString(flags))},MAX_OPEN_FDS:4096,nextfd:function(fd_start,fd_end){fd_start=fd_start||0;fd_end=fd_end||FS.MAX_OPEN_FDS;for(var fd=fd_start;fd<=fd_end;fd++){if(!FS.streams[fd]){return fd}}throw new FS.ErrnoError(33)},getStream:function(fd){return FS.streams[fd]},createStream:function(stream,fd_start,fd_end){if(!FS.FSStream){FS.FSStream=function(){};FS.FSStream.prototype={object:{get:function(){return this.node},set:function(val){this.node=val}},isRead:{get:function(){return(this.flags&2097155)!==1}},isWrite:{get:function(){return(this.flags&2097155)!==0}},isAppend:{get:function(){return this.flags&1024}}}}var newStream=new FS.FSStream;for(var p in stream){newStream[p]=stream[p]}stream=newStream;var fd=FS.nextfd(fd_start,fd_end);stream.fd=fd;FS.streams[fd]=stream;return stream},closeStream:function(fd){FS.streams[fd]=null},chrdev_stream_ops:{open:function(stream){var device=FS.getDevice(stream.node.rdev);stream.stream_ops=device.stream_ops;if(stream.stream_ops.open){stream.stream_ops.open(stream)}},llseek:function(){throw new FS.ErrnoError(70)}},major:function(dev){return dev>>8},minor:function(dev){return dev&255},makedev:function(ma,mi){return ma<<8|mi},registerDevice:function(dev,ops){FS.devices[dev]={stream_ops:ops}},getDevice:function(dev){return FS.devices[dev]},getMounts:function(mount){var mounts=[];var check=[mount];while(check.length){var m=check.pop();mounts.push(m);check.push.apply(check,m.mounts)}return mounts},syncfs:function(populate,callback){if(typeof populate==="function"){callback=populate;populate=false}FS.syncFSRequests++;if(FS.syncFSRequests>1){err("warning: "+FS.syncFSRequests+" FS.syncfs operations in flight at once, probably just doing extra work")}var mounts=FS.getMounts(FS.root.mount);var completed=0;function doCallback(errCode){FS.syncFSRequests--;return callback(errCode)}function done(errCode){if(errCode){if(!done.errored){done.errored=true;return doCallback(errCode)}return}if(++completed>=mounts.length){doCallback(null)}}mounts.forEach(function(mount){if(!mount.type.syncfs){return done(null)}mount.type.syncfs(mount,populate,done)})},mount:function(type,opts,mountpoint){var root=mountpoint==="/";var pseudo=!mountpoint;var node;if(root&&FS.root){throw new FS.ErrnoError(10)}else if(!root&&!pseudo){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});mountpoint=lookup.path;node=lookup.node;if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}if(!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}}var mount={type:type,opts:opts,mountpoint:mountpoint,mounts:[]};var mountRoot=type.mount(mount);mountRoot.mount=mount;mount.root=mountRoot;if(root){FS.root=mountRoot}else if(node){node.mounted=mount;if(node.mount){node.mount.mounts.push(mount)}}return mountRoot},unmount:function(mountpoint){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});if(!FS.isMountpoint(lookup.node)){throw new FS.ErrnoError(28)}var node=lookup.node;var mount=node.mounted;var mounts=FS.getMounts(mount);Object.keys(FS.nameTable).forEach(function(hash){var current=FS.nameTable[hash];while(current){var next=current.name_next;if(mounts.indexOf(current.mount)!==-1){FS.destroyNode(current)}current=next}});node.mounted=null;var idx=node.mount.mounts.indexOf(mount);node.mount.mounts.splice(idx,1)},lookup:function(parent,name){return parent.node_ops.lookup(parent,name)},mknod:function(path,mode,dev){var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);if(!name||name==="."||name===".."){throw new FS.ErrnoError(28)}var errCode=FS.mayCreate(parent,name);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.mknod){throw new FS.ErrnoError(63)}return parent.node_ops.mknod(parent,name,mode,dev)},create:function(path,mode){mode=mode!==undefined?mode:438;mode&=4095;mode|=32768;return FS.mknod(path,mode,0)},mkdir:function(path,mode){mode=mode!==undefined?mode:511;mode&=511|512;mode|=16384;return FS.mknod(path,mode,0)},mkdirTree:function(path,mode){var dirs=path.split("/");var d="";for(var i=0;ithis.length-1||idx<0){return undefined}var chunkOffset=idx%this.chunkSize;var chunkNum=idx/this.chunkSize|0;return this.getter(chunkNum)[chunkOffset]};LazyUint8Array.prototype.setDataGetter=function LazyUint8Array_setDataGetter(getter){this.getter=getter};LazyUint8Array.prototype.cacheLength=function LazyUint8Array_cacheLength(){var xhr=new XMLHttpRequest;xhr.open("HEAD",url,false);xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);var datalength=Number(xhr.getResponseHeader("Content-length"));var header;var hasByteServing=(header=xhr.getResponseHeader("Accept-Ranges"))&&header==="bytes";var usesGzip=(header=xhr.getResponseHeader("Content-Encoding"))&&header==="gzip";var chunkSize=1024*1024;if(!hasByteServing)chunkSize=datalength;var doXHR=function(from,to){if(from>to)throw new Error("invalid range ("+from+", "+to+") or no bytes requested!");if(to>datalength-1)throw new Error("only "+datalength+" bytes available! programmer error!");var xhr=new XMLHttpRequest;xhr.open("GET",url,false);if(datalength!==chunkSize)xhr.setRequestHeader("Range","bytes="+from+"-"+to);if(typeof Uint8Array!="undefined")xhr.responseType="arraybuffer";if(xhr.overrideMimeType){xhr.overrideMimeType("text/plain; charset=x-user-defined")}xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);if(xhr.response!==undefined){return new Uint8Array(xhr.response||[])}else{return intArrayFromString(xhr.responseText||"",true)}};var lazyArray=this;lazyArray.setDataGetter(function(chunkNum){var start=chunkNum*chunkSize;var end=(chunkNum+1)*chunkSize-1;end=Math.min(end,datalength-1);if(typeof lazyArray.chunks[chunkNum]==="undefined"){lazyArray.chunks[chunkNum]=doXHR(start,end)}if(typeof lazyArray.chunks[chunkNum]==="undefined")throw new Error("doXHR failed!");return lazyArray.chunks[chunkNum]});if(usesGzip||!datalength){chunkSize=datalength=1;datalength=this.getter(0).length;chunkSize=datalength;out("LazyFiles on gzip forces download of the whole file when length is accessed")}this._length=datalength;this._chunkSize=chunkSize;this.lengthKnown=true};if(typeof XMLHttpRequest!=="undefined"){if(!ENVIRONMENT_IS_WORKER)throw"Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";var lazyArray=new LazyUint8Array;Object.defineProperties(lazyArray,{length:{get:function(){if(!this.lengthKnown){this.cacheLength()}return this._length}},chunkSize:{get:function(){if(!this.lengthKnown){this.cacheLength()}return this._chunkSize}}});var properties={isDevice:false,contents:lazyArray}}else{var properties={isDevice:false,url:url}}var node=FS.createFile(parent,name,properties,canRead,canWrite);if(properties.contents){node.contents=properties.contents}else if(properties.url){node.contents=null;node.url=properties.url}Object.defineProperties(node,{usedBytes:{get:function(){return this.contents.length}}});var stream_ops={};var keys=Object.keys(node.stream_ops);keys.forEach(function(key){var fn=node.stream_ops[key];stream_ops[key]=function forceLoadLazyFile(){if(!FS.forceLoadFile(node)){throw new FS.ErrnoError(29)}return fn.apply(null,arguments)}});stream_ops.read=function stream_ops_read(stream,buffer,offset,length,position){if(!FS.forceLoadFile(node)){throw new FS.ErrnoError(29)}var contents=stream.node.contents;if(position>=contents.length)return 0;var size=Math.min(contents.length-position,length);if(contents.slice){for(var i=0;i>2]=stat.dev;HEAP32[buf+4>>2]=0;HEAP32[buf+8>>2]=stat.ino;HEAP32[buf+12>>2]=stat.mode;HEAP32[buf+16>>2]=stat.nlink;HEAP32[buf+20>>2]=stat.uid;HEAP32[buf+24>>2]=stat.gid;HEAP32[buf+28>>2]=stat.rdev;HEAP32[buf+32>>2]=0;tempI64=[stat.size>>>0,(tempDouble=stat.size,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+40>>2]=tempI64[0],HEAP32[buf+44>>2]=tempI64[1];HEAP32[buf+48>>2]=4096;HEAP32[buf+52>>2]=stat.blocks;HEAP32[buf+56>>2]=stat.atime.getTime()/1e3|0;HEAP32[buf+60>>2]=0;HEAP32[buf+64>>2]=stat.mtime.getTime()/1e3|0;HEAP32[buf+68>>2]=0;HEAP32[buf+72>>2]=stat.ctime.getTime()/1e3|0;HEAP32[buf+76>>2]=0;tempI64=[stat.ino>>>0,(tempDouble=stat.ino,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+80>>2]=tempI64[0],HEAP32[buf+84>>2]=tempI64[1];return 0},doMsync:function(addr,stream,len,flags,offset){var buffer=HEAPU8.slice(addr,addr+len);FS.msync(stream,buffer,offset,len,flags)},doMkdir:function(path,mode){path=PATH.normalize(path);if(path[path.length-1]==="/")path=path.substr(0,path.length-1);FS.mkdir(path,mode,0);return 0},doMknod:function(path,mode,dev){switch(mode&61440){case 32768:case 8192:case 24576:case 4096:case 49152:break;default:return-28}FS.mknod(path,mode,dev);return 0},doReadlink:function(path,buf,bufsize){if(bufsize<=0)return-28;var ret=FS.readlink(path);var len=Math.min(bufsize,lengthBytesUTF8(ret));var endChar=HEAP8[buf+len];stringToUTF8(ret,buf,bufsize+1);HEAP8[buf+len]=endChar;return len},doAccess:function(path,amode){if(amode&~7){return-28}var node;var lookup=FS.lookupPath(path,{follow:true});node=lookup.node;if(!node){return-44}var perms="";if(amode&4)perms+="r";if(amode&2)perms+="w";if(amode&1)perms+="x";if(perms&&FS.nodePermissions(node,perms)){return-2}return 0},doDup:function(path,flags,suggestFD){var suggest=FS.getStream(suggestFD);if(suggest)FS.close(suggest);return FS.open(path,flags,0,suggestFD,suggestFD).fd},doReadv:function(stream,iov,iovcnt,offset){var ret=0;for(var i=0;i>2];var len=HEAP32[iov+(i*8+4)>>2];var curr=FS.read(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(curr>2];var len=HEAP32[iov+(i*8+4)>>2];var curr=FS.write(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr}return ret},varargs:undefined,get:function(){SYSCALLS.varargs+=4;var ret=HEAP32[SYSCALLS.varargs-4>>2];return ret},getStr:function(ptr){var ret=UTF8ToString(ptr);return ret},getStreamFromFD:function(fd){var stream=FS.getStream(fd);if(!stream)throw new FS.ErrnoError(8);return stream},get64:function(low,high){return low}};function ___sys_fcntl64(fd,cmd,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(cmd){case 0:{var arg=SYSCALLS.get();if(arg<0){return-28}var newStream;newStream=FS.open(stream.path,stream.flags,0,arg);return newStream.fd}case 1:case 2:return 0;case 3:return stream.flags;case 4:{var arg=SYSCALLS.get();stream.flags|=arg;return 0}case 12:{var arg=SYSCALLS.get();var offset=0;HEAP16[arg+offset>>1]=2;return 0}case 13:case 14:return 0;case 16:case 8:return-28;case 9:setErrNo(28);return-1;default:{return-28}}}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_ioctl(fd,op,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(op){case 21509:case 21505:{if(!stream.tty)return-59;return 0}case 21510:case 21511:case 21512:case 21506:case 21507:case 21508:{if(!stream.tty)return-59;return 0}case 21519:{if(!stream.tty)return-59;var argp=SYSCALLS.get();HEAP32[argp>>2]=0;return 0}case 21520:{if(!stream.tty)return-59;return-28}case 21531:{var argp=SYSCALLS.get();return FS.ioctl(stream,op,argp)}case 21523:{if(!stream.tty)return-59;return 0}case 21524:{if(!stream.tty)return-59;return 0}default:abort("bad ioctl syscall "+op)}}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function syscallMunmap(addr,len){if((addr|0)===-1||len===0){return-28}var info=SYSCALLS.mappings[addr];if(!info)return 0;if(len===info.len){var stream=FS.getStream(info.fd);if(info.prot&2){SYSCALLS.doMsync(addr,stream,len,info.flags,info.offset)}FS.munmap(stream);SYSCALLS.mappings[addr]=null;if(info.allocated){_free(info.malloc)}}return 0}function ___sys_munmap(addr,len){try{return syscallMunmap(addr,len)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_open(path,flags,varargs){SYSCALLS.varargs=varargs;try{var pathname=SYSCALLS.getStr(path);var mode=SYSCALLS.get();var stream=FS.open(pathname,flags,mode);return stream.fd}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function _abort(){abort()}var setjmpId=0;function _saveSetjmp(env,label,table,size){env=env|0;label=label|0;table=table|0;size=size|0;var i=0;setjmpId=setjmpId+1|0;HEAP32[env>>2]=setjmpId;while((i|0)<(size|0)){if((HEAP32[table+(i<<3)>>2]|0)==0){HEAP32[table+(i<<3)>>2]=setjmpId;HEAP32[table+((i<<3)+4)>>2]=label;HEAP32[table+((i<<3)+8)>>2]=0;setTempRet0(size|0);return table|0}i=i+1|0}size=size*2|0;table=_realloc(table|0,8*(size+1|0)|0)|0;table=_saveSetjmp(env|0,label|0,table|0,size|0)|0;setTempRet0(size|0);return table|0}function _testSetjmp(id,table,size){id=id|0;table=table|0;size=size|0;var i=0,curr=0;while((i|0)<(size|0)){curr=HEAP32[table+(i<<3)>>2]|0;if((curr|0)==0)break;if((curr|0)==(id|0)){return HEAP32[table+((i<<3)+4)>>2]|0}i=i+1|0}return 0}function _longjmp(env,value){_setThrew(env,value||1);throw"longjmp"}function _emscripten_longjmp(env,value){_longjmp(env,value)}function _emscripten_memcpy_big(dest,src,num){HEAPU8.copyWithin(dest,src,src+num)}function _emscripten_get_heap_size(){return HEAPU8.length}function emscripten_realloc_buffer(size){try{wasmMemory.grow(size-buffer.byteLength+65535>>>16);updateGlobalBufferAndViews(wasmMemory.buffer);return 1}catch(e){}}function _emscripten_resize_heap(requestedSize){requestedSize=requestedSize>>>0;var oldSize=_emscripten_get_heap_size();var PAGE_MULTIPLE=65536;var maxHeapSize=2147483648;if(requestedSize>maxHeapSize){return false}var minHeapSize=16777216;for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignUp(Math.max(minHeapSize,requestedSize,overGrownHeapSize),PAGE_MULTIPLE));var replacement=emscripten_realloc_buffer(newSize);if(replacement){return true}}return false}var ENV={};function __getExecutableName(){return thisProgram||"./this.program"}function getEnvStrings(){if(!getEnvStrings.strings){var env={"USER":"web_user","LOGNAME":"web_user","PATH":"/","PWD":"/","HOME":"/home/web_user","LANG":(typeof navigator==="object"&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8","_":__getExecutableName()};for(var x in ENV){env[x]=ENV[x]}var strings=[];for(var x in env){strings.push(x+"="+env[x])}getEnvStrings.strings=strings}return getEnvStrings.strings}function _environ_get(__environ,environ_buf){var bufSize=0;getEnvStrings().forEach(function(string,i){var ptr=environ_buf+bufSize;HEAP32[__environ+i*4>>2]=ptr;writeAsciiToMemory(string,ptr);bufSize+=string.length+1});return 0}function _environ_sizes_get(penviron_count,penviron_buf_size){var strings=getEnvStrings();HEAP32[penviron_count>>2]=strings.length;var bufSize=0;strings.forEach(function(string){bufSize+=string.length+1});HEAP32[penviron_buf_size>>2]=bufSize;return 0}function _fd_close(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);FS.close(stream);return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return e.errno}}function _fd_read(fd,iov,iovcnt,pnum){try{var stream=SYSCALLS.getStreamFromFD(fd);var num=SYSCALLS.doReadv(stream,iov,iovcnt);HEAP32[pnum>>2]=num;return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return e.errno}}function _fd_seek(fd,offset_low,offset_high,whence,newOffset){try{var stream=SYSCALLS.getStreamFromFD(fd);var HIGH_OFFSET=4294967296;var offset=offset_high*HIGH_OFFSET+(offset_low>>>0);var DOUBLE_LIMIT=9007199254740992;if(offset<=-DOUBLE_LIMIT||offset>=DOUBLE_LIMIT){return-61}FS.llseek(stream,offset,whence);tempI64=[stream.position>>>0,(tempDouble=stream.position,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[newOffset>>2]=tempI64[0],HEAP32[newOffset+4>>2]=tempI64[1];if(stream.getdents&&offset===0&&whence===0)stream.getdents=null;return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return e.errno}}function _fd_write(fd,iov,iovcnt,pnum){try{var stream=SYSCALLS.getStreamFromFD(fd);var num=SYSCALLS.doWritev(stream,iov,iovcnt);HEAP32[pnum>>2]=num;return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return e.errno}}function _getTempRet0(){return getTempRet0()|0}function _round(d){d=+d;return d>=+0?+Math_floor(d+ +.5):+Math_ceil(d-+.5)}function _setTempRet0($i){setTempRet0($i|0)}function __isLeapYear(year){return year%4===0&&(year%100!==0||year%400===0)}function __arraySum(array,index){var sum=0;for(var i=0;i<=index;sum+=array[i++]){}return sum}var __MONTH_DAYS_LEAP=[31,29,31,30,31,30,31,31,30,31,30,31];var __MONTH_DAYS_REGULAR=[31,28,31,30,31,30,31,31,30,31,30,31];function __addDays(date,days){var newDate=new Date(date.getTime());while(days>0){var leap=__isLeapYear(newDate.getFullYear());var currentMonth=newDate.getMonth();var daysInCurrentMonth=(leap?__MONTH_DAYS_LEAP:__MONTH_DAYS_REGULAR)[currentMonth];if(days>daysInCurrentMonth-newDate.getDate()){days-=daysInCurrentMonth-newDate.getDate()+1;newDate.setDate(1);if(currentMonth<11){newDate.setMonth(currentMonth+1)}else{newDate.setMonth(0);newDate.setFullYear(newDate.getFullYear()+1)}}else{newDate.setDate(newDate.getDate()+days);return newDate}}return newDate}function _strftime(s,maxsize,format,tm){var tm_zone=HEAP32[tm+40>>2];var date={tm_sec:HEAP32[tm>>2],tm_min:HEAP32[tm+4>>2],tm_hour:HEAP32[tm+8>>2],tm_mday:HEAP32[tm+12>>2],tm_mon:HEAP32[tm+16>>2],tm_year:HEAP32[tm+20>>2],tm_wday:HEAP32[tm+24>>2],tm_yday:HEAP32[tm+28>>2],tm_isdst:HEAP32[tm+32>>2],tm_gmtoff:HEAP32[tm+36>>2],tm_zone:tm_zone?UTF8ToString(tm_zone):""};var pattern=UTF8ToString(format);var EXPANSION_RULES_1={"%c":"%a %b %d %H:%M:%S %Y","%D":"%m/%d/%y","%F":"%Y-%m-%d","%h":"%b","%r":"%I:%M:%S %p","%R":"%H:%M","%T":"%H:%M:%S","%x":"%m/%d/%y","%X":"%H:%M:%S","%Ec":"%c","%EC":"%C","%Ex":"%m/%d/%y","%EX":"%H:%M:%S","%Ey":"%y","%EY":"%Y","%Od":"%d","%Oe":"%e","%OH":"%H","%OI":"%I","%Om":"%m","%OM":"%M","%OS":"%S","%Ou":"%u","%OU":"%U","%OV":"%V","%Ow":"%w","%OW":"%W","%Oy":"%y"};for(var rule in EXPANSION_RULES_1){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_1[rule])}var WEEKDAYS=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];var MONTHS=["January","February","March","April","May","June","July","August","September","October","November","December"];function leadingSomething(value,digits,character){var str=typeof value==="number"?value.toString():value||"";while(str.length0?1:0}var compare;if((compare=sgn(date1.getFullYear()-date2.getFullYear()))===0){if((compare=sgn(date1.getMonth()-date2.getMonth()))===0){compare=sgn(date1.getDate()-date2.getDate())}}return compare}function getFirstWeekStartDate(janFourth){switch(janFourth.getDay()){case 0:return new Date(janFourth.getFullYear()-1,11,29);case 1:return janFourth;case 2:return new Date(janFourth.getFullYear(),0,3);case 3:return new Date(janFourth.getFullYear(),0,2);case 4:return new Date(janFourth.getFullYear(),0,1);case 5:return new Date(janFourth.getFullYear()-1,11,31);case 6:return new Date(janFourth.getFullYear()-1,11,30)}}function getWeekBasedYear(date){var thisDate=__addDays(new Date(date.tm_year+1900,0,1),date.tm_yday);var janFourthThisYear=new Date(thisDate.getFullYear(),0,4);var janFourthNextYear=new Date(thisDate.getFullYear()+1,0,4);var firstWeekStartThisYear=getFirstWeekStartDate(janFourthThisYear);var firstWeekStartNextYear=getFirstWeekStartDate(janFourthNextYear);if(compareByDay(firstWeekStartThisYear,thisDate)<=0){if(compareByDay(firstWeekStartNextYear,thisDate)<=0){return thisDate.getFullYear()+1}else{return thisDate.getFullYear()}}else{return thisDate.getFullYear()-1}}var EXPANSION_RULES_2={"%a":function(date){return WEEKDAYS[date.tm_wday].substring(0,3)},"%A":function(date){return WEEKDAYS[date.tm_wday]},"%b":function(date){return MONTHS[date.tm_mon].substring(0,3)},"%B":function(date){return MONTHS[date.tm_mon]},"%C":function(date){var year=date.tm_year+1900;return leadingNulls(year/100|0,2)},"%d":function(date){return leadingNulls(date.tm_mday,2)},"%e":function(date){return leadingSomething(date.tm_mday,2," ")},"%g":function(date){return getWeekBasedYear(date).toString().substring(2)},"%G":function(date){return getWeekBasedYear(date)},"%H":function(date){return leadingNulls(date.tm_hour,2)},"%I":function(date){var twelveHour=date.tm_hour;if(twelveHour==0)twelveHour=12;else if(twelveHour>12)twelveHour-=12;return leadingNulls(twelveHour,2)},"%j":function(date){return leadingNulls(date.tm_mday+__arraySum(__isLeapYear(date.tm_year+1900)?__MONTH_DAYS_LEAP:__MONTH_DAYS_REGULAR,date.tm_mon-1),3)},"%m":function(date){return leadingNulls(date.tm_mon+1,2)},"%M":function(date){return leadingNulls(date.tm_min,2)},"%n":function(){return"\n"},"%p":function(date){if(date.tm_hour>=0&&date.tm_hour<12){return"AM"}else{return"PM"}},"%S":function(date){return leadingNulls(date.tm_sec,2)},"%t":function(){return"\t"},"%u":function(date){return date.tm_wday||7},"%U":function(date){var janFirst=new Date(date.tm_year+1900,0,1);var firstSunday=janFirst.getDay()===0?janFirst:__addDays(janFirst,7-janFirst.getDay());var endDate=new Date(date.tm_year+1900,date.tm_mon,date.tm_mday);if(compareByDay(firstSunday,endDate)<0){var februaryFirstUntilEndMonth=__arraySum(__isLeapYear(endDate.getFullYear())?__MONTH_DAYS_LEAP:__MONTH_DAYS_REGULAR,endDate.getMonth()-1)-31;var firstSundayUntilEndJanuary=31-firstSunday.getDate();var days=firstSundayUntilEndJanuary+februaryFirstUntilEndMonth+endDate.getDate();return leadingNulls(Math.ceil(days/7),2)}return compareByDay(firstSunday,janFirst)===0?"01":"00"},"%V":function(date){var janFourthThisYear=new Date(date.tm_year+1900,0,4);var janFourthNextYear=new Date(date.tm_year+1901,0,4);var firstWeekStartThisYear=getFirstWeekStartDate(janFourthThisYear);var firstWeekStartNextYear=getFirstWeekStartDate(janFourthNextYear);var endDate=__addDays(new Date(date.tm_year+1900,0,1),date.tm_yday);if(compareByDay(endDate,firstWeekStartThisYear)<0){return"53"}if(compareByDay(firstWeekStartNextYear,endDate)<=0){return"01"}var daysDifference;if(firstWeekStartThisYear.getFullYear()=0;off=Math.abs(off)/60;off=off/60*100+off%60;return(ahead?"+":"-")+String("0000"+off).slice(-4)},"%Z":function(date){return date.tm_zone},"%%":function(){return"%"}};for(var rule in EXPANSION_RULES_2){if(pattern.indexOf(rule)>=0){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_2[rule](date))}}var bytes=intArrayFromString(pattern,false);if(bytes.length>maxsize){return 0}writeArrayToMemory(bytes,s);return bytes.length-1}function _strftime_l(s,maxsize,format,tm){return _strftime(s,maxsize,format,tm)}var FSNode=function(parent,name,mode,rdev){if(!parent){parent=this}this.parent=parent;this.mount=parent.mount;this.mounted=null;this.id=FS.nextInode++;this.name=name;this.mode=mode;this.node_ops={};this.stream_ops={};this.rdev=rdev};var readMode=292|73;var writeMode=146;Object.defineProperties(FSNode.prototype,{read:{get:function(){return(this.mode&readMode)===readMode},set:function(val){val?this.mode|=readMode:this.mode&=~readMode}},write:{get:function(){return(this.mode&writeMode)===writeMode},set:function(val){val?this.mode|=writeMode:this.mode&=~writeMode}},isFolder:{get:function(){return FS.isDir(this.mode)}},isDevice:{get:function(){return FS.isChrdev(this.mode)}}});FS.FSNode=FSNode;FS.staticInit();function intArrayFromString(stringy,dontAddNull,length){var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array}var asmLibraryArg={"o":__ZN7VRegionC1ERK5VRect,"m":__ZN7VRegionD1Ev,"n":__ZN7VRegionpLERK5VRect,"x":__ZNK7VRegion12boundingRectEv,"a":___assert_fail,"u":___map_file,"h":___sys_fcntl64,"z":___sys_ioctl,"t":___sys_munmap,"A":___sys_open,"d":_abort,"c":_emscripten_longjmp,"q":_emscripten_memcpy_big,"r":_emscripten_resize_heap,"v":_environ_get,"w":_environ_sizes_get,"g":_fd_close,"y":_fd_read,"p":_fd_seek,"f":_fd_write,"b":_getTempRet0,"k":invoke_iii,"B":invoke_vi,"memory":wasmMemory,"i":_round,"l":_saveSetjmp,"j":_setTempRet0,"s":_strftime_l,"table":wasmTable,"e":_testSetjmp};var asm=createWasm();Module["asm"]=asm;var ___wasm_call_ctors=Module["___wasm_call_ctors"]=function(){return(___wasm_call_ctors=Module["___wasm_call_ctors"]=Module["asm"]["C"]).apply(null,arguments)};var _lottie_init=Module["_lottie_init"]=function(){return(_lottie_init=Module["_lottie_init"]=Module["asm"]["D"]).apply(null,arguments)};var _lottie_resize=Module["_lottie_resize"]=function(){return(_lottie_resize=Module["_lottie_resize"]=Module["asm"]["E"]).apply(null,arguments)};var _free=Module["_free"]=function(){return(_free=Module["_free"]=Module["asm"]["F"]).apply(null,arguments)};var _lottie_load_from_data=Module["_lottie_load_from_data"]=function(){return(_lottie_load_from_data=Module["_lottie_load_from_data"]=Module["asm"]["G"]).apply(null,arguments)};var _lottie_buffer=Module["_lottie_buffer"]=function(){return(_lottie_buffer=Module["_lottie_buffer"]=Module["asm"]["H"]).apply(null,arguments)};var _lottie_destroy=Module["_lottie_destroy"]=function(){return(_lottie_destroy=Module["_lottie_destroy"]=Module["asm"]["I"]).apply(null,arguments)};var _lottie_render=Module["_lottie_render"]=function(){return(_lottie_render=Module["_lottie_render"]=Module["asm"]["J"]).apply(null,arguments)};var _malloc=Module["_malloc"]=function(){return(_malloc=Module["_malloc"]=Module["asm"]["K"]).apply(null,arguments)};var _realloc=Module["_realloc"]=function(){return(_realloc=Module["_realloc"]=Module["asm"]["L"]).apply(null,arguments)};var ___errno_location=Module["___errno_location"]=function(){return(___errno_location=Module["___errno_location"]=Module["asm"]["M"]).apply(null,arguments)};var _setThrew=Module["_setThrew"]=function(){return(_setThrew=Module["_setThrew"]=Module["asm"]["N"]).apply(null,arguments)};var dynCall_vi=Module["dynCall_vi"]=function(){return(dynCall_vi=Module["dynCall_vi"]=Module["asm"]["O"]).apply(null,arguments)};var dynCall_iii=Module["dynCall_iii"]=function(){return(dynCall_iii=Module["dynCall_iii"]=Module["asm"]["P"]).apply(null,arguments)};var stackSave=Module["stackSave"]=function(){return(stackSave=Module["stackSave"]=Module["asm"]["Q"]).apply(null,arguments)};var stackAlloc=Module["stackAlloc"]=function(){return(stackAlloc=Module["stackAlloc"]=Module["asm"]["R"]).apply(null,arguments)};var stackRestore=Module["stackRestore"]=function(){return(stackRestore=Module["stackRestore"]=Module["asm"]["S"]).apply(null,arguments)};var dynCall_v=Module["dynCall_v"]=function(){return(dynCall_v=Module["dynCall_v"]=Module["asm"]["T"]).apply(null,arguments)};function invoke_iii(index,a1,a2){var sp=stackSave();try{return dynCall_iii(index,a1,a2)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_vi(index,a1){var sp=stackSave();try{dynCall_vi(index,a1)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}Module["asm"]=asm;Module["intArrayFromString"]=intArrayFromString;Module["cwrap"]=cwrap;Module["allocate"]=allocate;var calledRun;function ExitStatus(status){this.name="ExitStatus";this.message="Program terminated with exit("+status+")";this.status=status}dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller};function run(args){args=args||arguments_;if(runDependencies>0){return}preRun();if(runDependencies>0)return;function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();preMain();if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("")},1);doRun()},1)}else{doRun()}}Module["run"]=run;if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}noExitRuntime=true;run(); diff --git a/rlottie_with_printf/rlottie-wasm.wasm b/rlottie_with_printf/rlottie-wasm.wasm new file mode 100644 index 00000000..62f61913 Binary files /dev/null and b/rlottie_with_printf/rlottie-wasm.wasm differ diff --git a/src/components/appMediaPlaybackController.ts b/src/components/appMediaPlaybackController.ts index 088a0edd..5efe51a8 100644 --- a/src/components/appMediaPlaybackController.ts +++ b/src/components/appMediaPlaybackController.ts @@ -1,8 +1,8 @@ import { $rootScope } from "../lib/utils"; import appMessagesManager from "../lib/appManagers/appMessagesManager"; import appDocsManager, {MyDocument} from "../lib/appManagers/appDocsManager"; -import { isSafari } from "../lib/config"; -import { CancellablePromise, deferredPromise } from "../lib/polyfill"; +import { CancellablePromise, deferredPromise } from "../helpers/cancellablePromise"; +import { isSafari } from "../helpers/userAgent"; // TODO: если удалить сообщение, и при этом аудио будет играть - оно не остановится, и можно будет по нему перейти вникуда diff --git a/src/components/appSelectPeers.ts b/src/components/appSelectPeers.ts index 30352e68..5dead86c 100644 --- a/src/components/appSelectPeers.ts +++ b/src/components/appSelectPeers.ts @@ -307,7 +307,7 @@ export class AppSelectPeers { this.selectedContainer.insertBefore(div, this.input); //this.selectedScrollable.scrollTop = this.selectedScrollable.scrollHeight; - this.selectedScrollable.scrollTo(this.selectedScrollable.scrollHeight, true, true); + this.selectedScrollable.scrollTo(this.selectedScrollable.scrollHeight, 'top', true, true); this.onChange && this.onChange(this.selected.size); return div; diff --git a/src/components/audio.ts b/src/components/audio.ts index 22189e99..df409093 100644 --- a/src/components/audio.ts +++ b/src/components/audio.ts @@ -5,8 +5,9 @@ import ProgressivePreloader from "./preloader"; import { MediaProgressLine } from "../lib/mediaPlayer"; import appMediaPlaybackController from "./appMediaPlaybackController"; import { DocumentAttribute } from "../layer"; -import { mediaSizes, isSafari } from "../lib/config"; import { Download } from "../lib/appManagers/appDownloadManager"; +import mediaSizes from "../helpers/mediaSizes"; +import { isSafari } from "../helpers/userAgent"; // https://github.com/LonamiWebs/Telethon/blob/4393ec0b83d511b6a20d8a20334138730f084375/telethon/utils.py#L1285 export function decodeWaveform(waveform: Uint8Array | number[]) { @@ -121,7 +122,7 @@ function wrapVoiceMessage(doc: MyDocument, audioEl: AudioElement) { let start = () => { clearInterval(interval); - interval = setInterval(() => { + interval = window.setInterval(() => { if(lastIndex > svg.childElementCount || isNaN(audio.duration) || audio.paused) { clearInterval(interval); return; diff --git a/src/components/chat/audio.ts b/src/components/chat/audio.ts index a3dff57d..a567eb49 100644 --- a/src/components/chat/audio.ts +++ b/src/components/chat/audio.ts @@ -34,11 +34,16 @@ export class ChatAudio { this.close.addEventListener('click', (e) => { cancelEvent(e); + const scrollTop = appImManager.scrollable.scrollTop; this.container.style.display = 'none'; - this.container.parentElement.classList.remove('is-audio-shown'); + appImManager.topbar.classList.remove('is-audio-shown'); if(this.toggle.classList.contains('flip-icon')) { appMediaPlaybackController.toggle(); } + + if(!appImManager.topbar.classList.contains('is-pinned-shown')) { + appImManager.scrollable.scrollTop = scrollTop - height; + } }); this.toggle.addEventListener('click', (e) => { @@ -46,6 +51,8 @@ export class ChatAudio { appMediaPlaybackController.toggle(); }); + const height = 52; + $rootScope.$on('audio_play', (e) => { const {doc, mid} = e.detail; @@ -68,8 +75,11 @@ export class ChatAudio { if(this.container.style.display) { const scrollTop = appImManager.scrollable.scrollTop; this.container.style.display = ''; - this.container.parentElement.classList.add('is-audio-shown'); - appImManager.scrollable.scrollTop = scrollTop; + appImManager.topbar.classList.add('is-audio-shown'); + + if(!appImManager.topbar.classList.contains('is-pinned-shown')) { + appImManager.scrollable.scrollTop = scrollTop + height; + } } }); diff --git a/src/components/emoticonsDropdown/index.ts b/src/components/emoticonsDropdown/index.ts index 41404183..e1bf65b2 100644 --- a/src/components/emoticonsDropdown/index.ts +++ b/src/components/emoticonsDropdown/index.ts @@ -6,7 +6,7 @@ import { horizontalMenu } from "../horizontalMenu"; import animationIntersector from "../animationIntersector"; import appSidebarRight from "../../lib/appManagers/appSidebarRight"; import appImManager from "../../lib/appManagers/appImManager"; -import Scrollable from "../scrollable_new"; +import Scrollable, { ScrollableX } from "../scrollable_new"; import EmojiTab from "./tabs/emoji"; import StickersTab from "./tabs/stickers"; import StickyIntersector from "../stickyIntersector"; @@ -240,7 +240,7 @@ export class EmoticonsDropdown { //animationIntersector.checkAnimations(false, EMOTICONSSTICKERGROUP); }; - public static menuOnClick = (menu: HTMLUListElement, scroll: Scrollable, menuScroll?: Scrollable) => { + public static menuOnClick = (menu: HTMLUListElement, scroll: Scrollable, menuScroll?: ScrollableX) => { let prevId = 0; let jumpedTo = -1; diff --git a/src/components/emoticonsDropdown/tabs/emoji.ts b/src/components/emoticonsDropdown/tabs/emoji.ts index 9d60c7cd..c52f95b6 100644 --- a/src/components/emoticonsDropdown/tabs/emoji.ts +++ b/src/components/emoticonsDropdown/tabs/emoji.ts @@ -81,7 +81,7 @@ export default class EmojiTab implements EmoticonsTab { //console.timeEnd('emojiParse'); const menu = this.content.previousElementSibling.firstElementChild as HTMLUListElement; - const emojiScroll = this.scroll = new Scrollable(this.content, 'y', 'EMOJI', null); + const emojiScroll = this.scroll = new Scrollable(this.content, 'EMOJI', null); //emojiScroll.setVirtualContainer(emojiScroll.container); diff --git a/src/components/emoticonsDropdown/tabs/gifs.ts b/src/components/emoticonsDropdown/tabs/gifs.ts index fd9b3deb..d8a9d60c 100644 --- a/src/components/emoticonsDropdown/tabs/gifs.ts +++ b/src/components/emoticonsDropdown/tabs/gifs.ts @@ -13,7 +13,7 @@ export default class GifsTab implements EmoticonsTab { const gifsContainer = this.content.firstElementChild as HTMLDivElement; gifsContainer.addEventListener('click', EmoticonsDropdown.onMediaClick); - const scroll = new Scrollable(this.content, 'y', 'GIFS', null); + const scroll = new Scrollable(this.content, 'GIFS', null); const masonry = new GifsMasonry(gifsContainer, EMOTICONSSTICKERGROUP, scroll); const preloader = putPreloader(this.content, true); diff --git a/src/components/emoticonsDropdown/tabs/stickers.ts b/src/components/emoticonsDropdown/tabs/stickers.ts index ac24b625..38aee93f 100644 --- a/src/components/emoticonsDropdown/tabs/stickers.ts +++ b/src/components/emoticonsDropdown/tabs/stickers.ts @@ -1,6 +1,6 @@ import emoticonsDropdown, { EmoticonsTab, EMOTICONSSTICKERGROUP, EmoticonsDropdown } from ".."; import { StickerSet } from "../../../layer"; -import Scrollable from "../../scrollable_new"; +import Scrollable, { ScrollableX } from "../../scrollable_new"; import { wrapSticker } from "../../wrappers"; import appStickersManager from "../../../lib/appManagers/appStickersManager"; import appDownloadManager from "../../../lib/appManagers/appDownloadManager"; @@ -230,7 +230,7 @@ export default class StickersTab implements EmoticonsTab { let menuWrapper = this.content.previousElementSibling as HTMLDivElement; this.menu = menuWrapper.firstElementChild.firstElementChild as HTMLUListElement; - let menuScroll = new Scrollable(menuWrapper, 'x'); + let menuScroll = new ScrollableX(menuWrapper); let stickersDiv = document.createElement('div'); stickersDiv.classList.add('stickers-categories'); @@ -274,7 +274,7 @@ export default class StickersTab implements EmoticonsTab { stickersDiv.addEventListener('click', EmoticonsDropdown.onMediaClick); - this.scroll = new Scrollable(this.content, 'y', 'STICKERS', undefined, undefined, 2); + this.scroll = new Scrollable(this.content, 'STICKERS', undefined, undefined, 2); this.scroll.setVirtualContainer(stickersDiv); this.stickyIntersector = EmoticonsDropdown.menuOnClick(this.menu, this.scroll, menuScroll); diff --git a/src/components/gifsMasonry.ts b/src/components/gifsMasonry.ts index 31ec1acc..427551a6 100644 --- a/src/components/gifsMasonry.ts +++ b/src/components/gifsMasonry.ts @@ -3,9 +3,9 @@ import appDocsManager, {MyDocument} from "../lib/appManagers/appDocsManager"; import { wrapVideo } from "./wrappers"; import { renderImageFromUrl } from "./misc"; import { LazyLoadQueueRepeat2 } from "./lazyLoadQueue"; -import { CancellablePromise, deferredPromise } from "../lib/polyfill"; import animationIntersector from "./animationIntersector"; import Scrollable from "./scrollable_new"; +import { CancellablePromise, deferredPromise } from "../helpers/cancellablePromise"; const width = 400; const maxSingleWidth = width - 100; diff --git a/src/components/horizontalMenu.ts b/src/components/horizontalMenu.ts index d0c72578..8857ea24 100644 --- a/src/components/horizontalMenu.ts +++ b/src/components/horizontalMenu.ts @@ -10,14 +10,15 @@ function slideNavigation(tabContent: HTMLElement, prevTabContent: HTMLElement, t tabContent.style.transform = `translateX(-25%)`; prevTabContent.style.transform = `translateX(20%)`; } */ + const width = prevTabContent.getBoundingClientRect().width; if(toRight) { prevTabContent.style.filter = `brightness(80%)`; - prevTabContent.style.transform = `translateX(-25%)`; - tabContent.style.transform = `translateX(100%)`; + prevTabContent.style.transform = `translate3d(${-width * .25}px, 0, 0)`; + tabContent.style.transform = `translate3d(${width}px, 0, 0)`; } else { tabContent.style.filter = `brightness(80%)`; - tabContent.style.transform = `translateX(-25%)`; - prevTabContent.style.transform = `translateX(100%)`; + tabContent.style.transform = `translate3d(${-width * .25}px, 0, 0)`; + prevTabContent.style.transform = `translate3d(${width}px, 0, 0)`; } tabContent.classList.add('active'); @@ -28,12 +29,13 @@ function slideNavigation(tabContent: HTMLElement, prevTabContent: HTMLElement, t } function slideTabs(tabContent: HTMLElement, prevTabContent: HTMLElement, toRight: boolean) { + const width = prevTabContent.getBoundingClientRect().width; if(toRight) { - tabContent.style.transform = `translateX(100%)`; - prevTabContent.style.transform = `translateX(-100%)`; + tabContent.style.transform = `translate3d(${width}px, 0, 0)`; + prevTabContent.style.transform = `translate3d(${-width}px, 0, 0)`; } else { - tabContent.style.transform = `translateX(-100%)`; - prevTabContent.style.transform = `translateX(100%)`; + tabContent.style.transform = `translate3d(${-width}px, 0, 0)`; + prevTabContent.style.transform = `translate3d(${width}px, 0, 0)`; } tabContent.classList.add('active'); @@ -83,7 +85,7 @@ export function horizontalMenu(tabs: HTMLElement, content: HTMLElement, onClick? const _prevId = prevId; if(hideTimeouts.hasOwnProperty(id)) clearTimeout(hideTimeouts[id]); if(p/* && false */) { - hideTimeouts[_prevId] = setTimeout(() => { + hideTimeouts[_prevId] = window.setTimeout(() => { p.style.transform = ''; p.style.filter = ''; p.classList.remove('active'); diff --git a/src/components/misc.ts b/src/components/misc.ts index 0740312d..56fc029e 100644 --- a/src/components/misc.ts +++ b/src/components/misc.ts @@ -1,4 +1,6 @@ -import Config, { touchSupport, isApple, mediaSizes } from "../lib/config"; +import mediaSizes from "../helpers/mediaSizes"; +import { isApple } from "../helpers/userAgent"; +import Config, { touchSupport } from "../lib/config"; export const loadedURLs: {[url: string]: boolean} = {}; const set = (elem: HTMLElement | HTMLImageElement | SVGImageElement | HTMLVideoElement, url: string) => { diff --git a/src/components/poll.ts b/src/components/poll.ts index 445f7090..33e3f52d 100644 --- a/src/components/poll.ts +++ b/src/components/poll.ts @@ -1,11 +1,12 @@ import appPollsManager, { PollResults, Poll } from "../lib/appManagers/appPollsManager"; import { RichTextProcessor } from "../lib/richtextprocessor"; import { findUpClassName, $rootScope, cancelEvent } from "../lib/utils"; -import { mediaSizes, touchSupport } from "../lib/config"; +import { touchSupport } from "../lib/config"; import appSidebarRight from "../lib/appManagers/appSidebarRight"; import appImManager from "../lib/appManagers/appImManager"; import serverTimeManager from "../lib/mtproto/serverTimeManager"; import { ripple } from "./ripple"; +import mediaSizes from "../helpers/mediaSizes"; let lineTotalLength = 0; const tailLength = 9; diff --git a/src/components/popupCreatePoll.ts b/src/components/popupCreatePoll.ts index 666dc47c..004a6f41 100644 --- a/src/components/popupCreatePoll.ts +++ b/src/components/popupCreatePoll.ts @@ -46,7 +46,7 @@ export default class PopupCreatePoll extends PopupElement { this.confirmBtn.addEventListener('click', this.onSubmitClick); - this.scrollable = new Scrollable(this.body, 'y', undefined); + this.scrollable = new Scrollable(this.body); this.appendMoreField(); } @@ -131,6 +131,6 @@ export default class PopupCreatePoll extends PopupElement { this.questions.append(questionField); - this.scrollable.scrollTo(this.scrollable.scrollHeight, true, true); + this.scrollable.scrollTo(this.scrollable.scrollHeight, 'top', true, true); } } \ No newline at end of file diff --git a/src/components/popupStickers.ts b/src/components/popupStickers.ts index 36a4d812..f6541044 100644 --- a/src/components/popupStickers.ts +++ b/src/components/popupStickers.ts @@ -64,7 +64,7 @@ export default class PopupStickers extends PopupElement { this.stickersFooter.innerText = 'Loading...'; this.body.append(div); - const scrollable = new Scrollable(this.body, 'y', undefined); + const scrollable = new Scrollable(this.body); this.body.append(this.stickersFooter); // const editButton = document.createElement('button'); diff --git a/src/components/preloader.ts b/src/components/preloader.ts index b9a1d42f..3f699db6 100644 --- a/src/components/preloader.ts +++ b/src/components/preloader.ts @@ -1,5 +1,5 @@ import { isInDOM, cancelEvent } from "../lib/utils"; -import { CancellablePromise } from "../lib/polyfill"; +import { CancellablePromise } from "../helpers/cancellablePromise"; export default class ProgressivePreloader { public preloader: HTMLDivElement; diff --git a/src/components/ripple.ts b/src/components/ripple.ts index cd6c0bd4..facc125a 100644 --- a/src/components/ripple.ts +++ b/src/components/ripple.ts @@ -1,4 +1,5 @@ import { touchSupport } from "../lib/config"; +import { findUpClassName } from "../lib/utils"; let rippleClickID = 0; export function ripple(elem: HTMLElement, callback: (id: number) => Promise = () => Promise.resolve(), onEnd: (id: number) => void = null) { @@ -28,6 +29,7 @@ export function ripple(elem: HTMLElement, callback: (id: number) => Promise { + //return; let elapsedTime = Date.now() - startTime; if(elapsedTime < duration) { let delay = Math.max(duration - elapsedTime, duration / 2); @@ -66,8 +68,8 @@ export function ripple(elem: HTMLElement, callback: (id: number) => Promise { - span.classList.add('c-ripple__circle'); let rect = r.getBoundingClientRect(); + span.classList.add('c-ripple__circle'); let clickX = clientX - rect.left; let clickY = clientY - rect.top; @@ -110,7 +112,7 @@ export function ripple(elem: HTMLElement, callback: (id: number) => Promise { //console.log('ripple touchstart', e); - if(e.touches.length > 1 || ((e.target as HTMLElement).tagName == 'BUTTON' && e.target != elem)) { + if(e.touches.length > 1 || ((e.target as HTMLElement).tagName == 'BUTTON' && e.target != elem) || findUpClassName(e.target as HTMLElement, 'c-ripple') != r) { return; } @@ -130,7 +132,9 @@ export function ripple(elem: HTMLElement, callback: (id: number) => Promise { - if(elem.dataset.ripple == '0') { + //console.log('ripple mousedown', e, e.target, findUpClassName(e.target as HTMLElement, 'c-ripple') == r); + + if(elem.dataset.ripple == '0' || findUpClassName(e.target as HTMLElement, 'c-ripple') != r) { return false; } else if(touchStartFired) { touchStartFired = false; diff --git a/src/components/scrollable_new.ts b/src/components/scrollable_new.ts index d76008db..e1be505e 100644 --- a/src/components/scrollable_new.ts +++ b/src/components/scrollable_new.ts @@ -1,10 +1,10 @@ import { logger, LogLevels } from "../lib/logger"; -import smoothscroll from '../vendor/smoothscroll'; -import { touchSupport, isSafari, mediaSizes } from "../lib/config"; -import { CancellablePromise, deferredPromise } from "../lib/polyfill"; +import smoothscroll, { SCROLL_TIME, SmoothScrollToOptions } from '../vendor/smoothscroll'; +import { touchSupport } from "../lib/config"; +//import { CancellablePromise, deferredPromise } from "../lib/polyfill"; //import { isInDOM } from "../lib/utils"; (window as any).__forceSmoothScrollPolyfill__ = true; -smoothscroll.polyfill(); +smoothscroll(); /* var el = $0; var height = 0; @@ -48,10 +48,88 @@ const scrollsIntersector = new IntersectionObserver(entries => { } }); */ -export default class Scrollable { - //public container: HTMLDivElement; - public overflowContainer: HTMLElement; +export class ScrollableBase { + protected log: ReturnType; + protected onScroll: () => void; + public getScrollValue: () => number; + + public scrollLocked = 0; + + constructor(public el: HTMLElement, logPrefix = '', public appendTo = el, public container: HTMLElement = document.createElement('div')) { + this.container.classList.add('scrollable'); + + if(!appendTo) { + this.appendTo = this.container; + } + + this.log = logger('SCROLL' + (logPrefix ? '-' + logPrefix : ''), LogLevels.error); + + if(el) { + Array.from(el.children).forEach(c => this.container.append(c)); + + el.append(this.container); + } + //this.onScroll(); + } + + protected setListeners() { + window.addEventListener('resize', this.onScroll); + this.container.addEventListener('scroll', this.onScroll, {passive: true, capture: true}); + } + + public prepend(element: HTMLElement) { + this.appendTo.prepend(element); + } + + public append(element: HTMLElement) { + this.appendTo.append(element); + } + + public contains(element: Element) { + return !!element.parentElement; + } + + public removeElement(element: Element) { + element.remove(); + } + + public scrollTo(value: number, side: 'top' | 'left', smooth = true, important = false, scrollTime = SCROLL_TIME) { + if(this.scrollLocked && !important) return; + + const scrollValue = this.getScrollValue(); + if(scrollValue == Math.floor(value)) { + return; + } + + if(this.scrollLocked) clearTimeout(this.scrollLocked); + /* else { + this.scrollLockedPromise = deferredPromise(); + } */ + + this.scrollLocked = window.setTimeout(() => { + this.scrollLocked = 0; + //this.scrollLockedPromise.resolve(); + //this.onScroll(); + this.container.dispatchEvent(new CustomEvent('scroll')); + }, scrollTime); + + const options: SmoothScrollToOptions = { + behavior: smooth ? 'smooth' : 'auto', + scrollTime + }; + + options[side] = value; + + this.container.scrollTo(options as any); + } + + get length() { + return this.appendTo.childElementCount; + } +} + +export default class Scrollable extends ScrollableBase { public splitUp: HTMLElement; public onScrolledTop: () => void = null; @@ -63,8 +141,6 @@ export default class Scrollable { private disableHoverTimeout: number = 0; - private log: ReturnType; - /* private sentinelsObserver: IntersectionObserver; private topSentinel: HTMLDivElement; private bottomSentinel: HTMLDivElement; */ @@ -80,8 +156,7 @@ export default class Scrollable { /* private onScrolledTopFired = false; private onScrolledBottomFired = false; */ - public scrollLocked = 0; - public scrollLockedPromise: CancellablePromise = Promise.resolve(); + //public scrollLockedPromise: CancellablePromise = Promise.resolve(); public isVisible = false; private reorderTimeout: number; @@ -102,8 +177,8 @@ export default class Scrollable { this.visible.delete(element); } - constructor(public el: HTMLElement, axis: 'y' | 'x' = 'y', logPrefix = '', public appendTo = el, public onScrollOffset = 300, public splitCount = 15, public container: HTMLElement = document.createElement('div')) { - this.container.classList.add('scrollable'); + constructor(el: HTMLElement, logPrefix = '', appendTo = el, public onScrollOffset = 300, public splitCount = 15, container: HTMLElement = document.createElement('div')) { + super(el, logPrefix, appendTo, container); this.visible = new Set(); this.observer = new IntersectionObserver(entries => { @@ -173,63 +248,11 @@ export default class Scrollable { } }); - if(!appendTo) { - this.appendTo = this.container; - } - - this.log = logger('SCROLL' + (logPrefix ? '-' + logPrefix : ''), LogLevels.error); - - if(axis == 'x') { - this.container.classList.add('scrollable-x'); - - if(!touchSupport) { - const scrollHorizontally = (e: any) => { - e = window.event || e; - if(e.which == 1) { - // maybe horizontal scroll is natively supports, works on macbook - return; - } - - const delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail))); - this.container.scrollLeft -= (delta * 20); - e.preventDefault(); - }; - if(this.container.addEventListener) { - // IE9, Chrome, Safari, Opera - this.container.addEventListener("mousewheel", scrollHorizontally, false); - // Firefox - this.container.addEventListener("DOMMouseScroll", scrollHorizontally, false); - } else { - // IE 6/7/8 - // @ts-ignore - this.container.attachEvent("onmousewheel", scrollHorizontally); - } - } - } else if(axis == 'y') { - this.container.classList.add('scrollable-y'); - } else { - throw new Error('no side for scroll'); - } - - window.addEventListener('resize', () => { - this.overflowContainer = mediaSizes.isMobile && false ? document.documentElement : this.container; - this.onScroll(); - }); - this.container.addEventListener('scroll', this.onScroll, {passive: true, capture: true}); - //document.documentElement.addEventListener('scroll', binded, {passive: true, capture: true}); - //window.addEventListener('scroll', binded, {passive: true, capture: true}); - - if(el) { - Array.from(el.children).forEach(c => this.container.append(c)); + this.container.classList.add('scrollable-y'); - el.append(this.container); - } //this.onScroll(); - this.overflowContainer = mediaSizes.isMobile && false ? document.documentElement : this.container; - - /* scrollables.set(this.container, this); - scrollsIntersector.observe(this.container); */ + this.setListeners(); } // public attachSentinels(container = this.container, offset = this.onScrollOffset) { @@ -329,12 +352,12 @@ export default class Scrollable { this.onScrollMeasure = window.requestAnimationFrame(() => { //if(!this.isVisible) return; - this.checkForTriggers(this.overflowContainer); + this.checkForTriggers(); this.onScrollMeasure = 0; if(!this.splitUp) return; - const scrollTop = this.overflowContainer.scrollTop; + const scrollTop = this.scrollTop; if(this.lastScrollTop != scrollTop) { this.lastScrollDirection = this.lastScrollTop < scrollTop ? 1 : -1; this.lastScrollTop = scrollTop; @@ -344,9 +367,10 @@ export default class Scrollable { }); }; - public checkForTriggers(container: HTMLElement) { + public checkForTriggers() { if(this.scrollLocked || (!this.onScrolledTop && !this.onScrolledBottom)) return; + const container = this.container; const scrollHeight = container.scrollHeight; if(!scrollHeight) { // незачем вызывать триггеры если блок пустой или не виден return; @@ -439,11 +463,11 @@ export default class Scrollable { if(element.parentElement && !this.scrollLocked) { const isFirstUnread = element.classList.contains('is-first-unread'); - let offsetTop = element.getBoundingClientRect().top - this.container.getBoundingClientRect().top; - offsetTop = this.container.scrollTop + offsetTop; + let offset = element.getBoundingClientRect().top - this.container.getBoundingClientRect().top; + offset = this.scrollTop + offset; if(!smooth && isFirstUnread) { - this.scrollTo(offsetTop, false); + this.scrollTo(offset, 'top', false); return; } @@ -451,39 +475,20 @@ export default class Scrollable { const height = element.scrollHeight; const d = (clientHeight - height) / 2; - offsetTop -= d; + offset -= d; - this.scrollTo(offsetTop, smooth); - } - } - - public scrollTo(top: number, smooth = true, important = false) { - if(this.scrollLocked && !important) return; - - const scrollTop = this.scrollTop; - if(scrollTop == Math.floor(top)) { - return; - } - - if(this.scrollLocked) clearTimeout(this.scrollLocked); - else { - this.scrollLockedPromise = deferredPromise(); + this.scrollTo(offset, 'top', smooth); } - - this.scrollLocked = window.setTimeout(() => { - this.scrollLocked = 0; - this.scrollLockedPromise.resolve(); - //this.onScroll(); - this.container.dispatchEvent(new CustomEvent('scroll')); - }, 468); - - this.container.scrollTo({behavior: smooth ? 'smooth' : 'auto', top}); } public removeElement(element: Element) { element.remove(); } + public getScrollValue = () => { + return this.scrollTop; + }; + set scrollTop(y: number) { this.container.scrollTop = y; } @@ -496,8 +501,57 @@ export default class Scrollable { get scrollHeight() { return this.container.scrollHeight; } +} - get length() { - return this.appendTo.childElementCount; +export class ScrollableX extends ScrollableBase { + constructor(public el: HTMLElement, logPrefix = '', public appendTo = el, public onScrollOffset = 300, public splitCount = 15, public container: HTMLElement = document.createElement('div')) { + super(el, logPrefix, appendTo, container); + + this.container.classList.add('scrollable-x'); + + if(!touchSupport) { + const scrollHorizontally = (e: any) => { + e = window.event || e; + if(e.which == 1) { + // maybe horizontal scroll is natively supports, works on macbook + return; + } + + const delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail))); + this.container.scrollLeft -= (delta * 20); + e.preventDefault(); + }; + if(this.container.addEventListener) { + // IE9, Chrome, Safari, Opera + this.container.addEventListener("mousewheel", scrollHorizontally, false); + // Firefox + this.container.addEventListener("DOMMouseScroll", scrollHorizontally, false); + } else { + // IE 6/7/8 + // @ts-ignore + this.container.attachEvent("onmousewheel", scrollHorizontally); + } + } + + this.setListeners(); } + + public scrollIntoView(element: HTMLElement, smooth = true, scrollTime?: number) { + if(element.parentElement && !this.scrollLocked) { + let offset = element.getBoundingClientRect().left - this.container.getBoundingClientRect().left; + offset = this.getScrollValue() + offset; + + const clientWidth = this.container.clientWidth; + const width = element.scrollWidth; + + const d = (clientWidth - width) / 2; + offset -= d; + + this.scrollTo(offset, 'left', smooth, undefined, scrollTime); + } + } + + public getScrollValue = () => { + return this.container.scrollLeft; + }; } diff --git a/src/components/sidebarLeft/editProfile.ts b/src/components/sidebarLeft/editProfile.ts index 173291aa..ef99f061 100644 --- a/src/components/sidebarLeft/editProfile.ts +++ b/src/components/sidebarLeft/editProfile.ts @@ -134,7 +134,7 @@ export default class AppEditProfileTab implements SliderTab { }); }); - let scrollable = new Scrollable(this.scrollWrapper as HTMLElement, 'y'); + let scrollable = new Scrollable(this.scrollWrapper as HTMLElement); } public fillElements() { diff --git a/src/components/sidebarRight/gifs.ts b/src/components/sidebarRight/gifs.ts index 33364428..d2ff5925 100644 --- a/src/components/sidebarRight/gifs.ts +++ b/src/components/sidebarRight/gifs.ts @@ -31,7 +31,7 @@ export default class AppGifsTab implements SliderTab { private searchPromise: ReturnType; constructor() { - this.scrollable = new Scrollable(this.contentDiv, 'y', ANIMATIONGROUP, undefined, undefined, 2); + this.scrollable = new Scrollable(this.contentDiv, ANIMATIONGROUP, undefined, undefined, 2); this.scrollable.setVirtualContainer(this.gifsDiv); this.masonry = new GifsMasonry(this.gifsDiv, ANIMATIONGROUP, this.scrollable); diff --git a/src/components/sidebarRight/pollResults.ts b/src/components/sidebarRight/pollResults.ts index 7d9f3577..0dce1490 100644 --- a/src/components/sidebarRight/pollResults.ts +++ b/src/components/sidebarRight/pollResults.ts @@ -17,7 +17,7 @@ export default class AppPollResultsTab implements SliderTab { private mid: number; constructor() { - this.scrollable = new Scrollable(this.contentDiv, 'y', 'POLL-RESULTS', undefined, undefined, 2); + this.scrollable = new Scrollable(this.contentDiv, 'POLL-RESULTS', undefined, undefined, 2); } public cleanup() { diff --git a/src/components/sidebarRight/stickers.ts b/src/components/sidebarRight/stickers.ts index 097ba438..8d90f2e5 100644 --- a/src/components/sidebarRight/stickers.ts +++ b/src/components/sidebarRight/stickers.ts @@ -23,7 +23,7 @@ export default class AppStickersTab implements SliderTab { private lazyLoadQueue: LazyLoadQueue; constructor() { - this.scrollable = new Scrollable(this.contentDiv, 'y', 'STICKERS-SEARCH', undefined, undefined, 2); + this.scrollable = new Scrollable(this.contentDiv, 'STICKERS-SEARCH', undefined, undefined, 2); this.scrollable.setVirtualContainer(this.setsDiv); this.lazyLoadQueue = new LazyLoadQueue(); diff --git a/src/components/wrappers.ts b/src/components/wrappers.ts index 0ee2d1eb..2647afab 100644 --- a/src/components/wrappers.ts +++ b/src/components/wrappers.ts @@ -10,7 +10,6 @@ import { renderImageFromUrl } from './misc'; import appMessagesManager from '../lib/appManagers/appMessagesManager'; import { Layouter, RectPart } from './groupedLayout'; import PollElement from './poll'; -import { mediaSizes, isSafari } from '../lib/config'; import animationIntersector from './animationIntersector'; import AudioElement from './audio'; import { DownloadBlob } from '../lib/appManagers/appDownloadManager'; @@ -18,7 +17,9 @@ import webpWorkerController from '../lib/webp/webpWorkerController'; import { readBlobAsText } from '../helpers/blob'; import appMediaPlaybackController from './appMediaPlaybackController'; import { PhotoSize } from '../layer'; -import { deferredPromise } from '../lib/polyfill'; +import { deferredPromise } from '../helpers/cancellablePromise'; +import mediaSizes from '../helpers/mediaSizes'; +import { isSafari } from '../helpers/userAgent'; export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTail, isOut, middleware, lazyLoadQueue, noInfo, group}: { doc: MyDocument, @@ -704,6 +705,14 @@ export function wrapReply(title: string, subtitle: string, message?: any, isPinn const replySubtitle = document.createElement('div'); replySubtitle.classList.add(prefix + '-subtitle'); + + if(title.length > 150) { + title = title.substr(0, 140) + '...'; + } + + if(subtitle.length > 150) { + subtitle = subtitle.substr(0, 140) + '...'; + } replyTitle.innerHTML = title ? RichTextProcessor.wrapEmojiText(title) : ''; diff --git a/src/helpers/cancellablePromise.ts b/src/helpers/cancellablePromise.ts new file mode 100644 index 00000000..139f49c5 --- /dev/null +++ b/src/helpers/cancellablePromise.ts @@ -0,0 +1,63 @@ +export interface CancellablePromise extends Promise { + resolve?: (...args: any[]) => void, + reject?: (...args: any[]) => void, + cancel?: () => void, + + notify?: (...args: any[]) => void, + notifyAll?: (...args: any[]) => void, + lastNotify?: any, + listeners?: Array<(...args: any[]) => void>, + addNotifyListener?: (callback: (...args: any[]) => void) => void, + + isFulfilled?: boolean, + isRejected?: boolean +} + +export function deferredPromise() { + let deferredHelper: any = { + isFulfilled: false, + isRejected: false, + + notify: () => {}, + notifyAll: (...args: any[]) => { + deferredHelper.lastNotify = args; + deferredHelper.listeners.forEach((callback: any) => callback(...args)); + }, + + lastNotify: undefined, + listeners: [], + addNotifyListener: (callback: (...args: any[]) => void) => { + if(deferredHelper.lastNotify) { + callback(...deferredHelper.lastNotify); + } + + deferredHelper.listeners.push(callback); + } + }; + + let deferred: CancellablePromise = new Promise((resolve, reject) => { + deferredHelper.resolve = (value: T) => { + if(deferred.isFulfilled) return; + + deferred.isFulfilled = true; + resolve(value); + }; + + deferredHelper.reject = (...args: any[]) => { + if(deferred.isRejected) return; + + deferred.isRejected = true; + reject(...args); + }; + }); + + deferred.finally(() => { + deferred.notify = null; + deferred.listeners.length = 0; + deferred.lastNotify = null; + }); + + Object.assign(deferred, deferredHelper); + + return deferred; +} \ No newline at end of file diff --git a/src/helpers/eventListenerBase.ts b/src/helpers/eventListenerBase.ts new file mode 100644 index 00000000..319938dc --- /dev/null +++ b/src/helpers/eventListenerBase.ts @@ -0,0 +1,48 @@ +import type { ArgumentTypes } from "../types"; + +export default class EventListenerBase { + protected listeners: Partial<{ + [k in keyof Listeners]: Array<{callback: Listeners[k], once?: true}> + }> = {}; + protected listenerResults: Partial<{ + [k in keyof Listeners]: ArgumentTypes + }> = {}; + + constructor(private reuseResults?: true) { + + } + + public addListener(name: keyof Listeners, callback: Listeners[typeof name], once?: true) { + (this.listeners[name] ?? (this.listeners[name] = [])).push({callback, once}); + + if(this.listenerResults.hasOwnProperty(name)) { + callback(this.listenerResults[name]); + + if(once) { + this.removeListener(name, callback); + } + } + } + + public removeListener(name: keyof Listeners, callback: Listeners[typeof name]) { + if(this.listeners[name]) { + this.listeners[name].findAndSplice(l => l.callback == callback); + } + } + + protected setListenerResult(name: keyof Listeners, ...args: ArgumentTypes) { + if(this.reuseResults) { + this.listenerResults[name] = args; + } + + if(this.listeners[name]) { + this.listeners[name].forEach(listener => { + listener.callback(...args); + + if(listener.once) { + this.removeListener(name, listener.callback); + } + }); + } + } +} \ No newline at end of file diff --git a/src/helpers/mediaSizes.ts b/src/helpers/mediaSizes.ts new file mode 100644 index 00000000..1b7a53f7 --- /dev/null +++ b/src/helpers/mediaSizes.ts @@ -0,0 +1,105 @@ +import EventListenerBase from "./eventListenerBase"; + +type Size = {width: number, height: number}; +type Sizes = { + regular: Size, + webpage: Size, + album: Size +}; + +export enum ScreenSize { + mobile, + medium, + large +} + +const MOBILE_SIZE = 896; +const MEDIUM_SIZE = 1275; +const LARGE_SIZE = 1680; + +class MediaSizes extends EventListenerBase<{ + changeScreen: (from: ScreenSize, to: ScreenSize) => void +}> { + private screenSizes: {key: ScreenSize, value: number}[] = [ + {key: ScreenSize.mobile, value: MOBILE_SIZE - 1}, + {key: ScreenSize.medium, value: MEDIUM_SIZE}, + {key: ScreenSize.large, value: LARGE_SIZE} + ]; + + private sizes: {[k in 'desktop' | 'handhelds']: Sizes} = { + handhelds: { + regular: { + width: 293, + height: 293 + }, + webpage: { + width: 293, + height: 213 + }, + album: { + width: 293, + height: 0 + } + }, + desktop: { + regular: { + width: 480, + height: 480 + }, + webpage: { + width: 480, + height: 400 + }, + album: { + width: 451, + height: 0 + } + } + }; + + public isMobile = false; + public active: Sizes; + public activeScreen: ScreenSize; + + constructor() { + super(); + + window.addEventListener('resize', this.handleResize); + this.handleResize(); + } + + private handleResize = () => { + const innerWidth = window.innerWidth; + //this.isMobile = innerWidth <= 720; + + let activeScreen = this.screenSizes[0].key; + for(let i = this.screenSizes.length - 1; i >= 0; --i) { + if(this.screenSizes[i].value < innerWidth) { + activeScreen = (this.screenSizes[i + 1] || this.screenSizes[i]).key; + break; + } + } + + if(this.activeScreen != activeScreen) { + //console.log('changeScreen', this.activeScreen, activeScreen); + this.setListenerResult('changeScreen', this.activeScreen, activeScreen); + } + + this.activeScreen = activeScreen; + + this.isMobile = this.activeScreen == ScreenSize.mobile; + + this.active = this.isMobile ? this.sizes.handhelds : this.sizes.desktop; + + /* if(this.isMobile) { + for(let i in this.active) { + // @ts-ignore + let size = this.active[i]; + size.width = innerWidth + } + } */ + }; +} + +const mediaSizes = new MediaSizes(); +export default mediaSizes; \ No newline at end of file diff --git a/src/index.hbs b/src/index.hbs index 10588436..a333c4f4 100644 --- a/src/index.hbs +++ b/src/index.hbs @@ -22,7 +22,7 @@ {{/ each }} - + @@ -212,7 +212,7 @@