The task is to implement a DOM Wrapper to support method chaining. The wrapper only needs to have css(propertyName: string, value: any).
The boilerplate code
function $(el) {
// your code here
}
The DOM wrapper needs to be flexible i.e it should handle several ways of identifying elements. If a string is passed to the css(), it should be treated as a CSS selector. If a NodeList (like the result of document.querySelectorAll) or an array of elements is passed, those are converted to a normal array. If a single HTML element is passed, it is wrapped in an array.
if(typeof el === 'string') {
elements = Array.from(document.querySelectorAll(el));
} else if(el instanceof NodeList || Array.isArray(el)) {
elements.from(el)
} else if(el instanceof HTMLElement) {
elements = [el]
}
Css property names are usually written in kebab case, while in Javascript's DOM API, they must be camelCase. To handle both forms, a helper function that converts kebab case to camel case is included
function toCamelCase(prop) {
return prop.replace(/-([a-z])/g, (_, ch) => ch.toUpperCase())
}
The css method accepts two arguments, a property name and a value. It loops through all the elements in the wrapper, setting each element to its corresponding value, converting to camel case where necessary. Every method in the wrapper returns the same api object at the end of its execution. This allows another method to be immediatelly called on the same line
const api = {
css(propertyName, value) {
if(typeof propertyName === 'undefined') return api;
const jsProp = toCamelCase(propertyName);
elements.forEach(elm => {
if(elm || elm.style) {
elm.style[jsProp] = value;
}
});
return api;
}
}
The final code is:
function $(el) {
// your code here
let elements = [];
if(typeof el === 'string') {
elements = Array.from(document.querySelectorAll(el));
} else if(el instanceof NodeList || Array.isArray(el)) {
elements.from(el)
} else if(el instanceof HTMLElement) {
elements = [el]
}
function toCamelCase(prop) {
return prop.replace(/-([a-z])/g, (_, ch) => ch.toUpperCase())
}
const api = {
css(propertyName, value) {
if(typeof propertyName === 'undefined') return api;
const jsProp = toCamelCase(propertyName);
elements.forEach(elm => {
if(elm || elm.style) {
elm.style[jsProp] = value;
}
});
return api;
}
}
return api;
}
That's all folks!
Top comments (0)