UNPKG

extes

Version:

A tiny library that extends native js with some handy tools

1,568 lines (1,365 loc) 37.1 kB
(()=>{ "use strict"; const writable=true, configurable=true, enumerable=false; const IsNodeJS = (typeof Buffer !== "undefined"); function Padding(val, length=2, stuffing='0'){ val = `${val}`; let remain = length - val.length; while( remain-- > 0 ) { val = stuffing + val; } return val; } function ExtractBytes(content) { if( IsNodeJS ){ if( Buffer.isBuffer(content) ){ return new Uint8Array(content); } } if( ArrayBuffer.isView(content) ){ return new Uint8Array(content.buffer); } if( content instanceof ArrayBuffer ){ return new Uint8Array(content); } return null; } const UTF8_DECODE_CHUNK_SIZE = 100; /** * Encode given input js string using utf8 format * @param {String} js_str * @returns {Uint8Array} **/ function UTF8Encode(js_str) { if ( typeof js_str !== "string" ) { throw new TypeError( "Given input argument must be a js string!" ); } let codePoints = []; let i=0; while( i < js_str.length ) { let codePoint = js_str.codePointAt(i); // 1-byte sequence if( (codePoint & 0xffffff80) === 0 ) { codePoints.push(codePoint); } // 2-byte sequence else if( (codePoint & 0xfffff800) === 0 ) { codePoints.push( 0xc0 | (0x1f & (codePoint >> 6)), 0x80 | (0x3f & codePoint) ); } // 3-byte sequence else if( (codePoint & 0xffff0000) === 0 ) { codePoints.push( 0xe0 | (0x0f & (codePoint >> 12)), 0x80 | (0x3f & (codePoint >> 6)), 0x80 | (0x3f & codePoint) ); } // 4-byte sequence else if( (codePoint & 0xffe00000) === 0 ) { codePoints.push( 0xf0 | (0x07 & (codePoint >> 18)), 0x80 | (0x3f & (codePoint >> 12)), 0x80 | (0x3f & (codePoint >> 6)), 0x80 | (0x3f & codePoint) ); } i += (codePoint>0xFFFF) ? 2 : 1; } return new Uint8Array(codePoints); } /** * Decode given input buffer using utf8 format * @param {ArrayBuffer|Uint8Array} raw_bytes * @returns {string} **/ function UTF8Decode(raw_bytes) { if ( raw_bytes instanceof ArrayBuffer ) { raw_bytes = new Uint8Array(raw_bytes); } if ( !(raw_bytes instanceof Uint8Array) ) { throw new TypeError( "Given input must be an Uint8Array contains UTF8 encoded value!" ); } let uint8 = raw_bytes; let codePoints = []; let i = 0; while( i < uint8.length ) { let codePoint = uint8[i] & 0xff; // 1-byte sequence (0 ~ 127) if( (codePoint & 0x80) === 0 ){ codePoints.push(codePoint); i += 1; } // 2-byte sequence (192 ~ 223) else if( (codePoint & 0xE0) === 0xC0 ){ codePoint = ((0x1f & uint8[i]) << 6) | (0x3f & uint8[i + 1]); codePoints.push(codePoint); i += 2; } // 3-byte sequence (224 ~ 239) else if( (codePoint & 0xf0) === 0xe0 ){ codePoint = ((0x0f & uint8[i]) << 12) | ((0x3f & uint8[i + 1]) << 6) | (0x3f & uint8[i + 2]); codePoints.push(codePoint); i += 3; } // 4-byte sequence (249 ~ ) else if( (codePoint & 0xF8) === 0xF0 ){ codePoint = ((0x07 & uint8[i]) << 18) | ((0x3f & uint8[i + 1]) << 12) | ((0x3f & uint8[i + 2]) << 6) | (0x3f & uint8[i + 3]); codePoints.push(codePoint); i += 4; } else { i += 1; } } let result_string = ""; while(codePoints.length > 0) { const chunk = codePoints.splice(0, UTF8_DECODE_CHUNK_SIZE); result_string += String.fromCodePoint(...chunk); } return result_string; } (()=>{ const HEX_FORMAT = /^(0x)?([0-9a-fA-F]+)$/; const BIT_FORMAT = /^(0b|0B)?([01]+)$/; const HEX_MAP = "0123456789abcdef"; const HEX_MAP_R = { "0":0, "1":1, "2":2, "3":3, "4":4, "5":5, "6":6, "7":7, "8":8, "9":9, "a":10, "b":11, "c":12, "d":13, "e":14, "f":15 }; Object.defineProperty(ArrayBuffer.prototype, 'bytes', { configurable, enumerable, get:function(){ return new Uint8Array(this); } }); Object.defineProperty(ArrayBuffer.prototype, 'toString', { configurable, writable, enumerable, value:function(format=16, padding=true){ const bytes = new Uint8Array(this); let result = ''; switch(format) { case 16: for(let i=0; i<bytes.length; i++) { const value = bytes[i]; result += HEX_MAP[(value&0xF0)>>>4] + HEX_MAP[value&0x0F]; } break; case 2: for(let i=0; i<bytes.length; i++) { const value = bytes[i]; for (let k=7; k>=0; k--) { result += ((value >>> k) & 0x01) ? '1' : '0'; } } break; default: throw new RangeError( "Unsupported numeric representation!" ); } return padding ? result : result.replace(/^0+/, ''); } }); Object.defineProperty(ArrayBuffer.prototype, 'compare', { configurable, writable, enumerable, value:function(array_buffer) { if ( !(array_buffer instanceof ArrayBuffer) ) { throw new TypeError("An ArrayBuffer can only be compared with another ArrayBuffer"); } const a = new Uint8Array(this); const b = new Uint8Array(array_buffer); const len = Math.max(a.length, b.length); for(let i=0; i<len; i++) { const val_a = a[i] || 0, val_b = b[i] || 0; if ( val_a > val_b ) return 1; if ( val_a < val_b ) return -1; } return 0; } }); Object.defineProperty(ArrayBuffer, 'extract', { configurable, writable, enumerable, value: function(input) { if ( typeof Buffer !== "undefined" ) { if ( input instanceof Buffer ) { let buff = Buffer.alloc(input.length); input.copy(buff, 0); return buff.buffer; } } if ( ArrayBuffer.isView(input) ) { return input.buffer; } if ( input instanceof ArrayBuffer ) { return input; } throw new TypeError( "Cannot convert given input data into array buffer" ); } }); Object.defineProperty(ArrayBuffer, 'from', { configurable, writable, enumerable, value: function(input, conversion_info=null) { if ( typeof Buffer !== "undefined" ) { if ( input instanceof Buffer ) { let buff = Buffer.alloc(input.length); input.copy(buff, 0); return buff.buffer; } } if ( ArrayBuffer.isView(input) ) { return input.buffer.slice(0); } if ( input instanceof ArrayBuffer ) { return input.slice(0); } if ( Array.isArray(input) ) { const buffer = new Uint8Array(input); return buffer.buffer; } if ( typeof input === "number" ) { let data_buffer = null; switch(conversion_info) { case 'int8': data_buffer = new Int8Array([input]); break; case 'uint8': data_buffer = new Uint8Array([input]); break; case 'int16': data_buffer = new Int16Array([input]); break; case 'uint16': data_buffer = new Uint16Array([input]); break; case 'int32': data_buffer = new Int32Array([input]); break; case 'int64':{ const negative = input < 0; if ( negative ) { input = -input; } let upper = Math.floor(input/0xFFFFFFFF); let lower = input & 0xFFFFFFFF; if ( negative ) { lower = ((~lower)>>>0) + 1; upper = (~upper) + Math.floor(lower/0xFFFFFFFF); } data_buffer = new Uint32Array([lower, upper]); break; } case 'uint64': { const upper = Math.floor(input/0xFFFFFFFF); const lower = input & 0xFFFFFFFF; data_buffer = new Uint32Array([lower, upper]); break; } case 'float32': data_buffer = new Float32Array([input]); break; case 'float64': data_buffer = new Float64Array([input]); break; case 'uint32': default: data_buffer = new Uint32Array([input]); break; } return data_buffer.buffer; } if ( typeof input === "string" ) { if ( conversion_info === "hex" ) { const matches = input.match(HEX_FORMAT); if ( !matches ) { throw new RangeError( "Input argument is not a valid hex string!" ); } let [,,hex_string] = matches; if ( hex_string.length % 2 === 0 ) { hex_string = hex_string.toLowerCase(); } else { hex_string = '0' + hex_string.toLowerCase(); } const buff = new Uint8Array((hex_string.length/2)|0); for ( let i=0; i<buff.length; i++ ) { const offset = i * 2; buff[i] = HEX_MAP_R[hex_string[offset]]<<4 | (HEX_MAP_R[hex_string[offset+1]] & 0x0F); } return buff.buffer; } else if ( conversion_info === "bits" ) { const matches = input.match(BIT_FORMAT); if ( !matches ) { throw new RangeError( "Input argument is not a valid bit string!" ); } let [,,bit_string] = matches; if ( bit_string.length % 8 !== 0 ) { bit_string = '0'.repeat(bit_string.length%8) + bit_string; } const buff = new Uint8Array((bit_string.length/8)|0); for ( let i=0; i<buff.length; i++ ) { const offset = i * 8; let value = (bit_string[offset]==='1'?1:0); for (let k=1; k<8; k++) { value = (value << 1) | (bit_string[offset + k]==='1'?1:0); } buff[i] = value; } return buff.buffer; } else { return UTF8Encode(input).buffer; } } throw new TypeError( "Cannot convert given input data into array buffer!" ); } }); Object.defineProperty(ArrayBuffer, 'compare', { configurable, writable, enumerable, value: function(a, b) { if ( !(a instanceof ArrayBuffer) || !(b instanceof ArrayBuffer) ) { throw new TypeError("ArrayBuffer.compare only accepts two array buffers!"); } return a.compare(b); } }); Object.defineProperty(ArrayBuffer, 'concat', { configurable, writable, enumerable, value: function(...args) { if ( Array.isArray(args[0]) ) { args = args[0]; } let temp = 0; for(let i=0; i<args.length; i++) { let arg = args[i] = ExtractBytes(args[i]); if (!(arg instanceof Uint8Array)) { throw new TypeError("ArrayBuffer.combine accept only ArrayBuffer, TypeArray and DataView."); } temp += arg.length; } const buff = new Uint8Array(temp); temp = 0; for(const arg of args) { buff.set(arg, temp); temp += arg.length; } return buff.buffer; } }); })(); (()=>{ Object.defineProperty(Array.prototype, 'unique', { writable, configurable, enumerable, value: function(){ const set = new Set(); for ( const item of this ) set.add(item); return Array.from(set); } }); Object.defineProperty(Array.prototype, 'exclude', { writable, configurable, enumerable, value: function(reject_list) { if ( !Array.isArray(reject_list) ) { reject_list = [reject_list]; } const new_ary = []; for(const item of this) { let reject = false; for(const reject_item of reject_list) { if ( item === reject_item ) { reject = reject || true; break; } } if ( !reject ) { new_ary.push(item); } } return new_ary; } }); Object.defineProperty(Array, 'concat', { writable, configurable, enumerable, value: function(...elements) { const result = []; for(const element of elements) { if ( !Array.isArray(element) ) { result.push(element); continue; } for(const elm of element) { result.push(elm); } } return result; } }); Object.defineProperty(Array, 'intersect', { writable, configurable, enumerable, value: function(...arrays) { let result = arrays[0]||[]; if ( !Array.isArray(result) ) { throw new TypeError(`Array.intersect only accepts list array arguments!`); } for(let i=1; i<arrays.length; i++) { const array = arrays[i]; if ( !Array.isArray(array) ) { throw new TypeError(`Array.intersect only accepts list array arguments!`); } const new_result = new Set(); for(const elm of result) { if ( array.indexOf(elm) >= 0 ) { new_result.add(elm); } } result = Array.from(new_result); } return result; } }) })(); (()=>{ if ( typeof Blob !== "undefined" ) { Object.defineProperty(Blob.prototype, 'arrayBuffer', { configurable, writable, enumerable, value:function() { return new Promise((resolve, reject)=>{ const reader = new FileReader(); reader.onerror = reject; reader.onload = ()=>resolve(reader.result); reader.readAsArrayBuffer(this); }); } }); } })(); (()=>{ Object.defineProperty(Date, 'from', { writable, configurable, enumerable, value: function(...args) { if ( args.length === 0 ) { throw new Error("Date.from expects at least one arguments!"); } try { return new Date(...args); } catch(e) { return null; } } }); Object.defineProperty(Date, 'present', { configurable, enumerable, get: ()=>new Date() }); Object.defineProperty(Date, 'unix', { writable, configurable, enumerable, value: function() { return Math.floor(Date.now()/1000); } }); Object.defineProperty(Date, 'zoneShift', { writable, configurable, enumerable, value: function() { const date = new Date(); return date.getTimezoneOffset() * 60000; } }); Object.defineProperty(Date.prototype, 'getUnixTime', { writable, configurable, enumerable, value: function() { return Math.floor(this.getTime()/1000); } }); Object.defineProperty(Date.prototype, 'toLocaleISOString', { writable, configurable, enumerable, value: function(show_milli=true){ let offset, zone = this.getTimezoneOffset(); if ( zone === 0 ) { offset = 'Z'; } else { const sign = zone > 0 ? '-' : '+'; zone = Math.abs(zone); const zone_hour = Math.floor(zone/60); const zone_min = zone%60; offset = sign + Padding(zone_hour) + Padding(zone_min); } const milli = show_milli ? ('.' + Padding(this.getMilliseconds() % 1000, 3)) : ''; return this.getFullYear() + '-' + Padding(this.getMonth()+1) + '-' + Padding(this.getDate()) + 'T' + Padding(this.getHours()) + ':' + Padding(this.getMinutes()) + ':' + Padding(this.getSeconds()) + milli + offset; } }); // getter Object.defineProperty(Date.prototype, 'unix', { configurable, enumerable, get: function() { return Math.floor(this.getTime()/1000); } }); Object.defineProperty(Date.prototype, 'time', { configurable, enumerable, get: function() { return this.getTime(); } }); Object.defineProperty(Date.prototype, 'zoneShift', { configurable, enumerable, get: function() { return this.getTimezoneOffset() * 60000; } }); })(); (()=>{ if ( typeof Document !== "undefined" ) { Object.defineProperties(Document.prototype, { parseHTML: { configurable, writable, enumerable, value: function(html) { const shadow = this.implementation.createHTMLDocument(); const shadowed_body = shadow.body; shadowed_body.innerHTML = html; if ( shadowed_body.children.length === 0 ) { return null; } if ( shadowed_body.children.length === 1 ) { const item = shadowed_body.children[0]; item.remove(); return item; } const elements = Array.prototype.slice.call(shadowed_body.children, 0); for(const element of elements) { element.remove(); } return elements; } } }); } })(); (()=>{ if ( typeof Element !== "undefined" ) { const _ELEMENT_SET_ATTRIBUTE = Element.prototype.setAttribute; const _ELEMENT_REMOVE_ATTRIBUTE = Element.prototype.removeAttribute; const _ELEMENT_SET_ATTRIBUTE_NS = Element.prototype.setAttributeNS; const _ELEMENT_REMOVE_ATTRIBUTE_NS = Element.prototype.removeAttributeNS; Object.defineProperties(Element.prototype, { addClass: { configurable, enumerable, writable, value: function(...classes) { const filtered = []; for( const class_name of classes ) { if ( class_name === undefined || class_name === null || class_name === '' ) { continue; } filtered.push(class_name); } this.classList.add(...filtered); return this; } }, removeClass: { configurable, enumerable, writable, value: function(...classes) { const filtered = []; for( const class_name of classes ) { if ( class_name === undefined || class_name === null || class_name === '' ) { continue; } filtered.push(class_name); } this.classList.remove(...filtered); return this; } }, setAttribute: { configurable, enumerable, writable, value: function(name, value) { if ( arguments.length < 2 ) { value = ''; } _ELEMENT_SET_ATTRIBUTE.call(this, name, value); return this; } }, removeAttribute: { configurable, enumerable, writable, value: function(...args) { _ELEMENT_REMOVE_ATTRIBUTE.apply(this, args); return this; } }, setAttributeNS: { configurable, enumerable, writable, value: function(...args) { _ELEMENT_SET_ATTRIBUTE_NS.apply(this, args); return this; } }, removeAttributeNS: { configurable, enumerable, writable, value: function(...args) { _ELEMENT_REMOVE_ATTRIBUTE_NS.apply(this, args); return this; } }, }); } })(); (()=>{ if ( typeof Error !== "undefined" ) { Object.defineProperty(Error.prototype, 'stack_trace', { get: function(){ if ( !this.stack ) return null; return this.stack.split(/\r\n|\n/g).map((item)=>item.trim()); }, enumerable, configurable }); } })(); (()=>{ if ( typeof EventTarget !== "undefined" ) { Object.defineProperty(EventTarget.prototype, 'on', { configurable, writable, enumerable, value: function(event_name, callback) { // Event name accepts name1#tag1,name2#tag1,name3#tag2 const inserted = []; const events = event_name.split(','); for( let evt_name of events ) { evt_name = evt_name.trim(); if ( inserted.indexOf(evt_name) >= 0 ) continue; inserted.push(evt_name); this.addEventListener(evt_name, callback); } return this; } }); Object.defineProperty(EventTarget.prototype, 'off', { configurable, writable, enumerable, value: function(event_name, callback) { const events = event_name.split(','); for( let evt_name of events ) { evt_name = evt_name.trim(); this.removeEventListener(evt_name, callback); } return this; } }); Object.defineProperty(EventTarget.prototype, 'emit', { configurable, writable, enumerable, value: function(event, inits={}) { const {bubbles, cancelable, composed, ...event_args} = inits; if ( typeof event === "string" ) { event = new Event(event, { bubbles:!!bubbles, cancelable:!!cancelable, composed:!!composed }); } if ( !(event instanceof Event) ) { throw new TypeError("Argument 1 accepts only string or Event instance!"); } Object.assign(event, event_args); this.dispatchEvent(event); } }); } })(); (()=>{ const REF = new WeakMap(); const boot_async={}, boot_sync={}; REF.set(boot_async, {async:true, funcs:[]}); REF.set(boot_sync, {async:false, funcs:[]}); Object.defineProperty(Function, 'sequential', { configurable, writable, enumerable, value: PackSequentialCall.bind(null, false) }); Object.defineProperty(Function.sequential, 'async', { configurable: false, writable: false, enumerable: true, value: PackSequentialCall.bind(null, true) }); function PackSequentialCall(is_async, func_list) { const args = Array.prototype.slice.call(arguments, 0); args[0] = is_async?boot_async:boot_sync; return PackSequential.call(...args); } function PackSequential(func_list) { const prev_state = REF.get(this); const state = {async:prev_state.async, funcs:prev_state.funcs.slice(0)}; if ( arguments.length > 0 ) { let func; if ( !Array.isArray(func_list) ) { func_list = [func_list]; } for( let i = 0; i < func_list.length; i++ ){ state.funcs.push((typeof (func=func_list[i]) === "function") ? func : ()=>func); } } const storage = {}; REF.set(storage, state); const trigger = DoSequentialCall.bind(storage); trigger.chain = PackSequential.bind(storage); Object.defineProperty(trigger, 'data', {configurable, enumerable:true, writable, value:storage}); return trigger; } function DoSequentialCall(...spread_args) { const {async:is_async, funcs:chain_items} = REF.get(this); this.current_call = {}; let result = undefined; if ( !is_async ) { for( const func of chain_items ){ result = func.call(this, ...spread_args, result); if( result === false ) break; } return result; } else { return Promise.resolve().then(async()=>{ for( const func of chain_items ){ result = await func.call(this, ...spread_args, result); if( result === false ) break; } return result; }); } } })(); (()=>{ if ( typeof HTMLElement !== "undefined" ) { Object.defineProperties(HTMLElement.prototype, { setData: { configurable, writable, enumerable, value: function(key, value) { if ( Object(key) === key ) { for(const _key in key) { this.dataset[_key] = key[_key]; } } else { this.dataset[key] = value; } return this; } }, getData: { configurable, writable, enumerable, value: function(key) { return this.dataset[key]; } }, removeData: { configurable, writable, enumerable, value: function(...data_names) { for( const name of data_names ) { delete this.dataset[name]; } return this; } }, setContentHtml: { configurable, writable, enumerable, value: function(html) { this.innerHTML = html; return this; } } }); } })(); (()=>{ if ( typeof HTMLInputElement !== "undefined" ) { Object.defineProperty( HTMLInputElement.prototype, 'setValue', { configurable, writable, enumerable, value: function(value) { this.value = value; return this; } }); } })(); (()=>{ if ( typeof Node !== "undefined" ) { Object.defineProperty( Node.prototype, 'prependChild', { configurable, writable, enumerable, value: function(child) { this.insertBefore(child, this.children[0]||null); return ( this instanceof DocumentFragment ) ? new DocumentFragment() : child; } }); Object.defineProperty( Node.prototype, 'insertNeighborBefore', { configurable, writable, enumerable, value: function(child) { if ( !this.parentNode ) { throw new RangeError( "Reference element is currently in detached mode! No way to add neighbors!" ); } this.parentNode.insertBefore(child, this); return ( this instanceof DocumentFragment ) ? new DocumentFragment() : child; } }); Object.defineProperty( Node.prototype, 'insertNeighborAfter', { configurable, writable, enumerable, value: function(child) { if ( !this.parentNode ) { throw new RangeError( "Reference element is currently in detached mode! No way to add neighbors!" ); } this.parentNode.insertBefore(child, this.nextSibling); return ( this instanceof DocumentFragment ) ? new DocumentFragment() : child; } }); Object.defineProperty( Node.prototype, 'setContentText', { configurable, writable, enumerable, value: function(text) { this.textContent = text; return this; } }); } })(); (()=>{ const _ObjectDefineProperty = Object.defineProperty; const _ObjectDefineProperties = Object.defineProperties; _ObjectDefineProperty(Object, 'defineProperty', { writable, configurable, enumerable, value: ObjectDefineProperty }); _ObjectDefineProperty(Object, 'defineProperties', { writable, configurable, enumerable, value: ObjectDefineProperties }); Object.defineProperty(Object, 'merge', { writable, configurable, enumerable, value: ObjectMerge }); Object.defineProperty(Object, 'typeOf', { writable, configurable, enumerable, value: TypeOf }); Object.defineProperty(Object.prototype, '_decorate', { writable, configurable, enumerable, value: function(processor, ...args) { if ( typeof processor === "function" ) { processor.call(this, ...args); } return this; } }); function ObjectDefineProperty(object, prop_name, prop_attr) { _ObjectDefineProperty(object, prop_name, prop_attr); return object; } function ObjectDefineProperties(object, prop_contents) { _ObjectDefineProperties(object, prop_contents); return object; } function ObjectMerge(target, ...sources) { if ( target === null || target === undefined ) { throw new TypeError("Cannot convert undefined or null to object"); } target = Object(target); for(const source of sources) { if ( Object(source) !== source ) continue; DeepMerge(target, source); } return target; } function DeepMerge(target, source) { for (const key in source) { let is_invalid = false; is_invalid = (source.hasOwnProperty && !source.hasOwnProperty(key)); is_invalid = is_invalid || (source[key] === undefined); if ( is_invalid ) continue; const tValue = target[key]; const sValue = source[key]; const tType = TypeOf(tValue); const sType = TypeOf(sValue); if ( tType !== "object" || sType !== "object" ) { if ( target instanceof Map ) { target.set(key, sValue); } else { target[key] = sValue; } continue; } DeepMerge(tValue, sValue); } } function TypeOf(input, resolveObj=false) { const type = typeof input; switch(type) { case "number": case "string": case "function": case "boolean": case "undefined": case "symbol": return type; } if ( input === null ) { return "null"; } if ( input instanceof String ) { return "string"; } if ( input instanceof Number ) { return "number"; } if ( input instanceof Boolean ) { return "boolean"; } if ( Array.isArray(input) ) { return "array"; } if ( !resolveObj ) { return "object"; } // None-primitive if ( input instanceof ArrayBuffer ) { return "array-buffer" } if ( input instanceof DataView ) { return "data-view"; } if ( input instanceof Uint8Array ) { return "uint8-array"; } if ( input instanceof Uint8ClampedArray ) { return "uint8-clamped-array"; } if ( input instanceof Int8Array ) { return "int8-array"; } if ( input instanceof Uint16Array ) { return "uint16-array"; } if ( input instanceof Int16Array ) { return "int16-array"; } if ( input instanceof Uint32Array ) { return "uint32-array"; } if ( input instanceof Int32Array ) { return "int32-array"; } if ( input instanceof Float32Array ) { return "float32-array"; } if ( input instanceof Float64Array ) { return "float64-array"; } if ( input instanceof Map ) { return "map"; } if ( input instanceof WeakMap ) { return "weak-map"; } if ( input instanceof Set ) { return "set"; } if ( input instanceof WeakSet ) { return "weak-set"; } if ( input instanceof RegExp ) { return "regexp" } if ( input instanceof Promise ) { return "promise"; } return "object"; } })(); (()=>{ const _PROMISE_THEN = Promise.prototype.then; const _PROMISE_CATCH = Promise.prototype.catch; const _PROMISE_FINALLY = Promise.prototype.finally; Object.defineProperties(Promise.prototype, { then: { writable, configurable, enumerable, value: function(...args) { return DecorateChainedPromise(_PROMISE_THEN.call(this, ...args), this); } }, catch: { writable, configurable, enumerable, value: function(...args) { return DecorateChainedPromise(_PROMISE_CATCH.call(this, ...args), this); } }, finally: { writable, configurable, enumerable, value: function(...args) { return DecorateChainedPromise(_PROMISE_FINALLY.call(this, ...args), this); } }, guard: { writable, configurable, enumerable, value: function() { return DecorateChainedPromise(_PROMISE_CATCH.call(this, (e)=>{ setTimeout(()=>{ if ( IsNodeJS ) { throw e; } else { const event = new Event('unhandledRejection'); event.error = e; window.dispatchEvent(event); } }, 0); return e; }), this); } } }); Object.defineProperties(Promise, { wait: { writable, configurable, enumerable, value: PromiseWaitAll }, create: { writable, configurable, enumerable, value: FlattenedPromise }, chain: { writable, configurable, enumerable, value: (func)=>{ const base_promise = Promise.resolve(); return ( typeof func !== "function" ) ? base_promise : base_promise.then(func); } } }); function PromiseWaitAll(promise_queue=[]) { if ( !Array.isArray(promise_queue) ){ promise_queue = [promise_queue]; } if( promise_queue.length === 0 ) { return Promise.resolve([]); } return new Promise((resolve, reject) =>{ let result_queue=[], ready_count=0, resolved = true; for(let idx=0; idx<promise_queue.length; idx++) { let item = {resolved:true, seq:idx, result:null}; result_queue.push(item); Promise.resolve(promise_queue[idx]).then( (result)=>{ resolved = (item.resolved = true) && resolved; item.result = result; }, (error)=>{ resolved = (item.resolved = false) && resolved; item.result = error; } ).then(()=>{ ready_count++; if ( promise_queue.length === ready_count ) { (resolved?resolve:reject)(result_queue); } }); } }); } function FlattenedPromise() { let _resolve=null, _reject=null; const promise = new Promise((resolve, reject)=>{ _resolve=resolve; _reject=reject; }); promise.resolve = _resolve; promise.reject = _reject; promise.promise = promise; return promise; } function DecorateChainedPromise(next_promise, previous) { for( const prop of Object.keys(previous)) { next_promise[prop] = previous[prop]; } return next_promise; } })(); (()=>{ const CAMEL_CASE_PATTERN = /(\w)(\w*)(\W*)/g; const CAMEL_REPLACER = (match, $1, $2, $3, index, input )=>{ return `${$1.toUpperCase()}${$2.toLowerCase()}${$3}`; }; function StringTemplateResolver(strings, ...dynamics) { if ( this instanceof StringTemplateResolver ) { this.strings = strings; this.fields = dynamics; return; } return new StringTemplateResolver(strings, ...dynamics); } StringTemplateResolver.prototype = { [Symbol.iterator]() { const strings = this.strings.slice(0).reverse(); const dynamics = this.fields.slice(0).reverse(); let i=0; return { next:()=>{ if ( strings.length === 0 ) { return {done:true}; } let value; if ( i%2===0 ) { value = strings.pop(); } else { value = dynamics.pop(); } i = i+1; return {value}; } }; }, toString() { let str = ''; for(const item of this) { str += '' + item; } return str; } }; Object.defineProperties(String.prototype, { charCount: { configurable, enumerable, get:function() { let i=0, count = 0; while(i<this.length) { const point = this.codePointAt(i); const length = ( point > 0xFFFF ) ? 2 : 1; count ++; i += length; } return count; } }, upperCase:{ configurable, enumerable, get:function() { return this.toUpperCase(); } }, localeUpperCase:{ configurable, enumerable, get:function() { return this.toLocaleUpperCase(); } }, lowerCase:{ configurable, enumerable, get:function() { return this.toLowerCase(); } }, localeLowerCase:{ configurable, enumerable, get:function() { return this.toLocaleLowerCase(); } }, toCamelCase: { configurable, enumerable, value:function() { return this.replace(CAMEL_CASE_PATTERN, CAMEL_REPLACER); } }, camelCase: { configurable, enumerable, get:function() { return this.replace(CAMEL_CASE_PATTERN, CAMEL_REPLACER); } }, pull: { configurable, enumerable, writable, value:function(token_separator='', from_begin=true) { if ( typeof token_separator !== "string" ) { throw new TypeError("Given token must be a string"); } const length = this.length; if ( length === 0 ) { return ['', '']; } if ( token_separator === '' ) { return from_begin ? [ this[0], this.substring(1) ] : [ this.substring(0, length-1), this[length-1] ]; } if ( from_begin ) { const index = this.indexOf(token_separator, token_separator.length); if ( index < 0 ) { return [this.substring(0), '']; } return [this.substring(0, index), this.substring(index)]; } else { const index = this.lastIndexOf(token_separator); if ( index < 0 ) { return ['', this.substring(0)]; } return [this.substring(0, index), this.substring(index)]; } } }, pop: { configurable, enumerable, writable, value:function(token_separator='') { return this.pull(token_separator, true); } }, shift: { configurable, enumerable, writable, value:function(token_separator='') { return this.pull(token_separator, false); } }, cutin: { configurable, enumerable, writable, value:function(start, deleteCount, ...items) { if ( start < 0 ) start = start + this.length; if ( deleteCount <= 0 ) deleteCount = 0; const head = this.substring(0, start); const tail = this.substring(start + deleteCount); return head + items.join('') + tail; } } }); Object.defineProperties(String, { encodeRegExpString: { writable, configurable, enumerable, value: function(input_string='') { return input_string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string } }, template: { writable, configurable, enumerable, value:StringTemplateResolver }, from: { writable, configurable, enumerable, value:(content)=>{ if ( typeof content === "string" ) return content; const bytes = ExtractBytes(content); if ( bytes !== null ) { return UTF8Decode(bytes); } return ''+content; } } }); })(); (()=>{ Object.defineProperty(setTimeout, 'create', { writable, configurable, enumerable, value:ThrottledTimeout }); Object.defineProperty(setTimeout, 'idle', { writable, configurable, enumerable, value:Idle }); Object.defineProperty(setInterval, 'create', { writable, configurable, enumerable, value:ThrottledTimer }); function ThrottledTimeout() { let _scheduled = null; let _executing = false; let _hTimeout = null; const timeout_cb = (cb, delay=0, ...args)=>{ _scheduled = {cb, delay, args}; if ( _executing ) return; if ( _hTimeout ) { clearTimeout(_hTimeout); _hTimeout = null; } __DO_TIMEOUT(); }; timeout_cb.clear=()=>{ _scheduled = null; if ( _hTimeout ) { clearTimeout(_hTimeout); _hTimeout = null; } }; return timeout_cb; function __DO_TIMEOUT() { if ( !_scheduled ) return; let {cb, delay, args} = _scheduled; _hTimeout = setTimeout(()=>{ _executing = true; Promise.resolve(cb(...args)) .then( ()=>{ _executing = false; _hTimeout = null; __DO_TIMEOUT(); }, (e)=>{ _executing = false; _hTimeout = null; _scheduled = null; throw e; } ); }, delay); _scheduled = null; } } function Idle(duration=0) { return new Promise((resolve)=>{setTimeout(resolve, duration)}); } function ThrottledTimer() { const _timeout = ThrottledTimeout(); const timeout_cb = (cb, interval=0, ...args)=>{ const ___DO_TIMEOUT=async()=>{ _timeout(___DO_TIMEOUT, interval); try { await cb(...args); } catch(e) { _timeout.clear(); throw e; } }; _timeout(___DO_TIMEOUT, interval, ...args); }; timeout_cb.clear=()=>{ _timeout.clear(); }; return timeout_cb; } })(); (()=>{ const TYPED_ARRAYS = [Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array]; const ARRAY_BUFFER_VIEWS = [DataView, ...TYPED_ARRAYS]; const REF = new WeakMap(); for(const type of ARRAY_BUFFER_VIEWS) { REF.set(type, { from: type.from, toString: type.toString }); Object.defineProperty(type, 'from', { value: function(input) { const original = REF.get(type).from; if (input instanceof ArrayBuffer) { return new type(input); } return original.call(type, input); }, configurable, enumerable, writable }); Object.defineProperty(type.prototype, 'toString', { value: function(...args) { const original = REF.get(type).toString; if ( args.length === 0 ) { return original.call(this, ...args); } return this.buffer.toString(...args); }, configurable, enumerable, writable }); } })(); })();