add new JS utility registry and proof-of-concept utility

This commit is contained in:
Felix Hamann 2019-04-03 23:21:12 +02:00
parent f75c1bdb70
commit af6a21438e
5 changed files with 157 additions and 128 deletions

View File

@ -1065,19 +1065,20 @@ siteLayout' headingOverride widget = do
addScript $ StaticR js_polyfills_fetchPolyfill_js
addScript $ StaticR js_polyfills_urlPolyfill_js
-- JavaScript utils
addScript $ StaticR js_utils_alerts_js
addScript $ StaticR js_utils_asidenav_js
addScript $ StaticR js_utils_asyncForm_js
addScript $ StaticR js_utils_asyncTable_js
addScript $ StaticR js_utils_asyncTableFilter_js
addScript $ StaticR js_utils_checkAll_js
addScript $ StaticR js_utils_httpClient_js
addScript $ StaticR js_utils_form_js
addScript $ StaticR js_utils_inputs_js
addScript $ StaticR js_utils_modal_js
addScript $ StaticR js_utils_setup_js
addScript $ StaticR js_utils_showHide_js
addScript $ StaticR js_utils_tabber_js
-- addScript $ StaticR js_utils_alerts_js
-- addScript $ StaticR js_utils_asidenav_js
-- addScript $ StaticR js_utils_asyncForm_js
-- addScript $ StaticR js_utils_asyncTable_js
-- addScript $ StaticR js_utils_asyncTableFilter_js
-- addScript $ StaticR js_utils_checkAll_js
-- addScript $ StaticR js_utils_httpClient_js
-- addScript $ StaticR js_utils_form_js
-- addScript $ StaticR js_utils_inputs_js
-- addScript $ StaticR js_utils_modal_js
addScript $ StaticR js_utils_registry_js
addScript $ StaticR js_utils_poc_js
-- addScript $ StaticR js_utils_showHide_js
-- addScript $ StaticR js_utils_tabber_js
addStylesheet $ StaticR css_utils_alerts_scss
addStylesheet $ StaticR css_utils_asidenav_scss
addStylesheet $ StaticR css_utils_asyncForm_scss

33
static/js/utils/poc.js Normal file
View File

@ -0,0 +1,33 @@
(function() {
var UTIL_NAME = 'poc';
var UTIL_SELECTOR = '[uw-poc]';
var util = function(element) {
function _init() {
var color = 'red';
if (element.dataset.color) {
color = element.dataset.color;
}
element.style.outline = '1px solid ' + color;
}
_init();
return {
name: UTIL_NAME,
element: element,
destroy: function() {},
};
};
if (UtilRegistry) {
UtilRegistry.register({
name: UTIL_NAME,
selector: UTIL_SELECTOR,
setup: util,
});
}
})();

109
static/js/utils/registry.js Normal file
View File

@ -0,0 +1,109 @@
(function() {
'use strict';
var registeredUtils = [];
var activeUtilInstances = [];
// Registry
// (revealing module pattern)
window.UtilRegistry = (function() {
/**
* 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
*/
function registerUtil(util) {
console.log('registering util', util);
registeredUtils.push(util);
}
function deregisterUtil(name, destroy) {
var utilIndex = _findUtilIndex(name);
if (utilIndex >= 0) {
if (destroy === true) {
_destroyUtilInstances(name);
}
registeredUtils.splice(utilIndex, 1);
}
}
function setupAllUtils() {
console.log('setting up all registered utils');
registeredUtils.forEach(function(util) {
setupUtil(util);
});
}
function setupUtil(util, scope) {
console.log('setting up util', { util });
scope = scope || document;
if (util && typeof util.setup === 'function') {
const elements = _findUtilElements(util, scope);
elements.forEach(function(element) {
var utilInstance = util.setup(element);
if (utilInstance) {
activeUtilInstances.push(utilInstance);
}
});
}
}
function findUtil(name) {
return registeredUtils.find(function(util) {
return util.name === name;
});
}
function _findUtilElements(util, scope) {
return Array.from(scope.querySelectorAll(util.selector));
}
function _findUtilIndex(name) {
return registeredUtils.findIndex(function(util) {
return util.name === name;
});
}
function _destroyUtilInstances(name) {
console.log('TODO: destroy util instances', { name });
// call destroy on each activeUtilInstance that matches the name
}
// public API
return {
register: registerUtil,
deregister: deregisterUtil,
setupAll: setupAllUtils,
setup: setupUtil,
find: findUtil,
}
})();
document.addEventListener('DOMContentLoaded', function() {
window.UtilRegistry.setupAll();
});
// REMOVE ME. JUST HERE TO AVOID JS ERRORS
window.utils = {
setup: function(name) {
console.log('not really setting up', name);
},
};
})();

View File

@ -1,114 +0,0 @@
(function() {
'use strict';
window.utils = window.utils || {};
var registeredSetupListeners = {};
var activeInstances = {};
/**
* setup function to initiate a util (utilName) on a scope (sope) with options (options).
*
* Utils need to be defined as property of `window.utils` and need to accept a scope and (optionally) options.
* Example: `window.utils.autoSubmit = function(scope, options) { ... };`
*/
window.utils.setup = function(utilName, scope, options) {
if (!utilName || !scope) {
return;
}
options = options || {};
var utilInstance;
// i18n
if (window.I18N) {
options.i18n = window.I18N;
}
if (activeInstances[utilName]) {
var instanceWithSameScope = activeInstances[utilName]
.filter(function(instance) { return !!instance; })
.find(function(instance) {
return instance.scope === scope;
});
var isAlreadySetup = !!instanceWithSameScope;
if (isAlreadySetup) {
console.warn('Trying to setup a JS utility that\'s already been set up', { utility: utilName, scope, options });
if (!options.force) {
return false;
}
}
}
function setup() {
var listener = function(event) {
if (event.detail.targetUtil !== utilName) {
return false;
}
if (options.setupFunction) {
utilInstance = options.setupFunction(scope, options);
} else {
var util = window.utils[utilName];
if (!util) {
throw new Error('"' + utilName + '" is not a known js util');
}
utilInstance = util(scope, options);
}
if (utilInstance) {
if (activeInstances[utilName] && Array.isArray(activeInstances[utilName])) {
activeInstances[utilName].push(utilInstance);
} else {
activeInstances[utilName] = [ utilInstance ];
}
}
};
if (registeredSetupListeners[utilName] && Array.isArray(registeredSetupListeners[utilName])) {
window.utils.teardown(utilName);
}
if (!registeredSetupListeners[utilName] || Array.isArray(registeredSetupListeners[utilName])) {
registeredSetupListeners[utilName] = [];
}
registeredSetupListeners[utilName].push(listener);
document.addEventListener('setup', listener);
document.dispatchEvent(new CustomEvent('setup', {
detail: { targetUtil: utilName, module: 'none' },
bubbles: true,
cancelable: true,
}));
}
setup();
return utilInstance;
};
window.utils.teardown = function(utilName, destroy) {
if (registeredSetupListeners[utilName]) {
registeredSetupListeners[utilName]
.filter(function(listener) { return !!listener })
.forEach(function(listener) {
document.removeEventListener('setup', listener);
});
delete registeredSetupListeners[utilName];
}
if (destroy === true && activeInstances[utilName]) {
activeInstances[utilName]
.filter(function(instance) { return !!instance })
.forEach(function(instance) {
instance.destroy();
});
delete activeInstances[utilName];
}
}
})();

View File

@ -6,7 +6,7 @@ $if not isModal
<div .main>
<div .main__content>
<div .main__content uw-poc>
$if not isModal
<!-- breadcrumbs -->