// Concrete Model Editor // // Copyright (c) 2010 Martin Thiede // // Concrete is freely distributable under the terms of an MIT-style license. Concrete.TemplateProvider = Class.create({ // +templateRoot+ is the DOM element containing the templates // // Options: // identifierAttribute: name of the feature that holds the identifier, default: none // featureSortFunc: function providing values for features used to sort them, default: none // alwaysHideFeatures: names of the features which should always be hidden, default: none // initialize: function(templateRoot, options) { this.templateRoot = templateRoot; this._templateByClass = {}; this.options = options || {}; this.options.alwaysHideFeatures = this.options.alwaysHideFeatures || []; }, emptyValue: function(feature) { var value = new Element("span"); value.className = "ct_value ct_empty"; value.innerHTML = "<"+feature.mmFeature.name+">"; return value; }, emptyElement: function(parentNode, feature) { if (feature) { var placeholderText = "<"+feature.mmFeature.name+">" } else { var placeholderText = "<root>" } if (parentNode.tagName.toUpperCase() == "TBODY") { cols = parentNode.up("table").select("tr").max(function(r) { return r.childElements().select(function(c) {return c.tagName.toUpperCase() == "TD";}).size(); }); var element = new Element("tr"); element.className = "ct_element ct_empty"; element.features = []; // adding child td node via innerHTML doesn't work in Firefox as long as the parent tr node is not child of a table var td = new Element("td"); td.writeAttribute("colspan", cols); td.innerHTML = placeholderText; element.appendChild(td); } else { var element = new Element("span"); element.className = "ct_element ct_empty"; element.innerHTML = placeholderText; element.features = []; } return element; }, templateByClass: function(clazz) { if (this._templateByClass[clazz.name]) return this._templateByClass[clazz.name]; var tmpl = this.templateRoot.down(".ctc_"+clazz.name); if (tmpl) { this._completeDomBasedTemplate(tmpl, clazz); } else { tmpl = this._createGenericTemplate(clazz); } return this._templateByClass[clazz.name] = tmpl; }, _createGenericTemplate: function(clazz) { this.templateRoot.insert({bottom: "
"}); var tmpl = this.templateRoot.childElements().last(); tmpl.mmClass = clazz; var headDiv = tmpl.down(); headDiv.insert({bottom: " "}); headDiv.insert({bottom: " "}); headDiv.insert({bottom: ""+clazz.name+" "}); var ftmpls = []; var features = clazz.allFeatures(); if (this.options.featureSortFunc) features = features.sortBy(this.options.featureSortFunc); features.each(function(f) { var ft; var hideStrat = this.options.alwaysHideFeatures.include(f.name) ? "ct_always_hide" : "ct_auto_hide"; if (f.kind == "attribute") { if (this.options.identifierAttribute && f.name == this.options.identifierAttribute) { headDiv.insert({bottom: ""+f.name+": "}); } else { headDiv.insert({bottom: ""+f.name+": "}); } ft = headDiv.childElements().last(); } else if (f.kind == "reference") { headDiv.insert({bottom: ""+f.name+": "}); ft = headDiv.childElements().last(); } else if (f.kind == "containment") { tmpl.insert({bottom: "
"+f.name+":
"}); ft = tmpl.childElements().last(); } else { throw new Error("Unknown feature kind"); } ft.mmFeature = f; ftmpls.push(ft); }, this); return tmpl; }, _completeDomBasedTemplate: function(tmpl, clazz) { tmpl.mmClass = clazz; var allFeatureTemplates = tmpl.select(".ct_attribute").concat(tmpl.select(".ct_reference")).concat(tmpl.select(".ct_containment")); clazz.allFeatures().each(function(f) { var msg = " template not found for '"+f.name+"' in class '"+clazz.name+"'"; var ft; if (f.isAttribute()) { ft = tmpl.down(".ct_attribute.ctn_"+f.name); if (!ft) throw new Error("attribute"+msg); } else if (f.isReference()) { ft = tmpl.down(".ct_reference.ctn_"+f.name); if (!ft) throw new Error("reference"+msg); } else if (f.isContainment()) { ft = tmpl.down(".ct_containment.ctn_"+f.name); if (!ft) throw new Error("containment"+msg); } else { throw new Error("Unknown feature kind"); } if (!ft.down(".ct_slot")) throw new Error("no slot in template for class '"+clazz.name+"' feature '"+f.name+"'"); ft.mmFeature = f; delete allFeatureTemplates[allFeatureTemplates.indexOf(ft)]; }); allFeatureTemplates.each(function(ft) { throw new Error("Unused feature template '"+ft.className+"' in class '"+clazz.name+"'"); }); } });