From 538d12e017a03bb44eb638b9008e849562997116 Mon Sep 17 00:00:00 2001 From: Jeremy Ruston Date: Sun, 2 Jun 2013 23:20:43 +0100 Subject: [PATCH] Add the fieldlist widget Allows us to render a sequence of fields --- core/modules/widgets/fieldlist.js | 150 ++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 core/modules/widgets/fieldlist.js diff --git a/core/modules/widgets/fieldlist.js b/core/modules/widgets/fieldlist.js new file mode 100644 index 000000000..eea73abec --- /dev/null +++ b/core/modules/widgets/fieldlist.js @@ -0,0 +1,150 @@ +/*\ +title: $:/core/modules/widgets/fieldlist.js +type: application/javascript +module-type: widget + +The fieldlist widget renders the fields of a tiddler through a template. + +\*/ +(function(){ + +/*jslint node: true, browser: true */ +/*global $tw: false */ +"use strict"; + +var FieldListWidget = function(renderer) { + // Save state + this.renderer = renderer; + // Generate child nodes + this.generate(); +}; + +FieldListWidget.prototype.generate = function() { + var self = this; + // Get parameters from our attributes + this.tiddlerTitle = this.renderer.getAttribute("tiddler",this.renderer.tiddlerTitle); + this.exclude = this.renderer.getAttribute("exclude"); + // Get the exclusion list + this.excludeList; + if(this.exclude) { + this.excludeList = this.exclude.split(" "); + } else { + this.excludeList = ["text"]; + } + // Get the list of fields + var fieldList = this.getFieldList(); + // Set the element + this.tag = "div"; + this.attributes = { + "class": "tw-fields" + }; + // Set up the attributes for the wrapper element + var classes = []; + if(this.renderer.hasAttribute("class")) { + $tw.utils.pushTop(classes,this.renderer.getAttribute("class").split(" ")); + } + if(classes.length > 0) { + this.attributes["class"] = classes.join(" "); + } + if(this.renderer.hasAttribute("style")) { + this.attributes.style = this.renderer.getAttribute("style"); + } + if(this.renderer.hasAttribute("tooltip")) { + this.attributes.title = this.renderer.getAttribute("tooltip"); + } + // Create the renderers for each list item + var items = []; + $tw.utils.each(fieldList,function(fieldName) { + items.push(self.createListElement(fieldName)); + }); + this.children = this.renderer.renderTree.createRenderers(this.renderer,items); +}; + +FieldListWidget.prototype.createListElement = function(fieldName) { + return { + type: "element", + tag: "$transclude", + isBlock: true, + attributes: { + currentField: {type: "string", value: fieldName}, + target: {type: "string", value: this.tiddlerTitle} + }, + children: this.renderer.parseTreeNode.children + }; +}; + +FieldListWidget.prototype.removeListElement = function(index) { + // Get the list element + var listElement = this.children[index]; + // Delete the DOM node + listElement.domNode.parentNode.removeChild(listElement.domNode); + // Then delete the actual renderer node + this.children.splice(index,1); +}; + +FieldListWidget.prototype.getFieldList = function() { + var tiddler = this.renderer.renderTree.wiki.getTiddler(this.tiddlerTitle), + fieldList = []; + if(tiddler) { + for(var fieldName in tiddler.fields) { + if(this.excludeList.indexOf(fieldName) === -1) { + fieldList.push(fieldName); + } + } + } + fieldList.sort(); + return fieldList; +}; + +FieldListWidget.prototype.refreshInDom = function(changedAttributes,changedTiddlers) { + // Check if any of our attributes have changed, or if a tiddler we're interested in has changed + if(changedAttributes.tiddler || changedAttributes.exclude || changedAttributes.style || changedAttributes.tooltip || changedAttributes["class"]) { + // Regenerate and rerender the widget and replace the existing DOM node + this.generate(); + var oldDomNode = this.renderer.domNode, + newDomNode = this.renderer.renderInDom(); + oldDomNode.parentNode.replaceChild(newDomNode,oldDomNode); + } else { + // Get the potentially updated list of fields + var fieldList = this.getFieldList(); + // Walk through the fields + for(var fieldIndex = 0; fieldIndex=fieldIndex; n--) { + this.removeListElement(n); + } + // Refresh the node we're reusing + this.children[fieldIndex].refreshInDom(changedTiddlers); + } + } + // Remove any left over elements + for(fieldIndex = this.children.length-1; fieldIndex>=fieldList.length; fieldIndex--) { + this.removeListElement(fieldIndex); + } + } +}; + +/* +Find the index of the child node representing the named field (or -1 if not present) +*/ +FieldListWidget.prototype.findChildNode = function(startIndex,fieldName) { + var index = startIndex; + while(index < this.children.length) { + if(this.children[index].attributes.currentField === fieldName) { + return index; + } + index++; + } + return -1; +}; + +exports.fieldlist = FieldListWidget; + +})();