jsf.js_next_gen
Version:
A next generation typescript reimplementation of jsf.js
264 lines • 11.8 kB
JavaScript
;
/*! Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to you under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExtLang = void 0;
const mona_dish_1 = require("mona-dish");
const Messages_1 = require("../i18n/Messages");
const Const_1 = require("../core/Const");
const RequestDataResolver_1 = require("../xhrCore/RequestDataResolver");
const mona_dish_2 = require("mona-dish");
var ExtLang;
(function (ExtLang) {
let installedLocale;
let nameSpace = "impl/util/Lang/";
function getLanguage() {
//TODO global config override
var _a, _b;
let language = (_b = (_a = navigator.languages) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : navigator === null || navigator === void 0 ? void 0 : navigator.language;
language = language.split("-")[0];
return language;
}
ExtLang.getLanguage = getLanguage;
//should be in lang, but for now here to avoid recursive imports, not sure if typescript still has a problem with those
/**
* helper function to safely resolve anything
* this is not an elvis operator, it resolves
* a value without exception in a tree and if
* it is not resolvable then an optional of
* a default value is restored or Optional\.empty
* if none is given
*
* usage
* <code>
* let var: Optional<string> = saveResolve(() => a.b.c.d.e, "foobaz")
* </code>
*
* @param resolverProducer a lambda which can produce the value
* @param defaultValue an optional default value if the producer fails to produce anything
* @returns an Optional of the produced value
*/
function failSaveResolve(resolverProducer, defaultValue = null) {
return mona_dish_1.Lang.saveResolve(resolverProducer, defaultValue);
}
ExtLang.failSaveResolve = failSaveResolve;
/**
* under some conditions it makes sense to swallow errors and return a default value in the error case
* classical example the optional resolution of values in a chain (thankfully now covered by Typescript itself)
* another example which we have in our system is that some operations fail only under test due to test framework
* limitations while they cannot fail in the real world.
*
* @param resolverProducer a producer function which produces a value in the non error case
* @param defaultValue the default value in case of a fail of the function
*/
function failSaveExecute(resolverProducer, defaultValue = null) {
mona_dish_1.Lang.saveResolve(resolverProducer, defaultValue);
}
ExtLang.failSaveExecute = failSaveExecute;
/**
* returns a given localized message upon a given key
* basic java log like templating functionality is included
*
* @param key the key for the message
* @param defaultMessage optional default message if none was found
*
* Additionally, you can pass additional arguments, which are used
* in the same way java log templates use the params
*
* @param templateParams the param list to be filled in
*/
function getMessage(key, defaultMessage, ...templateParams) {
var _a, _b;
installedLocale = installedLocale !== null && installedLocale !== void 0 ? installedLocale : new Messages_1.Messages();
let msg = (_b = (_a = installedLocale[key]) !== null && _a !== void 0 ? _a : defaultMessage) !== null && _b !== void 0 ? _b : key;
templateParams.forEach((param, cnt) => {
msg = msg.replace(new RegExp(["\\{", cnt, "\\}"].join(Const_1.EMPTY_STR), "g"), param);
});
return msg;
}
ExtLang.getMessage = getMessage;
/**
* transforms a key value pair into a string
* @param key the key
* @param val the value
* @param delimiter the delimiter
*/
function keyValToStr(key, val, delimiter = "\n") {
return [key, val].join(delimiter);
}
ExtLang.keyValToStr = keyValToStr;
/**
* creates an exception with additional internal parameters
* for extra information
*
* @param error
* @param title the exception title
* @param name the exception name
* @param callerCls the caller class
* @param callFunc the caller function
* @param message the message for the exception
*/
function makeException(error, title, name, callerCls, callFunc, message) {
var _a;
return new Error((_a = message + (callerCls !== null && callerCls !== void 0 ? callerCls : nameSpace) + callFunc) !== null && _a !== void 0 ? _a : (Const_1.EMPTY_STR + arguments.caller.toString()));
}
ExtLang.makeException = makeException;
/**
* fetches a global config entry
* @param configName the name of the configuration entry
* @param defaultValue
*
* @return either the config entry or if none is given the default value
*/
function getGlobalConfig(configName, defaultValue) {
var _a, _b, _c;
/**
* note we could use exists but this is a heavy operation, since the config name usually
* given this function here is called very often
* is a single entry without . in between we can do the lighter shortcut
*/
return (_c = (_b = (_a = window === null || window === void 0 ? void 0 : window.myfaces) === null || _a === void 0 ? void 0 : _a.config) === null || _b === void 0 ? void 0 : _b[configName]) !== null && _c !== void 0 ? _c : defaultValue;
}
ExtLang.getGlobalConfig = getGlobalConfig;
/**
* fetches the form in a fuzzy manner depending
* on an element or event target.
*
* The idea is that according to the jsf spec
* the enclosing form of the issuing element needs to be fetched.
*
* This is fine, but since then html5 came into the picture with the form attribute the element
* can be anywhere referencing its parent form.
*
* Also, theoretically you can have the case of an issuing element enclosing a set of forms
* (not really often used, but theoretically it could be input button allows to embed html for instance)
*
* So the idea is not to limit the issuing form determination to the spec case
* but also cover the theoretical and html5 corner case.
*
* @param elem
* @param event
*/
function getForm(elem, event) {
let queryElem = new mona_dish_1.DQ(elem);
let eventTarget = (event) ? new mona_dish_1.DQ((0, RequestDataResolver_1.getEventTarget)(event)) : mona_dish_1.DomQuery.absent;
if (queryElem.isTag(Const_1.HTML_TAG_FORM)) {
return queryElem;
}
//html 5 for handling
if (queryElem.attr(Const_1.HTML_TAG_FORM).isPresent()) {
let formId = queryElem.attr(Const_1.HTML_TAG_FORM).value;
let foundForm = mona_dish_1.DQ.byId(formId, true);
if (foundForm.isPresent()) {
return foundForm;
}
}
//no direct form is found we look for parent/child relationships as fallback
//(90% case)
let form = queryElem.firstParent(Const_1.HTML_TAG_FORM)
.orElseLazy(() => queryElem.byTagName(Const_1.HTML_TAG_FORM, true))
.orElseLazy(() => eventTarget.firstParent(Const_1.HTML_TAG_FORM))
.orElseLazy(() => eventTarget.byTagName(Const_1.HTML_TAG_FORM))
.first();
//either a form is found within parent child - nearest form (aka first)
//or we look for a single form
form = form.orElseLazy(() => mona_dish_1.DQ.byTagName(Const_1.HTML_TAG_FORM));
//the end result must be a found form otherwise - Exception
assertOnlyOneFormExists(form);
return form;
}
ExtLang.getForm = getForm;
/**
* gets the local or global options with local ones having higher priority
* if no local or global one was found then the default value is given back
*
* @param configName the name of the configuration entry
* @param localOptions the local options root for the configuration myfaces as default marker is added
* implicitly
*
* @param defaultValue
*
* @return either the config entry or if none is given the default value
*/
function getLocalOrGlobalConfig(localOptions, configName, defaultValue) {
var _a, _b, _c, _d, _e, _f, _g;
return (_g = (_d = (_c = (_b = (_a = localOptions.value) === null || _a === void 0 ? void 0 : _a.myfaces) === null || _b === void 0 ? void 0 : _b.config) === null || _c === void 0 ? void 0 : _c[configName]) !== null && _d !== void 0 ? _d : (_f = (_e = window === null || window === void 0 ? void 0 : window.myfaces) === null || _e === void 0 ? void 0 : _e.config) === null || _f === void 0 ? void 0 : _f[configName]) !== null && _g !== void 0 ? _g : defaultValue;
}
ExtLang.getLocalOrGlobalConfig = getLocalOrGlobalConfig;
/**
* expands an associative array into an array of key value tuples
* @param value
*/
function ofAssoc(value) {
return new mona_dish_2.Es2019Array(...Object.keys(value))
.map(key => [key, value[key]]);
}
ExtLang.ofAssoc = ofAssoc;
function collectAssoc(target, item) {
target[item[0]] = item[1];
return target;
}
ExtLang.collectAssoc = collectAssoc;
/**
* The active timeout for the "debounce".
* Since we only use it in the XhrController
* we can use a local module variable here
*/
let activeTimeouts = {};
/**
* a simple debounce function
* which waits until a timeout is reached and
* if something comes in in between debounces
*
* @param runnable a runnable which should go under debounce control
* @param timeout a timeout for the debounce window
*/
function debounce(key, runnable, timeout) {
function clearActiveTimeout() {
clearTimeout(activeTimeouts[key]);
delete activeTimeouts[key];
}
if (!!(activeTimeouts === null || activeTimeouts === void 0 ? void 0 : activeTimeouts[key])) {
clearActiveTimeout();
}
if (timeout > 0) {
activeTimeouts[key] = setTimeout(() => {
try {
runnable();
}
finally {
clearActiveTimeout();
}
}, timeout);
}
else {
runnable();
}
}
ExtLang.debounce = debounce;
/**
* assert that the form exists and only one form exists and throw an exception in the case it does not
*
* @param forms the form to check for
*/
function assertOnlyOneFormExists(forms) {
if (forms.isAbsent() || forms.length > 1) {
throw makeException(new Error(), null, null, "Impl", "getForm", getMessage("ERR_FORM"));
}
}
})(ExtLang || (exports.ExtLang = ExtLang = {}));
//# sourceMappingURL=Lang.js.map