/** * Return an endpoint URL that has a protocol, domain and path */ function normalizedEndpoint(endpoint) { let matches = endpoint.match(/^(https?:\/\/)?([^\/]+)(\/.*)?$/i); if (!matches) throw Error("Invalid endpoint URL"); let protocol = matches[1] || "https://"; let domain = matches[2]; let path = matches[3] || "/api/v4"; return `${protocol}${domain}${path}`; } /** * Return the endpoint as it should be shown to the user */ function humanReadableEndpoint(endpoint) { let matches = endpoint.match(/^(https?:\/\/.+)\/api\/v4$/i); if (!matches) throw Error("Invalid endpoint URL"); return matches[1]; } /** * Shorthand for document.getElementById */ function byId(id, nullOk=false) { const el = document.getElementById(id); if (!el && !nullOk) { console.error(`No element #${id}`); } return el; } /** * Wrap a function so that it receives `this` as first argument */ function thisToArg(f) { return function(...rest) { return f(this, ...rest); } } /** * Extend an object in-place with own properties of a second one */ function extend(obj1, obj2) { for (let key in Object.getOwnPropertyNames(obj1)) { obj1[key] = obj2[key]; } } function padLeft(input, width, padding=" ") { text = input + ""; while (text.length < width) { text = padding + text; } return text; } function formatDdddMmYy(date) { return `${date.getFullYear()}-${padLeft(date.getMonth() + 1, 2, "0")}-${padLeft(date.getDate(), 2, "0")}`; } function formatHhMm(date) { return `${padLeft(date.getHours(), 2, "0")}:${padLeft(date.getMinutes(), 2, "0")}`; } const DATE_SIMILARITY = { none: 0, year: 1, month: 2, date: 3, hours: 4, minutes: 5, seconds: 6 } function dateSimilarity(d1, d2) { if (!d1 || !d2) return DATE_SIMILARITY.none; if (d1.getFullYear() != d2.getFullYear()) return DATE_SIMILARITY.none; if (d1.getMonth() != d2.getMonth()) return DATE_SIMILARITY.year; if (d1.getDate() != d2.getDate()) return DATE_SIMILARITY.month; if (d1.getHours() != d2.getHours()) return DATE_SIMILARITY.date; if (d1.getMinutes() != d2.getMinutes()) return DATE_SIMILARITY.hours; if (d1.getSeconds() != d2.getSeconds()) return DATE_SIMILARITY.minutes; return DATE_SIMILARITY.seconds; } class AssertionError extends Error {} /** * Throw an AssertionError if the first argument is not true */ function assert(condition, message) { if (!condition) { if (message) { throw new AssertionError(`Assertion failed: ${message}`); } else { throw new AssertionError("Assertion failed"); } } } const MATTERMOST_ID_REGEXP = /^[a-z0-9]{26}$/; function assertIsMattermostId(string, name="") { assert(MATTERMOST_ID_REGEXP.test(string), `${name} has the form of a Mattermost ID`); } function assertIsNullOrMattermostId(string, name="") { assert(string === null || MATTERMOST_ID_REGEXP.test(string), `${name} is null or has the form of a Mattermost ID`); }