/*\ title: $:/core/modules/wiki.js type: application/javascript module-type: wikimethod Extension methods for the $tw.Wiki object Adds the following properties to the wiki object: * `eventListeners` is a hashmap by type of arrays of listener functions * `changedTiddlers` is a hashmap describing changes to named tiddlers since wiki change events were last dispatched. Each entry is a hashmap containing two fields: modified: true/false deleted: true/false * `changeCount` is a hashmap by tiddler title containing a numerical index that starts at zero and is incremented each time a tiddler is created changed or deleted * `caches` is a hashmap by tiddler title containing a further hashmap of named cache objects. Caches are automatically cleared when a tiddler is modified or deleted * `globalCache` is a hashmap by cache name of cache objects that are cleared whenever any tiddler change occurs \*/ (function(){ /*jslint node: true, browser: true */ /*global $tw: false */ "use strict"; var widget = require("$:/core/modules/widgets/widget.js"); var USER_NAME_TITLE = "$:/status/UserName"; /* Get the value of a text reference. Text references can have any of these forms: !! !! - specifies a field of the current tiddlers ## */ exports.getTextReference = function(textRef,defaultText,currTiddlerTitle) { var tr = $tw.utils.parseTextReference(textRef), title = tr.title || currTiddlerTitle; if(tr.field) { var tiddler = this.getTiddler(title); if(tr.field === "title") { // Special case so we can return the title of a non-existent tiddler return title; } else if(tiddler && $tw.utils.hop(tiddler.fields,tr.field)) { return tiddler.getFieldString(tr.field); } else { return defaultText; } } else if(tr.index) { return this.extractTiddlerDataItem(title,tr.index,defaultText); } else { return this.getTiddlerText(title,defaultText); } }; exports.setTextReference = function(textRef,value,currTiddlerTitle) { var tr = $tw.utils.parseTextReference(textRef), title,tiddler,fields; // Check if it is a reference to a tiddler if(tr.title && !tr.field) { tiddler = this.getTiddler(tr.title); this.addTiddler(new $tw.Tiddler(tiddler,{title: tr.title,text: value},this.getModificationFields())); // Else check for a field reference } else if(tr.field) { title = tr.title || currTiddlerTitle; tiddler = this.getTiddler(title); if(tiddler) { fields = {}; fields[tr.field] = value; this.addTiddler(new $tw.Tiddler(tiddler,fields,this.getModificationFields())); } } }; exports.deleteTextReference = function(textRef,currTiddlerTitle) { var tr = $tw.utils.parseTextReference(textRef), title,tiddler,fields; // Check if it is a reference to a tiddler if(tr.title && !tr.field) { this.deleteTiddler(tr.title); // Else check for a field reference } else if(tr.field) { title = tr.title || currTiddlerTitle; tiddler = this.getTiddler(title); if(tiddler && $tw.utils.hop(tiddler.fields,tr.field)) { fields = {}; fields[tr.field] = undefined; this.addTiddler(new $tw.Tiddler(tiddler,fields,this.getModificationFields())); } } }; exports.addEventListener = function(type,listener) { this.eventListeners = this.eventListeners || {}; this.eventListeners[type] = this.eventListeners[type] || []; this.eventListeners[type].push(listener); }; exports.removeEventListener = function(type,listener) { var listeners = this.eventListeners[type]; if(listeners) { var p = listeners.indexOf(listener); if(p !== -1) { listeners.splice(p,1); } } }; exports.dispatchEvent = function(type /*, args */) { var args = Array.prototype.slice.call(arguments,1), listeners = this.eventListeners[type]; if(listeners) { for(var p=0; p bb) { return 1; } else { return 0; } } }); for(t=0; t b) { return isDescending ? -1 : +1; } else { return 0; } } }); }; /* For every tiddler invoke a callback(title,tiddler) with `this` set to the wiki object. Options include: sortField: field to sort by excludeTag: tag to exclude includeSystem: whether to include system tiddlers (defaults to false) */ exports.forEachTiddler = function(/* [options,]callback */) { var arg = 0, options = arguments.length >= 2 ? arguments[arg++] : {}, callback = arguments[arg++], titles = this.getTiddlers(options), t, tiddler; for(t=0; t b.info.priority) { return +1; } else { return 0; } } }); }; /* Invoke the highest priority saver that successfully handles a method */ exports.callSaver = function(method /*, args */ ) { for(var t=this.savers.length-1; t>=0; t--) { var saver = this.savers[t]; if(saver[method].apply(saver,Array.prototype.slice.call(arguments,1))) { return true; } } return false; }; /* Save the wiki contents. Options are: method: "save" or "download" template: the tiddler containing the template to save downloadType: the content type for the saved file */ exports.saveWiki = function(options) { options = options || {}; var method = options.method || "save", template = options.template || "$:/core/save/all", downloadType = options.downloadType || "text/plain"; var text = this.renderTiddler(downloadType,template); this.callSaver("save",text,method,function(err) { if(err) { alert("Error while saving:\n\n" + err); } else { $tw.notifier.display("$:/messages/Saved"); } }); }; /* Return an array of tiddler titles that match a search string text: The text string to search for options: see below Options available: titles: Hashmap or array of tiddler titles to limit search exclude: An array of tiddler titles to exclude from the search invert: If true returns tiddlers that do not contain the specified string caseSensitive: If true forces a case sensitive search literal: If true, searches for literal string, rather than separate search terms */ exports.search = function(text,options) { options = options || {}; var self = this,t; // Convert the search string into a regexp for each term var terms, searchTermsRegExps, flags = options.caseSensitive ? "" : "i"; if(options.literal) { if(text.length === 0) { searchTermsRegExps = null; } else { searchTermsRegExps = [new RegExp("(" + $tw.utils.escapeRegExp(text) + ")",flags)]; } } else { terms = text.replace(/( +)/g," ").split(" "); if(terms.length === 1 && terms[0] === "") { searchTermsRegExps = null; } else { searchTermsRegExps = []; for(t=0; t