/*\ title: $:/core/modules/widgets/list/list.js type: application/javascript module-type: widget The list widget \*/ (function(){ /*jslint node: true, browser: true */ /*global $tw: false */ "use strict"; var ListWidget = function(renderer) { // Save state this.renderer = renderer; // Generate widget elements this.generate(); }; /* These types are shorthands for particular filters */ var typeMappings = { all: "[!is[shadow]sort[title]]", recent: "[!is[shadow]sort[modified]]", missing: "[is[missing]sort[title]]", orphans: "[is[orphan]sort[title]]", shadows: "[is[shadow]sort[title]]" }; ListWidget.prototype.generate = function() { // Get our attributes this.itemClass = this.renderer.getAttribute("itemClass"); this.template = this.renderer.getAttribute("template"); this.editTemplate = this.renderer.getAttribute("editTemplate"); this.emptyMessage = this.renderer.getAttribute("emptyMessage"); // Get the list of tiddlers object this.getTiddlerList(); // Create the list var listMembers = []; if(this.list.length === 0) { // Check for an empty list listMembers = [this.getEmptyMessage()]; } else { // Create the list for(var t=0; t 0) { // Use our content as the template templateTree = this.renderer.parseTreeNode.children; } else { // Use default content templateTree = [{ type: "element", tag: "$view", attributes: { field: {type: "string", value: "title"}, format: {type: "string", value: "link"} } }]; } } // Create the transclude widget return { type: "element", tag: "$transclude", attributes: { target: {type: "string", value: title}, template: {type: "string", value: template} }, children: templateTree }; }; /* Remove a list element from the list, along with the attendant DOM nodes */ ListWidget.prototype.removeListElement = function(index) { // Get the list element var listElement = this.children[index]; // Remove the DOM node listElement.domNode.parentNode.removeChild(listElement.domNode); // Then delete the actual renderer node this.children.splice(index,1); }; /* Return the index of the list element that corresponds to a particular title startIndex: index to start search (use zero to search from the top) title: tiddler title to seach for */ ListWidget.prototype.findListElementByTitle = function(startIndex,title) { while(startIndex < this.children.length) { if(this.children[startIndex].widget.children[0].attributes.target === title) { return startIndex; } startIndex++; } return undefined; }; ListWidget.prototype.refreshInDom = function(changedAttributes,changedTiddlers) { // Reexecute the widget if any of our attributes have changed if(changedAttributes.itemClass || changedAttributes.template || changedAttributes.editTemplate || changedAttributes.emptyMessage || changedAttributes.type || changedAttributes.filter || changedAttributes.template) { // 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 { // Handle any changes to the list, and refresh any nodes we're reusing this.handleListChanges(changedTiddlers); } }; ListWidget.prototype.handleListChanges = function(changedTiddlers) { var t, prevListLength = this.list.length; // Get the list of tiddlers, having saved the previous length this.getTiddlerList(); // Check if the list is empty if(this.list.length === 0) { // Check if it was empty before if(prevListLength === 0) { // If so, just refresh the empty message $tw.utils.each(this.children,function(node) { if(node.refreshInDom) { node.refreshInDom(changedTiddlers); } }); return; } else { // If the list wasn't empty before, empty it for(t=prevListLength-1; t>=0; t--) { this.removeListElement(t); } // Insert the empty message this.children = this.renderer.renderTree.createRenderers(this.renderer.renderContext,[this.getEmptyMessage()]); $tw.utils.each(this.children,function(node) { if(node.renderInDom) { this.renderer.domNode.appendChild(node.renderInDom()); } }); return; } } else { // If it is not empty now, but was empty previously, then remove the empty message if(prevListLength === 0) { this.removeListElement(0); } } // Step through the list and adjust our child list elements appropriately for(t=0; t=t; n--) { this.removeListElement(n); } // Refresh the node we're reusing this.children[t].refreshInDom(changedTiddlers); } } // Remove any left over elements for(t=this.children.length-1; t>=this.list.length; t--) { this.removeListElement(t); } }; exports.list = ListWidget; })();