import {LogCategory} from "../../log"; import {settings, Settings} from "../../settings"; import * as log from "../../log"; import * as loader from "tc-loader"; import { tr } from "tc-shared/i18n/localize"; export enum ChatType { GENERAL, SERVER, CHANNEL, CLIENT } export function htmlEscape(message: string) : string[] { const div = document.createElement('div'); div.innerText = message; message = div.innerHTML; return message.replace(/ /g, ' ').split(/
/); } export function formatElement(object: any, escape_html: boolean = true) : JQuery[] { if($.isArray(object)) { let result = []; for(let element of object) result.push(...formatElement(element, escape_html)); return result; } else if(typeof(object) == "string") { if(object.length == 0) return []; return escape_html ? htmlEscape(object).map((entry, idx, array) => $.spawn("a").css("display", (idx == 0 || idx + 1 == array.length ? "inline" : "") + "block").html(entry == "" && idx != 0 ? " " : entry)) : [$.spawn("div").css("display", "inline-block").html(object)]; } else if(typeof(object) === "object") { if(object instanceof $) return [object as any]; return formatElement(""); } else if(typeof(object) === "function") return formatElement(object(), escape_html); else if(typeof(object) === "undefined") return formatElement(""); else if(typeof(object) === "number") return [$.spawn("a").text(object)]; return formatElement(""); } export function formatMessage(pattern: string, ...objects: any[]) : JQuery[] { let begin = 0, found = 0; let result: JQuery[] = []; do { found = pattern.indexOf('{', found); if(found == -1 || pattern.length <= found + 1) { result.push(...formatElement(pattern.substr(begin))); break; } if(found > 0 && pattern[found - 1] == '\\') { //TODO remove the escape! found++; continue; } result.push(...formatElement(pattern.substr(begin, found - begin))); //Append the text let offset = 0; if(pattern[found + 1] == ':') { offset++; /* the beginning : */ while (pattern[found + 1 + offset] != ':' && found + 1 + offset < pattern.length) offset++; const tag = pattern.substr(found + 2, offset - 1); offset++; /* the ending : */ if(pattern[found + offset + 1] != '}' && found + 1 + offset < pattern.length) { found++; continue; } result.push($.spawn(tag as any)); } else { let number; while ("0123456789".includes(pattern[found + 1 + offset])) offset++; number = parseInt(offset > 0 ? pattern.substr(found + 1, offset) : "0"); if(pattern[found + offset + 1] != '}') { found++; continue; } if(objects.length < number) log.warn(LogCategory.GENERAL, tr("Message to format contains invalid index (%o)"), number); result.push(...formatElement(objects[number])); } found = found + 1 + offset; begin = found + 1; } while(found++); return result; } export function formatMessageString(pattern: string, ...args: string[]) : string { return parseMessageWithArguments(pattern, args.length).map(e => typeof e === "string" ? e : args[e]).join(""); } export function parseMessageWithArguments(pattern: string, argumentCount: number) : (string | number)[] { let begin = 0, found = 0; let unspecifiedIndex = 0; let result: string[] = []; do { found = pattern.indexOf('{', found); if(found == -1 || pattern.length <= found + 1) { result.push(pattern.substr(begin)); break; } if(found > 0 && pattern[found - 1] == '\\') { //TODO remove the escape! found++; continue; } result.push(pattern.substring(begin, found)); //Append the text let offset = 0; let number; while ("0123456789".includes(pattern[found + 1 + offset])) offset++; if(offset > 0) { number = parseInt(pattern.substr(found + 1, offset)); } else { number = unspecifiedIndex++; } if(pattern[found + offset + 1] != '}') { found++; continue; } if(argumentCount < number) { log.warn(LogCategory.GENERAL, tr("Message to format contains invalid index (%o)"), number); result.push("{" + offset.toString() + "}"); } else { result.push(number); } found = found + 1 + offset; begin = found + 1; } while(found++); return result.reduce((prev, element) => { if(typeof element === "string" && typeof prev.last() === "string") prev.push(prev.pop() + element); else prev.push(element); return prev; }, []); } export namespace network { export const KB = 1024; export const MB = 1024 * KB; export const GB = 1024 * MB; export const TB = 1024 * GB; export function byteSizeToString(value: number) { let v: number, unit; if(value > 5 * TB) { unit = "tb"; v = value / TB; } else if(value > 5 * GB) { unit = "gb"; v = value / GB; } else if(value > 5 * MB) { unit = "mb"; v = value / MB; } else if(value > 5 * KB) { unit = "kb"; v = value / KB; } else { return value + "b"; } return v.toFixed(2) + unit; } export function format_bytes(value: number, options?: { time?: string, unit?: string, exact?: boolean }) : string { options = options || {}; if(typeof options.exact !== "boolean") options.exact = true; if(typeof options.unit !== "string") options.unit = "Bytes"; let points = value.toFixed(0).replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,'); let v, unit; if(value > 2 * TB) { unit = "TB"; v = value / TB; } else if(value > GB) { unit = "GB"; v = value / GB; } else if(value > MB) { unit = "MB"; v = value / MB; } else if(value > KB) { unit = "KB"; v = value / KB; } else { unit = ""; v = value; } let result = ""; if(options.exact || !unit) { result += points; if(options.unit) { result += " " + options.unit; if(options.time) result += "/" + options.time; } } if(unit) { result += (result ? " / " : "") + v.toFixed(2) + " " + unit; if(options.time) result += "/" + options.time; } return result; } } export const K = 1000; export const M = 1000 * K; export const G = 1000 * M; export const T = 1000 * G; export function format_number(value: number, options?: { time?: string, unit?: string }) { options = Object.assign(options || {}, {}); let points = value.toFixed(0).replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,'); let v, unit; if(value > 2 * T) { unit = "T"; v = value / T; } else if(value > G) { unit = "G"; v = value / G; } else if(value > M) { unit = "M"; v = value / M; } else if(value > K) { unit = "K"; v = value / K; } else { unit = ""; v = value; } if(unit && options.time) unit = unit + "/" + options.time; return points + " " + (options.unit || "") + (unit ? (" / " + v.toFixed(2) + " " + unit) : ""); } export const TIME_SECOND = 1000; export const TIME_MINUTE = 60 * TIME_SECOND; export const TIME_HOUR = 60 * TIME_MINUTE; export const TIME_DAY = 24 * TIME_HOUR; export const TIME_WEEK = 7 * TIME_DAY; export function format_time(time: number, default_value: string) { let result = ""; if(time > TIME_WEEK) { const amount = Math.floor(time / TIME_WEEK); result += " " + amount + " " + (amount > 1 ? tr("Weeks") : tr("Week")); time -= amount * TIME_WEEK; } if(time > TIME_DAY) { const amount = Math.floor(time / TIME_DAY); result += " " + amount + " " + (amount > 1 ? tr("Days") : tr("Day")); time -= amount * TIME_DAY; } if(time > TIME_HOUR) { const amount = Math.floor(time / TIME_HOUR); result += " " + amount + " " + (amount > 1 ? tr("Hours") : tr("Hour")); time -= amount * TIME_HOUR; } if(time > TIME_MINUTE) { const amount = Math.floor(time / TIME_MINUTE); result += " " + amount + " " + (amount > 1 ? tr("Minutes") : tr("Minute")); time -= amount * TIME_MINUTE; } if(time > TIME_SECOND) { const amount = Math.floor(time / TIME_SECOND); result += " " + amount + " " + (amount > 1 ? tr("Seconds") : tr("Second")); time -= amount * TIME_SECOND; } return result.length > 0 ? result.substring(1) : default_value; } let _icon_size_style: HTMLStyleElement; export function set_icon_size(size: string) { if(!_icon_size_style) { _icon_size_style = document.createElement("style"); document.head.append(_icon_size_style); } _icon_size_style.innerText = ("\n" + ".chat-emoji {\n" + " height: " + size + "!important;\n" + " width: " + size + "!important;\n" + "}\n" ); } loader.register_task(loader.Stage.JAVASCRIPT_INITIALIZING, { name: "icon size init", function: async () => { set_icon_size((settings.static_global(Settings.KEY_ICON_SIZE) / 100).toFixed(2) + "em"); }, priority: 10 });