-
Notifications
You must be signed in to change notification settings - Fork 0
/
lght.js
132 lines (124 loc) · 5.04 KB
/
lght.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
const lght = {
newInstanceOfTemplate: function({ templateSelector, templateData }) {
const template = document.querySelector(templateSelector).innerHTML;
let newTemplate = template;
let warnAboutPropsNotFound = true;
for (let prop in templateData) {
const searchString = `{${prop}}`;
const searchRegexp = new RegExp(searchString, "g");
const newString = templateData[prop];
if (
newTemplate.includes("{" + prop + "}") &&
typeof newString === "object"
) {
if (Array.isArray(newString)) {
if (console) {
console.log(newString);
}
}
throw new Error(
`Properties in the 'templateData' object must evaluate to strings, booleans or numbers in order for the template to render correctly, ${prop} has type of: ${typeof newString}`
);
}
newTemplate = newTemplate.replace(searchRegexp, templateData[prop]);
}
if (newTemplate.match(/{.*}/g)) {
const matches = newTemplate.match(/{.*}/g);
matches.forEach((match, index) => {
if (!match.includes("!")) {
const searchRegexp = new RegExp(match, "g");
newTemplate = newTemplate.replace(searchRegexp, "");
} else {
const excapedTemplateCode = match.replace("!", "");
newTemplate = newTemplate.replace(match, excapedTemplateCode);
}
});
const unEscapedMatches = matches.filter(item => !item.includes("!"));
console.warn(
`The following properties were referred to in the template HTML but not found in the related template data object, and have been replaced with empty strings. This may be totally fine, but here are the properties that were not matched, just in case: `,
unEscapedMatches.join(", ")
);
}
return newTemplate;
},
addContentToTarget: function({
templateSelector, // identifies the element containing the template in your HTML. Usually an ID written like "#article-template".
targetSelector, // identifies the element where we should place that template after it gets its content. Usually an ID written like "#article-container", "#article-targe" or even just "#article".
templateData // can a javascript object, or array of objects, whose values all return strings or numbers.
}) {
const target = document.querySelector(targetSelector);
if (Array.isArray(templateData)) {
templateData.forEach((item, index) => {
item.index = index;
addContentToTarget(item);
});
} else {
addContentToTarget(templateData);
}
function addContentToTarget(templateData) {
if (target.querySelector(".loading")) {
lght.removeLoader({ targetElement: target });
}
target.innerHTML += lght.newInstanceOfTemplate({
templateSelector,
templateData
});
if (templateData.$callback) {
templateData.$callback(templateData.index);
} else {
// remove all loaders, cause without callbacks nothing else will happen
let loaders = Array.from(target.querySelectorAll(".loading"));
if (loaders) {
loaders.forEach(element => {
element.remove();
});
}
}
}
},
removeLoader: function({ targetElement, loadingClass = "loading" }) {
const loadingElement = Array.from(targetElement.children).find(element =>
element.className.includes(loadingClass)
); // will be undefined if there is not a direct child of the element that contains the loader... in which case the loader is deeply nested so we don't know yet if we can remove it.
if (loadingElement) {
loadingElement.remove();
}
},
repeatedItemIdGenerator: (function*() {
let i = 0;
while (i < i + 1) {
yield `array-item-${i++}`;
}
})(),
arrayToHTMLString: function({
array,
itemWrapperTagName = "",
wrapperTagAttributeString = "",
idGenerator = lght.repeatedItemIdGenerator // this defaults to the Generator object returned by repeatedItemIdGenerator so that globally we will always have unique IDs no matter where arrayToHTMLString is called.
}) {
if (!itemWrapperTagName) {
throw new Error(
"arrayToHTMLString requires a an item wrapper tag to specified. If you don't want to wrap array items in HTML tags, you may want to use Array.join() instead."
);
} else if (wrapperTagAttributeString) {
if (wrapperTagAttributeString.includes(" id=")) {
throw new Error(
"Setting IDs in your wrapperTagAttributeString gives every HTML element generated by the same ID, which was probably not what you intended. Unique IDs are automatically generated in the format 'array-item-0' "
);
}
}
return array
.map(item => {
const id = idGenerator.next().value;
return `<${itemWrapperTagName} ${wrapperTagAttributeString} id="${id}">
${item}
</${itemWrapperTagName}>
`;
})
.join("");
}
};
if (window) {
// make this globally available in spite of potential bundler-related shenanigans
window.lght = lght;
}