port js services to class syntax and move to static/es
This commit is contained in:
parent
6f2b887b01
commit
f6c0ddf45c
43
static/es/services/htmlHelpers.js
Normal file
43
static/es/services/htmlHelpers.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
class HtmlHelpers {
|
||||||
|
|
||||||
|
// `parseResponse` takes a raw HttpClient response and an options object.
|
||||||
|
// Returns an object with `element` being an contextual fragment of the
|
||||||
|
// HTML in the response and `ifPrefix` being the prefix that was used to
|
||||||
|
// "unique-ify" the ids of the received HTML.
|
||||||
|
// Original Response IDs can optionally be kept by adding `keepIds: true`
|
||||||
|
// to the `options` object.
|
||||||
|
parseResponse(response, options = {}) {
|
||||||
|
return response.text()
|
||||||
|
.then(
|
||||||
|
(responseText) => {
|
||||||
|
const docFrag = document.createRange().createContextualFragment(responseText);
|
||||||
|
let idPrefix;
|
||||||
|
if (!options.keepIds) {
|
||||||
|
idPrefix = this._getIdPrefix();
|
||||||
|
this._prefixIds(docFrag, idPrefix);
|
||||||
|
}
|
||||||
|
return Promise.resolve({ idPrefix, element: docFrag });
|
||||||
|
},
|
||||||
|
Promise.reject,
|
||||||
|
).catch(console.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
_prefixIds(element, idPrefix) {
|
||||||
|
const idAttrs = ['id', 'for', 'data-conditional-input', 'data-modal-trigger'];
|
||||||
|
|
||||||
|
idAttrs.forEach((attr) => {
|
||||||
|
Array.from(element.querySelectorAll('[' + attr + ']')).forEach((input) => {
|
||||||
|
const value = idPrefix + input.getAttribute(attr);
|
||||||
|
input.setAttribute(attr, value);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_getIdPrefix() {
|
||||||
|
// leading 'r'(andom) to overcome the fact that IDs
|
||||||
|
// starting with a numeric value are not valid in CSS
|
||||||
|
return 'r' + Math.floor(Math.random() * 100000) + '__';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.HtmlHelpers = new HtmlHelpers();
|
||||||
58
static/es/services/httpClient.js
Normal file
58
static/es/services/httpClient.js
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
class HttpClient {
|
||||||
|
|
||||||
|
static ACCEPT = {
|
||||||
|
TEXT_HTML: 'text/html',
|
||||||
|
JSON: 'application/json',
|
||||||
|
};
|
||||||
|
|
||||||
|
_responseInterceptors = [];
|
||||||
|
|
||||||
|
addResponseInterceptor(interceptor) {
|
||||||
|
if (typeof interceptor === 'function') {
|
||||||
|
this._responseInterceptors.push(interceptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get(args) {
|
||||||
|
args.method = 'GET';
|
||||||
|
return this._fetch(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
post(args) {
|
||||||
|
args.method = 'POST';
|
||||||
|
return this._fetch(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
_fetch(options) {
|
||||||
|
const requestOptions = {
|
||||||
|
credentials: 'same-origin',
|
||||||
|
...options,
|
||||||
|
};
|
||||||
|
|
||||||
|
return fetch(options.url, requestOptions)
|
||||||
|
.then(
|
||||||
|
(response) => {
|
||||||
|
this._responseInterceptors.forEach((interceptor) => interceptor(response, options));
|
||||||
|
return Promise.resolve(response);
|
||||||
|
},
|
||||||
|
Promise.reject,
|
||||||
|
).catch(console.error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.HttpClient = new HttpClient();
|
||||||
|
|
||||||
|
// HttpClient ships with its own little interceptor to throw an error
|
||||||
|
// if the response does not match the expected content-type
|
||||||
|
function contentTypeInterceptor(response, options) {
|
||||||
|
if (!options || !options.accept) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const contentType = response.headers.get("content-type");
|
||||||
|
if (!contentType.match(options.accept)) {
|
||||||
|
throw new Error('Server returned with "' + contentType + '" when "' + options.accept + '" was expected');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.HttpClient.addResponseInterceptor(contentTypeInterceptor);
|
||||||
34
static/es/services/i18n.js
Normal file
34
static/es/services/i18n.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/**
|
||||||
|
* I18n
|
||||||
|
*
|
||||||
|
* This module stores and serves translated strings, according to the users language settings.
|
||||||
|
*
|
||||||
|
* Translations are stored in /messages/frontend/*.msg.
|
||||||
|
*
|
||||||
|
* To make additions to any of these files accessible to JavaScrip Utilities
|
||||||
|
* you need to add them to the respective *.msg file and to the list of FrontendMessages
|
||||||
|
* in /src/Utils/Frontend/I18n.hs.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
class I18n {
|
||||||
|
|
||||||
|
translations = {};
|
||||||
|
|
||||||
|
add(id, translation) {
|
||||||
|
this.translations[id] = translation;
|
||||||
|
}
|
||||||
|
|
||||||
|
addMany(manyTranslations) {
|
||||||
|
Object.keys(manyTranslations).forEach((key) => this.add(key, manyTranslations[key]));
|
||||||
|
}
|
||||||
|
|
||||||
|
get(id) {
|
||||||
|
if (!this.translations[id]) {
|
||||||
|
throw new Error('I18N Error: Translation missing for »' + id + '«!');
|
||||||
|
}
|
||||||
|
return this.translations[id];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.I18n = new I18n();
|
||||||
121
static/es/services/utilRegistry.js
Normal file
121
static/es/services/utilRegistry.js
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
const DEBUG_MODE = /localhost/.test(window.location.href) && 0;
|
||||||
|
|
||||||
|
class UtilRegistry {
|
||||||
|
|
||||||
|
_registeredUtils = [];
|
||||||
|
_activeUtilInstances = [];
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
document.addEventListener('DOMContentLoaded', () => this.setupAll());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* function registerUtil
|
||||||
|
*
|
||||||
|
* utils need to have at least these properties:
|
||||||
|
* name: string | utils name, e.g. 'example'
|
||||||
|
* selector: string | utils selector, e.g. '[uw-example]'
|
||||||
|
* setup: Function | utils setup function, see below
|
||||||
|
*
|
||||||
|
* setup function must return instance object with at least these properties:
|
||||||
|
* name: string | utils name
|
||||||
|
* element: HTMLElement | element the util is applied to
|
||||||
|
* destroy: Function | function to destroy the util and remove any listeners
|
||||||
|
*
|
||||||
|
* @param util Object Utility that should be added to the registry
|
||||||
|
*/
|
||||||
|
register(util) {
|
||||||
|
if (DEBUG_MODE > 2) {
|
||||||
|
console.log('registering util "' + util.name + '"');
|
||||||
|
console.log({ util });
|
||||||
|
}
|
||||||
|
console.log('register...', { this: this });
|
||||||
|
this._registeredUtils.push(util);
|
||||||
|
}
|
||||||
|
|
||||||
|
deregister(name, destroy) {
|
||||||
|
const utilIndex = this._findUtilIndex(name);
|
||||||
|
|
||||||
|
if (utilIndex >= 0) {
|
||||||
|
if (destroy === true) {
|
||||||
|
this._destroyUtilInstances(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._registeredUtils.splice(utilIndex, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setupAll = (scope) => {
|
||||||
|
console.log('setupAll', { scope });
|
||||||
|
if (DEBUG_MODE > 1) {
|
||||||
|
console.info('registered js utilities:');
|
||||||
|
console.table(this._registeredUtils);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._registeredUtils.forEach((util) => this.setup(util, scope));
|
||||||
|
}
|
||||||
|
|
||||||
|
setup(util, scope = document.body) {
|
||||||
|
if (DEBUG_MODE > 2) {
|
||||||
|
console.log('setting up util', { util });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (util && typeof util.setup === 'function') {
|
||||||
|
const elements = this._findUtilElements(util, scope);
|
||||||
|
|
||||||
|
elements.forEach((element) => {
|
||||||
|
let utilInstance = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
utilInstance = util.setup(element);
|
||||||
|
} catch(err) {
|
||||||
|
if (DEBUG_MODE > 0) {
|
||||||
|
console.warn('Error while trying to initialize a utility!', { util , element, err });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (utilInstance) {
|
||||||
|
if (DEBUG_MODE > 2) {
|
||||||
|
console.info('Got utility instance for utility "' + util.name + '"', { utilInstance });
|
||||||
|
}
|
||||||
|
|
||||||
|
this._activeUtilInstances.push(utilInstance);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
find(name) {
|
||||||
|
return this._registeredUtils.find((util) => util.name === name);
|
||||||
|
}
|
||||||
|
|
||||||
|
_findUtilElements(util, scope) {
|
||||||
|
if (scope && scope.matches(util.selector)) {
|
||||||
|
return [scope];
|
||||||
|
}
|
||||||
|
return Array.from(scope.querySelectorAll(util.selector));
|
||||||
|
}
|
||||||
|
|
||||||
|
_findUtilIndex(name) {
|
||||||
|
return this._registeredUtils.findIndex((util) => util.name === name);
|
||||||
|
}
|
||||||
|
|
||||||
|
_destroyUtilInstances(name) {
|
||||||
|
this._activeUtilInstances
|
||||||
|
.map((util, index) => ({
|
||||||
|
util: util,
|
||||||
|
index: index,
|
||||||
|
}))
|
||||||
|
.filter((activeUtil) => activeUtil.util.name === name)
|
||||||
|
.forEach((activeUtil) => {
|
||||||
|
// destroy util instance
|
||||||
|
activeUtil.util.destroy();
|
||||||
|
delete this._activeUtilInstances[activeUtil.index];
|
||||||
|
});
|
||||||
|
|
||||||
|
// get rid of now empty array slots
|
||||||
|
this._activeUtilInstances = this._activeUtilInstances.filter((util) => !!util);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.UtilRegistry = new UtilRegistry();
|
||||||
Reference in New Issue
Block a user