// Returns true if path is a valid field name (path), // i.e. a sequence of identifiers, separated by "." TiddlyWiki.isValidFieldName = function(name) { var match = /[a-zA-Z_]\w*(\.[a-zA-Z_]\w*)*/.exec(name); return match && (match[0] == name); }; // Throws an exception when name is not a valid field name. TiddlyWiki.checkFieldName = function(name) { if(!TiddlyWiki.isValidFieldName(name)) throw config.messages.invalidFieldName.format([name]); }; function StringFieldAccess(n,readOnly) { this.set = readOnly ? function(t,v) {if(v != t[n]) throw config.messages.fieldCannotBeChanged.format([n]);} : function(t,v) {if(v != t[n]) {t[n] = v; return true;}}; this.get = function(t) {return t[n];}; } function DateFieldAccess(n) { this.set = function(t,v) { var d = v instanceof Date ? v : Date.convertFromYYYYMMDDHHMM(v); if(d != t[n]) { t[n] = d; return true; } }; this.get = function(t) {return t[n].convertToYYYYMMDDHHMM();}; } function LinksFieldAccess(n) { this.set = function(t,v) { var s = (typeof v == "string") ? v.readBracketedList() : v; if(s.toString() != t[n].toString()) { t[n] = s; return true; } }; this.get = function(t) {return String.encodeTiddlyLinkList(t[n]);}; } TiddlyWiki.standardFieldAccess = { // The set functions return true when setting the data has changed the value. "title": new StringFieldAccess("title",true), // Handle the "tiddler" field name as the title "tiddler": new StringFieldAccess("title",true), "text": new StringFieldAccess("text"), "modifier": new StringFieldAccess("modifier"), "modified": new DateFieldAccess("modified"), "creator": new StringFieldAccess("creator"), "created": new DateFieldAccess("created"), "tags": new LinksFieldAccess("tags") }; TiddlyWiki.isStandardField = function(name) { return TiddlyWiki.standardFieldAccess[name] != undefined; }; // Sets the value of the given field of the tiddler to the value. // Setting an ExtendedField's value to null or undefined removes the field. // Setting a namespace to undefined removes all fields of that namespace. // The fieldName is case-insensitive. // All values will be converted to a string value. TiddlyWiki.prototype.setValue = function(tiddler,fieldName,value) { TiddlyWiki.checkFieldName(fieldName); var t = this.resolveTiddler(tiddler); if(!t) return; fieldName = fieldName.toLowerCase(); var isRemove = (value === undefined) || (value === null); var accessor = TiddlyWiki.standardFieldAccess[fieldName]; if(accessor) { if(isRemove) // don't remove StandardFields return; var h = TiddlyWiki.standardFieldAccess[fieldName]; if(!h.set(t,value)) return; } else { var oldValue = t.fields[fieldName]; if(isRemove) { if(oldValue !== undefined) { // deletes a single field delete t.fields[fieldName]; } else { // no concrete value is defined for the fieldName // so we guess this is a namespace path. // delete all fields in a namespace var re = new RegExp("^"+fieldName+"\\."); var dirty = false; var n; for(n in t.fields) { if(n.match(re)) { delete t.fields[n]; dirty = true; } } if(!dirty) return; } } else { // the "normal" set case. value is defined (not null/undefined) // For convenience provide a nicer conversion Date->String value = value instanceof Date ? value.convertToYYYYMMDDHHMMSSMMM() : String(value); if(oldValue == value) return; t.fields[fieldName] = value; } } // When we are here the tiddler/store really was changed. this.notify(t.title,true); if(!fieldName.match(/^temp\./)) this.setDirty(true); }; // Returns the value of the given field of the tiddler. // The fieldName is case-insensitive. // Will only return String values (or undefined). TiddlyWiki.prototype.getValue = function(tiddler,fieldName) { var t = this.resolveTiddler(tiddler); if(!t) return undefined; if(fieldName.indexOf(config.textPrimitives.sectionSeparator) === 0 || fieldName.indexOf(config.textPrimitives.sliceSeparator) === 0) { var sliceType = fieldName.substr(0, 2); var sliceName = fieldName.substring(2); return store.getTiddlerText("%0%1%2".format(t.title,sliceType,sliceName)); } else { fieldName = fieldName.toLowerCase(); var accessor = TiddlyWiki.standardFieldAccess[fieldName]; if(accessor) { return accessor.get(t); } } return t.fields[fieldName]; }; // Calls the callback function for every field in the tiddler. // When callback function returns a non-false value the iteration stops // and that value is returned. // The order of the fields is not defined. // @param callback a function(tiddler,fieldName,value). TiddlyWiki.prototype.forEachField = function(tiddler,callback,onlyExtendedFields) { var t = this.resolveTiddler(tiddler); if(!t) return undefined; var n,result; for(n in t.fields) { result = callback(t,n,t.fields[n]); if(result) return result; } if(onlyExtendedFields) return undefined; for(n in TiddlyWiki.standardFieldAccess) { if(n != "tiddler") { // even though the "title" field can also be referenced through the name "tiddler" // we only visit this field once. result = callback(t,n,TiddlyWiki.standardFieldAccess[n].get(t)); if(result) return result; } } return undefined; };