@sujalchoudhari/solaris-ui
Version:
A UI framework to create HTML pages with just JavaScript.
248 lines • 11.4 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const filemanager_1 = __importDefault(require("../utils/filemanager"));
const htmlparser2 = __importStar(require("htmlparser2"));
const logger_1 = __importDefault(require("../utils/logger"));
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const components_1 = require("../components");
/**
* Atomizer
* -----
* An utility class for loading/parsing and creating templates.
*
* @remarks
* This class is responsible for loading the templates from the template folder.
* It also provides a function to build the component tree from the HTML string.
*
* @author Sujal Choudhari <sjlchoudhari.gmail.com>
*/
class Atomizer {
/**
* The folder where the templates are stored.
* @remarks
* Only the templated from this folder will be preloaded loaded.
* If there are many template folders then those components will have to be loaded manually.
* or change the template folder and preload the templates again.
*
* @author Ansh Sharma
*/
static templateFolders = [{ baseDir: `${__dirname}/../../templates/`, htmlDir: "", cssDir: "css", jsDir: "js" }];
static templateFilesToInclude = [];
/**
* The preloaded templates (the default ones)
*/
static templates = Atomizer.preloadTemplates();
/**
* Load a template from the template folder
* @param filename The name of the template file
* @returns New atomizer template
*/
static loadTemplate(filename, templateFolderIndex) {
const fm = new filemanager_1.default(Atomizer.templateFolders[templateFolderIndex].baseDir);
const newName = filename;
const template = fm.readFile(newName);
if (template == null) {
logger_1.default.error(__filename, `Template ${newName} not found`);
return null;
}
let baseName = newName.split(".")[0];
if (fs_1.default.existsSync(Atomizer.templateFolders[templateFolderIndex].baseDir
+ Atomizer.templateFolders[templateFolderIndex].cssDir
+ "/"
+ baseName
+ ".css")) {
Atomizer.templateFilesToInclude.push(Atomizer.templateFolders[templateFolderIndex].baseDir
+ Atomizer.templateFolders[templateFolderIndex].cssDir
+ "/"
+ baseName
+ ".css");
}
if (fs_1.default.existsSync(Atomizer.templateFolders[templateFolderIndex].baseDir
+ Atomizer.templateFolders[templateFolderIndex].jsDir
+ "/"
+ baseName
+ ".js")) {
Atomizer.templateFilesToInclude.push(Atomizer.templateFolders[templateFolderIndex].baseDir
+ Atomizer.templateFolders[templateFolderIndex].jsDir
+ "/"
+ baseName
+ ".js");
}
logger_1.default.info(__filename, `Template ${newName} loaded`);
return template;
}
/**
* Preload All the templates from the template folder.
* @returns A dictionary of all the preloaded templates with their names as keys.
*/
static preloadTemplates() {
const templatesArray = [];
Atomizer.templateFolders.forEach((templateFolder, index) => {
const templates = {};
const files = fs_1.default.readdirSync(templateFolder.baseDir, { withFileTypes: true });
files.forEach(file => {
if (!file.isDirectory()) {
let newKey = file.name.split(".")[0];
const template = Atomizer.loadTemplate(path_1.default.join(templateFolder.baseDir, file.name), index);
if (template != null) {
templates[newKey] = template;
}
}
else {
if (file.name === templateFolder.htmlDir) {
const htmlFiles = fs_1.default.readdirSync(path_1.default.join(templateFolder.baseDir, templateFolder.htmlDir), { withFileTypes: true });
htmlFiles.forEach(htmlFile => {
if (!htmlFile.isDirectory()) {
let newKey = htmlFile.name.split(".")[0];
if (templateFolder.htmlDir != "") {
const template = Atomizer.loadTemplate(path_1.default.join(templateFolder.baseDir, templateFolder.htmlDir, htmlFile.name), index);
if (template != null) {
templates[newKey] = template;
}
}
}
});
}
}
});
logger_1.default.info(__filename, `Templates loaded from ${templateFolder.baseDir}`);
templatesArray.push(templates);
});
return templatesArray;
}
/**
* Build the component tree from the atom.
* @param atom The atom to be parsed and built into a component tree
* @returns The root component of the component tree.
*/
static buildComponentTreeFromAtom(atom) {
return Atomizer.buildComponentTree(atom.toString());
}
/**
A static method in the Atomizer class that adds a new template folder to the templateFolders array.
@param {object} templateFolder - An object containing the base directory and optional subdirectories for the template folder.
@param {string} templateFolder.baseDir - The base directory for the template folder.
@param {string} [templateFolder.htmlDir] - Optional subdirectory for HTML templates.
@param {string} [templateFolder.cssDir] - Optional subdirectory for CSS templates.
@param {string} [templateFolder.jsDir] - Optional subdirectory for JavaScript templates.
@remarks
If the templateFolder object's baseDir property does not already exist in Atomizer.templateFolders,
the templateFolder object is pushed into Atomizer.templateFolders.
Then, the templates in the newly added folder are preloaded and pushed into Atomizer.templates.
If the baseDir already exists in Atomizer.templateFolders, a warning is logged.
@author Ansh Sharma
*/
static addTemplateFolder(templateFolder) {
if (!Atomizer.templateFolders.find((folder) => folder.baseDir === templateFolder.baseDir)) {
Atomizer.templateFolders.push(templateFolder);
console.log(Atomizer.templateFolders);
Atomizer.templates.push(Atomizer.preloadTemplates()[Atomizer.templateFolders.length - 1]);
}
else {
logger_1.default.warn(__filename, `Template folder ${templateFolder.baseDir} already exists`);
}
}
/**
A static method in the Atomizer class that retrieves a template with the specified name and index from the templates property.
@param {string} templateName - The name of the template to retrieve.
@param {number} [templateFolderIndex=0] - The index of the folder containing the template. Defaults to 0.
@returns {AtomizerTemplate} - The requested template.
@remarks
If the template is found in the templates property, it is returned immediately.
If the template is not found, this method searches through all template folders for the specified name.
If a template is found, it is returned and cached in the templates property for future use.
If no template is found, an error message is logged and an empty string is returned.
@author Ansh Sharma
*/
static getTemplate(templateName, templateFolderIndex) {
const template = Atomizer.templates[templateFolderIndex || 0][templateName];
if (!template) {
const newTemplate = Atomizer.templates.map((templateFolder) => {
if (templateFolder[templateName]) {
return templateFolder[templateName];
}
}).join("");
if (!newTemplate) {
const new_Template = Atomizer.loadTemplate(templateName, templateFolderIndex || 0);
if (new_Template) {
Atomizer.templates[templateFolderIndex || 0][templateName] = new_Template;
return new_Template;
}
else {
logger_1.default.error(__filename, `Template ${templateName} not found`);
return "";
}
}
else {
return newTemplate;
}
}
else {
return template;
}
}
/**
* Build the component tree from the HTML string.
* @param html The HTML string to be parsed and built into a component tree
* @returns The root component of the component tree.
*/
static buildComponentTree(html) {
let rootComponent = new components_1.Component("root");
let currentComponent = rootComponent;
const parser = new htmlparser2.Parser({
onopentag: (tag, attributes) => {
const newComponent = new components_1.Component(tag, attributes);
currentComponent.addChildren(newComponent);
currentComponent = newComponent;
},
ontext: (text) => {
if (text.trim() === "")
return;
const lastChild = currentComponent.getChildren().at(-1);
if (lastChild && lastChild instanceof components_1.String)
lastChild.content += text;
else
currentComponent.addChildren(new components_1.String(text));
},
onclosetag: (tag) => {
const newComponent = currentComponent.getParent();
if (newComponent)
currentComponent = newComponent;
},
}, { decodeEntities: true });
parser.write(html);
parser.end();
logger_1.default.info(__filename, `Component tree built`);
return rootComponent.getChildren()[0];
}
}
exports.default = Atomizer;
;
//# sourceMappingURL=atomizer.js.map