{"version":3,"file":"index.global.js","sources":["../../base/src/blockui.ts","../../base/src/config.ts","../../base/src/criteria.ts","../../base/src/debounce.ts","../../base/src/environment.ts","../../base/src/eventhandler.ts","../../base/src/html.ts","../../base/src/fluent.ts","../../base/src/icons.ts","../../base/src/symbols.ts","../../base/src/system-internal.ts","../../base/src/system.ts","../../base/src/localtext.ts","../../base/src/dialogs.ts","../../base/src/toastr2.ts","../../base/src/notify.ts","../../base/src/errorhandling.ts","../../base/src/formatting.ts","../../base/src/lookup.ts","../../base/src/propertyitem.ts","../../base/src/services.ts","../../base/src/scriptdata.ts","../../base/src/servicetypes.ts","../../base/src/tooltip.ts","../../base/src/uploader.ts","../../base/src/validator.ts","../corelib/q/arrays-compat.ts","../corelib/q/scriptdata-compat.ts","../corelib/q/authorization.ts","../corelib/q/dialogs-compat.ts","../corelib/q/formatting-compat.ts","../corelib/q/html-compat.ts","../corelib/q/layouttimer.ts","../corelib/q/router.ts","../corelib/q/system-compat.ts","../corelib/q/layout.ts","../corelib/q/localtext-compat.ts","../corelib/q/services-compat.ts","../corelib/q/strings-compat.ts","../corelib/q/validation.ts","../corelib/slick/aggregators.ts","../corelib/slick/remoteview.ts","../../../node_modules/.pnpm/@rollup+plugin-typescript@11.1.5_rollup@4.9.0_tslib@2.6.2_typescript@5.3.3/node_modules/tslib/tslib.es6.js","../corelib/types/attributes.ts","../corelib/types/decorators.ts","../corelib/interfaces/ibooleanvalue.ts","../corelib/interfaces/idoublevalue.ts","../corelib/interfaces/idialog.ts","../corelib/interfaces/ieditdialog.ts","../corelib/interfaces/igeteditvalue.ts","../corelib/interfaces/ireadonly.ts","../corelib/interfaces/iseteditvalue.ts","../corelib/interfaces/istringvalue.ts","../corelib/interfaces/ivalidaterequired.ts","../corelib/types/captureoperationtype.ts","../corelib/types/commontyperegistry.ts","../corelib/types/dialogtyperegistry.ts","../corelib/ui/widgets/widgetutils.ts","../corelib/patch/jquerypatch.ts","../corelib/patch/reactpatch.ts","../corelib/ui/editors/select2.ts","../corelib/ui/editors/combobox.ts","../corelib/ui/editors/editorutils.ts","../corelib/ui/widgets/widgetinternal.ts","../corelib/ui/widgets/widget.ts","../corelib/types/editortyperegistry.ts","../corelib/types/enumtyperegistry.ts","../corelib/types/reflectionutils.ts","../corelib/ui/helpers/lazyloadhelper.ts","../corelib/ui/widgets/prefixedcontext.ts","../corelib/ui/widgets/toolbar.ts","../corelib/ui/widgets/templatedwidget.ts","../corelib/ui/helpers/tabsextensions.ts","../corelib/ui/dialogs/dialogextensions.ts","../corelib/ui/dialogs/templateddialog.ts","../corelib/ui/widgets/templatedpanel.ts","../corelib/ui/editors/cascadedwidgetlink.ts","../corelib/ui/widgets/reflectionoptionssetter.ts","../corelib/ui/widgets/propertygrid.ts","../corelib/ui/widgets/propertypanel.ts","../corelib/ui/helpers/subdialoghelper.ts","../corelib/ui/dialogs/propertydialog.ts","../corelib/ui/editors/stringeditor.ts","../corelib/ui/editors/passwordeditor.ts","../corelib/ui/editors/textareaeditor.ts","../corelib/ui/editors/booleaneditor.ts","../corelib/ui/editors/autonumeric.ts","../corelib/ui/editors/decimaleditor.ts","../corelib/ui/editors/integereditor.ts","../corelib/ui/helpers/dateediting.ts","../corelib/ui/editors/dateeditor.ts","../corelib/ui/editors/datetimeeditor.ts","../corelib/ui/editors/timeeditor.ts","../corelib/ui/editors/emaileditor.ts","../corelib/ui/editors/emailaddresseditor.ts","../corelib/ui/editors/urleditor.ts","../corelib/ui/editors/radiobuttoneditor.ts","../corelib/ui/editors/comboboxeditor.ts","../corelib/ui/editors/selecteditor.ts","../corelib/ui/editors/dateyeareditor.ts","../corelib/ui/editors/enumeditor.ts","../corelib/ui/editors/lookupeditor.ts","../corelib/ui/editors/servicelookupeditor.ts","../corelib/ui/editors/htmlcontenteditor.ts","../corelib/ui/editors/maskededitor.ts","../corelib/ui/editors/recaptcha.ts","../corelib/ui/helpers/uploadhelper.ts","../corelib/ui/editors/uploadeditors.ts","../corelib/ui/filtering/filterstore.ts","../corelib/ui/datagrid/quickfilterbar.ts","../corelib/ui/datagrid/quicksearchinput.ts","../corelib/ui/filtering/filteroperator.ts","../corelib/ui/filtering/filtering.ts","../corelib/ui/filtering/filterwidgetbase.ts","../corelib/ui/filtering/filterpanel.ts","../corelib/ui/filtering/filterdialog.ts","../corelib/ui/filtering/filterdisplaybar.ts","../corelib/ui/datagrid/slickpager.ts","../corelib/types/formattertyperegistry.ts","../corelib/ui/formatters/formatters.ts","../corelib/ui/helpers/slickhelpers.ts","../corelib/ui/datagrid/datagrid.ts","../corelib/ui/datagrid/columnpickerdialog.ts","../corelib/ui/datagrid/treegridmixin.ts","../corelib/ui/editors/checktreeeditor.ts","../corelib/ui/datagrid/entitygrid.ts","../corelib/ui/dialogs/entitydialog.ts"],"sourcesContent":["let blockUICount: number = 0;\n\n/**\n * Tries to block the page\n */\nexport function blockUI(options?: { zIndex?: number, useTimeout?: boolean }) {\n\n function block() {\n if (blockUICount++ > 0 ||\n typeof document === \"undefined\")\n return;\n \n var div = document.createElement(\"div\");\n div.className = \"blockUI blockOverlay\";\n div.setAttribute(\"style\", `z-index: ${options?.zIndex ?? 2000}; border: none; margin: 0px; padding: 0px; width: 100%; height: 100%; top: 0px; left: 0px; opacity: 0; cursor: wait; position: fixed;`);\n document.body.appendChild(div);\n }\n \n (options?.useTimeout && (window.setTimeout(block, 0))) || block();\n}\n\n/**\n * Unblocks the page. \n */\nexport function blockUndo() {\n if (blockUICount < 1)\n return;\n if (--blockUICount === 0 && typeof document !== \"undefined\")\n document.body.querySelector(':scope > .blockUI.blockOverlay')?.remove();\n}","var Config = {\n /**\n * This is the root path of your application. If your application resides under http://localhost/mysite/,\n * your root path is \"/mysite/\". This variable is automatically initialized by reading from a element\n * with ID \"ApplicationPath\" from current page, which is usually located in your _LayoutHead.cshtml file\n */\n applicationPath: '/',\n\n /**\n * Email validation by default only allows ASCII characters. Set this to true if you want to allow unicode.\n */\n emailAllowOnlyAscii: true,\n\n /**\n * This is the list of root namespaces that may be searched for types. For example, if you specify an editor type\n * of \"MyEditor\", first a class with name \"MyEditor\" will be searched, if not found, search will be followed by\n * \"Serenity.MyEditor\" and \"MyApp.MyEditor\" if you added \"MyApp\" to the list of root namespaces.\n *\n * You should usually add your application root namespace to this list in ScriptInit(ialization).ts file.\n */\n rootNamespaces: ['Serenity'],\n\n /**\n * This is an optional method for handling when user is not logged in. If a users session is expired \n * and when a NotAuthorized response is received from a service call, Serenity will call this handler, so\n * you may intercept it and notify user about this situation and ask if she wants to login again...\n */\n notLoggedInHandler: null\n}\n\nif (typeof document !== 'undefined') {\n var pathLink = document.querySelector('link#ApplicationPath') as HTMLLinkElement;\n if (pathLink != null) {\n Config.applicationPath = pathLink.getAttribute('href');\n }\n}\n\nexport { Config };\n\n","/**\n * CriteriaBuilder is a class that allows to build unary or binary criteria with completion support.\n */\nexport class CriteriaBuilder extends Array {\n /**\n * Creates a between criteria.\n * @param fromInclusive from value\n * @param toInclusive to value\n */\n bw(fromInclusive: any, toInclusive: any): Array {\n return [[this, '>=', fromInclusive], 'and', [this, '<=', toInclusive]];\n }\n\n /**\n * Creates a contains criteria\n * @param value contains value\n */\n contains(value: string): Array {\n return [this, 'like', '%' + value + '%'];\n }\n\n /**\n * Creates a endsWith criteria\n * @param value endsWith value\n */\n endsWith(value: string): Array {\n return [this, 'like', '%' + value];\n }\n\n /**\n * Creates an equal (=) criteria\n * @param value equal value\n */\n eq(value: any): Array {\n return [this, '=', value];\n }\n\n /**\n * Creates a greater than criteria\n * @param value greater than value\n */\n gt(value: any): Array {\n return [this, '>', value];\n }\n\n /**\n * Creates a greater than or equal criteria\n * @param value greater than or equal value\n */\n ge(value: any): Array {\n return [this, '>=', value];\n }\n\n /**\n * Creates a in criteria\n * @param values in values\n */\n in(values: any[]): Array {\n return [this, 'in', [values]];\n }\n\n /**\n * Creates a IS NULL criteria\n */\n isNull(): Array {\n return ['is null', this];\n }\n\n /**\n * Creates a IS NOT NULL criteria\n */\n isNotNull(): Array {\n return ['is not null', this];\n }\n\n /**\n * Creates a less than or equal to criteria\n * @param value less than or equal to value\n */\n le(value: any): Array {\n return [this, '<=', value];\n }\n\n /**\n * Creates a less than criteria\n * @param value less than value\n */\n lt(value: any): Array {\n return [this, '<', value];\n }\n\n /**\n * Creates a not equal criteria\n * @param value not equal value\n */\n ne(value: any): Array {\n return [this, '!=', value];\n }\n\n /**\n * Creates a LIKE criteria\n * @param value like value\n */\n like(value: any): Array {\n return [this, 'like', value];\n }\n\n /**\n * Creates a STARTS WITH criteria\n * @param value startsWith value\n */\n startsWith(value: string): Array {\n return [this, 'like', value + '%'];\n }\n\n /**\n * Creates a NOT IN criteria\n * @param values array of NOT IN values\n */\n notIn(values: any[]): Array {\n return [this, 'not in', [values]];\n }\n\n /**\n * Creates a NOT LIKE criteria\n * @param value not like value\n */\n notLike(value: any): Array {\n return [this, 'not like', value];\n }\n}\n\nconst TOKEN_IDENTIFIER = 1;\nconst TOKEN_OPERATOR = 2;\nconst TOKEN_VALUE = 3;\nconst TOKEN_PARAM = 4;\n\ninterface Token {\n t: number;\n v: any;\n}\n\ninterface ParseError {\n error: string;\n pos: number;\n}\n\nconst ParseError: any = function (expression: string, error: string, position: number) {\n this.expression = expression;\n this.error = error;\n this.position = position;\n this.toString = function () {\n return 'Error parsing expression: \"' + expression + '\", \"' +\n error + ', position: ' + position;\n };\n}\n\nfunction tokenize(expression: string): Token[] {\n var end: number, v: any;\n var tokens: Token[] = [];\n var l = expression.length;\n var l1 = expression.length - 1;\n var openParens = 0;\n var index: number;\n var ch: string;\n\n function skipWhiteSpace() {\n while (index < l) {\n ch = expression.charAt(index);\n\n if (ch === ' ' || ch === '\\t') {\n index++;\n continue;\n }\n\n break;\n }\n }\n\n function readString() {\n end = index;\n var foundDoubles = false;\n while (end++ < l1) {\n ch = expression.charAt(end);\n if (ch === \"'\") {\n if (end < l1 && expression.charAt(end + 1) === \"'\") {\n end++;\n foundDoubles = true;\n continue;\n }\n else\n break;\n }\n }\n\n if (end === index ||\n expression.charAt(end) !== \"'\")\n throw new ParseError(expression, 'unterminated string', index);\n\n v = expression.substr(index + 1, end - index - 1);\n if (foundDoubles)\n v = v.replace(/''/g, \"'\");\n }\n\n function readNumber() {\n end = index;\n var foundDot = false;\n while (end < l1) {\n ch = expression.charAt(end + 1);\n if ((ch >= '0' && ch <= '9') ||\n (!foundDot && (ch === '.'))) {\n if (ch === '.')\n foundDot = true;\n end++;\n }\n else\n break;\n }\n\n v = parseFloat(expression.substring(index, end + 1));\n }\n\n function readIdentifier() {\n end = index;\n while (end < l1) {\n ch = expression.charAt(end + 1);\n if (ch == '_' ||\n (ch >= 'A' && ch <= 'Z') ||\n (ch >= 'a' && ch <= 'z') ||\n (ch >= '0' && ch <= '9')) {\n end++;\n }\n else\n break;\n }\n\n v = expression.substr(index, end - index + 1);\n }\n\n function readParam() {\n index++;\n readIdentifier();\n if (!v.length)\n throw new ParseError(expression, 'expected parameter name', index);\n }\n\n function readArrayList() {\n skipWhiteSpace();\n\n if (index >= l || expression.charAt(index) != '(') {\n if (index < l && expression.charAt(index) == '@') {\n readParam();\n index = end;\n return;\n }\n throw new ParseError(expression, 'expected parenthesis', index);\n }\n\n index++;\n\n let values = [];\n\n while (true) {\n skipWhiteSpace();\n\n if (index >= l)\n throw new ParseError(expression, 'expected parenthesis', index);\n\n ch = expression.charAt(index);\n\n if (ch == ',') {\n if (values.length == 0)\n throw new ParseError(expression, 'unexpected comma', index);\n index++;\n skipWhiteSpace();\n ch = expression.charAt(index);\n }\n else if (ch == ')') {\n break;\n }\n else if (values.length > 0)\n throw new ParseError(expression, 'expected comma', index);\n\n\n if (ch === \"'\") {\n readString();\n\n values.push(v);\n index = end + 1;\n continue;\n }\n\n if (ch >= '0' && ch <= '9') {\n readNumber();\n\n values.push(v);\n index = end + 1;\n continue;\n }\n\n if (ch == 'n') {\n readIdentifier();\n\n if (v === 'null') {\n values.push(null)\n index = end + 1;\n continue;\n }\n }\n\n throw new ParseError(expression, 'unexpected token', index);\n }\n\n v = values;\n }\n\n for (index = 0; index < l; index++) {\n ch = expression.charAt(index);\n if (ch === ' ' || ch === '\\t')\n continue;\n\n if (ch == '_' ||\n (ch >= 'A' && ch <= 'Z') ||\n (ch >= 'a' && ch <= 'z')) {\n readIdentifier();\n var w = v.toLowerCase();\n if (w == 'is') {\n index = end + 1;\n skipWhiteSpace();\n\n readIdentifier();\n w = v.toLowerCase();\n if (w === 'not') {\n index = end + 1;\n skipWhiteSpace();\n readIdentifier();\n if (v.toLowerCase() === 'null') {\n tokens.push({\n t: TOKEN_OPERATOR,\n v: 'is not null'\n });\n }\n else\n throw new ParseError(expression, 'expected \"null\"', index);\n }\n else if (w === 'null') {\n tokens.push({\n t: TOKEN_OPERATOR,\n v: 'is null'\n });\n }\n else\n throw new ParseError(expression, 'expected \"null\" or \"not\" keyword', index);\n }\n else if (w === 'and' || w === 'or' || w === 'xor') {\n tokens.push({\n t: TOKEN_OPERATOR,\n v: w\n });\n }\n else if (w === 'not') {\n const currentEnd = end;\n\n index = end + 1;\n skipWhiteSpace();\n\n readIdentifier();\n w = v.toLowerCase();\n\n if (w === 'in') {\n index = end + 1;\n\n tokens.push({\n t: TOKEN_OPERATOR,\n v: 'not in'\n });\n\n readArrayList();\n\n if (typeof v === \"string\") {\n tokens.push({\n t: TOKEN_PARAM,\n v: v\n })\n }\n else {\n tokens.push({\n t: TOKEN_VALUE,\n v: v\n });\n }\n }\n else if (w === \"like\") {\n tokens.push({\n t: TOKEN_OPERATOR,\n v: 'not like'\n });\n\n index = end;\n } else {\n tokens.push({\n t: TOKEN_OPERATOR,\n v: 'not'\n });\n\n index = currentEnd;\n }\n\n continue;\n }\n else if (w === 'in') {\n tokens.push({\n t: TOKEN_OPERATOR,\n v: 'in'\n });\n\n index = end + 1;\n\n readArrayList();\n\n if (typeof v === \"string\") {\n tokens.push({\n t: TOKEN_PARAM,\n v: v\n })\n }\n else {\n tokens.push({\n t: TOKEN_VALUE,\n v: v\n });\n }\n\n continue;\n }\n else if (w === \"like\") {\n tokens.push({\n t: TOKEN_OPERATOR,\n v: 'like'\n });\n }\n else {\n tokens.push({\n t: TOKEN_IDENTIFIER,\n v: v\n });\n }\n\n index = end;\n continue;\n }\n\n if (ch === '@') {\n readParam();\n tokens.push({\n t: TOKEN_PARAM,\n v: v\n });\n index = end;\n continue;\n }\n\n if ((((ch === '-') || (ch === '+')) &&\n index < l1 &&\n expression.charAt(index + 1) >= '0' &&\n expression.charAt(index + 1) <= '9') ||\n (ch >= '0' && ch <= '9')) {\n end = index;\n readNumber();\n\n tokens.push({\n t: TOKEN_VALUE,\n v: v\n });\n\n index = end;\n continue;\n }\n\n if (ch === \"'\") {\n end = index;\n readString();\n\n tokens.push({\n t: TOKEN_VALUE,\n v: v\n });\n index = end;\n continue;\n }\n\n if (ch === '=') {\n tokens.push({\n t: TOKEN_OPERATOR,\n v: ch\n });\n continue;\n }\n\n if (ch === '(') {\n openParens++;\n tokens.push({\n t: TOKEN_OPERATOR,\n v: ch\n });\n continue;\n }\n\n if (ch == ')') {\n if (openParens <= 0)\n throw new ParseError(expression, 'unexpected parenthesis', index);\n\n openParens--;\n tokens.push({\n t: TOKEN_OPERATOR,\n v: ch\n });\n continue;\n }\n\n if (ch === '>' || ch === '<') {\n if (index < l1 &&\n expression.charAt(index + 1) === '=') {\n tokens.push({\n t: TOKEN_OPERATOR,\n v: ch + '='\n });\n index++;\n }\n else {\n tokens.push({\n t: TOKEN_OPERATOR,\n v: ch\n });\n }\n continue;\n }\n\n throw new ParseError(expression, 'unknown token', index);\n }\n\n if (openParens > 0)\n throw new ParseError(expression, 'missing parenthesis', index);\n\n return tokens;\n}\n\nconst operatorPrecedence: Record = {\n '=': 4,\n '>': 4,\n '<': 4,\n '>=': 4,\n '<=': 4,\n '<>': 4,\n '!=': 4,\n 'like': 5,\n 'not like': 5,\n 'in': 5,\n 'not in': 5,\n 'is null': 5,\n 'is not null': 5,\n 'not': 6,\n 'and': 7,\n 'xor': 8,\n 'or': 9\n}\n\nfunction shuntingYard(tokens: Token[]): Token[] {\n var result: Token[] = [];\n var stack: Token[] = [];\n for (var token of tokens) {\n if (token.t === TOKEN_OPERATOR) {\n var precedence = operatorPrecedence[token.v];\n\n if (precedence != null) {\n while (stack.length) {\n var prev = stack[stack.length - 1];\n if (prev.t !== TOKEN_OPERATOR || prev.v == '(')\n break;\n var prevPrecedence = operatorPrecedence[prev.v];\n if (prevPrecedence == null || prevPrecedence > precedence)\n break;\n\n result.push(stack.pop());\n }\n\n stack.push(token);\n }\n else if (token.v === '(') {\n stack.push(token);\n }\n else if (token.v === ')') {\n while (stack.length &&\n (stack[stack.length - 1].t !== TOKEN_OPERATOR ||\n stack[stack.length - 1].v !== '(')) {\n result.push(stack.pop());\n }\n\n stack.pop();\n }\n else\n result.push(token);\n }\n else\n result.push(token);\n }\n\n while (stack.length) {\n var tok = stack.pop();\n\n if (tok.t == TOKEN_OPERATOR &&\n (tok.v === '(' || tok.v === ')'))\n throw \"Mismatched parentheses in criteria expression!\";\n\n result.push(tok);\n }\n\n return result;\n}\n\nfunction rpnTokensToCriteria(rpnTokens: Token[], getParam?: (name: string) => any): any[] {\n var stack: any[] = [];\n\n for (var token of rpnTokens) {\n switch (token.t) {\n case TOKEN_IDENTIFIER:\n {\n stack.push([token.v]);\n break;\n }\n\n case TOKEN_VALUE:\n {\n stack.push(Array.isArray(token.v) ? [token.v] : token.v);\n break;\n }\n\n case TOKEN_PARAM:\n {\n if (!getParam)\n throw new Error(\"getParam must be passed for parameterized expressions!\");\n var prm = getParam(token.v)\n stack.push(Array.isArray(prm) ? [prm] : prm);\n break;\n }\n\n case TOKEN_OPERATOR:\n {\n switch (token.v as string) {\n case 'not':\n case 'is null':\n case 'is not null':\n if (!stack.length)\n throw new Error(\"Unary operator \" + token.v + \" requires a value!\");\n\n stack.push([token.v, stack.pop()]);\n break;\n default:\n if (stack.length < 2)\n throw new Error(\"Binary operator \" + token.v + \" requires two values!\");\n\n var r = stack.pop();\n var l = stack.pop();\n stack.push([l, token.v, r]);\n break;\n }\n break;\n }\n default:\n throw new Error(\"Invalid operator type: \" + token.t + \"!\");\n }\n }\n\n if (stack.length != 1)\n throw new Error(\"Error evaluating expression!\");\n\n return stack.pop();\n}\n\nfunction internalParse(expression: string, getParam?: (name: string) => any) {\n var tokens = tokenize(expression);\n var rpnTokens = shuntingYard(tokens);\n return rpnTokensToCriteria(rpnTokens, getParam);\n}\n\n/** \n * Parses a criteria expression to Serenity Criteria array format.\n * The string may optionally contain parameters like `A >= @p1 and B < @p2`.\n * @param expression The criteria expression.\n * @param params The dictionary containing parameter values like { p1: 10, p2: 20 }.\n * @example\n * parseCriteria('A >= @p1 and B < @p2', { p1: 5, p2: 4 }) // [[[a], '>=' 5], 'and', [[b], '<', 4]]\n */\nexport function parseCriteria(expression: string, params?: any): any[];\n/** \n * Parses a criteria expression to Serenity Criteria array format.\n * The expression may contain parameter placeholders like `A >= ${p1}`\n * where p1 is a variable in the scope.\n * @param strings The string fragments.\n * @param values The tagged template arguments.\n * @example \n * var a = 5, b = 4;\n * parseCriteria`A >= ${a} and B < ${b}` // [[[a], '>=' 5], 'and', [[b], '<', 4]]\n */\nexport function parseCriteria(strings: TemplateStringsArray, ...values: any[]): any[];\nexport function parseCriteria(exprOrStrings: TemplateStringsArray | string, ...values: any[]): any[] {\n if (!exprOrStrings?.length)\n return [];\n\n if (typeof exprOrStrings === \"string\") {\n return internalParse(exprOrStrings,\n values == null || values[0] == null ? null : name => values[0][name]);\n }\n else if (!values.length)\n return internalParse(exprOrStrings.join(''));\n\n var expression = String.raw({ raw: exprOrStrings }, ...values.map((x, i) => '@__' + i));\n return internalParse(expression, name => name.startsWith('__') ?\n values[parseInt(name.substring(2), 10)] : void 0);\n}\n\n/**\n * Enumeration of Criteria operator keys.\n */\nexport enum CriteriaOperator {\n paren = \"()\",\n not = \"not\",\n isNull = \"is null\",\n isNotNull = \"is not null\",\n exists = \"exists\",\n and = \"and\",\n or = \"or\",\n xor = \"xor\",\n eq = \"=\",\n ne = \"!=\",\n gt = \">\",\n ge = \">=\",\n lt = \"<\",\n le = \"<=\",\n in = \"in\",\n notIn = \"not in\",\n like = \"like\",\n notLike = \"not like\"\n}\n\n/**\n * Creates a new criteria builder containg the passed field name.\n * @param field The field name.\n */\nexport function Criteria(field: string) {\n var builder = CriteriaBuilder.of(field);\n // workaround for subclassing array until corelib switched to ES6\n !(builder as any).eq && ((builder as any).__proto__ = CriteriaBuilder.prototype);\n return builder as CriteriaBuilder\n}\n\n/**\n * Ands two or more criteria together.\n * @param c1 First criteria.\n * @param c2 Second criteria.\n * @param rest Other criteria.\n */\nCriteria.and = function and(c1: any[], c2: any[], ...rest: any[][]) {\n var result = Criteria.join(c1, 'and', c2);\n if (rest) {\n for (let k of rest)\n result = Criteria.join(result, 'and', k);\n }\n\n return result;\n};\n\n/** Provides access to the `CriteriaOperator` enum, e.g list of operator keys */\nCriteria.Operator = CriteriaOperator;\n\n/** \n * Determines if a criteria is empty.\n */\nCriteria.isEmpty = function isEmpty(c: any[]): boolean {\n return c == null ||\n c.length === 0 ||\n (c.length === 1 && typeof c[0] === \"string\" && c[0].length === 0);\n};\n\n/**\n * Joins two criteria together.\n * @param c1 First criteria.\n * @param op Operator to insert between, e.g. 'or', 'and'.\n * @param c2 Second criteria\n */\nCriteria.join = function join(c1: any[], op: string, c2: any[]): any[] {\n if (Criteria.isEmpty(c1))\n return c2;\n\n if (Criteria.isEmpty(c2))\n return c1;\n\n return [c1, op, c2];\n};\n\n/**\n * Negates a criteria.\n * @param c Criteria to negate.\n */\nCriteria.not = function not(c: any[]) {\n return ['not', c]\n}\n\n/**\n * Ors two or more criteria together.\n * @param c1 First criteria.\n * @param c2 Second criteria.\n * @param rest Other criteria.\n */\nCriteria.or = function or(c1: any[], c2: any[], ...rest: any[][]) {\n var result = Criteria.join(c1, 'or', c2);\n\n if (rest) {\n for (let k of rest)\n result = Criteria.join(result, 'or', k);\n }\n\n return result;\n}\n\n/**\n * Puts a criteria in parens. Exists only for compatibility reasons.\n */\nCriteria.paren = function parent(c: any[]): any[] {\n return Criteria.isEmpty(c) ? c : ['()', c];\n}\n\n/** \n * Parses a criteria expression to Serenity Criteria array format.\n * The expression string may be a string literal, optionally containining \n * parameters like `A >= @p1 and B < @p2`.\n * \n * Or, the expression might be a tagged string literal that \n * contain parameter placeholders like `A >= ${p1}`\n * where p1 is a variable in the scope.\n *\n * @example\n * Criteria.parse(\"A >= @p1 and B < @p2\", { p1: 5, p2: 4 }) // [[[a], '>=' 5], 'and', [[b], '<', 4]]\n * \n * @example\n * var a = 5; b = 4;\n * Criteria.parse`A >= ${a} and B < ${b}` // [[[a], '>=' 5], 'and', [[b], '<', 4]]\n*/\nCriteria.parse = parseCriteria;","export interface DebouncedFunction any> {\n /**\n * Call the original function, but applying the debounce rules.\n *\n * If the debounced function can be run immediately, this calls it and returns its return\n * value.\n *\n * Otherwise, it returns the return value of the last invocation, or undefined if the debounced\n * function was not invoked yet.\n */\n (...args: Parameters): ReturnType | undefined;\n\n /**\n * Throw away any pending invocation of the debounced function.\n */\n clear(): void;\n\n /**\n * If there is a pending invocation of the debounced function, invoke it immediately and return\n * its return value.\n *\n * Otherwise, return the value from the last invocation, or undefined if the debounced function\n * was never invoked.\n */\n flush(): ReturnType | undefined;\n}\n\n/**\n * Returns a function, that, as long as it continues to be invoked, will not\n * be triggered. The function also has a property 'clear' that can be used \n * to clear the timer to prevent previously scheduled executions, and flush method\n * to invoke scheduled executions now if any.\n * @param wait The function will be called after it stops being called for\n * N milliseconds. \n * @param immediate If passed, trigger the function on the leading edge, instead of the trailing. \n *\n * @source underscore.js\n */\nexport function debounce any>(func: T, wait?: number, immediate?: boolean): DebouncedFunction {\n var timeout: any, args: any, context: any, timestamp: number, result: any;\n if (null == wait) wait = 100;\n\n var later = function () {\n var last = Date.now() - timestamp;\n\n if (last < wait && last >= 0) {\n timeout = setTimeout(later, wait - last);\n } else {\n timeout = null;\n if (!immediate)\n result = func.apply(context, args);\n if (!timeout)\n context = args = null;\n }\n };\n\n var debounced = function () {\n context = this;\n args = arguments;\n timestamp = Date.now();\n if (!timeout) {\n timeout = setTimeout(later, wait);\n if (immediate)\n result = func.apply(context, args);\n }\n return result;\n };\n\n (debounced as any).clear = function () {\n if (timeout) {\n clearTimeout(timeout);\n timeout = null;\n }\n };\n\n (debounced as any).flush = function () {\n if (timeout) {\n result = func.apply(context, args);\n context = args = null;\n\n clearTimeout(timeout);\n timeout = null;\n }\n };\n\n return debounced as DebouncedFunction;\n};","export function getjQuery(): any {\n // @ts-ignore\n return typeof jQuery === \"function\" ? jQuery : typeof $ === \"function\" && ($ as any).fn ? $ : undefined;\n}\n\n/** Returns true if Bootstrap 3 is loaded */\nexport function isBS3(): boolean {\n return (getjQuery()?.fn?.modal?.Constructor?.VERSION + \"\").charAt(0) == '3';\n}\n\n/** Returns true if Bootstrap 5+ is loaded */\nexport function isBS5Plus(): boolean {\n return typeof bootstrap !== \"undefined\" && !!bootstrap.Modal && (bootstrap.Modal.VERSION + \"\").charAt(0) != '4';\n}\n","/**\n * --------------------------------------------------------------------------\n * Adapted from: Bootstrap dom/event-handler.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport { getjQuery } from \"./environment\"\n\nconst namespaceRegex = /[^.]*(?=\\..*)\\.|.*/\nconst stripNameRegex = /\\..*/\nconst stripUidRegex = /::\\d+$/\nlet uidEvent = 1\nconst customEvents: Record = {\n mouseenter: 'mouseover',\n mouseleave: 'mouseout'\n}\n\nfunction makeEventUid(prefix: string): string {\n return `${prefix}::${uidEvent++}`;\n}\n\nconst eventRegistry: WeakMap = new WeakMap();\n\nexport function triggerRemoveAndClearAll(element: EventTarget): void {\n let events = eventRegistry.get(element);\n if (!events)\n return;\n\n var removeEvents = events[\"remove\"];\n eventRegistry.delete(element);\n if (removeEvents) {\n for (const [_, event] of Object.entries(removeEvents)) {\n if (typeof (event as any).callable === \"function\") {\n try {\n (event as any).callable.call(element, { target: element });\n }\n catch {\n }\n }\n }\n }\n}\n\nfunction getElementEvents(element: EventTarget): any {\n var events = eventRegistry.get(element);\n if (!events)\n eventRegistry.set(element, events = {});\n return events;\n}\n\nfunction hydrateObj(obj: any, meta = {}) {\n for (const [key, value] of Object.entries(meta)) {\n try {\n obj[key] = value\n } catch {\n Object.defineProperty(obj, key, {\n configurable: true,\n get() {\n return value\n }\n })\n }\n }\n\n return obj;\n}\n\nfunction baseHandler(element: EventTarget, fn: any) {\n return function handler(event: Event) {\n hydrateObj(event, { delegateTarget: element })\n\n if ((handler as any).oneOff) {\n EventHandler.off(element, event.type as any, fn)\n }\n\n return fn.apply(element, [event])\n }\n}\n\nfunction delegationHandler(element: EventTarget, selector: string, fn: Function) {\n return function handler(event: Event) {\n const domElements = (element as any).querySelectorAll(selector)\n\n for (let { target } = event; target && target !== this; target = (target as any).parentNode) {\n for (const domElement of (domElements as any)) {\n if (domElement !== target) {\n continue\n }\n\n hydrateObj(event, { delegateTarget: target })\n\n if ((handler as any).oneOff) {\n EventHandler.off(element, event.type, selector, fn)\n }\n\n return fn.apply(target, [event])\n }\n }\n }\n}\n\nfunction findHandler(events: any, callable: any, delegationSelector: any = null) {\n return Object.values(events)\n .find((event: any) => event.callable === callable && event.delegationSelector === delegationSelector)\n}\n\nfunction normalizeParameters(originalTypeEvent: string, handler: any, delegationFunction: any) {\n const isDelegated = typeof handler === 'string'\n const callable = isDelegated ? delegationFunction : (handler || delegationFunction);\n let typeEvent = getTypeEvent(originalTypeEvent)\n if (originalTypeEvent.indexOf(\".bs.\") >= 0)\n typeEvent = originalTypeEvent;\n return [isDelegated, callable, typeEvent]\n}\n\nfunction addHandler(element: EventTarget, originalTypeEvent: string, handler: Function | string, delegationFunction: Function, oneOff?: boolean) {\n if (typeof originalTypeEvent !== 'string' || !element) {\n return;\n }\n\n const $ = getjQuery();\n if ($) {\n let $element = $(element);\n if (oneOff)\n $element.one(originalTypeEvent, handler, delegationFunction);\n else\n $element.on(originalTypeEvent, handler, delegationFunction);\n return;\n }\n \n let [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction);\n if (!callable)\n return;\n\n if (originalTypeEvent in customEvents) {\n const wrapFunction = (fn: Function) => {\n return function (event: Event & { relatedTarget?: any, delegateTarget: any }) {\n if (!event.relatedTarget || (event.relatedTarget !== event.delegateTarget && !event.delegateTarget.contains(event.relatedTarget))) {\n return fn.call(this, event)\n }\n }\n }\n\n callable = wrapFunction(callable)\n }\n\n const events = getElementEvents(element);\n const handlers = events[typeEvent] || (events[typeEvent] = {});\n const previousFunction = findHandler(handlers, callable, isDelegated ? handler : null);\n\n if (previousFunction) {\n (previousFunction as any).oneOff = (previousFunction as any).oneOff && oneOff\n return;\n }\n\n const uid = makeEventUid(originalTypeEvent.replace(namespaceRegex, ''))\n const fn: any = isDelegated ?\n delegationHandler(element, handler as string, callable) :\n baseHandler(element, callable);\n\n fn.delegationSelector = isDelegated ? handler : null;\n fn.callable = callable;\n fn.oneOff = oneOff;\n fn.uidEvent = uid;\n handlers[uid] = fn;\n\n element.addEventListener(typeEvent, fn, isDelegated);\n}\n\nfunction removeHandler(element: EventTarget, events: any, typeEvent: string, handler: any, delegationSelector: string) {\n const fn = findHandler(events[typeEvent], handler, delegationSelector)\n\n if (!fn) {\n return\n }\n\n element.removeEventListener(typeEvent, fn as any, Boolean(delegationSelector))\n delete events[typeEvent][(fn as any).uidEvent]\n}\n\nfunction removeNamespacedHandlers(element: EventTarget, events: any, typeEvent: string, namespace: string) {\n const storeElementEvent = events[typeEvent] || {};\n\n for (const [handlerKey, event] of Object.entries(storeElementEvent)) {\n if (handlerKey.includes(namespace)) {\n removeHandler(element, events, typeEvent, (event as any).callable, (event as any).delegationSelector);\n }\n }\n}\n\nfunction getTypeEvent(event: string) {\n // allow to get the native events from namespaced events ('click.bs.button' --> 'click')\n event = event.replace(stripNameRegex, '')\n return customEvents[event] || event\n}\n\nexport namespace EventHandler {\n export function on(element: EventTarget, type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any): void;\n export function on(element: EventTarget, type: string, listener: EventListener): void;\n export function on(element: EventTarget, type: string, selector: string, delegationHandler: Function): void;\n export function on(element: EventTarget, type: string, handler: any, delegationHandler?: Function): void {\n addHandler(element, type, handler, delegationHandler, /*oneOff*/ false);\n }\n\n export function one(element: EventTarget, type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any): void;\n export function one(element: EventTarget, type: string, listener: EventListener): void;\n export function one(element: EventTarget, type: string, selector: string, delegationHandler: Function): void;\n export function one(element: EventTarget, type: string, handler: any, delegationHandler?: Function): void {\n addHandler(element, type, handler, delegationHandler, true);\n }\n\n export function off(element: EventTarget, type: K, listener?: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any): void;\n export function off(element: EventTarget, type: string, listener?: EventListener): void;\n export function off(element: EventTarget, type: string, selector?: string, delegationHandler?: Function): void;\n export function off(element: EventTarget, originalTypeEvent: string, handler?: any, delegationHandler?: Function): void {\n if (typeof originalTypeEvent !== 'string' || !element) {\n return\n }\n\n const $ = getjQuery();\n if ($) {\n $(element).off(originalTypeEvent, handler, delegationHandler);\n return;\n }\n\n const [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationHandler);\n const inNamespace = typeEvent !== originalTypeEvent;\n const events = getElementEvents(element);\n const storeElementEvent = events[typeEvent] || {};\n const isNamespace = originalTypeEvent.startsWith('.');\n\n if (typeof callable !== 'undefined') {\n if (!Object.keys(storeElementEvent).length) {\n return;\n }\n\n removeHandler(element, events, typeEvent, callable, isDelegated ? handler : null);\n return\n }\n\n if (isNamespace) {\n for (const elementEvent of Object.keys(events)) {\n removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.slice(1));\n }\n }\n\n for (const [keyHandlers, event] of Object.entries(storeElementEvent)) {\n const handlerKey = keyHandlers.replace(stripUidRegex, '');\n\n if (!inNamespace || originalTypeEvent.includes(handlerKey)) {\n removeHandler(element, events, typeEvent, (event as any).callable, (event as any).delegationSelector);\n }\n }\n }\n\n export function trigger(element: EventTarget, type: string, args?: any): Event & { isDefaultPrevented?(): boolean } {\n if (typeof type !== 'string' || !element) {\n return null;\n }\n\n const $ = getjQuery();\n const typeEvent = getTypeEvent(type);\n const inNamespace = type !== typeEvent;\n\n let jQueryEvent = null;\n let bubbles = true;\n let nativeDispatch = true;\n let defaultPrevented = false;\n\n if (inNamespace && $) {\n jQueryEvent = $.Event(type, args);\n $(element).trigger(jQueryEvent);\n bubbles = !jQueryEvent.isPropagationStopped();\n nativeDispatch = !jQueryEvent.isImmediatePropagationStopped();\n defaultPrevented = jQueryEvent.isDefaultPrevented();\n }\n\n const evt = hydrateObj(new Event(type, { bubbles, cancelable: true }), args);\n\n if (defaultPrevented) {\n evt.preventDefault();\n }\n\n if (nativeDispatch) {\n element.dispatchEvent(evt);\n }\n\n if (evt.defaultPrevented && jQueryEvent) {\n jQueryEvent.preventDefault();\n }\n\n return evt\n }\n}\n","\nconst esc: Record = {\n '<': '<',\n '>': '>',\n '\"': '"',\n \"'\": \"'\",\n '&': '&',\n}\n\nfunction escFunc(a: string): string {\n return esc[a];\n}\n\n/**\n * Html encodes a string (encodes single and double quotes, & (ampersand), > and < characters)\n * @param s String (or number etc.) to be HTML encoded\n */\nexport function htmlEncode(s: any): string {\n if (s == null)\n return '';\n\n if (typeof s !== \"string\")\n s = \"\" + s;\n\n return s.replace(/[<>\"'&]/g, escFunc)\n}\n\n/** \n * Toggles the class on the element handling spaces like addClass does.\n * @param el the element\n * @param cls the class to toggle\n * @param add if true, the class will be added, if false the class will be removed, otherwise it will be toggled.\n */\nexport function toggleClass(el: Element, cls: string, add?: boolean) {\n if (!el || cls == null || !cls.length)\n return;\n\n if (cls.indexOf(' ') < 0) {\n el.classList.toggle(cls, add);\n return;\n }\n\n var k = cls.split(' ').map(x => x.trim()).filter(x => x.length);\n for (var a of k)\n el.classList.toggle(a, add);\n}\n\nexport function addClass(el: Element, cls: string) {\n return toggleClass(el, cls, true);\n}\n\nexport function removeClass(el: Element, cls: string) {\n return toggleClass(el, cls, false);\n}","import { getjQuery } from \"./environment\";\nimport { EventHandler, triggerRemoveAndClearAll } from \"./eventhandler\";\nimport { toggleClass as toggleCls } from \"./html\";\n\nexport interface Fluent extends ArrayLike {\n addClass(value: string | boolean | (string | boolean)[]): this;\n append(child: string | Node | Fluent): this;\n appendTo(parent: Element | Fluent): this;\n attr(name: string): string;\n attr(name: string, value: string | number | boolean | null | undefined): this;\n children(selector?: string): HTMLElement[];\n class(value: string | boolean | (string | boolean)[]): this;\n closest(selector: string): Fluent;\n data(name: string): string;\n data(name: string, value: string): this;\n each(callback: (el: TElement) => void): this;\n getNode(): TElement;\n empty(): this;\n findFirst(selector: string): Fluent;\n findAll(selector: string): TElement[];\n hasClass(klass: string): boolean;\n hide(): this;\n getWidget(type?: { new(...args: any[]): TWidget }): TWidget;\n insertAfter(referenceNode: HTMLElement | Fluent): this;\n insertBefore(referenceNode: HTMLElement | Fluent): this;\n [Symbol.iterator]: TElement[];\n readonly [n: number]: TElement;\n readonly length: number;\n off(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any): this;\n off(type: string): this;\n off(type: string, listener: EventListener): this;\n off(type: string, selector: string, delegationHandler: Function): this;\n on(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any): this;\n on(type: string, listener: EventListener): this;\n on(type: string, selector: string, delegationHandler: Function): this;\n one(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any): this;\n one(type: string, listener: EventListener): this;\n one(type: string, selector: string, delegationHandler: Function): this;\n matches(selector?: string): boolean;\n nextSibling(selector?: string): Fluent;\n parent(): Fluent;\n prepend(child: string | Node | Fluent): this;\n prependTo(parent: Element | Fluent): this;\n prevSibling(selector?: string): Fluent;\n remove(): this;\n removeAttr(name: string): this;\n removeClass(value: string | boolean | (string | boolean)[]): this;\n show(): this;\n style(callback: (css: CSSStyleDeclaration) => void): this;\n text(): string;\n text(value: string): this;\n toggle(flag?: boolean): this;\n toggleClass(value: (string | boolean | (string | boolean)[]), add?: boolean): this;\n trigger(type: string, args?: any): this;\n tryGetWidget(type?: { new(...args: any[]): TWidget }): TWidget;\n val(value: string): this;\n val(): string;\n}\n\nexport function Fluent(tag: K): Fluent;\nexport function Fluent(element: TElement): Fluent;\nexport function Fluent(element: EventTarget): Fluent;\nexport function Fluent(tagOrElement: K | HTMLElementTagNameMap[K]): Fluent {\n if (!(this instanceof Fluent)) {\n if (typeof tagOrElement === \"string\")\n return new (Fluent as any)(document.createElement(tagOrElement));\n\n return new (Fluent as any)(tagOrElement);\n }\n\n this.el = tagOrElement;\n return this;\n}\n\nexport namespace Fluent {\n export const off = EventHandler.off;\n export const on = EventHandler.on;\n export const one = EventHandler.one;\n export const trigger = EventHandler.trigger;\n\n export function addClass(el: Element, value: string | boolean | (string | boolean)[]) {\n toggleCls(el, toClassName(value), true);\n }\n\n export function empty(el: Element) {\n if (!el)\n return;\n\n if (typeof el.hasChildNodes === \"function\" && el.hasChildNodes()) {\n let $ = getjQuery();\n if ($)\n $(el).empty();\n else {\n cleanContents(el);\n el.innerHTML = \"\";\n }\n }\n else\n el.innerHTML = \"\";\n }\n\n /** For compatibility with jQuery's :visible selector, e.g. has offsetWidth or offsetHeight or any client rect */\n export function isVisibleLike(el: Element) {\n return !!(el && ((el as any).offsetWidth || (el as any).offsetHeight || el.getClientRects().length));\n }\n\n export function remove(el: Element) {\n if (!el)\n return;\n let $ = getjQuery();\n if ($)\n $(el).remove();\n else {\n cleanContents(el);\n triggerRemoveAndClearAll(el);\n el.remove();\n }\n return this;\n }\n\n export function removeClass(el: Element, value: string | boolean | (string | boolean)[]) {\n toggleCls(el, toClassName(value), false);\n }\n\n export function toggle(el: Element, flag?: boolean): void {\n el && (el as any).style && ((el as any).style.display = flag ? \"\" : (flag != null && !flag) ? \"none\" : (el as any).style.display == \"none\" ? \"\" : \"none\");\n }\n\n export function toggleClass(el: Element, value: string | boolean | (string | boolean)[], add?: boolean): void {\n el && toggleCls(el, toClassName(value), add);\n }\n\n export function toClassName(value: string | boolean | (string | boolean)[]): string {\n if (typeof value === \"string\")\n return value;\n if (Array.isArray(value))\n return value.map(toClassName).filter(Boolean).join(\" \");\n if (typeof value !== \"boolean\" && value != null)\n return \"\" + value;\n return \"\";\n }\n\n export function isInputLike(node: Element): node is (HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement | HTMLButtonElement) {\n return isInputTag(node?.nodeName);\n }\n\n export const inputLikeSelector = \"input,select,textarea,button\";\n\n export function isInputTag(tag: string) {\n return /^(?:input|select|textarea|button)$/i.test(tag);\n }\n\n export function isDefaultPrevented(e: { defaultPrevented?: boolean, isDefaultPrevented?: () => boolean }) {\n return e != null && (!!e.defaultPrevented ||\n (typeof e.isDefaultPrevented === \"function\" && !!e.isDefaultPrevented()));\n }\n\n export function eventProp(e: any, prop: string) {\n if (!e)\n return void 0;\n\n if (typeof e[prop] !== \"undefined\")\n return e[prop];\n\n if (typeof e.originalEvent === \"object\" && typeof e.originalEvent[prop] !== \"undefined\")\n return e.originalEvent[prop];\n\n if (typeof e.detail === \"object\")\n return e.detail[prop];\n }\n}\n\ntype FluentThis = Fluent & {\n el?: HTMLElement;\n}\n\nfunction extractNode(element: string | Node | FluentThis): (string | Node) {\n return (element instanceof EventTarget || typeof element === \"string\") ? element : element?.el;\n}\n\nfunction extractElement(element: Element | FluentThis): HTMLElement {\n return (element instanceof EventTarget || typeof element === \"string\") ? element as HTMLElement : element?.el;\n}\n\nFluent.prototype.addClass = function (this: FluentThis, value: string | boolean | (string | boolean)[]) {\n Fluent.addClass(this.el, value);\n return this;\n}\n\nFluent.prototype.append = function (this: FluentThis, child: string | Node | Fluent) {\n this.el && this.el.append(extractNode(child));\n return this;\n}\n\nFluent.prototype.appendTo = function (this: FluentThis, parent: Element | Fluent) {\n if (this.el) {\n parent = extractElement(parent);\n if (!parent)\n this.el.remove();\n else\n parent.appendChild(this.el);\n }\n return this;\n}\n\nFluent.prototype.attr = function (this: FluentThis, name: string, value?: string | boolean | number | null | undefined) {\n if (value === void 0 && arguments.length < 2)\n return this.el?.getAttribute(name);\n\n if (this.el) {\n if (value == null)\n this.el.removeAttribute(name);\n else if (typeof value === \"string\")\n this.el.setAttribute(name, value);\n else if (typeof value === \"number\")\n this.el.setAttribute(name, \"\" + value);\n else if (value != null && value !== false)\n this.el.setAttribute(name, \"true\");\n }\n\n return this;\n}\n\nFluent.prototype.children = function (this: FluentThis, selector?: string): Element[] {\n if (selector == null)\n return Array.from(this.el?.children || []);\n return Array.from(this.el?.children || []).filter(x => x.matches(selector));\n}\n\nFluent.prototype.class = function (this: FluentThis, value: string | boolean | (string | boolean)[]): Fluent {\n this.el && (this.el.className = Fluent.toClassName(value));\n return this;\n}\n\nFluent.prototype.closest = function (this: FluentThis, selector: string): Fluent {\n return new (Fluent as any)(this.el?.closest(selector));\n}\n\nFluent.prototype.each = function (this: FluentThis, callback: (el: HTMLElement) => void) {\n this.el && callback(this.el);\n return this;\n}\n\nFluent.prototype.empty = function (this: FluentThis) {\n Fluent.empty(this.el);\n return this;\n}\n\nFluent.prototype.getNode = function (this: FluentThis) {\n return this.el;\n}\n\nFluent.prototype.hasClass = function (this: FluentThis, klass: string) {\n return !!this.el?.classList.contains(klass);\n}\n\nFluent.prototype.insertAfter = function (this: FluentThis, referenceNode: HTMLElement | Fluent) {\n if (!this.el)\n return this;\n referenceNode = extractElement(referenceNode);\n let parent = referenceNode?.parentNode;\n if (!parent)\n this.el.remove();\n else\n parent.insertBefore(this.el, referenceNode.nextSibling);\n return this;\n}\n\nFluent.prototype.isVisibleLike = function (this: FluentThis) {\n return Fluent.isVisibleLike(this.el);\n}\n\nFluent.prototype.insertBefore = function (this: FluentThis, referenceNode: HTMLElement | Fluent) {\n if (!this.el)\n return this;\n referenceNode = extractElement(referenceNode);\n let parent = referenceNode?.parentElement;\n if (!parent)\n this.el.remove();\n else\n parent.insertBefore(this.el, referenceNode);\n return this;\n}\n\nFluent.prototype.prependTo = function (this: FluentThis, parent: HTMLElement | Fluent) {\n if (this.el) {\n parent = extractElement(parent);\n if (!parent)\n this.el.remove();\n else\n parent.prepend(this.el);\n }\n return this;\n}\n\nFluent.prototype.removeAttr = function (this: FluentThis, name: string) {\n this.el?.removeAttribute(name);\n return this;\n}\n\nFluent.prototype.data = function (this: FluentThis, name: string, value?: string) {\n if (value === void 0 && arguments.length < 2)\n return this.attr(\"data-\" + name);\n return this.attr(\"data-\" + name, value);\n}\n\nFluent.prototype.off = function (this: FluentThis, type: string, handler: any, delegationHandler?: Function) {\n this.el && EventHandler.off(this.el, type, handler, delegationHandler);\n return this;\n}\n\nFluent.prototype.on = function (this: FluentThis, type: string, handler: any, delegationHandler?: Function) {\n this.el && EventHandler.on(this.el, type, handler, delegationHandler);\n return this;\n}\n\nFluent.prototype.one = function (this: FluentThis, type: string, handler: any, delegationHandler?: Function) {\n this.el && EventHandler.one(this.el, type, handler, delegationHandler);\n return this;\n}\n\nFluent.prototype.removeClass = function (this: FluentThis, value: string | boolean | (string | boolean)[]) {\n Fluent.removeClass(this.el, value);\n return this;\n}\n\nFluent.prototype.findFirst = function (this: FluentThis, selector: string): Fluent {\n return new (Fluent as any)(this.el?.querySelector(selector));\n}\n\nFluent.prototype.findAll = function (this: FluentThis, selector: string): HTMLElement[] {\n if (!this.el)\n return [];\n return Array.from(this.el.querySelectorAll(selector));\n}\n\nFluent.prototype.hide = function (this: FluentThis) {\n this.el && (this.el.style.display = \"none\");\n return this;\n}\n\nFluent.prototype.matches = function (this: FluentThis, selector?: string): boolean {\n return !!this.el && typeof this.el.matches === \"function\" && this.el.matches(selector);\n}\n\nFluent.prototype.nextSibling = function (this: FluentThis, selector?: string): Fluent {\n var sibling = this.el?.nextElementSibling;\n while (sibling && selector != null && !sibling.matches(selector))\n sibling = sibling.nextElementSibling;\n return new (Fluent as any)(sibling);\n}\n\nFluent.prototype.parent = function (this: FluentThis): Fluent {\n return new (Fluent as any)(this.el?.parentNode);\n}\n\nFluent.prototype.prepend = function (this: FluentThis, child: string | Node | Fluent) {\n this.el && this.el.prepend(extractNode(child));\n return this;\n}\n\nFluent.prototype.prevSibling = function (this: FluentThis, selector?: string): Fluent {\n var sibling = this.el?.previousElementSibling;\n while (sibling && selector != null && !sibling.matches(selector))\n sibling = sibling.previousElementSibling;\n return new (Fluent as any)(sibling);\n}\n\nfunction cleanContents(element: Element) {\n element.querySelectorAll(\"*\").forEach(node => triggerRemoveAndClearAll(node));\n}\n\nFluent.prototype.remove = function (this: FluentThis) {\n Fluent.remove(this.el);\n return this;\n}\n\nFluent.prototype.show = function (this: FluentThis) {\n this.el && (this.el.style.display = \"\");\n return this;\n}\n\nFluent.prototype.style = function (this: FluentThis, callback: (css: CSSStyleDeclaration) => void) {\n if (this.el && this.el.style instanceof CSSStyleDeclaration)\n callback(this.el.style);\n return this;\n}\n\nFluent.prototype.trigger = function (this: FluentThis, type: string, args?: any) {\n this.el && EventHandler.trigger(this.el, type, args);\n return this;\n}\n\nFluent.prototype.val = function (this: FluentThis, value?: string) {\n if (value === void 0 && !arguments.length)\n return Fluent.isInputLike(this.el) ? this.el.value : \"\";\n if (Fluent.isInputLike(this.el))\n this.el.value = value ?? \"\";\n return this as any;\n}\n\nFluent.prototype.text = function (this: FluentThis, value?: string) {\n if (value === void 0 && !arguments.length)\n return this.el?.textContent;\n\n if (!this.el)\n return this;\n\n if (typeof this.el.hasChildNodes === \"function\" && this.el.hasChildNodes()) {\n let $ = getjQuery();\n if ($)\n $(this.el).text(value ?? \"\");\n else {\n cleanContents(this.el);\n this.el.textContent = value ?? \"\";\n }\n }\n else\n this.el.textContent = value ?? \"\";\n\n return this;\n}\n\nFluent.prototype.toggle = function (this: FluentThis, flag?: boolean) {\n Fluent.toggle(this.el, flag);\n return this;\n}\n\nFluent.prototype.toggleClass = function (this: FluentThis, value: string | boolean | (string | boolean)[], add?: boolean) {\n Fluent.toggleClass(this.el, value, add);\n return this;\n}\n\nObject.defineProperty(Fluent.prototype, \"length\", { get: function () { return this.el ? 1 : 0 } });\nObject.defineProperty(Fluent.prototype, 0, { get: function () { return this.el; } });\nObject.defineProperty(Fluent.prototype, Symbol.iterator, { get: function () { return (this.el ? [this.el] : [])[Symbol.iterator]; } });\n\n\nFluent.ready = function (callback: () => void) {\n if (!callback)\n return;\n \n let $ = getjQuery();\n if ($) {\n $(callback);\n return;\n }\n \n if (typeof document !== \"undefined\" && document.readyState === 'loading') {\n const loaded = () => {\n document.removeEventListener('DOMContentLoaded', loaded);\n callback();\n }\n document.addEventListener('DOMContentLoaded', loaded);\n return;\n }\n \n setTimeout(callback, 0);\n}\n\nFluent.byId = function (id: string): Fluent {\n return Fluent(document.getElementById(id) as TElement);\n}\n\nexport function H(tag: K): Fluent {\n return new (Fluent as any)(document.createElement(tag));\n}","export type UtilityColor = \"primary\" | \"secondary\" | \"success\" | \"danger\" | \"warning\" | \"info\" | \"light\" | \"dark\" | \"muted\" | \"white\";\nexport type TextColor = UtilityColor | \"aqua\" | \"blue\" | \"fuschia\" | \"gray\" | \"green\" | \"light-blue\" | \"lime\" | \"maroon\" | \"navy\" | \"olive\" | \"orange\" | \"purple\" | \"red\" | \"teal\" | \"yellow\";\n\nexport function bgColor(color: UtilityColor) {\n return \"bg-\" + color;\n}\n\nexport function textColor(color: TextColor): string {\n return \"text-\" + color;\n}\n\nexport function faIcon(key: faIconKey, color?: TextColor): string {\n return \"fa fa-\" + key + (color ? \" \" + textColor(color) : \"\");\n}\n\nexport function fabIcon(key: fabIconKey, color?: TextColor): string {\n return \"fab fa-\" + key + (color ? \" \" + textColor(color) : \"\");\n}\n\nexport type KnownIconClass = `fa fa-${faIconKey}` | `fab fa-${fabIconKey}`;\nexport type AnyIconClass = KnownIconClass | (string & {});\nexport type IconClassName = AnyIconClass | (AnyIconClass[]);\n\nexport function iconClassName(icon: IconClassName): string {\n let klass = Array.isArray(icon) ? icon.join(\" \") : icon;\n if (!klass)\n return klass;\n if (klass.startsWith('fa-') && klass.indexOf(\"fa \") < 0 && !klass.endsWith(\" fa\"))\n return 'fa ' + klass;\n return klass;\n}\n\n/*\nGenerated from https://icons8.com/line-awesome via following code\nvar c = Array.from(document.querySelectorAll('.icons__item')).map(x => x.querySelector('.icons__before i:not(.icons__arrow)').className).filter((x, i, a) => a && (a.indexOf(x) === i));\n[false, true].map(b => { var l = 0; var a = c.filter(x => !!x.startsWith(\"fab \") == b).map(x => '\"' + x.replace(\"fas fa-\", \"\").replace(\"fab fa-\", \"\") + '\"').sort()\n .map((x)=>{if (l + x.length > 120) { l = 0; x = x + '\\n' } l += x.length; return x}); \n var t = (b && \"fab\") || \"fa\"; return `export type ${t}Icon =\\n${a.join('|')};` }).join('\\n\\n');\n*/\n\nexport type faIconKey =\n \"ad\" | \"address-book\" | \"address-card\" | \"adjust\" | \"air-freshener\" | \"align-center\" | \"align-justify\" | \"align-left\" | \"align-right\" | \"allergies\" | \"ambulance\"\n | \"american-sign-language-interpreting\" | \"anchor\" | \"angle-double-down\" | \"angle-double-left\" | \"angle-double-right\" | \"angle-double-up\"\n | \"angle-down\" | \"angle-left\" | \"angle-right\" | \"angle-up\" | \"angry\" | \"ankh\" | \"apple-alt\" | \"archive\" | \"archway\" | \"arrow-alt-circle-down\"\n | \"arrow-alt-circle-left\" | \"arrow-alt-circle-right\" | \"arrow-alt-circle-up\" | \"arrow-circle-down\" | \"arrow-circle-left\"\n | \"arrow-circle-right\" | \"arrow-circle-up\" | \"arrow-down\" | \"arrow-left\" | \"arrow-right\" | \"arrow-up\" | \"arrows-alt\" | \"arrows-alt-h\"\n | \"arrows-alt-v\" | \"assistive-listening-systems\" | \"asterisk\" | \"at\" | \"atlas\" | \"atom\" | \"audio-description\" | \"award\" | \"baby\" | \"baby-carriage\"\n | \"backspace\" | \"backward\" | \"bacon\" | \"balance-scale\" | \"balance-scale-left\" | \"balance-scale-right\" | \"ban\" | \"band-aid\" | \"barcode\"\n | \"bars\" | \"baseball-ball\" | \"basketball-ball\" | \"bath\" | \"battery-empty\" | \"battery-full\" | \"battery-half\" | \"battery-quarter\" | \"battery-three-quarters\"\n | \"bed\" | \"beer\" | \"bell\" | \"bell-o\" | \"bell-slash\" | \"bezier-curve\" | \"bible\" | \"bicycle\" | \"biking\" | \"binoculars\" | \"biohazard\" | \"birthday-cake\"\n | \"blender\" | \"blender-phone\" | \"blind\" | \"blog\" | \"bold\" | \"bolt\" | \"bomb\" | \"bone\" | \"bong\" | \"book\" | \"book-dead\" | \"book-medical\" | \"book-open\"\n | \"book-reader\" | \"bookmark\" | \"border-all\" | \"border-none\" | \"border-style\" | \"bowling-ball\" | \"box\" | \"box-open\" | \"boxes\" | \"braille\" | \"brain\"\n | \"bread-slice\" | \"briefcase\" | \"briefcase-medical\" | \"broadcast-tower\" | \"broom\" | \"brush\" | \"bug\" | \"building\" | \"bullhorn\" | \"bullseye\" | \"burn\"\n | \"bus\" | \"bus-alt\" | \"business-time\" | \"calculator\" | \"calendar\" | \"calendar-alt\" | \"calendar-check\" | \"calendar-day\" | \"calendar-minus\" | \"calendar-plus\"\n | \"calendar-times\" | \"calendar-week\" | \"camera\" | \"camera-retro\" | \"campground\" | \"candy-cane\" | \"cannabis\" | \"capsules\" | \"car\" | \"car-alt\"\n | \"car-battery\" | \"car-crash\" | \"car-side\" | \"caret-down\" | \"caret-left\" | \"caret-right\" | \"caret-square-down\" | \"caret-square-left\" | \"caret-square-right\"\n | \"caret-square-up\" | \"caret-up\" | \"carrot\" | \"cart-arrow-down\" | \"cart-plus\" | \"cash-register\" | \"cat\" | \"certificate\" | \"chair\"\n | \"chalkboard\" | \"chalkboard-teacher\" | \"charging-station\" | \"chart-area\" | \"chart-bar\" | \"chart-line\" | \"chart-pie\" | \"check\" | \"check-circle\"\n | \"check-double\" | \"check-square\" | \"cheese\" | \"chess\" | \"chess-bishop\" | \"chess-board\" | \"chess-king\" | \"chess-knight\" | \"chess-pawn\"\n | \"chess-queen\" | \"chess-rook\" | \"chevron-circle-down\" | \"chevron-circle-left\" | \"chevron-circle-right\" | \"chevron-circle-up\"\n | \"chevron-down\" | \"chevron-left\" | \"chevron-right\" | \"chevron-up\" | \"child\" | \"church\" | \"circle\" | \"circle-notch\" | \"city\" | \"clinic-medical\"\n | \"clipboard\" | \"clipboard-check\" | \"clipboard-list\" | \"clock\" | \"clock-o\" | \"clone\" | \"closed-captioning\" | \"cloud\" | \"cloud-download-alt\"\n | \"cloud-meatball\" | \"cloud-moon\" | \"cloud-moon-rain\" | \"cloud-rain\" | \"cloud-showers-heavy\" | \"cloud-sun\" | \"cloud-sun-rain\"\n | \"cloud-upload-alt\" | \"cocktail\" | \"code\" | \"code-branch\" | \"coffee\" | \"cog\" | \"cogs\" | \"coins\" | \"columns\" | \"comment\" | \"comment-alt\"\n | \"comment-dollar\" | \"comment-dots\" | \"comment-medical\" | \"comment-slash\" | \"comments\" | \"comments-dollar\" | \"compact-disc\" | \"compass\"\n | \"compress\" | \"compress-arrows-alt\" | \"concierge-bell\" | \"cookie\" | \"cookie-bite\" | \"copy\" | \"copyright\" | \"couch\" | \"credit-card\" | \"crop\"\n | \"crop-alt\" | \"cross\" | \"crosshairs\" | \"crow\" | \"crown\" | \"crutch\" | \"cube\" | \"cubes\" | \"cut\" | \"database\" | \"deaf\" | \"democrat\" | \"desktop\" | \"dharmachakra\"\n | \"diagnoses\" | \"dice\" | \"dice-d20\" | \"dice-d6\" | \"dice-five\" | \"dice-four\" | \"dice-one\" | \"dice-six\" | \"dice-three\" | \"dice-two\" | \"digital-tachograph\"\n | \"directions\" | \"divide\" | \"dizzy\" | \"dna\" | \"dog\" | \"dollar-sign\" | \"dolly\" | \"dolly-flatbed\" | \"donate\" | \"door-closed\" | \"door-open\"\n | \"dot-circle\" | \"dove\" | \"download\" | \"drafting-compass\" | \"dragon\" | \"draw-polygon\" | \"drum\" | \"drum-steelpan\" | \"drumstick-bite\" | \"dumbbell\"\n | \"dumpster\" | \"dumpster-fire\" | \"dungeon\" | \"edit\" | \"egg\" | \"eject\" | \"ellipsis-h\" | \"ellipsis-v\" | \"envelope\" | \"envelope-o\" | \"envelope-open\" | \"envelope-open-text\"\n | \"envelope-square\" | \"equals\" | \"eraser\" | \"ethernet\" | \"euro-sign\" | \"exchange-alt\" | \"exclamation\" | \"exclamation-circle\"\n | \"exclamation-triangle\" | \"expand\" | \"expand-arrows-alt\" | \"external-link-alt\" | \"external-link-square-alt\" | \"eye\" | \"eye-dropper\"\n | \"eye-slash\" | \"fan\" | \"fast-backward\" | \"fast-forward\" | \"fax\" | \"feather\" | \"feather-alt\" | \"female\" | \"fighter-jet\" | \"file\" | \"file-alt\" | \"file-archive\"\n | \"file-audio\" | \"file-code\" | \"file-contract\" | \"file-csv\" | \"file-download\" | \"file-excel\" | \"file-excel-o\" | \"file-export\" | \"file-image\" | \"file-import\" \n | \"file-invoice\" | \"file-invoice-dollar\" | \"file-medical\" | \"file-medical-alt\" | \"file-pdf\" | \"file-pdf-o\" | \"file-powerpoint\" | \"file-prescription\"\n | \"file-signature\" | \"file-upload\" | \"file-text\" | \"file-text-o\" | \"file-video\" | \"file-word\" | \"fill\" | \"fill-drip\" | \"film\" | \"filter\" | \"fingerprint\" | \"fire\" \n | \"floppy-o\" | \"fire-alt\" | \"fire-extinguisher\" | \"first-aid\" | \"fish\" | \"fist-raised\" | \"flag\" | \"flag-checkered\" | \"flag-usa\" | \"flask\" | \"flushed\" | \"folder\"\n | \"folder-minus\" | \"folder-open\" | \"folder-open-o\" | \"folder-plus\" | \"font\" | \"football-ball\" | \"forward\" | \"frog\" | \"frown\" | \"frown-open\" | \"funnel-dollar\" | \"futbol\"\n | \"gamepad\" | \"gas-pump\" | \"gavel\" | \"gem\" | \"genderless\" | \"ghost\" | \"gift\" | \"gifts\" | \"glass-cheers\" | \"glass-martini\" | \"glass-martini-alt\" | \"glass-whiskey\"\n | \"glasses\" | \"globe\" | \"globe-africa\" | \"globe-americas\" | \"globe-asia\" | \"globe-europe\" | \"golf-ball\" | \"gopuram\" | \"graduation-cap\"\n | \"greater-than\" | \"greater-than-equal\" | \"grimace\" | \"grin\" | \"grin-alt\" | \"grin-beam\" | \"grin-beam-sweat\" | \"grin-hearts\" | \"grin-squint\"\n | \"grin-squint-tears\" | \"grin-stars\" | \"grin-tears\" | \"grin-tongue\" | \"grin-tongue-squint\" | \"grin-tongue-wink\" | \"grin-wink\" | \"grip-horizontal\"\n | \"grip-lines\" | \"grip-lines-vertical\" | \"grip-vertical\" | \"guitar\" | \"h-square\" | \"hamburger\" | \"hammer\" | \"hamsa\" | \"hand-holding\"\n | \"hand-holding-heart\" | \"hand-holding-usd\" | \"hand-lizard\" | \"hand-middle-finger\" | \"hand-paper\" | \"hand-peace\" | \"hand-point-down\"\n | \"hand-point-left\" | \"hand-point-right\" | \"hand-point-up\" | \"hand-pointer\" | \"hand-rock\" | \"hand-scissors\" | \"hand-spock\" | \"hands\"\n | \"hands-helping\" | \"handshake\" | \"hanukiah\" | \"hard-hat\" | \"hashtag\" | \"hat-cowboy\" | \"hat-cowboy-side\" | \"hat-wizard\" | \"haykal\" | \"hdd\" | \"heading\"\n | \"headphones\" | \"headphones-alt\" | \"headset\" | \"heart\" | \"heart-broken\" | \"heartbeat\" | \"helicopter\" | \"highlighter\" | \"hiking\" | \"hippo\" | \"history\"\n | \"hockey-puck\" | \"holly-berry\" | \"home\" | \"horse\" | \"horse-head\" | \"hospital\" | \"hospital-alt\" | \"hospital-symbol\" | \"hot-tub\" | \"hotdog\" | \"hotel\"\n | \"hourglass\" | \"hourglass-end\" | \"hourglass-half\" | \"hourglass-start\" | \"house-damage\" | \"hryvnia\" | \"i-cursor\" | \"ice-cream\" | \"icicles\" | \"icons\"\n | \"id-badge\" | \"id-card\" | \"id-card-alt\" | \"igloo\" | \"image\" | \"images\" | \"inbox\" | \"indent\" | \"industry\" | \"infinity\" | \"info\" | \"info-circle\" | \"italic\"\n | \"jedi\" | \"joint\" | \"journal-whills\" | \"kaaba\" | \"key\" | \"keyboard\" | \"khanda\" | \"kiss\" | \"kiss-beam\" | \"kiss-wink-heart\" | \"kiwi-bird\" | \"landmark\"\n | \"language\" | \"laptop\" | \"laptop-code\" | \"laptop-medical\" | \"laugh\" | \"laugh-beam\" | \"laugh-squint\" | \"laugh-wink\" | \"layer-group\" | \"leaf\"\n | \"lemon\" | \"less-than\" | \"less-than-equal\" | \"level-down-alt\" | \"level-up-alt\" | \"life-ring\" | \"lightbulb\" | \"link\" | \"lira-sign\" | \"list\" | \"list-alt\"\n | \"list-ol\" | \"list-ul\" | \"location-arrow\" | \"lock\" | \"lock-open\" | \"long-arrow-alt-down\" | \"long-arrow-alt-left\" | \"long-arrow-alt-right\" | \"long-arrow-alt-up\"\n | \"low-vision\" | \"luggage-cart\" | \"magic\" | \"magnet\" | \"mail-bulk\" | \"mail-forward\" | \"mail-reply\" | \"male\" | \"map\" | \"map-marked\" | \"map-marked-alt\"\n | \"map-marker\" | \"map-marker-alt\" | \"map-pin\" | \"map-signs\" | \"marker\" | \"mars\" | \"mars-double\" | \"mars-stroke\" | \"mars-stroke-h\" | \"mars-stroke-v\"\n | \"mask\" | \"medal\" | \"medkit\" | \"meh\" | \"meh-blank\" | \"meh-rolling-eyes\" | \"memory\" | \"menorah\" | \"mercury\" | \"meteor\" | \"microchip\" | \"microphone\"\n | \"microphone-alt\" | \"microphone-alt-slash\" | \"microphone-slash\" | \"microscope\" | \"minus\" | \"minus-circle\" | \"minus-square\" | \"mitten\"\n | \"mobile\" | \"mobile-alt\" | \"money-bill\" | \"money-bill-alt\" | \"money-bill-wave\" | \"money-bill-wave-alt\" | \"money-check\" | \"money-check-alt\"\n | \"monument\" | \"moon\" | \"mortar-pestle\" | \"mosque\" | \"motorcycle\" | \"mountain\" | \"mouse\" | \"mouse-pointer\" | \"mug-hot\" | \"music\" | \"network-wired\"\n | \"neuter\" | \"newspaper\" | \"not-equal\" | \"notes-medical\" | \"object-group\" | \"object-ungroup\" | \"oil-can\" | \"om\" | \"otter\" | \"outdent\" | \"pager\"\n | \"paint-brush\" | \"paint-roller\" | \"palette\" | \"pallet\" | \"paper-plane\" | \"paperclip\" | \"parachute-box\" | \"paragraph\" | \"parking\" | \"passport\"\n | \"pastafarianism\" | \"paste\" | \"pause\" | \"pause-circle\" | \"paw\" | \"peace\" | \"pen\" | \"pen-alt\" | \"pen-fancy\" | \"pen-nib\" | \"pen-square\" | \"pencil-alt\"\n | \"pencil-ruler\" | \"pencil-square-o\" | \"people-carry\" | \"pepper-hot\" | \"percent\" | \"percentage\" | \"person-booth\" | \"phone\" | \"phone-alt\" | \"phone-slash\" | \"phone-square\"\n | \"phone-square-alt\" | \"phone-volume\" | \"photo-video\" | \"piggy-bank\" | \"pills\" | \"pizza-slice\" | \"place-of-worship\" | \"plane\" | \"plane-arrival\"\n | \"plane-departure\" | \"play\" | \"play-circle\" | \"plug\" | \"plus\" | \"plus-circle\" | \"plus-square\" | \"podcast\" | \"poll\" | \"poll-h\" | \"poo\" | \"poo-storm\"\n | \"poop\" | \"portrait\" | \"pound-sign\" | \"power-off\" | \"pray\" | \"praying-hands\" | \"prescription\" | \"prescription-bottle\" | \"prescription-bottle-alt\"\n | \"print\" | \"procedures\" | \"project-diagram\" | \"puzzle-piece\" | \"qrcode\" | \"question\" | \"question-circle\" | \"quidditch\" | \"quote-left\"\n | \"quote-right\" | \"quran\" | \"radiation\" | \"radiation-alt\" | \"rainbow\" | \"random\" | \"receipt\" | \"record-vinyl\" | \"recycle\" | \"redo\" | \"refresh\"\n | \"redo-alt\" | \"registered\" | \"remove-format\" | \"reply\" | \"reply-all\" | \"republican\" | \"restroom\" | \"retweet\" | \"ribbon\" | \"ring\" | \"road\" | \"robot\" | \"rocket\"\n | \"route\" | \"rss\" | \"rss-square\" | \"ruble-sign\" | \"ruler\" | \"ruler-combined\" | \"ruler-horizontal\" | \"ruler-vertical\" | \"running\" | \"rupee-sign\"\n | \"sad-cry\" | \"sad-tear\" | \"satellite\" | \"satellite-dish\" | \"save\" | \"school\" | \"screwdriver\" | \"scroll\" | \"sd-card\" | \"search\" | \"search-dollar\"\n | \"search-location\" | \"search-minus\" | \"search-plus\" | \"seedling\" | \"server\" | \"shapes\" | \"share\" | \"share-alt\" | \"share-alt-square\"\n | \"share-square\" | \"shekel-sign\" | \"shield-alt\" | \"ship\" | \"shipping-fast\" | \"shoe-prints\" | \"shopping-bag\" | \"shopping-basket\"\n | \"shopping-cart\" | \"shower\" | \"shuttle-van\" | \"sign\" | \"sign-in-alt\" | \"sign-language\" | \"sign-out\" | \"sign-out-alt\" | \"signal\" | \"signature\"\n | \"sim-card\" | \"sitemap\" | \"skating\" | \"skiing\" | \"skiing-nordic\" | \"skull\" | \"skull-crossbones\" | \"slash\" | \"sleigh\" | \"sliders-h\" | \"smile\"\n | \"smile-beam\" | \"smile-wink\" | \"smog\" | \"smoking\" | \"smoking-ban\" | \"sms\" | \"snowboarding\" | \"snowflake\" | \"snowman\" | \"snowplow\" | \"socks\" | \"solar-panel\"\n | \"sort\" | \"sort-alpha-down\" | \"sort-alpha-down-alt\" | \"sort-alpha-up\" | \"sort-alpha-up-alt\" | \"sort-amount-down\" | \"sort-amount-down-alt\"\n | \"sort-amount-up\" | \"sort-amount-up-alt\" | \"sort-down\" | \"sort-numeric-down\" | \"sort-numeric-down-alt\" | \"sort-numeric-up\"\n | \"sort-numeric-up-alt\" | \"sort-up\" | \"spa\" | \"space-shuttle\" | \"spell-check\" | \"spider\" | \"spinner\" | \"splotch\" | \"spray-can\" | \"square\"\n | \"square-full\" | \"square-root-alt\" | \"stamp\" | \"star\" | \"star-and-crescent\" | \"star-half\" | \"star-half-alt\" | \"star-o\" | \"star-of-david\" | \"star-of-life\"\n | \"step-backward\" | \"step-forward\" | \"stethoscope\" | \"sticky-note\" | \"stop\" | \"stop-circle\" | \"stopwatch\" | \"store\" | \"store-alt\" | \"stream\"\n | \"street-view\" | \"strikethrough\" | \"stroopwafel\" | \"subscript\" | \"subway\" | \"suitcase\" | \"suitcase-rolling\" | \"sun\" | \"superscript\" | \"surprise\"\n | \"swatchbook\" | \"swimmer\" | \"swimming-pool\" | \"synagogue\" | \"sync\" | \"sync-alt\" | \"syringe\" | \"table\" | \"table-tennis\" | \"tablet\" | \"tablet-alt\"\n | \"tablets\" | \"tachometer-alt\" | \"tag\" | \"tags\" | \"tape\" | \"tasks\" | \"taxi\" | \"teeth\" | \"teeth-open\" | \"temperature-high\" | \"temperature-low\"\n | \"tenge\" | \"terminal\" | \"text-height\" | \"text-width\" | \"th\" | \"th-large\" | \"th-list\" | \"theater-masks\" | \"thermometer\" | \"thermometer-empty\"\n | \"thermometer-full\" | \"thermometer-half\" | \"thermometer-quarter\" | \"thermometer-three-quarters\" | \"thumbs-down\" | \"thumbs-up\"\n | \"thumbtack\" | \"ticket-alt\" | \"times\" | \"times-circle\" | \"tint\" | \"tint-slash\" | \"tired\" | \"toggle-off\" | \"toggle-on\" | \"toilet\" | \"toilet-paper\"\n | \"toolbox\" | \"tools\" | \"tooth\" | \"torah\" | \"torii-gate\" | \"tractor\" | \"trademark\" | \"traffic-light\" | \"train\" | \"tram\" | \"transgender\" | \"transgender-alt\"\n | \"trash\" | \"trash-alt\" | \"trash-o\" | \"trash-restore\" | \"trash-restore-alt\" | \"tree\" | \"trophy\" | \"truck\" | \"truck-loading\" | \"truck-monster\"\n | \"truck-moving\" | \"truck-pickup\" | \"tshirt\" | \"tty\" | \"tv\" | \"umbrella\" | \"umbrella-beach\" | \"underline\" | \"undo\" | \"undo-alt\" | \"universal-access\"\n | \"university\" | \"unlink\" | \"unlock\" | \"unlock-alt\" | \"upload\" | \"user\" | \"user-alt\" | \"user-alt-slash\" | \"user-astronaut\" | \"user-check\"\n | \"user-circle\" | \"user-clock\" | \"user-cog\" | \"user-edit\" | \"user-friends\" | \"user-graduate\" | \"user-injured\" | \"user-lock\" | \"user-md\"\n | \"user-minus\" | \"user-ninja\" | \"user-nurse\" | \"user-plus\" | \"user-secret\" | \"user-shield\" | \"user-slash\" | \"user-tag\" | \"user-tie\" | \"user-times\"\n | \"users\" | \"users-cog\" | \"utensil-spoon\" | \"utensils\" | \"vector-square\" | \"venus\" | \"venus-double\" | \"venus-mars\" | \"vial\" | \"vials\" | \"video\"\n | \"video-slash\" | \"vihara\" | \"voicemail\" | \"volleyball-ball\" | \"volume-down\" | \"volume-mute\" | \"volume-off\" | \"volume-up\" | \"vote-yea\" | \"vr-cardboard\"\n | \"walking\" | \"wallet\" | \"warehouse\" | \"water\" | \"wave-square\" | \"weight\" | \"weight-hanging\" | \"wheelchair\" | \"wifi\" | \"wind\" | \"window-close\"\n | \"window-maximize\" | \"window-minimize\" | \"window-restore\" | \"wine-bottle\" | \"wine-glass\" | \"wine-glass-alt\" | \"won-sign\" | \"wrench\"\n | \"x-ray\" | \"yen-sign\" | \"yin-yang\";\n\nexport type fabIconKey =\n \"500px\" | \"accessible-icon\" | \"accusoft\" | \"acquisitions-incorporated\" | \"adn\" | \"adobe\" | \"adversal\" | \"affiliatetheme\" | \"airbnb\" | \"algolia\" | \"alipay\"\n | \"amazon\" | \"amazon-pay\" | \"amilia\" | \"android\" | \"angellist\" | \"angrycreative\" | \"angular\" | \"app-store\" | \"app-store-ios\" | \"apper\" | \"apple\"\n | \"apple-pay\" | \"artstation\" | \"asymmetrik\" | \"atlassian\" | \"audible\" | \"autoprefixer\" | \"avianex\" | \"aviato\" | \"aws\" | \"bandcamp\" | \"battle-net\"\n | \"behance\" | \"behance-square\" | \"bimobject\" | \"bitbucket\" | \"bitcoin\" | \"bity\" | \"black-tie\" | \"blackberry\" | \"blogger\" | \"blogger-b\" | \"bluetooth\"\n | \"bluetooth-b\" | \"bootstrap\" | \"btc\" | \"buffer\" | \"buromobelexperte\" | \"buy-n-large\" | \"buysellads\" | \"canadian-maple-leaf\" | \"cc-amazon-pay\"\n | \"cc-amex\" | \"cc-apple-pay\" | \"cc-diners-club\" | \"cc-discover\" | \"cc-jcb\" | \"cc-mastercard\" | \"cc-paypal\" | \"cc-stripe\" | \"cc-visa\"\n | \"centercode\" | \"centos\" | \"chrome\" | \"chromecast\" | \"cloudscale\" | \"cloudsmith\" | \"cloudversify\" | \"codepen\" | \"codiepie\" | \"confluence\" | \"connectdevelop\"\n | \"contao\" | \"cotton-bureau\" | \"cpanel\" | \"creative-commons\" | \"creative-commons-by\" | \"creative-commons-nc\" | \"creative-commons-nc-eu\"\n | \"creative-commons-nc-jp\" | \"creative-commons-nd\" | \"creative-commons-pd\" | \"creative-commons-pd-alt\" | \"creative-commons-remix\"\n | \"creative-commons-sa\" | \"creative-commons-sampling\" | \"creative-commons-sampling-plus\" | \"creative-commons-share\"\n | \"creative-commons-zero\" | \"critical-role\" | \"css3\" | \"css3-alt\" | \"cuttlefish\" | \"d-and-d\" | \"d-and-d-beyond\" | \"dashcube\"\n | \"delicious\" | \"deploydog\" | \"deskpro\" | \"dev\" | \"deviantart\" | \"dhl\" | \"diaspora\" | \"digg\" | \"digital-ocean\" | \"discord\" | \"discourse\" | \"dochub\"\n | \"docker\" | \"draft2digital\" | \"dribbble\" | \"dribbble-square\" | \"dropbox\" | \"drupal\" | \"dyalog\" | \"earlybirds\" | \"ebay\" | \"edge\" | \"elementor\" | \"ello\"\n | \"ember\" | \"empire\" | \"envira\" | \"erlang\" | \"ethereum\" | \"etsy\" | \"evernote\" | \"expeditedssl\" | \"facebook\" | \"facebook-f\" | \"facebook-messenger\" | \"facebook-square\"\n | \"fantasy-flight-games\" | \"fedex\" | \"fedora\" | \"figma\" | \"firefox\" | \"first-order\" | \"first-order-alt\" | \"firstdraft\" | \"flickr\"\n | \"flipboard\" | \"fly\" | \"font-awesome\" | \"font-awesome-alt\" | \"font-awesome-flag\" | \"fonticons\" | \"fonticons-fi\" | \"fort-awesome\" | \"fort-awesome-alt\"\n | \"forumbee\" | \"foursquare\" | \"free-code-camp\" | \"freebsd\" | \"fulcrum\" | \"galactic-republic\" | \"galactic-senate\" | \"get-pocket\"\n | \"gg\" | \"gg-circle\" | \"git\" | \"git-alt\" | \"git-square\" | \"github\" | \"github-alt\" | \"github-square\" | \"gitkraken\" | \"gitlab\" | \"gitter\" | \"glide\"\n | \"glide-g\" | \"gofore\" | \"goodreads\" | \"goodreads-g\" | \"google\" | \"google-drive\" | \"google-play\" | \"google-plus\" | \"google-plus-g\" | \"google-plus-square\"\n | \"google-wallet\" | \"gratipay\" | \"grav\" | \"gripfire\" | \"grunt\" | \"gulp\" | \"hacker-news\" | \"hacker-news-square\" | \"hackerrank\" | \"hips\"\n | \"hire-a-helper\" | \"hooli\" | \"hornbill\" | \"hotjar\" | \"houzz\" | \"html5\" | \"hubspot\" | \"imdb\" | \"instagram\" | \"intercom\" | \"internet-explorer\" | \"invision\"\n | \"ioxhost\" | \"itch-io\" | \"itunes\" | \"itunes-note\" | \"java\" | \"jedi-order\" | \"jenkins\" | \"jira\" | \"joget\" | \"joomla\" | \"js\" | \"js-square\" | \"jsfiddle\"\n | \"kaggle\" | \"keybase\" | \"keycdn\" | \"kickstarter\" | \"kickstarter-k\" | \"korvue\" | \"laravel\" | \"lastfm\" | \"lastfm-square\" | \"leanpub\" | \"less\" | \"line\"\n | \"linkedin\" | \"linkedin-in\" | \"linode\" | \"linux\" | \"lyft\" | \"magento\" | \"mailchimp\" | \"mandalorian\" | \"markdown\" | \"mastodon\" | \"maxcdn\" | \"mdb\" | \"medapps\"\n | \"medium\" | \"medium-m\" | \"medrt\" | \"meetup\" | \"megaport\" | \"mendeley\" | \"microsoft\" | \"mix\" | \"mixcloud\" | \"mizuni\" | \"modx\" | \"monero\" | \"napster\" | \"neos\"\n | \"nimblr\" | \"node\" | \"node-js\" | \"npm\" | \"ns8\" | \"nutritionix\" | \"odnoklassniki\" | \"odnoklassniki-square\" | \"old-republic\" | \"opencart\" | \"openid\"\n | \"opera\" | \"optin-monster\" | \"orcid\" | \"osi\" | \"page4\" | \"pagelines\" | \"palfed\" | \"patreon\" | \"paypal\" | \"penny-arcade\" | \"periscope\" | \"phabricator\"\n | \"phoenix-framework\" | \"phoenix-squadron\" | \"php\" | \"pied-piper\" | \"pied-piper-alt\" | \"pied-piper-hat\" | \"pied-piper-pp\" | \"pinterest\"\n | \"pinterest-p\" | \"pinterest-square\" | \"playstation\" | \"product-hunt\" | \"pushed\" | \"python\" | \"qq\" | \"quinscape\" | \"quora\" | \"r-project\" | \"raspberry-pi\"\n | \"ravelry\" | \"react\" | \"reacteurope\" | \"readme\" | \"rebel\" | \"red-river\" | \"reddit\" | \"reddit-alien\" | \"reddit-square\" | \"redhat\" | \"renren\"\n | \"replyd\" | \"researchgate\" | \"resolving\" | \"rev\" | \"rocketchat\" | \"rockrms\" | \"safari\" | \"salesforce\" | \"sass\" | \"schlix\" | \"scribd\" | \"searchengin\"\n | \"sellcast\" | \"sellsy\" | \"servicestack\" | \"shirtsinbulk\" | \"shopware\" | \"simplybuilt\" | \"sistrix\" | \"sith\" | \"sketch\" | \"skyatlas\" | \"skype\"\n | \"slack\" | \"slack-hash\" | \"slideshare\" | \"snapchat\" | \"snapchat-ghost\" | \"snapchat-square\" | \"soundcloud\" | \"sourcetree\" | \"speakap\" | \"speaker-deck\"\n | \"spotify\" | \"squarespace\" | \"stack-exchange\" | \"stack-overflow\" | \"stackpath\" | \"staylinked\" | \"steam\" | \"steam-square\" | \"steam-symbol\"\n | \"sticker-mule\" | \"strava\" | \"stripe\" | \"stripe-s\" | \"studiovinari\" | \"stumbleupon\" | \"stumbleupon-circle\" | \"superpowers\" | \"supple\"\n | \"suse\" | \"swift\" | \"symfony\" | \"teamspeak\" | \"telegram\" | \"telegram-plane\" | \"tencent-weibo\" | \"the-red-yeti\" | \"themeco\" | \"themeisle\" | \"think-peaks\"\n | \"trade-federation\" | \"trello\" | \"tripadvisor\" | \"tumblr\" | \"tumblr-square\" | \"twitch\" | \"twitter\" | \"twitter-square\" | \"typo3\" | \"uber\"\n | \"ubuntu\" | \"uikit\" | \"umbraco\" | \"uniregistry\" | \"untappd\" | \"ups\" | \"usb\" | \"usps\" | \"ussunnah\" | \"vaadin\" | \"viacoin\" | \"viadeo\" | \"viadeo-square\" | \"viber\"\n | \"vimeo\" | \"vimeo-square\" | \"vimeo-v\" | \"vine\" | \"vk\" | \"vnv\" | \"vuejs\" | \"waze\" | \"weebly\" | \"weibo\" | \"weixin\" | \"whatsapp\" | \"whatsapp-square\" | \"whmcs\"\n | \"wikipedia-w\" | \"windows\" | \"wix\" | \"wizards-of-the-coast\" | \"wolf-pack-battalion\" | \"wordpress\" | \"wordpress-simple\" | \"wpbeginner\" | \"wpexplorer\"\n | \"wpforms\" | \"wpressr\" | \"xbox\" | \"xing\" | \"xing-square\" | \"y-combinator\" | \"yahoo\" | \"yammer\" | \"yandex\" | \"yandex-international\" | \"yarn\"\n | \"yelp\" | \"yoast\" | \"youtube\" | \"youtube-square\" | \"zhihu\";","/** @internal */\nexport const isAssignableFromSymbol: unique symbol = Symbol.for(\"Serenity.isAssignableFrom\");\n/** @internal */\nexport const isInstanceOfTypeSymbol: unique symbol = Symbol.for(\"Serenity.isInstanceOfType\");\n/** @internal */\nexport const implementedInterfacesSymbol: unique symbol = Symbol.for(\"Serenity.implementedInterfaces\");\n/** @internal */\nexport const localTextTableSymbol: unique symbol = Symbol.for(\"Serenity.localTextTable\");\n/** @internal */\nexport const scriptDataHashSymbol: unique symbol = Symbol.for(\"Serenity.scriptDataHash\");\n/** @internal */\nexport const scriptDataSymbol: unique symbol = Symbol.for(\"Serenity.scriptData\");\n/** @internal */\nexport const isInterfaceTypeSymbol: unique symbol = Symbol.for(\"Serenity.isInterfaceType\"); // true: interface, false: class, null: enum\n/** @internal */\nexport const typeRegistrySymbol: unique symbol = Symbol.for(\"Serenity.typeRegistry\");\n\n","import { implementedInterfacesSymbol, isInterfaceTypeSymbol, typeRegistrySymbol } from \"./symbols\";\n\nexport const typeInfoProperty = \"typeInfo\";\n\nexport const globalObject: any =\n (typeof globalThis !== \"undefined\" && globalThis) ||\n (typeof window !== \"undefined\" && window) ||\n (typeof self !== \"undefined\" && self) ||\n // @ts-ignore check for global\n (typeof global !== \"undefined\" && global) || {};\n\nexport function merge(arr1: any[], arr2: any[]) {\n if (!arr1 || !arr2)\n return (arr1 || arr2 || []).slice();\n\n function distinct(arr: any[]) {\n return arr.filter((item, pos) => arr.indexOf(item) === pos);\n }\n\n return distinct(arr1.concat(arr2));\n}\n\nexport type StringLiteral = T extends string ? string extends T ? never : T : never;\n\nexport type TypeInfo = {\n typeKind: \"class\" | \"enum\" | \"interface\" | \"editor\" | \"formatter\";\n typeName: StringLiteral | (string & {});\n interfaces?: any[];\n customAttributes?: any[];\n enumFlags?: boolean;\n registered?: boolean;\n}\n\nexport function getTypeRegistry() {\n let typeRegistry = globalObject[typeRegistrySymbol];\n if (!typeRegistry)\n typeRegistry = globalObject[typeRegistrySymbol] = {};\n return typeRegistry;\n}\n\nfunction autoRegisterViaTypeInfo(type: any): void {\n if (!Object.prototype.hasOwnProperty.call(type, typeInfoProperty))\n return;\n\n var typeInfo = type[typeInfoProperty] as TypeInfo;\n if (!typeInfo || typeInfo.registered || !typeInfo.typeName)\n return;\n\n if (!getTypeRegistry()[typeInfo.typeName])\n getTypeRegistry()[typeInfo.typeName] = type;\n\n if (typeInfo.interfaces?.length &&\n !Object.prototype.hasOwnProperty.call(implementedInterfacesSymbol)) {\n Object.defineProperty(type, implementedInterfacesSymbol, {\n value: merge(type[implementedInterfacesSymbol], typeInfo.interfaces),\n configurable: true\n });\n }\n\n if (!Object.prototype.hasOwnProperty.call(isInterfaceTypeSymbol)) {\n if (typeInfo.typeKind === \"class\" || typeInfo.typeKind === \"editor\" || typeInfo.typeKind === \"formatter\") {\n Object.defineProperty(type, isInterfaceTypeSymbol, { value: false, configurable: true });\n }\n else if (typeInfo.typeKind === \"enum\") {\n Object.defineProperty(type, isInterfaceTypeSymbol, { value: null, configurable: true });\n }\n else if (typeInfo.typeKind === \"interface\") {\n Object.defineProperty(type, isInterfaceTypeSymbol, { value: true, configurable: true });\n }\n }\n\n typeInfo.registered = true;\n return;\n}\n\nexport function internalRegisterType(type: any, typeName?: string, interfaces?: any[]): TypeInfo {\n let typeInfo = ensureTypeInfo(type);\n\n if (typeName && typeName !== typeInfo.typeName)\n typeInfo.typeName = typeName;\n\n if (typeInfo.typeName)\n getTypeRegistry()[typeInfo.typeName] = type;\n\n if (interfaces?.length && typeInfo.interfaces !== interfaces) {\n interfaces = typeInfo.interfaces = merge(typeInfo.interfaces, interfaces);\n\n Object.defineProperty(type, implementedInterfacesSymbol, {\n value: merge(type[implementedInterfacesSymbol], interfaces),\n configurable: true\n });\n }\n\n typeInfo.registered = true;\n return typeInfo;\n}\n\nexport function ensureTypeInfo(type: any): TypeInfo {\n let typeInfo: TypeInfo;\n if (!Object.prototype.hasOwnProperty.call(type, typeInfoProperty) ||\n !(typeInfo = type[typeInfoProperty])) {\n typeInfo = {} as any;\n Object.defineProperty(type, typeInfoProperty, { value: typeInfo, configurable: true });\n return typeInfo;\n }\n if (!typeInfo.registered)\n autoRegisterViaTypeInfo(type);\n return typeInfo;\n}\n\nexport function peekTypeInfo(type: any): TypeInfo {\n if (!type || !Object.prototype.hasOwnProperty.call(type, typeInfoProperty))\n return void 0;\n\n var typeInfo = type[typeInfoProperty];\n if (typeInfo && !typeInfo.registered)\n autoRegisterViaTypeInfo(type);\n\n return typeInfo;\n}\n\nexport function getTypeNameProp(type: any): string {\n return peekTypeInfo(type)?.typeName || void 0;\n}\n\nexport function setTypeNameProp(type: any, value: string) {\n ensureTypeInfo(type).typeName = value;\n autoRegisterViaTypeInfo(type);\n}\n\n","import { implementedInterfacesSymbol, isAssignableFromSymbol, isInstanceOfTypeSymbol, isInterfaceTypeSymbol } from \"./symbols\";\nimport { StringLiteral, TypeInfo, ensureTypeInfo, getTypeNameProp, getTypeRegistry, globalObject, internalRegisterType, merge, peekTypeInfo, typeInfoProperty } from \"./system-internal\";\nexport { getTypeNameProp, getTypeRegistry, setTypeNameProp, typeInfoProperty, type StringLiteral } from \"./system-internal\";\n\nexport function getGlobalObject(): any {\n return globalObject;\n}\n\nexport function omitUndefined(x: { [key: string]: any }) {\n if (x == null)\n return x;\n let obj = Object.create(null);\n Object.entries(x).forEach(([key, value]) => value !== void 0 && (obj[key] = value));\n return obj;\n}\n\nexport type Type = Function | Object;\n\nexport function getNested(from: any, name: string) {\n var a = name.split('.');\n for (var i = 0; i < a.length; i++) {\n from = from[a[i]];\n if (from == null)\n return null;\n }\n return from;\n}\n\nexport function getType(name: string, target?: any): Type {\n var type: any;\n if (target == null) {\n type = getTypeRegistry()[name];\n if (type != null || globalObject == void 0 || name === \"Object\")\n return type;\n\n target = globalObject;\n }\n\n type = getNested(target, name)\n if (typeof type !== 'function')\n return null;\n\n return type;\n}\n\nexport function getTypeFullName(type: Type): string {\n return getTypeNameProp(type) || (type as any).name ||\n (type.toString().match(/^\\s*function\\s*([^\\s(]+)/) || [])[1] || 'Object';\n};\n\nexport function getTypeShortName(type: Type): string {\n var fullName = getTypeFullName(type);\n var bIndex = fullName?.indexOf('[');\n var nsIndex = fullName?.lastIndexOf('.', bIndex >= 0 ? bIndex : fullName.length);\n return nsIndex > 0 ? fullName.substring(nsIndex + 1) : fullName;\n};\n\nexport function getInstanceType(instance: any): any {\n if (instance == null)\n throw \"Can't get instance type of null or undefined!\";\n\n // Have to catch as constructor cannot be looked up on native COM objects\n try {\n return instance.constructor;\n }\n catch (ex) {\n return Object;\n }\n};\n\nexport function isAssignableFrom(target: any, type: Type) {\n if (target === type || (type as any).prototype instanceof target)\n return true;\n\n if (typeof target[isAssignableFromSymbol] === 'function')\n return target[isAssignableFromSymbol](type);\n\n return false;\n}\n\nexport function isInstanceOfType(instance: any, type: Type) {\n if (instance == null)\n return false;\n\n if (typeof (type as any)[isInstanceOfTypeSymbol] === 'function')\n return (type as any)[isInstanceOfTypeSymbol](instance);\n\n return isAssignableFrom(type, getInstanceType(instance));\n}\n\nexport function getBaseType(type: any) {\n if (type == null ||\n type === Object ||\n !type.prototype ||\n (type as any)[isInterfaceTypeSymbol] === true)\n return null;\n\n return Object.getPrototypeOf(type.prototype).constructor;\n}\n\nfunction interfaceIsAssignableFrom(from: any) {\n return from != null &&\n Array.isArray((from as any)[implementedInterfacesSymbol]) &&\n (from as any)[implementedInterfacesSymbol].some((x: any) =>\n x === this ||\n (getTypeNameProp(this) &&\n x[isInterfaceTypeSymbol] &&\n getTypeNameProp(x) === getTypeNameProp(this)));\n}\n\nexport function registerClass(type: any, name: string, intf?: any[]) {\n internalRegisterType(type, name, intf);\n Object.defineProperty(type, isInterfaceTypeSymbol, { value: false, configurable: true });\n}\n\nexport function registerEnum(type: any, name: string, enumKey?: string) {\n internalRegisterType(type, name, undefined);\n if (enumKey && enumKey != name) {\n const typeStore = getTypeRegistry();\n if (!typeStore[enumKey])\n typeStore[enumKey] = type;\n }\n Object.defineProperty(type, isInterfaceTypeSymbol, { value: null, configurable: true });\n}\n\nexport function registerInterface(type: any, name: string, intf?: any[]) {\n internalRegisterType(type, name, intf);\n Object.defineProperty(type, isInterfaceTypeSymbol, { value: true, configurable: true });\n Object.defineProperty(type, isAssignableFromSymbol, { value: interfaceIsAssignableFrom, configurable: true });\n}\n\nexport namespace Enum {\n export let toString = (enumType: any, value: number): string => {\n if (value == null)\n return \"\";\n\n if (typeof value !== \"number\")\n return \"\" + value;\n\n var values = enumType;\n if (value === 0 || !peekTypeInfo(enumType)?.enumFlags) {\n for (var i in values) {\n if (values[i] === value) {\n return i;\n }\n }\n return value == null ? \"\" : value.toString();\n }\n else {\n var parts: string[] = [];\n for (var i in values) {\n if (typeof values[i] !== \"number\")\n continue;\n\n if (values[i] & value) {\n parts.push(i);\n value -= values[i];\n }\n }\n if (value != 0)\n parts.push(value.toString());\n return parts.join(' | ');\n }\n };\n\n export let getValues = (enumType: any) => {\n var parts = [];\n var values = enumType;\n for (var i in values) {\n if (Object.prototype.hasOwnProperty.call(values, i) &&\n typeof values[i] === \"number\")\n parts.push(values[i]);\n }\n return parts;\n };\n}\n\nexport const isEnum = (type: any) => {\n return typeof type !== \"function\" &&\n type[isInterfaceTypeSymbol] === null;\n};\n\nexport function initFormType(typ: Function, nameWidgetPairs: any[]) {\n for (var i = 0; i < nameWidgetPairs.length - 1; i += 2) {\n (function (name: string, widget: any) {\n Object.defineProperty(typ.prototype, name, {\n get: function () {\n return this.w(name, widget);\n },\n enumerable: true,\n configurable: true\n });\n })(nameWidgetPairs[i], nameWidgetPairs[i + 1]);\n }\n}\n\nconst _fieldsProxy = new Proxy({}, { get: (_, p) => p }) as any;\n\nexport function fieldsProxy(): Readonly> {\n return _fieldsProxy\n}\n\nexport function isArrayLike(obj: any): obj is ArrayLike {\n return typeof obj === \"object\" && obj != null && typeof obj.length === \"number\" && typeof obj.nodeType !== \"number\";\n}\n\nexport function isPromiseLike(obj: any): obj is PromiseLike {\n return obj instanceof Promise || ((typeof obj === \"object\" && obj != null && typeof obj.then === \"function\" && typeof obj.catch === \"function\"));\n}\n\nexport type NoInfer = [T][T extends any ? 0 : never];\n\nexport class EditorAttribute { }\nregisterClass(EditorAttribute, 'Serenity.EditorAttribute');\n\nexport class ISlickFormatter { }\nregisterInterface(ISlickFormatter, 'Serenity.ISlickFormatter');\n\nexport function registerFormatter(type: any, name: string, intf?: any[]) {\n return registerClass(type, name, merge([ISlickFormatter], intf));\n}\n\nexport function registerEditor(type: any, name: string, intf?: any[]) {\n registerClass(type, name, intf);\n if (!peekTypeInfo(type).customAttributes?.some(x => getInstanceType(x) === x))\n addCustomAttribute(type, new EditorAttribute());\n}\n\nexport function addCustomAttribute(type: any, attr: any) {\n let typeInfo = ensureTypeInfo(type);\n if (!typeInfo.customAttributes)\n typeInfo.customAttributes = [attr];\n else\n typeInfo.customAttributes.push(attr);\n}\n\nexport function getCustomAttribute(type: any, attrType: { new(...args: any[]): TAttr }, inherit: boolean = true): TAttr {\n if (!type || attrType == null)\n return null;\n\n do {\n let attrs = peekTypeInfo(type)?.customAttributes;\n if (attrs) {\n for (var i = attrs.length - 1; i >= 0; i--) {\n let attr = attrs[i];\n if (attr != null && isInstanceOfType(attr, attrType))\n return attr;\n }\n }\n }\n while (inherit && (type = getBaseType(type)))\n}\n\nexport function hasCustomAttribute(type: any, attrType: { new(...args: any[]): TAttr }, inherit: boolean = true): boolean {\n return getCustomAttribute(type, attrType, inherit) != null;\n}\n\nexport function getCustomAttributes(type: any, attrType: { new(...args: any[]): TAttr }, inherit: boolean = true): TAttr[] {\n if (!type)\n return [];\n\n var result: any[] = [];\n do {\n let attrs = peekTypeInfo(type)?.customAttributes;\n if (attrs) {\n for (var i = attrs.length - 1; i >= 0; i--) {\n let attr = attrs[i];\n if (attrType != null || (attr && isInstanceOfType(attr, attrType))) {\n result.push(attr);\n }\n }\n }\n }\n while (inherit && (type = getBaseType(type)));\n return result;\n};\n\nexport type ClassTypeInfo = TypeInfo;\nexport type EditorTypeInfo = TypeInfo;\nexport type FormatterTypeInfo = TypeInfo;\nexport type InterfaceTypeInfo = TypeInfo;\n\nexport function classTypeInfo(typeName: StringLiteral, interfaces?: any[]): ClassTypeInfo {\n return { typeKind: \"class\", typeName, interfaces: interfaces }\n}\n\nexport function editorTypeInfo(typeName: StringLiteral, interfaces?: any[]): EditorTypeInfo {\n return { typeKind: \"editor\", typeName, interfaces: interfaces, customAttributes: [new EditorAttribute()] }\n}\n\nexport function formatterTypeInfo(typeName: StringLiteral, interfaces?: any[]): FormatterTypeInfo {\n return { typeKind: \"formatter\", typeName, interfaces: merge([ISlickFormatter], interfaces) }\n}\n\nexport function interfaceTypeInfo(typeName: StringLiteral, interfaces?: any[]): InterfaceTypeInfo {\n return { typeKind: \"interface\", typeName, interfaces }\n}\n\nexport function registerType(type: { [typeInfoProperty]: TypeInfo, name: string }) {\n if (!type)\n throw \"Decorators.register is called with null target!\";\n\n // peekTypeInfo should auto handle registration\n let typeInfo: TypeInfo = peekTypeInfo(type);\n if (!typeInfo)\n throw `Decorators.register is called on type \"${type.name}\" that does not have a static typeInfo property!`;\n\n if (!typeInfo.typeName)\n throw `Decorators.register is called on type \"${type.name}\", but it's typeInfo property does not have a typeName!`;\n}\n","import { localTextTableSymbol } from \"./symbols\";\nimport { getGlobalObject } from \"./system\";\n\nfunction getTable(): { [key: string]: string } {\n let localTextTable = getGlobalObject()[localTextTableSymbol];\n if (!localTextTable)\n getGlobalObject()[localTextTableSymbol] = localTextTable = {};\n return localTextTable;\n}\n\nexport function addLocalText(obj: string | Record> | string, pre?: string) {\n if (!obj)\n return;\n \n let table = getTable();\n\n if (typeof obj === \"string\") {\n table[obj] = pre;\n return;\n }\n\n pre ??= '';\n for (let k of Object.keys(obj)) {\n let actual = pre + k;\n let o = obj[k];\n if (typeof (o) === 'object') {\n addLocalText(o, actual + '.');\n }\n else {\n table[actual] = o;\n }\n }\n}\n\nexport function localText(key: string, defaultText?: string): string {\n return getTable()[key] ?? defaultText ?? key ?? '';\n}\n\nexport function tryGetText(key: string): string {\n return getTable()[key];\n}\n\nexport function proxyTexts(o: Record, p: string, t: Record): Object {\n return new Proxy(o, {\n get: (_: Object, y: string) => {\n if (typeof y === \"symbol\")\n return;\n var tv = t[y];\n if (tv == null)\n return localText(p + y);\n else {\n var z = o[y];\n if (z != null)\n return z;\n o[y] = z = proxyTexts({}, p + y + '.', tv);\n return z;\n }\n },\n ownKeys: (_: Object) => Object.keys(t)\n });\n}\n\nlet global = getGlobalObject();\n(global.Serenity || (global.Serenity = {})).addLocalText = addLocalText;","import { getjQuery, isBS3, isBS5Plus } from \"./environment\";\nimport { Fluent } from \"./fluent\";\nimport { htmlEncode } from \"./html\";\nimport { iconClassName, type IconClassName } from \"./icons\";\nimport { localText } from \"./localtext\";\nimport { isArrayLike, isPromiseLike, omitUndefined } from \"./system\";\n\n/**\n * Options for a message dialog button\n */\nexport interface DialogButton {\n /** Button text */\n text?: string;\n /** Button hint */\n hint?: string;\n /** Button icon */\n icon?: IconClassName;\n /** Click handler */\n click?: (e: MouseEvent) => void | false | Promise;\n /** CSS class for button */\n cssClass?: string;\n /** The code that is returned from message dialog function when this button is clicked.\n * If this is set, and click event will not be defaultPrevented dialog will close.\n */\n result?: string;\n}\n\nexport type DialogType = \"bsmodal\" | \"uidialog\" | \"panel\";\n\n/**\n * Options that apply to all dialog types\n */\nexport interface DialogOptions {\n /** Auto dispose dialog on close, default is true */\n autoDispose?: boolean;\n /** True to auto open dialog */\n autoOpen?: boolean;\n /** Backdrop type, static to make it modal, e.g. can't be closed by clicking outside */\n backdrop?: boolean | \"static\"\n /** List of buttons to show on the dialog */\n buttons?: DialogButton[];\n /** Vertically center modal */\n centered?: boolean;\n /** Show close button, default is true */\n closeButton?: boolean;\n /** Close dialog on escape key. Default is true for message dialogs. */\n closeOnEscape?: boolean;\n /** CSS class to use for all dialog types. Is added to the top ui-dialog, panel or modal element */\n dialogClass?: string;\n /** Dialog content/body element, or callback that will populate the content element */\n element?: HTMLElement | ArrayLike | ((element: HTMLElement) => void);\n /** Enable / disable animation. Default is false for message dialogs, true for other dialogs */\n fade?: boolean;\n /** Sets one of modal-fullscreen{-...-down} classes. Only used for bootstrap modals */\n fullScreen?: boolean | \"sm-down\" | \"md-down\" | \"lg-down\" | \"xl-down\" | \"xxl-down\",\n /** Modal option for jQuery UI dialog compatibility only. Not to be confused with Bootstrap modal. */\n modal?: boolean;\n /** Event handler that is called when dialog is opened */\n onOpen?: (e?: Event) => void;\n /** Event handler that is called when dialog is closed */\n onClose?: (result: string, e?: Event) => void;\n /** Prefer Bootstrap modals to jQuery UI dialogs when both are available */\n preferBSModal?: boolean;\n /** Prefer Panel even when Modal / jQuery UI is available */\n preferPanel?: boolean;\n /** Callback to get options specific to the dialog provider type */\n providerOptions?: (type: DialogType, opt: DialogOptions) => any;\n /** Scrollable, sets content of the modal to scrollable, only for Bootstrap */\n scrollable?: boolean;\n /** Size. Default is null for (500px) message dialogs, lg for normal dialogs */\n size?: \"sm\" | \"md\" | \"lg\" | \"xl\";\n /** Dialog title */\n title?: string;\n /** Only used for jQuery UI dialogs for backwards compatibility */\n width?: number;\n}\n\nexport class Dialog {\n\n private el: HTMLElement;\n private dialogResult: string;\n\n constructor(opt?: DialogOptions);\n constructor(opt?: DialogOptions, create = true) {\n\n if (isArrayLike(opt?.element))\n this.el = opt.element[0];\n else if (typeof opt?.element !== \"function\")\n this.el = opt?.element;\n this.dialogResult = this.el?.dataset.dialogResult;\n\n if (!create) {\n return;\n }\n\n this.el ??= document.createElement(\"div\");\n opt = Object.assign({}, Dialog.defaults, omitUndefined(opt));\n if (opt.closeOnEscape === void 0 && opt.closeButton)\n opt.closeOnEscape = true;\n if (typeof opt.element === \"function\")\n opt.element(this.el);\n\n if (this.el.classList.contains(\"hidden\") &&\n typeof opt.element !== \"function\")\n this.el.classList.remove(\"hidden\");\n\n if (opt.preferPanel || (!hasBSModal() && !hasUIDialog))\n this.createPanel(opt);\n else if (hasUIDialog() && (!hasBSModal() || !opt.preferBSModal))\n this.createUIDialog(opt);\n else {\n this.createBSModal(opt);\n }\n\n if (opt.onOpen)\n this.onOpen(opt.onOpen);\n\n if (opt.onClose)\n this.onClose(opt.onClose);\n\n if (opt.autoDispose)\n this.onClose(() => setTimeout(this.dispose.bind(this), 0));\n\n if (opt.title !== void 0) {\n this.title(opt.title);\n }\n\n if (opt.autoOpen)\n this.open();\n }\n\n static defaults: DialogOptions = {\n autoDispose: true,\n autoOpen: true,\n backdrop: false,\n centered: true,\n closeButton: true,\n fade: false,\n fullScreen: \"md-down\",\n modal: true,\n preferBSModal: true,\n size: \"lg\"\n }\n\n static messageDefaults: MessageDialogOptions = {\n autoDispose: true,\n autoOpen: true,\n backdrop: false,\n centered: true,\n closeButton: true,\n closeOnEscape: true,\n fade: true,\n fullScreen: null,\n htmlEncode: true,\n modal: true,\n preferBSModal: true,\n preWrap: true,\n size: \"md\"\n }\n\n static getInstance(el: HTMLElement | ArrayLike): Dialog {\n el = getDialogContentNode(el);\n if (!el)\n return null;\n return new (Dialog as any)({ element: el }, false);\n }\n\n /** The result code of the button that is clicked. Also attached to the dialog element as data-dialog-result */\n get result(): string {\n return this.el ? this.el.dataset.dialogResult : this.dialogResult;\n }\n\n /** Closes dialog setting the result to null */\n close(): this;\n /** Closes dialog with the result set to value */\n close(result: string): this;\n close(result?: string): this {\n this.el && (this.el.dataset.dialogResult = result ?? null);\n this.dialogResult = result ?? null;\n\n var target = getDialogEventsNode(this.el);\n if (!target)\n return;\n\n if (target.classList.contains(\"panel-body\"))\n closePanel(this.el);\n else if (target.classList.contains(\"ui-dialog-content\"))\n getjQuery()?.(this.el).dialog?.(\"close\");\n else if (target.classList.contains(\"modal\")) {\n if (isBS5Plus()) {\n bootstrap?.Modal?.getInstance?.(target)?.hide?.();\n } else {\n let $ = getjQuery();\n if ($?.fn?.modal)\n $(target).modal?.(\"close\");\n }\n }\n\n return this;\n }\n\n onClose(handler: (result?: string, e?: Event) => void, before = false) {\n var target = getDialogEventsNode(this.el);\n if (!target)\n return;\n if (target.classList.contains(\"panel-body\"))\n Fluent.on(target, before ? \"panelbeforeclose\" : \"panelclose\", e => handler(this.result, e));\n else if (target.classList.contains(\"ui-dialog-content\"))\n Fluent.on(target, before ? \"dialogbeforeclose\" : \"dialogclose\", e => handler(this.result, e));\n else if (target.classList.contains(\"modal\"))\n Fluent.on(target, before ? \"hide.bs.modal\" : \"hidden.bs.modal\", e => handler(this.result, e));\n }\n\n onOpen(handler: (e?: Event) => void, before = false): this {\n var target = getDialogEventsNode(this.el);\n if (!target)\n return;\n if (target.classList.contains(\"panel-body\"))\n Fluent.on(target, before ? \"panelbeforeopen\" : \"panelopen\", handler);\n else if (target.classList.contains(\"ui-dialog-content\"))\n Fluent.on(target, before ? \"dialogbeforeopen\" : \"dialogopen\", handler);\n else if (target.classList.contains(\"modal\"))\n Fluent.on(target, before ? \"show.bs.modal\" : \"shown.bs.modal\", handler);\n return this;\n }\n\n /** Closes dialog */\n open() {\n var target = getDialogEventsNode(this.el);\n if (!target)\n return;\n if (target.classList.contains(\"panel-body\"))\n openPanel(this.el);\n else if (target.classList.contains(\"ui-dialog-content\"))\n getjQuery()?.(target).dialog(\"open\");\n else if (target.classList.contains(\"modal\")) {\n if (isBS5Plus()) {\n bootstrap?.Modal?.getInstance?.(target)?.show?.();\n } else {\n let $ = getjQuery();\n if ($?.fn?.modal)\n $(target).modal?.(\"show\");\n }\n }\n\n return this;\n }\n\n /** Gets the title text of the dialog */\n title(): string;\n /** Sets the title text of the dialog. */\n title(value: string): this;\n title(value?: string): string | this {\n let title = this.getHeaderNode()?.querySelector(\".modal-title, .panel-titlebar-text, .ui-dialog-title\");\n if (value === void 0 && !arguments.length)\n return title?.textContent;\n\n title && (title.textContent = value);\n return this;\n }\n\n get type(): DialogType {\n var root = getDialogNode(this.el);\n if (!root)\n return null;\n if (root.classList.contains(\"modal\"))\n return \"bsmodal\";\n if (root.classList.contains(\"ui-dialog\"))\n return \"uidialog\";\n if (root.classList.contains(\"s-Panel\"))\n return \"panel\";\n return null;\n }\n\n /** Gets the body/content element of the dialog */\n getContentNode(): HTMLElement {\n return this.el;\n }\n\n /** Gets the dialog element of the dialog */\n getDialogNode(): HTMLElement {\n return getDialogNode(this.el);\n }\n\n /** Gets the node that receives events for the dialog. It's .ui-dialog-content, .modal, or .panel-body */\n getEventsNode(): HTMLElement {\n return getDialogEventsNode(this.el);\n }\n\n /** Gets the footer element of the dialog */\n getFooterNode(): HTMLElement {\n return this.getDialogNode()?.querySelector(\".modal-footer, .panel-footer, .ui-dialog-footer\");\n }\n\n /** Gets the header element of the dialog */\n getHeaderNode(): HTMLElement {\n return this.getDialogNode()?.querySelector(\".modal-header, .panel-titlebar, .ui-dialog-titlebar\");\n }\n\n private onButtonClick(e: MouseEvent, btn: DialogButton) {\n e ??= new Event(\"click\") as MouseEvent;\n if (!btn.click) {\n if (btn.result)\n this.close(btn.result);\n return;\n }\n\n var value = btn.click(e);\n if (!btn.result)\n return;\n\n if (isPromiseLike(value))\n value.then(value => value !== false && !Fluent.isDefaultPrevented(e) && this.close(btn.result));\n else if (value !== false && !Fluent.isDefaultPrevented(e))\n this.close(btn.result);\n }\n\n private createBSButtons(footer: Fluent, buttons: DialogButton[]) {\n for (let btn of buttons) {\n Fluent(dialogButtonToBS(btn))\n .appendTo(footer)\n .on(\"click\", e => this.onButtonClick(e, btn));\n }\n }\n\n createBSModal(opt: DialogOptions): void {\n\n var modal = Fluent(\"div\")\n .class([\"modal\", opt.dialogClass, opt.fade && \"fade\"])\n .attr(\"tabindex\", \"-1\")\n .appendTo(document.body);\n\n let header = Fluent(\"div\")\n .class(\"modal-header\")\n .append(Fluent(\"h5\").class(\"modal-title\"));\n\n let bs5 = isBS5Plus();\n if (opt.closeButton) {\n let closeButton = Fluent(\"button\")\n .class(bs5 ? \"btn-close\" : \"close\")\n .attr(\"type\", \"button\")\n .data(`${bs5 ? \"bs-\" : \"\"}dismiss`, \"modal\")\n .attr(\"aria-label\", DialogTexts.CloseButton);\n\n if (!bs5) {\n closeButton.append(Fluent(\"span\").attr(\"aria-hidden\", \"true\").text(\"\\u2715\"));\n }\n\n if (isBS3()) {\n closeButton.prependTo(header);\n } else {\n closeButton.appendTo(header);\n }\n }\n\n this.el.classList.add(\"modal-body\");\n\n let footer = Fluent(\"div\")\n .class(\"modal-footer\");\n\n Fluent(\"div\")\n .class([\n \"modal-dialog\",\n opt.size && \"modal-\" + opt.size,\n opt.fullScreen && \"modal-fullscreen\" + (typeof opt.fullScreen === \"string\" ? `-${opt.fullScreen}` : \"\"),\n opt.centered && \"modal-dialog-centered\",\n opt.scrollable && \"modal-scrollable\"])\n .append(Fluent(\"div\")\n .class(\"modal-content\")\n .append(header)\n .append(this.el)\n .append(footer))\n .appendTo(modal);\n\n\n if (opt.buttons) {\n this.createBSButtons(footer, opt.buttons);\n }\n\n let modalOpt = {\n backdrop: opt.backdrop,\n keyboard: opt.closeOnEscape\n };\n\n if (opt.providerOptions)\n Object.assign(modalOpt, opt.providerOptions(\"bsmodal\", opt));\n\n if (bs5 && bootstrap.Modal) {\n var modalObj = new bootstrap.Modal(modal.getNode(), modalOpt);\n if (modalObj && modalObj._focustrap && modalObj._focustrap._handleFocusin) {\n var org: Function = modalObj._focustrap._handleFocusin;\n modalObj._focustrap._handleFocusin = function (event: Event) {\n if (event.target &&\n (event.target as any).closest('.ui-datepicker, .select2-drop, .cke, .cke_dialog, .flatpickr-calendar'))\n return;\n org.apply(this, arguments);\n }\n }\n }\n else {\n getjQuery()?.(modal.getNode())?.modal?.(modalOpt);\n };\n }\n\n private createPanel(opt: DialogOptions) {\n\n let titlebar = Fluent(\"div\")\n .class(\"panel-titlebar\")\n .append(Fluent(\"div\")\n .class(\"panel-titlebar-text\"));\n\n let panel = Fluent(\"div\")\n .class([\"s-Panel\", opt.dialogClass])\n .append(titlebar)\n\n this.el.classList.add(\"panel-body\");\n\n if (this.el.parentElement &&\n this.el.parentElement !== document.body) {\n this.el.parentElement.insertBefore(panel.getNode(), this.el);\n }\n\n panel.append(this.el);\n\n if (opt.closeButton) {\n Fluent(\"button\")\n .class(\"panel-titlebar-close\")\n .attr(\"type\", \"button\")\n .on(\"click\", this.close.bind(this, null))\n .appendTo(titlebar);\n }\n\n opt.buttons && this.createBSButtons(Fluent(\"div\")\n .class(\"panel-footer\")\n .appendTo(panel), opt.buttons);\n\n }\n\n createUIDialog(opt: DialogOptions): void {\n\n let uiOpt: any = {\n autoOpen: opt.autoOpen,\n dialogClass: opt.dialogClass,\n title: opt.title,\n modal: opt.modal,\n width: opt.width,\n resizable: false\n } as any;\n\n if (opt.centered)\n uiOpt.position = { my: 'center', at: 'center', of: window };\n\n if (opt.buttons) {\n uiOpt.buttons = opt.buttons.map(btn => {\n let uiButton = dialogButtonToUI(btn);\n uiButton.click = (e: MouseEvent) => this.onButtonClick(e, btn);\n return uiButton;\n });\n }\n\n if (opt.providerOptions)\n uiOpt = Object.assign(uiOpt, opt.providerOptions(\"uidialog\", omitUndefined(opt)));\n\n getjQuery()?.(this.el).dialog(uiOpt);\n }\n\n\n dispose(): void {\n try {\n let target = getDialogEventsNode(this.el);\n if (!target)\n return;\n\n try {\n if (target.classList.contains(\"ui-dialog-content\")) {\n getjQuery?.()(target)?.dialog?.('destroy');\n target.classList.remove(\"ui-dialog-content\");\n target = target.closest(\".ui-dialog\");\n }\n else if (target.classList.contains(\"modal\")) {\n if (!getjQuery() && isBS5Plus()) {\n if (typeof bootstrap !== \"undefined\")\n bootstrap.Modal?.getInstance(target)?.dispose?.();\n }\n else {\n getjQuery()?.(target)?.modal?.(isBS3() ? \"destroy\" : \"dispose\");\n }\n this.el?.classList.remove(\"modal-body\");\n }\n else {\n this.el?.classList.remove(\"panel-body\");\n target = target.closest(\".s-Panel\") ?? target;\n }\n }\n finally {\n Fluent.remove(target);\n }\n }\n finally {\n this.el = null;\n }\n }\n}\n\nexport function hasBSModal() {\n return isBS5Plus() || !!(getjQuery()?.fn?.modal);\n}\n\nexport function hasUIDialog() {\n return !!(getjQuery()?.ui?.dialog);\n}\n\nexport function uiAndBSButtonNoConflict() {\n const $ = getjQuery();\n\n // if both jQuery UI and bootstrap button exists, prefer jQuery UI button as UI dialog needs them\n if ($ && $.fn?.button?.noConflict && $.ui?.button) {\n $.fn.btn = $.fn.button.noConflict();\n }\n}\n\nuiAndBSButtonNoConflict();\n\nfunction dialogButtonToBS(x: DialogButton): HTMLButtonElement {\n let html = htmlEncode(x.text);\n let iconClass = iconClassName(x.icon);\n if (iconClass)\n html = '' + (html ? (\" \" + html) : \"\");\n let button = document.createElement(\"button\");\n button.type = \"button\";\n button.classList.add(\"btn\");\n Fluent.addClass(button, x.cssClass ?? \"btn-secondary\");\n if (x.hint)\n button.setAttribute(\"title\", x.hint);\n button.innerHTML = html;\n return button;\n}\n\nfunction dialogButtonToUI(x: DialogButton): any {\n let html = htmlEncode(x.text);\n let iconClass = iconClassName(x.icon);\n if (iconClass)\n html = '' + (html ? (\" \" + html) : \"\");\n let button = {\n text: html,\n click: x.click\n } as any;\n if (x.cssClass)\n button.cssClass = x.cssClass;\n return button;\n}\n\nexport function okDialogButton(opt?: DialogButton): DialogButton {\n return {\n text: opt?.text != void 0 ? opt.text : DialogTexts.OkButton,\n cssClass: opt?.cssClass != void 0 ? opt.cssClass : 'btn-info',\n result: opt?.result != void 0 ? opt.result : 'ok',\n click: opt?.click\n }\n}\n\nexport function yesDialogButton(opt?: DialogButton): DialogButton {\n return {\n text: opt?.text != void 0 ? opt.text : DialogTexts.YesButton,\n cssClass: opt?.cssClass != void 0 ? opt.cssClass : 'btn-primary',\n result: opt?.result != void 0 ? opt.result : 'yes',\n click: opt?.click\n }\n}\n\nexport function noDialogButton(opt?: DialogButton): DialogButton {\n return {\n text: opt?.text != void 0 ? opt.text : DialogTexts.NoButton,\n cssClass: opt?.cssClass != void 0 ? opt.cssClass : isBS5Plus() ? 'btn-danger' : 'btn-default',\n result: opt?.result != void 0 ? opt.result : 'no',\n click: opt?.click\n }\n}\n\nexport function cancelDialogButton(opt?: DialogButton): DialogButton {\n return {\n text: opt?.text != void 0 ? opt.text : DialogTexts.CancelButton,\n cssClass: opt?.cssClass != void 0 ? opt.cssClass : isBS5Plus() ? 'btn-secondary' : 'btn-default',\n result: 'cancel',\n click: opt?.click\n }\n}\n\nexport namespace DialogTexts {\n export declare const AlertTitle: string;\n export declare const CancelButton: string;\n export declare const CloseButton: string;\n export declare const ConfirmationTitle: string;\n export declare const InformationTitle: string;\n export declare const MaximizeHint: string;\n export declare const NoButton: string;\n export declare const OkButton: string;\n export declare const RestoreHint: string;\n export declare const SuccessTitle: string;\n export declare const WarningTitle: string;\n export declare const YesButton: string;\n\n const defaultTxt: Record = {\n AlertTitle: 'Alert',\n CancelButton: 'Cancel',\n CloseButton: 'Close',\n ConfirmationTitle: 'Confirm',\n InformationTitle: 'Information',\n MaximizeHint: 'Maximize',\n NoButton: 'No',\n OkButton: 'OK',\n RestoreHint: 'Restore',\n SuccessTitle: 'Success',\n WarningTitle: 'Warning',\n YesButton: 'Yes'\n };\n\n function get(this: string) {\n return htmlEncode(localText(\"Dialogs.\" + this, defaultTxt[this]));\n }\n\n for (let k of Object.keys(defaultTxt)) {\n Object.defineProperty(DialogTexts, k, {\n get: get.bind(k)\n });\n }\n}\n\nfunction closePanel(el: (HTMLElement | ArrayLike)) {\n\n let panel = getDialogNode(el);\n if (!panel || panel.classList.contains(\"hidden\"))\n return;\n\n var eventsNode = getDialogEventsNode(el) ?? panel;\n\n let event = Fluent.trigger(eventsNode, \"panelbeforeclose\");\n if (Fluent.isDefaultPrevented(event))\n return;\n panel.classList.add(\"hidden\");\n\n let uniqueName = panel.dataset.paneluniquename;\n if (uniqueName) {\n document.querySelectorAll(`[data-hiddenby=\"${uniqueName}\"]`).forEach(hiddenBy => {\n hiddenBy.removeAttribute(\"data-hiddenby\");\n });\n }\n\n Fluent.trigger(window, \"resize\");\n document.querySelectorAll(\".require-layout\").forEach((rl: HTMLElement) => Fluent.isVisibleLike(rl) && Fluent.trigger(rl, \"layout\"));\n Fluent.trigger(eventsNode, \"panelclose\");\n}\n\nfunction openPanel(element: HTMLElement | ArrayLike, uniqueName?: string) {\n\n let panel = getDialogNode(element);\n if (!panel)\n return;\n\n let container = panel.parentElement && panel.parentElement !== document.body ? panel.parentElement :\n (document.querySelector('.panels-container') ?? document.querySelector('section.content') as HTMLElement ?? panel.parentElement ?? document.body);\n\n if (panel.parentElement !== container) {\n container.appendChild(panel);\n }\n\n let eventNode = getDialogEventsNode(element) ?? panel;\n\n let event = Fluent.trigger(eventNode, \"panelbeforeopen\");\n if (Fluent.isDefaultPrevented(event))\n return;\n\n panel.dataset.paneluniquename = uniqueName || panel.id || new Date().getTime().toString();\n function setHideBy(e: HTMLElement) {\n if (e === panel ||\n e.tagName === \"LINK\" ||\n e.tagName === \"SCRIPT\" ||\n e.classList.contains(\"hidden\") ||\n e.dataset.hiddenby ||\n (container && e.parentElement !== container) && !Fluent.isVisibleLike(e))\n return;\n\n e.dataset.hiddenby = panel.dataset.paneluniquename;\n }\n\n if (container) {\n let c = container.children;\n const cl = c.length;\n for (let i = 0; i < cl; i++) {\n setHideBy(c[i] as HTMLElement);\n }\n }\n\n document.querySelectorAll('.ui-dialog, .ui-widget-overlay, .modal.show, .modal.in').forEach(setHideBy);\n\n panel.classList.remove(\"hidden\");\n delete panel.dataset.hiddenby;\n\n Fluent.trigger(eventNode, \"panelopen\");\n}\n\n/** Returns .s-Panel, .modal, .ui-dialog */\nfunction getDialogNode(element: HTMLElement | ArrayLike): HTMLElement {\n if (isArrayLike(element))\n element = element[0];\n if (!element)\n return null;\n return element.closest(\".modal, .s-Panel, .ui-dialog\");\n\n}\n\n/** Returns .panel-body, .modal, .ui-dialog-content */\nfunction getDialogEventsNode(element: HTMLElement | ArrayLike): HTMLElement {\n if (isArrayLike(element))\n element = element[0];\n if (!element)\n return null;\n return element.closest(\".modal, .panel-body, .ui-dialog-content\") as HTMLElement ??\n getDialogNode(element)?.querySelector(\".panel-body, .ui-dialog-content\");\n}\n\n/** Returns .panel-body, .modal, .ui-dialog-content */\nfunction getDialogContentNode(element: HTMLElement | ArrayLike): HTMLElement {\n if (isArrayLike(element))\n element = element[0];\n if (!element)\n return null;\n return element.closest(\".modal-body, .panel-body, .ui-dialog-content\") ??\n getDialogNode(element)?.querySelector(\".modal-body, .panel-body, .ui-dialog-content\");\n}\n\n/**\n * Options that apply to all message dialog types\n */\nexport interface MessageDialogOptions extends DialogOptions {\n /** HTML encode the message, default is true */\n htmlEncode?: boolean;\n /** Wrap the message in a `
` element, so that line endings are preserved, default is true */\n    preWrap?: boolean;\n}\n\nfunction getMessageBodyHtml(message: string, options?: MessageDialogOptions): string {\n    let encode = options == null || options.htmlEncode == null || options.htmlEncode;\n    if (encode)\n        message = htmlEncode(message);\n\n    let preWrap = options == null || (options.preWrap == null && encode) || options.preWrap;\n    return '
' : '>') + message + '
';\n}\n\nfunction createMessageDialog(opt: {\n cssClass: string,\n title: string,\n getButtons: () => DialogButton[],\n native: (msg: string) => string,\n message: string,\n options: MessageDialogOptions\n}): Partial {\n\n if (!hasBSModal() && !hasUIDialog()) {\n var result = opt.native(opt.message);\n opt.options?.onClose(result);\n return {\n result\n }\n }\n\n let options: MessageDialogOptions = Object.assign({}, Dialog.messageDefaults, {\n dialogClass: \"s-MessageDialog\" + (opt.cssClass ? \" \" + opt.cssClass : \"\"),\n title: opt.title\n } satisfies MessageDialogOptions, opt.options);\n\n if (options.buttons == void 0) {\n options.buttons = opt.getButtons();\n }\n\n if (options.providerOptions === void 0) {\n options.providerOptions = (type) => {\n if (type === \"uidialog\") {\n return {\n width: '40%',\n maxWidth: 450,\n minWidth: 180,\n resizable: false\n }\n }\n }\n }\n\n if (options.element === void 0) {\n options.element = el => el.innerHTML = getMessageBodyHtml(opt.message, options);\n }\n\n return new Dialog(options);\n}\n\n/** \n * Displays an alert dialog \n * @param message The message to display\n * @param options Additional options. \n * @see AlertOptions \n * @example \n * alertDialog(\"An error occured!\"); }\n */\nexport function alertDialog(message: string, options?: MessageDialogOptions): Partial {\n return createMessageDialog({\n message,\n options,\n cssClass: \"s-AlertDialog\",\n title: DialogTexts.AlertTitle,\n getButtons: () => [okDialogButton({ cssClass: 'btn-danger' })],\n native: (msg) => {\n alert(msg);\n return \"ok\";\n }\n });\n}\n\n/** Additional options for confirm dialog */\nexport interface ConfirmDialogOptions extends MessageDialogOptions {\n /** True to also add a cancel button */\n cancelButton?: boolean;\n /** Event handler for cancel button click */\n onCancel?: () => void;\n /** Event handler for no button click */\n onNo?: () => void;\n}\n\n/** \n * Display a confirmation dialog \n * @param message The message to display\n * @param onYes Callback for Yes button click \n * @param options Additional options. \n * @see ConfirmOptions \n * @example \n * confirmDialog(\"Are you sure you want to delete?\", () => { \n * // do something when yes is clicked\n * }\n */\nexport function confirmDialog(message: string, onYes: () => void, options?: ConfirmDialogOptions): Partial {\n return createMessageDialog({\n message,\n options,\n cssClass: \"s-ConfirmDialog\",\n title: DialogTexts.ConfirmationTitle,\n getButtons: () => {\n let buttons = [yesDialogButton({ click: onYes }), noDialogButton({ click: options?.onNo })];\n if (options?.cancelButton)\n buttons.push(cancelDialogButton({ click: options?.onCancel }));\n return buttons;\n },\n native: (msg) => {\n var result = window.confirm(msg);\n if (result) {\n onYes?.();\n return 'yes';\n }\n else {\n options?.onNo();\n return result === false ? \"no\" : \"\";\n }\n }\n });\n}\n\n/** \n * Display an information dialog \n * @param message The message to display\n * @param onOk Callback for OK button click \n * @param options Additional options. \n * @see ConfirmOptions \n * @example \n * informationDialog(\"Operation complete\", () => { \n * // do something when OK is clicked\n * }\n */\nexport function informationDialog(message: string, onOk?: () => void, options?: MessageDialogOptions): Partial {\n return createMessageDialog({\n message,\n options,\n cssClass: \"s-InformationDialog\",\n title: DialogTexts.InformationTitle,\n getButtons: () => [okDialogButton({ click: onOk, cssClass: 'btn-info' })],\n native: (msg) => {\n alert(msg);\n onOk?.();\n return \"ok\";\n }\n });\n}\n\n/** \n * Display a success dialog \n * @param message The message to display\n * @param onOk Callback for OK button click \n * @param options Additional options. \n * @see MessageDialogOptions \n * @example \n * successDialog(\"Operation complete\", () => { \n * // do something when OK is clicked\n * }\n */\nexport function successDialog(message: string, onOk?: () => void, options?: MessageDialogOptions): Partial {\n return createMessageDialog({\n message,\n options,\n cssClass: \"s-SuccessDialog\",\n title: DialogTexts.SuccessTitle,\n getButtons: () => [okDialogButton({ click: onOk, cssClass: 'btn-success' })],\n native: (msg) => {\n alert(msg);\n onOk?.();\n return \"ok\";\n }\n });\n}\n\n/** \n * Display a warning dialog \n * @param message The message to display\n * @param options Additional options. \n * @see MessageDialogOptions \n * @example \n * warningDialog(\"Something is odd!\");\n */\nexport function warningDialog(message: string, options?: MessageDialogOptions): Partial {\n return createMessageDialog({\n message,\n options,\n cssClass: \"s-WarningDialog\",\n title: DialogTexts.WarningTitle,\n getButtons: () => [okDialogButton({ cssClass: 'btn-warning' })],\n native: (msg) => {\n alert(msg);\n return \"ok\";\n }\n });\n}\n\n/** Options for `iframeDialog` **/\nexport interface IFrameDialogOptions {\n html?: string;\n}\n\n/** \n * Display a dialog that shows an HTML block in an IFRAME, which is usually returned from server callbacks\n * @param options The options\n */\nexport function iframeDialog(options: IFrameDialogOptions): Partial {\n\n if (!hasBSModal() && !hasUIDialog()) {\n window.alert(options.html);\n return {\n result: \"ok\"\n }\n }\n\n let doc: Document;\n function onOpen(div: HTMLElement) {\n if (div) {\n let iframe = div.appendChild(document.createElement('iframe'));\n iframe.setAttribute(\"style\", \"border: none; width: 100%; height: 100%;\");\n doc = iframe.contentDocument;\n if (doc) {\n doc.open();\n doc.write(options.html);\n doc.close();\n }\n }\n }\n\n return new Dialog({\n title: DialogTexts.AlertTitle,\n dialogClass: \"s-IFrameDialog\",\n size: \"lg\",\n autoOpen: true,\n element: el => {\n let div = document.createElement(\"div\");\n div.style.overflow = \"hidden\";\n el.append(div);\n onOpen(div);\n },\n providerOptions: (type) => {\n if (type == \"uidialog\") {\n return {\n width: '60%',\n height: '400'\n }\n }\n }\n });\n}\n\nconst modalShow = (e: Event) => {\n var body = Dialog.getInstance(e.target as HTMLElement)?.getContentNode();\n if (body) {\n var evt = Fluent.trigger(body, \"modalbeforeopen\");\n if (Fluent.isDefaultPrevented(evt))\n e.preventDefault();\n }\n}\n\nconst modalShown = (e: Event) => {\n var body = Dialog.getInstance(e.target as HTMLElement)?.getContentNode();\n if (body) {\n Fluent.trigger(body, \"modalopen\");\n }\n}\n\nconst modalHide = (e: Event) => {\n var body = Dialog.getInstance(e.target as HTMLElement)?.getContentNode();\n if (body) {\n var evt = Fluent.trigger(body, \"modalbeforeclose\");\n if (Fluent.isDefaultPrevented(evt))\n e.preventDefault();\n }\n}\n\nconst modalHidden = (e: Event) => {\n var body = Dialog.getInstance(e.target as HTMLElement)?.getContentNode();\n if (body) {\n Fluent.trigger(body, \"modalclose\");\n }\n}\n\nfunction installBsModalEventPropagation() {\n uninstallBsModalEventPropagation();\n if (typeof document === \"undefined\" || typeof document.addEventListener !== \"function\")\n return;\n document.addEventListener(\"show.bs.modal\", modalShow);\n document.addEventListener(\"shown.bs.modal\", modalShown);\n document.addEventListener(\"hide.bs.modal\", modalHide);\n document.addEventListener(\"hidden.bs.modal\", modalHidden);\n}\n\nfunction uninstallBsModalEventPropagation() {\n if (typeof document === \"undefined\" || typeof document.removeEventListener !== \"function\")\n return;\n document.removeEventListener(\"show.bs.modal\", modalShow);\n document.removeEventListener(\"shown.bs.modal\", modalShown);\n document.removeEventListener(\"hide.bs.modal\", modalHide);\n document.removeEventListener(\"hidden.bs.modal\", modalHidden);\n}\n\ninstallBsModalEventPropagation();","import { addClass, htmlEncode } from \"./html\";\n\n// adapted from https://github.com/JPeer264/toastr2\nexport type ToastContainerOptions = {\n containerId?: string;\n positionClass?: string;\n target?: string;\n}\n\nexport type ToastrOptions = ToastContainerOptions & {\n tapToDismiss?: boolean;\n toastClass?: string;\n showDuration?: number;\n onShown?: () => void;\n hideDuration?: number;\n onHidden?: () => void;\n closeMethod?: boolean;\n closeDuration?: number | false;\n closeEasing?: boolean;\n closeOnHover?: boolean;\n extendedTimeOut?: number;\n iconClass?: string;\n positionClass?: string;\n timeOut?: number; // Set timeOut and extendedTimeOut to 0 to make it sticky\n titleClass?: string;\n messageClass?: string;\n escapeHtml?: boolean;\n target?: string;\n closeHtml?: string;\n closeClass?: string;\n newestOnTop?: boolean;\n preventDuplicates?: boolean;\n onclick?: (event: MouseEvent) => void;\n onCloseClick?: (event: Event) => void;\n closeButton?: boolean;\n rtl?: boolean;\n}\n\nexport type NotifyMap = {\n type: string;\n iconClass: string;\n title?: string;\n message?: string;\n}\n\nconst initialOptions: ToastrOptions = {\n tapToDismiss: true,\n toastClass: 'toast',\n containerId: 'toast-container',\n showDuration: 300,\n onShown: () => { },\n hideDuration: 1000,\n onHidden: () => { },\n closeMethod: false,\n closeDuration: false,\n closeEasing: false,\n closeOnHover: true,\n extendedTimeOut: 1000,\n iconClass: 'toast-info',\n positionClass: 'toast-top-right',\n timeOut: 5000, // Set timeOut and extendedTimeOut to 0 to make it sticky\n titleClass: 'toast-title',\n messageClass: 'toast-message',\n escapeHtml: true,\n target: 'body',\n closeHtml: '',\n closeClass: 'toast-close-button',\n newestOnTop: true,\n preventDuplicates: false,\n rtl: false,\n onCloseClick: () => { },\n closeButton: false,\n onclick: () => { },\n}\n\nvar initialInstance: Toastr = null;\n\nexport class Toastr {\n private listener: any;\n\n private toastId = 0;\n\n private previousToast: string | null = null;\n\n public options: ToastrOptions;\n\n public constructor(options?: ToastrOptions) {\n this.options = Object.assign(Object.assign({}, initialInstance?.options ?? initialOptions), options);\n }\n\n public getContainer(options?: ToastContainerOptions, create = false): HTMLElement {\n let container = document.getElementById(options?.containerId ?? this.options.containerId);\n if (container || !create)\n return container;\n\n container = document.createElement('div');\n\n container.setAttribute('id', this.options.containerId);\n let positionClass = options?.positionClass ?? this.options.positionClass;\n if (positionClass)\n addClass(container, positionClass);\n\n let targetSelector = options?.target ?? this.options.target;\n const target = document.querySelector(targetSelector);\n if (target)\n target.appendChild(container);\n \n return container; \n }\n\n public error(\n message?: string,\n title?: string,\n opt?: ToastrOptions,\n ): HTMLElement | null {\n return this.notify({\n type: 'error',\n iconClass: 'toast-error',\n message,\n title,\n }, opt);\n }\n\n public warning(\n message?: string,\n title?: string,\n opt?: ToastrOptions,\n ): HTMLElement | null {\n return this.notify({\n type: 'warning',\n iconClass: 'toast-warning',\n message,\n title,\n }, opt);\n }\n\n public success(\n message?: string,\n title?: string,\n opt?: ToastrOptions,\n ): HTMLElement | null {\n return this.notify({\n type: 'success',\n iconClass: 'toast-success',\n message,\n title,\n }, opt);\n }\n\n public info(\n message?: string,\n title?: string,\n opt?: ToastrOptions,\n ): HTMLElement | null {\n return this.notify({\n type: 'info',\n iconClass: 'toast-info',\n message,\n title,\n }, opt);\n }\n\n public subscribe(callback: (response: Toastr) => void): void {\n this.listener = callback;\n }\n\n public publish(args: Toastr): void {\n if (!this.listener) {\n return;\n }\n\n this.listener(args);\n }\n\n private removeContainerIfEmpty(options?: ToastrOptions) {\n let container = this.getContainer(options);\n if (!container)\n return;\n if (!container.hasChildNodes?.() && container.parentNode)\n container.parentNode.removeChild(container);\n }\n\n public removeToast(toastElement: HTMLElement, options?: ToastContainerOptions) {\n if (!toastElement)\n return;\n\n if (toastElement !== document.activeElement) {\n toastElement.parentNode?.removeChild(toastElement);\n this.previousToast = null;\n this.removeContainerIfEmpty(options);\n }\n }\n\n public clear(options?: ToastContainerOptions) {\n let container = this.getContainer(options);\n if (!container)\n return;\n\n const toastsToClear = Array.from(container.childNodes) as HTMLElement[];\n for (let i = toastsToClear.length - 1; i >= 0; i -= 1)\n this.removeToast(toastsToClear[i], options);\n\n this.removeContainerIfEmpty();\n }\n\n private notify(map: NotifyMap, opt: ToastrOptions): HTMLElement | null {\n opt = Object.assign(Object.assign(Object.assign({}, this.options), map), opt);\n\n const shouldExit = (opts: ToastrOptions, exitMap: NotifyMap): boolean => {\n if (opts.preventDuplicates) {\n if (exitMap.message === this.previousToast) {\n return true;\n }\n\n this.previousToast = exitMap.message || '';\n }\n return false;\n };\n\n\n if (shouldExit(opt, map)) {\n return null;\n }\n\n this.toastId += 1;\n\n var container = this.getContainer(opt, true);\n\n let intervalId: number = null;\n const toastElement = document.createElement('div');\n const $titleElement = document.createElement('div');\n const $messageElement = document.createElement('div');\n const closeContainer = document.createElement('div');\n closeContainer.innerHTML = opt.closeHtml.trim();\n const closeElement = closeContainer.firstChild as HTMLElement | null;\n\n const response: any = {\n toastId: this.toastId,\n state: 'visible',\n startTime: new Date(),\n endTime: undefined,\n opt,\n map,\n };\n\n const hideToast = (override: any = null): void => {\n if (toastElement === document.activeElement && !override) {\n return;\n }\n\n this.removeToast(toastElement);\n\n if (intervalId) {\n clearTimeout(intervalId);\n }\n\n if (opt.onHidden && response.state !== 'hidden') {\n opt.onHidden();\n }\n\n response.state = 'hidden';\n response.endTime = new Date();\n this.publish(response);\n };\n\n const setAria = (): void => {\n let ariaValue = '';\n\n switch (opt.iconClass) {\n case 'toast-success':\n case 'toast-info':\n ariaValue = 'polite';\n\n break;\n\n default:\n ariaValue = 'assertive';\n }\n\n toastElement.setAttribute('aria-live', ariaValue);\n };\n\n const delayedHideToast = (): void => {\n if (opt.timeOut > 0 || opt.extendedTimeOut > 0) {\n intervalId = setTimeout(hideToast, opt.extendedTimeOut);\n }\n };\n\n const stickAround = (): void => {\n if (intervalId) {\n clearTimeout(intervalId);\n }\n };\n\n const handleEvents = (): void => {\n if (opt.closeOnHover) {\n toastElement.addEventListener('mouseover', () => stickAround());\n toastElement.addEventListener('mouseout', () => delayedHideToast());\n }\n\n if (!opt.onclick && opt.tapToDismiss) {\n toastElement.addEventListener('click', hideToast);\n }\n\n if (opt.closeButton && closeElement) {\n closeElement.addEventListener('click', (event) => {\n event.stopPropagation();\n\n if (opt.onCloseClick) {\n opt.onCloseClick(event);\n }\n\n hideToast(true);\n });\n }\n\n if (opt.onclick) {\n toastElement.addEventListener('click', (event) => {\n // ts needs another check here\n if (opt.onclick) {\n opt.onclick(event);\n }\n\n if (opt.tapToDismiss)\n hideToast();\n });\n }\n };\n\n const setTitle = (): void => {\n if (map.title) {\n let suffix = map.title;\n if (opt.escapeHtml) {\n suffix = htmlEncode(map.title);\n }\n $titleElement.innerHTML = suffix;\n addClass($titleElement, opt.titleClass);\n toastElement.appendChild($titleElement);\n }\n };\n\n const setMessage = (): void => {\n if (map.message) {\n let suffix = map.message;\n\n if (opt.escapeHtml) {\n suffix = htmlEncode(map.message);\n }\n\n $messageElement.innerHTML = suffix;\n addClass($messageElement, opt.messageClass);\n toastElement.appendChild($messageElement);\n }\n };\n\n const setCloseButton = (): void => {\n if (opt.closeButton && closeElement) {\n addClass(closeElement, opt.closeClass);\n closeElement.setAttribute('role', 'button');\n toastElement.insertBefore(closeElement, toastElement.firstChild);\n }\n };\n\n const setSequence = (): void => {\n if (opt.newestOnTop) {\n container.insertBefore(toastElement, container.firstChild);\n } else {\n container.appendChild(toastElement);\n }\n };\n\n const displayToast = (): void => {\n if (opt.onShown) {\n opt.onShown();\n }\n\n if (opt.timeOut > 0) {\n intervalId = setTimeout(hideToast, opt.timeOut);\n\n }\n };\n\n const personalizeToast = (): void => {\n toastElement.classList.add('show');\n opt.rtl && toastElement.classList.add('rtl');\n opt.toastClass && addClass(toastElement, opt.toastClass);\n opt.iconClass && addClass(toastElement, opt.iconClass);\n setTitle();\n setMessage();\n setCloseButton();\n setSequence();\n setAria();\n };\n\n personalizeToast();\n displayToast();\n handleEvents();\n this.publish(response);\n return toastElement;\n }\n}\n\ninitialInstance = new Toastr();\n\nexport default initialInstance;\n","import toastr, { type ToastrOptions } from \"./toastr2\";\n\nexport let defaultNotifyOptions: ToastrOptions = {\n timeOut: 3000,\n showDuration: 250,\n hideDuration: 500,\n escapeHtml: true,\n extendedTimeOut: 500,\n positionClass: 'position-toast toast-top-full-width'\n}\n\nexport function positionToastContainer(options?: ToastrOptions, create = true) {\n let container = toastr.getContainer(options, create);\n if (!container || !container.classList.contains('position-toast') || typeof document === \"undefined\" || !document.body)\n return;\n\n let dialogs = Array.from(document.body.children);\n let dialogIndex = dialogs.findIndex(x => x.matches('.ui-dialog, .modal.in, .modal.show') && !x.matches('[style*=\"display:none\"], [style*=\"display: none\"], .hidden'));\n let dialog = dialogs[dialogIndex];\n if (dialog) {\n const { top, left, right } = dialog.getBoundingClientRect();\n container.classList.add('positioned-toast');\n container.style.position = 'absolute';\n container.style.top = top + 28 + 'px';\n container.style.left = left + 6 + 'px';\n container.style.width = Math.max(((right - left) - 12), 150) + 'px';\n }\n else if (container.classList.contains('positioned-toast')) {\n container.classList.remove('positioned-toast');\n container.style.position = '';\n container.style.top = '';\n container.style.left = '';\n container.style.width = '';\n }\n}\n\nfunction getToastrOptions(options: ToastrOptions) {\n options = Object.assign(Object.assign({}, defaultNotifyOptions), options);\n positionToastContainer(options);\n return options;\n}\n\nfunction showToast(type: \"error\" | \"info\" | \"success\" | \"warning\", message: string, title?: string, options?: ToastrOptions) {\n return toastr[type](message, title, getToastrOptions(options));\n}\n\nexport function notifyError(message: string, title?: string, options?: ToastrOptions): void {\n showToast('error', message, title, options);\n}\n\nexport function notifyInfo(message: string, title?: string, options?: ToastrOptions): void {\n showToast('info', message, title, options);\n}\n\nexport function notifySuccess(message: string, title?: string, options?: ToastrOptions): void {\n showToast('success', message, title, options);\n}\n\nexport function notifyWarning(message: string, title?: string, options?: ToastrOptions): void {\n showToast('warning', message, title, options);\n}","import { alertDialog, iframeDialog } from \"./dialogs\";\nimport { htmlEncode } from \"./html\";\nimport { notifyError } from \"./notify\";\nimport { RequestErrorInfo, ServiceError } from \"./servicetypes\";\n\nexport namespace ErrorHandling {\n\n /**\n * Shows a service error as an alert dialog. If the error\n * is null, has no message or code, it shows \"??ERROR??\".\n */\n export function showServiceError(error: ServiceError, errorInfo?: RequestErrorInfo) {\n \n if (error || !errorInfo) {\n alertDialog(error?.Message ?? error?.Code ?? \"??ERROR??\");\n return;\n }\n\n if (!errorInfo?.responseText) {\n if (!errorInfo?.status) {\n if (errorInfo?.statusText != \"abort\")\n alertDialog(\"An unknown AJAX connection error occurred! Check browser console for details.\");\n }\n else if (errorInfo?.status == 500)\n alertDialog(\"HTTP 500: Connection refused! Check browser console for details.\");\n else\n alertDialog(\"HTTP \" + errorInfo?.status + ' error! Check browser console for details.');\n }\n else\n iframeDialog({ html: errorInfo.responseText });\n }\n\n /**\n * Runtime error handler that shows a runtime error as a notification\n * by default only in development mode (@see isDevelopmentMode)\n * This function is assigned as window.onerror handler in \n * ScriptInit.ts for Serenity applications so that developers\n * can notice an error without having to check the browser console.\n */\n export function runtimeErrorHandler(message: string, filename?: string,\n lineno?: number, colno?: number, error?: Error) {\n try {\n if (!ErrorHandling.isDevelopmentMode())\n return;\n var errorInfo = error?.stack ?? error?.toString();\n\n message =\n '

Message: ' + htmlEncode(message) +\n '

File: ' + htmlEncode(filename) +\n ', Line: ' + lineno + ', Column: ' + colno +\n (errorInfo ? ('

' + htmlEncode(errorInfo)) : \"\") + '

';\n\n window.setTimeout(function () {\n try {\n notifyError(message, \"SCRIPT ERROR! See browser console (F12) for details.\", {\n escapeHtml: false,\n timeOut: 15000\n });\n }\n catch {\n }\n }, 0);\n }\n catch {\n }\n }\n\n /** \n * Determines if the current environment is development mode.\n * The runtimeErrorHandler (window.onerror) shows error notifications only\n * when this function returns true. The default implementation considers \n * the environment as development mode if the host is localhost, 127.0.0.1, ::1,\n * or a domain name that ends with .local/.localhost.\n * @returns true if the current environment is development mode, false otherwise. \n */\n export function isDevelopmentMode() {\n var hostname = (window.location.hostname ?? \"\").toLowerCase();\n return (hostname === \"localhost\" ||\n hostname === \"127.0.0.1\" ||\n hostname === \"[::1]\" ||\n hostname.endsWith(\".local\") ||\n hostname.endsWith(\".localhost\"));\n }\n}","/**\n * Interface for number formatting, similar to .NET's NumberFormatInfo\n */\nexport interface NumberFormat {\n /** Decimal separator */\n decimalSeparator: string;\n /** Group separator */\n groupSeparator?: string;\n /** Number of digits after decimal separator */\n decimalDigits?: number;\n /** Positive sign */\n positiveSign?: string;\n /** Negative sign */\n negativeSign?: string;\n /** Zero symbol */\n nanSymbol?: string;\n /** Percentage symbol */\n percentSymbol?: string;\n /** Currency symbol */\n currencySymbol?: string;\n}\n\n/** Interface for date formatting, similar to .NET's DateFormatInfo */\nexport interface DateFormat {\n /** Date separator */\n dateSeparator?: string;\n /** Default date format string */\n dateFormat?: string;\n /** Date order, like dmy, or ymd */\n dateOrder?: string;\n /** Default date time format string */\n dateTimeFormat?: string;\n /** AM designator */\n amDesignator?: string;\n /** PM designator */\n pmDesignator?: string;\n /** Time separator */\n timeSeparator?: string;\n /** First day of week, 0 = Sunday, 1 = Monday */\n firstDayOfWeek?: number;\n /** Array of day names */\n dayNames?: string[];\n /** Array of short day names */\n shortDayNames?: string[];\n /** Array of two letter day names */\n minimizedDayNames?: string[];\n /** Array of month names */\n monthNames?: string[];\n /** Array of short month names */\n shortMonthNames?: string[];\n}\n\n/** Interface for a locale, similar to .NET's CultureInfo */\nexport interface Locale extends NumberFormat, DateFormat {\n /** Locale string comparison function, similar to .NET's StringComparer */\n stringCompare?: (a: string, b: string) => number;\n /** Locale string to upper case function */\n toUpper?: (a: string) => string;\n}\n\n/** Invariant locale (e.g. CultureInfo.InvariantCulture) */\nexport let Invariant: Locale = {\n decimalSeparator: '.',\n groupSeparator: ',',\n decimalDigits: 2,\n negativeSign: '-',\n positiveSign: '+',\n percentSymbol: '%',\n currencySymbol: '$',\n dateSeparator: '/',\n dateOrder: 'mdy',\n dateFormat: 'MM/dd/yyyy',\n dateTimeFormat: 'MM/dd/yyyy HH:mm:ss',\n amDesignator: 'AM',\n pmDesignator: 'PM',\n timeSeparator: ':',\n firstDayOfWeek: 0,\n dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],\n shortDayNames: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],\n minimizedDayNames: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'],\n monthNames: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December', ''],\n shortMonthNames: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec', ''],\n stringCompare: (a, b) => a < b ? -1 : (a > b ? 1 : 0)\n}\n\n/** \n * Factory for a function that compares two strings, based on a character order \n * passed in the `order` argument.\n */\nexport function compareStringFactory(order: string): ((a: string, b: string) => number) {\n\n var o: { [key: string]: number } = {};\n for (let z = 0; z < order.length; z++) {\n o[order.charAt(z)] = z + 1;\n }\n\n return function (a: string, b: string) {\n a = a || \"\";\n b = b || \"\";\n if (a == b)\n return 0;\n\n let c: number;\n for (let i = 0, _len = Math.min(a.length, b.length); i < _len; i++) {\n let x = a.charAt(i), y = b.charAt(i);\n if (x === y) {\n continue;\n }\n let ix = o[x], iy = o[y];\n if (ix != null && iy != null)\n return ix < iy ? -1 : 1;\n c = x.localeCompare(y);\n if (c == 0)\n continue;\n return c;\n }\n if (c != null)\n return c;\n return a.localeCompare(b);\n }\n}\n\n/**\n * Current culture, e.g. CultureInfo.CurrentCulture. This is overridden by\n * settings passed from a `