fonteva-design-guide
Version:
## Dev, Build and Test
258 lines (224 loc) • 7.72 kB
JavaScript
const parseToObject = value => {
if (typeof value === 'string' || value instanceof String) {
value = JSON.parse(value);
}
if (value == null) {
value = {};
}
return value;
};
const fireEvent = (cmp, name, value, opts = {}) => {
const customEvent = new CustomEvent(name, {
detail: value,
...opts
});
cmp.dispatchEvent(customEvent);
};
const refireEvents = (component, target, eventNames, that) => {
if (!eventNames) {
return;
}
eventNames.split(',').forEach(eventName => {
const extraDetails = {};
target.addEventListener(eventName.trim(), refireEvent(that, extraDetails));
});
};
const refireEvent = (that, extraDetails = {}) => {
return function (event) {
// eat this event, and re-fire a new one with additional info
event.stopPropagation();
// represents the 'details' object passed to CustomEvent
const details = Object.assign(extraDetails,event.detail);
fireEvent(this, event.type, details, {
bubbles: true,
composed: true
})
}.bind(that);
};
const cloneDeep = value => {
return JSON.parse(JSON.stringify(value));
};
const generateId = len => {
let text = '';
let possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
for (let i = 0; i < len; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
};
const cleanName = name => {
return name.replace(/[^A-Z0-9]+/gi, '_');
};
const isValidUrl = val => {
if (/^(?:https:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:\/?#[\]@!\$&\(\)\*\+,;=.]+$/i.test(val)) {
return true;
}
return false;
};
const valueProvided = val => {
if (val == null) {
return false;
}
return true;
};
const setValueInObj = (valueObj, params) => {
valueObj[params.field] = params.value;
return valueObj;
};
const addSitePrefix = url => {
let systemPrefixes = ['apex', 's', 'one', 'profile', 'lightning'];
let systemPrefix = false;
let pathSegments = window.location.pathname.split('/');
//if first element of the current path is not to be ignored, then it's a site prefix
systemPrefixes.forEach(function (prefix) {
if (pathSegments[1] === prefix) {
systemPrefix = true;
}
});
if (systemPrefix) {
return url;
} else if (pathSegments.length >= 3) {
if (pathSegments[1] !== '') {
return '/' + pathSegments[1] + url;
}
}
return url;
};
const BindInputGroups = superclass =>
class extends superclass {
_boundGroups = {};
bindGroup(groupName) {
this._boundGroups[groupName] = { get: () => this[groupName] };
}
bindGroups(groups) {
if (groups instanceof Array) {
groups.forEach(g => this.bindGroup(g));
} else {
this._boundGroups = groups;
}
}
_bound = false;
renderedCallback() {
if (!this._bound) {
this.template.querySelectorAll('c-pfm-input').forEach(ctl => {
if (ctl.group && !ctl.val) {
const boundGroup = this._boundGroups[ctl.group];
ctl.val = typeof boundGroup === 'function' ? boundGroup() : boundGroup.get();
}
});
this._bound = true;
}
}
constructor() {
super();
this.addEventListener('valuechange', evt => {
const boundGroup = this._boundGroups[evt.detail.group];
if (boundGroup) {
evt.stopPropagation();
let val = typeof boundGroup === 'function' ? boundGroup() : boundGroup.get();
val[evt.detail.field] = evt.detail.value;
if (boundGroup.onChange) {
boundGroup.onChange(val, evt.detail.field);
}
}
});
}
};
const rafPromise = () => {
return new Promise(resolve => {
requestAnimationFrame(resolve); //faster than set time out
});
};
const sleep = ms => {
return new Promise(resolve => {
setTimeout(() => resolve(), ms);
});
};
const Selector = superclass =>
class extends superclass {
constructor() {
super();
}
rafPromise() {
return rafPromise();
}
waitForElement(selector) {
const element = this.template.querySelector(selector);
if (!element) {
return this.rafPromise().then(() => this.waitForElement(selector));
} else {
return Promise.resolve(element);
}
}
/**
*
* @param selector
* @param [callbackIfFound]
* @returns {Element | any}
*/
querySelector(selector, callbackIfFound) {
const element = this.template.querySelector(selector.replace(/##([A-Z-_a-z]*)/g, "[data-name='$1']"));
if (callbackIfFound && element) {
return callbackIfFound(element);
}
return element;
}
/**
* Wait for an element to appear, then return it or run the callback with the found element.
* @param selector
* @param callback
* @returns {Promise}
*/
waitSelector(selector, callback) {
const selectorStr = selector.replace(/##([A-Z-_a-z]*)/g, "[data-name='$1']");
return this.waitForElement(selectorStr).then(element => {
if (callback) {
return callback(element);
}
return element;
});
}
hasSlot(slotName) {
return this.querySelectorAll('span[slot="' + slotName + '"]').length > 0;
}
};
Array.prototype.sum = function (valModifier) {
console.log('Array.prototyp.sum is deprecated.\n Use { arrSum } from `c/utils`.\n i.e. arrSum(list, valModifier)')
};
const arrSum = (list, valModifier) => {
return list.reduce((total, val) => total + parseInt(valModifier(val), 10), 0);
};
const formatLabel = (targetStr, argumentList) => {
// searches through argumentList and uses index to replace {index} in targetStr
argumentList.forEach((arg, i) => {
if (arg) { // if condition to check for null argument
const regex = new RegExp(`\\{${i}\\}`, 'g'); // regex to locate {index}
targetStr = targetStr.replace(regex, arg); // replacing found variable with argument from argumentList
}
});
// scans final targetStr for incorrect variables and arguments
const emptyArg = new RegExp(`\{\\d*\}\\s*|\{\\D*\}\\s*`, 'g'); // if {index} > argumentList.length
targetStr = targetStr.replace(emptyArg, '').trim(); // removes extra space when an incorrect value is removed at the end of targetStr
return targetStr // returns formatted label value
}
const fireChangeEvent = fireEvent;
export {
parseToObject,
fireChangeEvent,
fireEvent,
refireEvent,
refireEvents,
cloneDeep,
generateId,
cleanName,
valueProvided,
isValidUrl,
setValueInObj,
addSitePrefix,
BindInputGroups,
Selector,
rafPromise,
sleep,
formatLabel,
arrSum
};