/** Templates are to be able to re-use layouts without copy/paste. They can be a "main" template for the overall page layout, or just sub-layouts e.g. header/footer that always looks the same and in cases where they are the same we also can re-use static data easily. Templates are created with a single argument, options which is a dict that contain at least this: { layout : layout || this, classPrefix: "templateClassPrefix" } Easiest you just use TemplateData like this: this.template = new Template({ layout : layout || this, classPrefix: "templateClassPrefix" }) this.dataHandler = new TemplateData({layout: this, template: this.template, table: "menu_contents", isStatic: 1}) this.dataHandler.fetchData() ... (then in you layoutFunction:) var filledData = this.template.templateJSON(); var layout = [ { ... divs with stuff ... }, { children : filledData }, { ... divs with more stuff ... } ] Or you can handle filling the template with content yourself by calling setContentData, which takes a JSONLayout array OR title/lead/body formatted data, we call this form "article formatted data". Looks like this: [ { title : "optional paragraph title", lead: "shorter optional intro", body: "main text" }, ... ] Whenever you change data, or before layoutFunction, call setContentData(data) Simply take the json in your layoutFunction by calling templateJSON() and lay out. By always fetching the JSON like this templates can both be inserted into the rootElement or as a sub-layout (below a menu, etc). They can also use each other. So, in short: this.template = new Template({ layout : layout || this, classPrefix: "templateClassPrefix" }) this.template.setContentData(...) this.layout.layoutJSON(rootElement, this.template.templateJSON()) */ /** StaticTemplate just holds a JSON to be used by main templates for filling out stuff that never (or at least seldom) changes. */ function StaticTemplate(json_data) { if (json_data) this.setContentData(json_data) } StaticTemplate.prototype.setContentData = function(json_data) { this.json_data = json_data } StaticTemplate.prototype.templateJSON = function() { return this.json_data || []; } /** ToggleFAQTemplate makes articleData a foldable list of items. @arg showAll, make the items already unfolded. @arg titleList, set leadList or bodyList to : ol/ul TODO: * Allow for all titles to be standalone just like the first! * you should be able to combine titleList with leadList, so you have paragraphs and subsections - e.g. paragraph 1, section 1.2, 1.3 etc. * ALSO: the same for leadList with bodyList */ function ToggleFAQTemplate(options) { this.layout = options.layout this.classPrefix = options.classPrefix || "faq" this.showAll = options.showAll this.titleList = options.titleList this.leadList = options.leadList this.bodyList = options.bodyList var mainDivCSS = "." + this.classPrefix + "MainDiv"; this.layout.setCSSFromSelector(mainDivCSS, { maxWidth: "512px", margin : "auto", padding: "0px 10px" }) this.layout.setCSSFromSelector(mainDivCSS + " ul > li", { listStyleType: "disc" }) this.layout.setCSSFromSelector(mainDivCSS + " ul ul", { listStyleType: "circle" }) this.layout.setCSSFromSelector(mainDivCSS + " ol ol", { listStyleType: "upper-alpha" }) //all ordered lists inside ordered lists this.layout.setCSSFromSelector(mainDivCSS + " ol ol ol", { listStyleType: "lower-roman" }) //all ordered lists inside ordered lists, leverl 3 //note that you can use counter-reset: steps ; counter-increment: steps; //content: counter(steps) ". "; if you want to this.layout.setCSSFromSelector("." + this.classPrefix + "Separator", { height : "5em"}) } ToggleFAQTemplate.prototype.setContentData = function(faqData) { var layout = [] var item; var separatorClass = this.classPrefix + "Separator" var subMain = { children : layout } var faq = { className : this.classPrefix + "MainDiv", }; var startIndex = 0; if (faqData.length > 1 && faqData[startIndex].title) { //Allow for a first standalone item to be the a title faq.children = [{ text: faqData[startIndex].title, type: "h1"}, subMain] startIndex++; } else faq.children = [subMain] for (var index = startIndex; index < faqData.length; index++) { //how do we standardize this? with callbacks? //var postJSON = this.layout.convertPostDataToJSON(post, this.classPrefix); var post = faqData[index]; if (post.body) { var children = []; if (post.title) children.push({ text: post.title, type: "h1"}); if (post.lead) { if (this.showAll) item = { text: post.lead }; else item = { autoType: AUTO_TYPE.button, html: "➡︎ " + post.lead, autoListeners: { "click" : { target: this, includeEvent : 1, includeElement : 1, function: "toggleFAQButtonClick"}}, type: "div", className: "toggle_button" } if (this.leadList) children.push({ type: "h2", children : [{ type: "li", children : [item] }]}); else children.push({ type: "h2", children : [item]}); } if (post.body) { if (this.showAll) item = { text: post.body } else item = { text: post.body, style : { display : "none" }} if (this.bodyList) children.push({ type: "li", children : [item] }); else children.push(item) } layout.push({ children : children }) layout.push({ className : separatorClass }) } else { layout.push(post) layout.push({ className : separatorClass }) } } if (this.titleList || this.leadList || this.bodyList) subMain.type = (this.titleList || this.leadList || this.bodyList) this.layoutJSON = [faq] } ToggleFAQTemplate.prototype.templateJSON = function() { return this.layoutJSON; } ToggleFAQTemplate.prototype.toggleFAQButtonClick = function(event, element) { var index = element.auto_data element.style.display = "none" var postBody = element.nextSibling postBody.style.display = "block" } /** A simple structure for centered content, having text to the left and a floating image to the right. */ function SimpleFloatingImageTemplate(options) { var layout = options.layout; this.layout = layout if (options.classPrefix || options.classPrefix === "") this.classPrefix = options.classPrefix else this.classPrefix = "SFIT_" layout.setCSSFromSelector("." + this.classPrefix + "stretcher", { position : "relative", width: "100%", verticalAlign: "bottom", display: "inlineBlock" }) layout.setCSSFromSelector("." + this.classPrefix + "flex", { padding: "10px", margin: "auto", maxWidth: "800px", verticalAlign: "bottom", display: "inlineBlock" }) layout.setCSSFromSelector("." + this.classPrefix + "flex a", { fontWeight : "bold", color : "inherit" }) layout.setCSSFromSelector("." + this.classPrefix + "icon_container", { cssFloat: "right" }) layout.setCSSFromSelector("." + this.classPrefix + "floatingLogo", { paddingLeft: "10px", width: "50vw", maxWidth : "512px", lineHeight: "25px", verticalAlign: "bottom", display: "inlineBlock" }) } SimpleFloatingImageTemplate.prototype.setContentData = function(data) { var content = []; for (var index = 0; index < data.length; index++) { var item = data[index]; //if you have an image div - insert it as a floater if ((item.autoType && item.autoType == AUTO_TYPE.image) || (item.type && item.type.toUpperCase() == "IMG")) { if (item.className) item.className += " " + this.classPrefix + "floatingLogo"; else item.className = this.classPrefix + "floatingLogo"; item = { className : this.classPrefix + "icon_container", children : [item] } } content.push(item); } //think about { style: { clear: "both"} } - should we try to do this programatically? No, too hard to align images anyway. Let this be the simple one! this.layoutJSON = [ { className : this.classPrefix + "stretcher", children: [ { className: this.classPrefix + "flex", children: content } ]} ] }; SimpleFloatingImageTemplate.prototype.templateJSON = function() { if (!this.layoutJSON) { this.layoutJSON = [{ html : "fetching..." }] } return this.layoutJSON; }