/***\nThis is a sample style definition to demonstrate CustomCssClass formatting\n***/\n/*{{{*/\n.testClass {color: #f00; background: #7ff;}\n/*}}}*/\n\n/***\nTo use:\n{{testClass{this text now has the ''testclass'' style applied}}}\n***/\n\n/***\nfrom http://groups.google.com/group/TiddlyWikiDev/msg/7aa64a938b7faba7\n***/\n/*{{{*/\n@media print {\n.tiddler { border-bottom: 1px solid #666;}\n.footer { display: none;}\n}\n/*}}}*/
/***\n|''Name:''|YourSearchPlugin|\n|''Version:''|2.0.2 (2006-02-13)|\n|''Source:''|http://tiddlywiki.abego-software.de/#YourSearchPlugin|\n|''Author:''|UdoBorkowski (ub [at] abego-software [dot] de)|\n|''Licence:''|[[BSD open source license]]|\n|''TiddlyWiki:''|2.0|\n|''Browser:''|Firefox 1.0.4+; Firefox 1.5; InternetExplorer 6.0|\n<<tiddler [[YourSearch Introduction]]>>\nFor more information see [[Help|YourSearch Help]].\n\n!Compatibility\nThis plugin requires TiddlyWiki 2.0. \nUse http://tiddlywiki.abego-software.de/#YourSearchPlugin-1.0.1 for older TiddlyWiki versions.\n\n!Revision history\n/%\n***/\n//{{{\n//============================================================================\n//============================================================================\n// YourSearchPlugin\n//============================================================================\n//============================================================================\n\n// Ensure that the Plugin is only installed once.\n//\nif (!version.extensions.YourSearchPlugin) {\n\nversion.extensions.YourSearchPlugin = {\n major: 2, minor: 0, revision: 2,\n date: new Date(2006, 2, 13), \n type: 'plugin',\n source: "http://tiddlywiki.abego-software.de/#YourSearchPlugin"\n};\n\nvar alertAndThrow = function(msg) {alert(msg);throw msg;};\n\nif (!window.abego) window.abego = {};\nif (abego.YourSearch) alertAndThrow("abego.YourSearch already defined");\nabego.YourSearch = {};\n\nif (version.major < 2) alertAndThrow("YourSearchPlugin requires TiddlyWiki 2.0 or newer.\sn\snGet YourSearch 1.0.1 to use YourSearch with older versions of TiddlyWiki.\sn\snhttp://tiddlywiki.abego-software.de/#YourSearchPlugin-1.0.1");\n\n//----------------------------------------------------------------------------\n// The STQ (SimpleTiddlerQuery) Class\n//----------------------------------------------------------------------------\n\n// Internal.\n// \nvar STQ = function(queryText, caseSensitive, matchTitleOnly, useRegExp) {\n this.queryText = queryText;\n this.caseSensitive = caseSensitive;\n\n if (useRegExp) {\n this.regExp = new RegExp(queryText, caseSensitive ? "mg" : "img");\n return;\n }\n \n this.terms = [];\n\n // The regular expression that matches a single search term of the form\n // (whitespace handling and grouping omitted for clarity):\n //\n // -?[#!%]*(<doubleQuoteStringLiteral>|<wordWithoutSpace>) (AND|OR)?\n //\n // group 1: '-' (negate, optional)\n // group 2: [!%#]* (may be empty)\n // group 3: String literal "..."\n // group 4: word\n // group 5: AND / OR (optional) \n //\n // (group 3 xor group 4 is defined)\n //\n var re = /\ss*(\s-)?([#%!=]*)(?:(?:("(?:(?:\s\s")|[^"])*")|(\sS+)))(?:\ss+((?:[aA][nN][dD])|(?:[oO][rR]))(?!\sS))?/mg;\n\n var matches = re.exec(queryText);\n\n while (matches != null && matches.length == 6) {\n var negate = '-' == matches[1];\n var flags = matches[2];\n var inTitle = flags.indexOf('!') >= 0;\n var inText = flags.indexOf('%') >= 0;\n var inTag = flags.indexOf('#') >= 0;\n var wordMatch = flags.indexOf('=') >= 0;\n if (!inTitle && !inText && !inTag) {\n inTitle = config.options.chkSearchInTitle;\n inText = config.options.chkSearchInText;\n inTag = config.options.chkSearchInTags;\n \n // If all settings are off (i.e. all results would be empty, \n // i.e user error or checkboxes are gone) set all settings\n if (!inTitle && !inText && !inTag) {\n inTitle = inText = inTag = true;\n }\n }\n if (matchTitleOnly) {\n inText = false;\n inTag = false;\n }\n \n var text;\n if (matches[3]) {\n //Quoted String\n try {\n text = eval(matches[3]);\n } catch (ex) {\n // ignore error. Will be handled right after this.\n }\n } else {\n text = matches[4];\n }\n if (!text) {\n throw "Invalid search expression: %0".format([queryText]);\n }\n var orFollows = matches[5] && matches[5].charAt(0).toLowerCase() == 'o';\n this.terms.push(new STQ.Term(text, inTitle, inText, inTag, negate, orFollows, caseSensitive, wordMatch));\n \n matches = re.exec(queryText);\n }\n};\n\nvar me = STQ.prototype;\n\n// Internal.\n// \n// Returns an array with those tiddlers from the tiddlersMap that \n// match the query.\n//\nme.getMatchingTiddlers = function(tiddlersMap) {\n var result = [];\n for (var i in tiddlersMap) {\n var t = tiddlersMap[i];\n if ((t instanceof Tiddler) && this.matchesTiddler(t)) {\n result.push(t);\n }\n }\n return result;\n};\n\n\n// Internal.\n// \n// Returns true if the query has a match in the given tiddler.\n//\n// @param tiddler [may be null]\n//\nme.matchesTiddler = function(tiddler) {\n if (this.regExp) {\n return this.regExp.test(tiddler.title) || this.regExp.test(tiddler.text);\n }\n \n var n = this.terms.length;\n if (n == 0) {\n return false;\n }\n \n var hasMatch = this.terms[0].matchesTiddler(tiddler);\n for (var i = 1; i < this.terms.length; i++) {\n if (this.terms[i-1].orFollows) {\n // the OR case.\n \n // shortcut: when the first operand of an OR is true \n // we don't need to evaluate the second operand since \n // the result of the OR will always be true.\n \n // In the other case we actually to the "OR"\n if (!hasMatch) {\n hasMatch |= this.terms[i].matchesTiddler(tiddler);\n }\n } else {\n // the AND case.\n \n // shortcut: when the first operand of an AND is false \n // we don't need to evaluate the second operand since\n // the result of the AND will always be false.\n \n // Otherwise we actually to the "AND"\n if (hasMatch) {\n hasMatch &= this.terms[i].matchesTiddler(tiddler);\n }\n }\n }\n return hasMatch;\n};\n\n// Internal.\n// \nme.getOnlyMatchTitleQuery = function() {\n if (!this.onlyMatchTitleQuery) {\n this.onlyMatchTitleQuery = new STQ(this.queryText, this.caseSensitive, true, this.useRegExp);\n }\n return this.onlyMatchTitleQuery;\n};\n\n\n// Returns a regular expression that can be used to marking/hiliting\n// matches in the text.\n//\n// @return [may be null] null when the query does not provide marking information.\n//\nme.getMarkRegExp = function() {\n if (this.regExp) {\n // Only use the regExp for marking when it does not match the empty string.\n return "".search(this.regExp) >= 0 ? null : this.regExp;\n }\n \n var stringSet = {};\n var n = this.terms.length;\n for (var i = 0; i < this.terms.length; i++) {\n var term = this.terms[i];\n if (!term.negate) stringSet[term.text] = true;\n }\n\n var pattern = [];\n for (var t in stringSet) pattern.push("(" + t.escapeRegExp() + ")");\n \n if (pattern.length == 0) return null;\n\n var joinedPattern = pattern.join("|");\n return new RegExp(joinedPattern, this.caseSensitive ? "mg" : "img");\n};\n\n// Internal.\n// \nme.toString = function() {\n if (this.regExp) {\n return this.regExp.toString();\n }\n \n var result = "";\n for (var i = 0; i < this.terms.length; i++) {\n result += this.terms[i].toString();\n }\n return result;\n};\n\n//----------------------------------------------------------------------------\n// The STQ.Term Class\n//----------------------------------------------------------------------------\n\n// Internal.\n//\nSTQ.Term = function(text, inTitle, inText, inTag, negate, orFollows, caseSensitive, wordMatch) {\n this.text = text;\n this.inTitle = inTitle;\n this.inText = inText;\n this.inTag = inTag;\n this.negate = negate;\n this.orFollows = orFollows;\n this.caseSensitive = caseSensitive;\n this.wordMatch = wordMatch;\n \n var reText = text.escapeRegExp();\n if (this.wordMatch) reText = "\s\sb"+reText+"\s\sb";\n this.regExp = new RegExp(reText, "m"+(caseSensitive ? "" : "i"));\n};\n\n// Internal.\n//\nSTQ.Term.prototype.toString = function() {\n return (this.negate ? "-" : "")+(this.inTitle ? "!" : "")+(this.inText? "%" : "")+(this.inTag? "#" : "")+(this.wordMatch ? "=" : "")+'"'+this.text+'"'+ (this.orFollows ? " OR " : " AND ");\n};\n\n// Internal.\n//\n// Returns true if the term has a match in the given tiddler.\n//\n// @param tiddler [may be null]\n//\nSTQ.Term.prototype.matchesTiddler = function(tiddler) {\n if (!tiddler) {\n return false;\n }\n \n if (this.inTitle && this.regExp.test(tiddler.title)) {\n return !this.negate;\n }\n if (this.inText && this.regExp.test(tiddler.text)) {\n return !this.negate;\n }\n if (this.inTag) {\n var tags = tiddler.tags;\n if (tags) {\n for (var i = 0; i < tags.length; i++) {\n if (this.regExp.test(tags[i])) {\n return !this.negate;\n }\n }\n }\n }\n \n return this.negate;\n};\n\n//----------------------------------------------------------------------------\n// Utils\n//----------------------------------------------------------------------------\n\nvar stringToInt = function(s, defaultValue) {\n if (!s) return defaultValue;\n var n = parseInt(s);\n return (n == NaN) ? defaultValue : n;\n};\n\nvar getIntAttribute = function(elem, name, defaultValue) {\n return stringToInt(elem.getAttribute(name));\n};\n\n// Returns true if e is either self or a descendant (child, grandchild,...) of self.\n//\n// @param self DOM:Element\n// @param e DOM:Element or null\n//\nvar isDescendantOrSelf = function(self, e) {\n while (e != null) {\n if (self == e) return true;\n e = e.parentNode;\n }\n return false;\n};\n\nvar getMatchCount = function(s, re) {\n var m = s.match(re);\n return m ? m.length : 0;\n};\n\nvar createEllipsis = function(place) {\n var e = createTiddlyElement(place,"span");\n e.innerHTML = "&hellip;";\n};\n\nvar isWordChar = function(c) {\n return (c >= "a" && c <= "z") || (c >= "A" && c <= "Z") || c == "_";\n};\n\n// Returns the bounds of the word in s around offset as a {start: , end:} object.\n//\n// Returns null when the char at offset is not a word char.\n//\nvar getWordBounds = function(s, offset) {\n // Handle the "offset is not in word" case\n if (!isWordChar(s[offset])) return null;\n\n for (var i = offset-1; i >= 0 && isWordChar(s[i]); i--) \n {/*empty*/}\n \n var startIndex = i+1;\n var n = s.length;\n for (i = offset+1; i < n && isWordChar(s[i]); i++) \n {/*empty*/}\n \n return {start: startIndex, end: i};\n};\n\n\nvar removeTextDecoration = function(s) {\n var removeThis = ["''", "{{{", "}}}", "//", "<<<", "/***", "***/"];\n var reText = "";\n for (var i = 0; i < removeThis.length; i++) {\n if (i != 0) reText += "|";\n reText += "("+removeThis[i].escapeRegExp()+")";\n }\n return s.replace(new RegExp(reText, "mg"), "").trim();\n};\n\nvar logText = "";\nvar lastLogTime = null;\nvar logMessage = function(kind, s) {\n var now = new Date();\n var delta = lastLogTime ? (now-lastLogTime).toString() : "";\n logText += "<tr><td>"+now.convertToYYYYMMDDHHMMSSMMM()+"</td><td align='right'>"+delta+"</td><td>"+kind+"</td><td>"+s.htmlEncode()+"</td></tr>\sn";\n lastLogTime = now;\n};\n\nfunction writeLog() {\n var t = " <<JsDoIt 'WriteLog' 'WriteLog' 'javascript:writeLog();story.closeTiddler(\s"Log\s");story.displayTiddler(null,\s"Log\s");'>>"+\n "<html><table><tbody><tr><th>Time</th><th>Delta (ms)</th><th>Kind</th><th>Message</th></tr>\sn" + logText + "</tbody></table></html>";\n store.saveTiddler("Log", "Log",t,config.options.txtUserName,new Date(),["System", "Log"]);\n logText = "";\n lastLogTime = null;\n}\n\n//----------------------------------------------------------------------------\n// The Search Core\n//----------------------------------------------------------------------------\n\n// Constants\n\n// DOM IDs\nvar yourSearchResultID = "yourSearchResult";\nvar yourSearchResultItemsID = "yourSearchResultItems";\n\n// Visual appearance of the result page\nvar maxCharsInTitle = 80;\nvar maxCharsInTags = 50;\nvar maxCharsInText = 250;\nvar maxPagesInNaviBar = 10; // Maximum number of pages listed in the navigation bar (before or after the current page)\n\nvar itemsPerPageDefault = 25; // Default maximum number of items on one search result page\nvar itemsPerPageWithPreviewDefault = 10; // Default maximum number of items on one search result page when PreviewText is on\n\n// Context Calculation\nvar minMatchWithContextSize = 40; \nvar maxMovementForWordCorrection = 4; // When a "match" context starts or end on a word the context borders may be changed to at most this amound to include or exclude the word.\n\n// Ranking Weights\nvar matchInTitleWeight = 4;\nvar precisionInTitleWeight = 10;\nvar matchInTagsWeight = 2;\n\n// Variables\nvar resultElement; // The (popup) DOM element containing the search result [may be null]\nvar lastResults; // Array of tiddlers that matched the last search\nvar lastQuery; // The last Search query (STQ)\nvar lastSearchText; // The last search text, as used to create the lastQuery\nvar searchInputField; // The "search" input field\nvar searchButton; // The "search" button\nvar firstIndexOnPage = 0; // The index of the first item of the lastResults list displayed on the search result page\n\nvar currentTiddler; // While creating the search result page the tiddler that is currently rendered.\nvar indexInPage; // The index (in the current page) of the tiddler currently rendered.\nvar indexInResult; // The index (in the result array) of the tiddler currently rendered.\n\n\nvar getItemsPerPage = function() {\n var n = (config.options.chkPreviewText) \n ? stringToInt(config.options.txtItemsPerPageWithPreview, itemsPerPageWithPreviewDefault) \n : stringToInt(config.options.txtItemsPerPage, itemsPerPageDefault);\n return (n > 0) ? n : 1;\n};\n\nvar standardRankFunction = function(tiddler, query) { \n // Count the matches in the title and the tags\n var markRE = query.getMarkRegExp();\n if (!markRE) return 1;\n \n var matchesInTitle = tiddler.title.match(markRE);\n var nMatchesInTitle = matchesInTitle ? matchesInTitle.length : 0;\n var nMatchesInTags = getMatchCount(tiddler.getTags(), markRE);\n\n // Calculate the "precision" of the matches in the title as the ratio of\n // the length of the matches to the total length of the title.\n var lengthOfMatchesInTitle = matchesInTitle ? matchesInTitle.join("").length : 0;\n var precisionInTitle = tiddler.title.length > 0 ? lengthOfMatchesInTitle/tiddler.title.length : 0;\n \n // calculate a weighted score\n var rank= nMatchesInTitle * matchInTitleWeight \n + nMatchesInTags * matchInTagsWeight \n + precisionInTitle * precisionInTitleWeight \n + 1;\n\n return rank;\n};\n\n// @return Tiddler[]\n//\nvar findMatches = function(store, searchText,caseSensitive,useRegExp,sortField,excludeTag) {\n lastSearchText = searchText;\n\n var candidates = store.reverseLookup("tags",excludeTag,false);\n var query = new STQ(searchText,caseSensitive, false, useRegExp); \n lastQuery = query;\n\n var results = query.getMatchingTiddlers(candidates);\n\n // Rank the results\n var rankFunction = abego.YourSearch.getRankFunction();\n for (var i = 0; i < results.length; i++) {\n var tiddler = results[i];\n var rank = rankFunction(tiddler, query);\n // Add the rank information to the tiddler.\n // This is used during the sorting, but it may also\n // be used in the result, e.g. to display some "relevance" \n // information in the result \n tiddler.searchRank = rank; \n }\n \n // sort the result, taking care of the rank and the sortField \n if(!sortField) {\n sortField = "title";\n }\n \n var sortFunction = function (a,b) {\n var searchRankDiff = a.searchRank - b.searchRank;\n if (searchRankDiff == 0) {\n if (a[sortField] == b[sortField]) {\n return(0); \n } else {\n return (a[sortField] < b[sortField]) ? -1 : +1; \n }\n } else {\n return (searchRankDiff > 0) ? -1 : +1; \n }\n };\n results.sort(sortFunction);\n \n lastResults = results;\n \n return results;\n};\n\n\n//----------------------------------------------------------------------------\n// Handling "limited marked text" in the preview\n//\n// The found/matched texts should be displayed to the user in the preview. To make \n// it more useful the matched texts should be shown in their contexts, i.e. with\n// some text around them. Since we only have limited space for the preview \n// (around two lines for the text preview, less for the tags and title) and \n// also don't want to both the user with "too much context" we use some \n// heuristics to find the "best context (size)". \n//\n// On the other hand we want to use as much as possible of the preview area, \n// so if there is room left we also display as much text from the beginning\n// of the text as possible. This gives the user some kind of "overall context"\n// especiallay if the start of the text is introductorily.\n//\n// Text Ranges\n//\n// To represent the ranges that should be displayed "Range" object are used.\n// This are objects with a "start" and "end" property. In a corresponding\n// "Ranges array" these objects are sorted by their start and no range object \n// intersects/touches any other of the array.\n//\n//----------------------------------------------------------------------------\n\nvar moveToWordBorder = function(s, offset, isStartOffset) {\n var wordBounds;\n if (isStartOffset) {\n wordBounds = getWordBounds(s, offset);\n } else {\n if (offset <= 0) return offset;\n wordBounds = getWordBounds(s, offset-1);\n }\n if (!wordBounds) return offset;\n \n if (isStartOffset) {\n if (wordBounds.start >= offset-maxMovementForWordCorrection) return wordBounds.start;\n if (wordBounds.end <= offset+maxMovementForWordCorrection) return wordBounds.end;\n } else {\n if (wordBounds.end <= offset+maxMovementForWordCorrection) return wordBounds.end;\n if (wordBounds.start >= offset-maxMovementForWordCorrection) return wordBounds.start;\n }\n return offset;\n};\n\nvar getContextRangeAround = function(s, startIndex, endIndex, matchCount, maxLen) {\n // Partition the available space into equal sized areas for each match and one \n // for the text start.\n // But the size should not go below a certain limit\n var size = Math.max(Math.floor(maxLen/(matchCount+1)), minMatchWithContextSize);\n \n // Substract the size of the range to get the size of the context.\n var contextSize = Math.max(size-(endIndex-startIndex), 0);\n // Two thirds of the context should be before the match, one third after.\n var contextEnd = Math.min(Math.floor(endIndex+contextSize/3), s.length);\n var contextStart = Math.max(contextEnd - size, 0);\n\n // If the contextStart/End is inside a word and the end of the word is\n // close move the pointers accordingly to make the text more readable.\n contextStart = moveToWordBorder(s, contextStart, true);\n contextEnd = moveToWordBorder(s, contextEnd, false);\n \n return {start: contextStart, end: contextEnd};\n};\n\n// Splits s into a sequence of "matched" and "unmatched" substrings, using the \n// matchRegExp to do the matching.\n// \n// Returns an array of objects with a "text" property containing the substring text. \n// Substrings that are "matches" also contain a boolean "isMatch" property set to true.\n// \n// @param matchRegExp [may be null] when null no matching is performed and the returned \n// array just contains one item with s as its text\n// \nvar getTextAndMatchArray = function(s, matchRegExp) {\n var result = [];\n if (matchRegExp) {\n var startIndex = 0;\n var n = s.length;\n var currentLen = 0;\n do {\n matchRegExp.lastIndex = startIndex;\n var match = matchRegExp.exec(s);\n if (match) {\n if (startIndex < match.index) {\n var t = s.substring(startIndex, match.index);\n result.push({text:t});\n }\n result.push({text:match[0], isMatch:true});\n startIndex = match.index + match[0].length;\n } else {\n result.push({text: s.substr(startIndex)});\n break;\n }\n } while (true);\n } else {\n result.push({text: s});\n }\n return result;\n};\n\n\nvar simpleCreateLimitedTextWithMarks = function(place, s, maxLen) {\n if (!lastQuery) return;\n \n var textAndMatches = getTextAndMatchArray(s, lastQuery.getMarkRegExp());\n var currentLen = 0;\n for (var i=0; i < textAndMatches.length && currentLen < maxLen; i++) {\n var t = textAndMatches[i];\n var text = t.text;\n if (t.isMatch) {\n createTiddlyElement(place,"span",null,"marked",text); \n } else {\n var remainingLen = maxLen-currentLen;\n if (remainingLen < text.length) {\n text = text.substring(0, remainingLen)+"...";\n }\n createTiddlyText(place, text);\n }\n currentLen += text.length;\n }\n};\n\n\n\nvar addRange = function(ranges, startIndex, endIndex) {\n var n = ranges.length;\n \n // When there are no ranges in ranges, just add it.\n if (n == 0) {\n ranges.push({start: startIndex, end: endIndex});\n return;\n }\n \n var i = 0;\n for (; i < n; i++) {\n var range = ranges[i];\n \n // find the first range that intersects or "touches" [startIndex, endIndex[\n if (range.start <= endIndex && startIndex <= range.end) {\n // Found.\n \n var r;\n // find the first range behind the new range that does not interfere\n var rIndex = i+1;\n for (; rIndex < n; rIndex++) {\n r = ranges[rIndex];\n if (r.start > endIndex || startIndex > range.end) {\n break;\n }\n }\n \n // Replace the ranges i to rIndex-1 with the union of the new range with these ranges.\n var unionStart = startIndex;\n var unionEnd = endIndex;\n for (var j = i; j < rIndex; j++) {\n r = ranges[j];\n unionStart = Math.min(unionStart, r.start);\n unionEnd = Math.max(unionEnd, r.end);\n }\n ranges.splice(i, rIndex-i, {start: unionStart, end: unionEnd});\n return; \n }\n \n // if we found a range R that is right of the new range there is no\n // intersection and we can insert the new range before R.\n if (range.start > endIndex) {\n break;\n }\n }\n\n // When we are here the new range does not interfere with any range in ranges and\n // i is the index of the first range right to it (or ranges.length, when the new range\n // becomes the right most range). \n\n ranges.splice(i, 0, {start: startIndex, end: endIndex});\n};\n\nvar getTotalRangesSize = function(ranges) {\n var totalRangeSize = 0;\n for (var i=0; i < ranges.length; i++) {\n var range = ranges[i];\n totalRangeSize += range.end-range.start;\n }\n return totalRangeSize;\n};\n\n// Processes the text between startIndex and endIndex of the textAndMatches\n// "writes" them (as DOM elements) at the given place, possibly as "marked" text.\n//\n// When endIndex is not the end of the full text an ellisis is appended. \n//\nvar writeTextAndMatchRange = function(place, s, textAndMatches, startIndex, endIndex) {\n var t;\n var text;\n \n // find the first text item to write\n var pos = 0;\n var i = 0;\n var offset = 0;\n for (;i < textAndMatches.length; i++) {\n t = textAndMatches[i];\n text = t.text;\n if (startIndex < pos+text.length) {\n offset = startIndex - pos;\n break;\n }\n pos += text.length;\n }\n \n var remainingLen = endIndex - startIndex;\n for (; i < textAndMatches.length && remainingLen > 0; i++) {\n t = textAndMatches[i];\n text = t.text.substr(offset);\n offset = 0;\n if (text.length > remainingLen) text = text.substr(0,remainingLen);\n \n if (t.isMatch) {\n createTiddlyElement(place,"span",null,"marked",text);\n } else {\n createTiddlyText(place, text);\n }\n remainingLen -= text.length;\n }\n \n if (endIndex < s.length) {\n createEllipsis(place);\n }\n};\n\nvar getMatchedTextCount = function(textAndMatches) {\n var result = 0;\n for (var i=0; i < textAndMatches.length; i++) {\n if (textAndMatches[i].isMatch) {\n result++;\n }\n }\n return result; \n};\n\n// Get all ranges around matched substrings with their contexts\n//\nvar getMatchedTextWithContextRanges = function(textAndMatches, s, maxLen) {\n var ranges = [];\n var matchCount = getMatchedTextCount(textAndMatches);\n var pos = 0;\n for (var i=0; i < textAndMatches.length; i++) {\n var t = textAndMatches[i];\n var text = t.text;\n if (t.isMatch) {\n var range = getContextRangeAround(s, pos, pos+text.length, matchCount, maxLen);\n addRange(ranges, range.start, range.end);\n }\n pos += text.length;\n }\n return ranges;\n};\n\nvar fillUpRanges = function(s, ranges, maxLen) {\n var remainingLen = maxLen - getTotalRangesSize(ranges);\n while (remainingLen > 0) {\n if (ranges.length == 0) {\n // No matches added yet. Make one large range.\n addRange(ranges, 0, moveToWordBorder(s, maxLen, false));\n return;\n } else {\n var range = ranges[0];\n var startIndex;\n var maxEndIndex;\n if (range.start == 0) {\n // The first range already starts at the beginning of the string.\n\n // When there is a second range fill to the next range start or to the maxLen.\n startIndex = range.end;\n if (ranges.length > 1) {\n maxEndIndex = ranges[1].start;\n } else {\n // Only one range. Add a range after that with the complete remaining len \n // (corrected to "beautify" the output)\n addRange(ranges, startIndex, moveToWordBorder(s, startIndex+remainingLen, false));\n return;\n }\n } else {\n // There is unused space between the start of the text and the first range.\n startIndex = 0;\n maxEndIndex = range.start;\n }\n var endIndex = Math.min(maxEndIndex, startIndex+remainingLen);\n addRange(ranges, startIndex, endIndex);\n remainingLen -= (endIndex-startIndex);\n }\n }\n};\n\n// Write the given ranges of s, using textAndMatches for marking portions of the text.\n//\nvar writeRanges = function(place, s, textAndMatches, ranges, maxLen) {\n if (ranges.length == 0) return;\n \n // When the first range is not at the start of the text write an ellipsis("...")\n // (Ellipses between ranges are written in the writeTextAndMatchRange method)\n if (ranges[0].start > 0) createEllipsis(place);\n\n var remainingLen = maxLen;\n for (var i = 0; i < ranges.length && remainingLen > 0; i++) {\n var range = ranges[i];\n var len = Math.min(range.end - range.start, remainingLen);\n writeTextAndMatchRange(place, s, textAndMatches, range.start, range.start+len);\n remainingLen -= len;\n }\n};\n\nvar createLimitedTextWithMarksAndContext = function(place, s, maxLen) {\n if (!lastQuery) return;\n \n if (s.length < maxLen) maxLen = s.length;\n \n var textAndMatches = getTextAndMatchArray(s, lastQuery.getMarkRegExp());\n \n var ranges = getMatchedTextWithContextRanges(textAndMatches, s, maxLen);\n \n // When the maxLen is not yet reached add more ranges \n // starting from the beginning until either maxLen or \n // the end of the string is reached.\n fillUpRanges(s, ranges, maxLen);\n\n writeRanges(place, s, textAndMatches, ranges, maxLen);\n};\n\nvar createLimitedTextWithMarks = function(place, s, maxLen) {\n// return simpleCreateLimitedTextWithMarks(place, s, maxLen);\n return createLimitedTextWithMarksAndContext(place, s, maxLen);\n};\n\n\n//----------------------------------------------------------------------------\n// The Search Result\n//----------------------------------------------------------------------------\n\nvar myStorySearch = function(text,useCaseSensitive,useRegExp)\n{\n highlightHack = new RegExp(useRegExp ? text:text.escapeRegExp(),useCaseSensitive ? "mg" : "img");\n var matches = findMatches(store, text,useCaseSensitive,useRegExp,"title","excludeSearch");\n\n firstIndexOnPage = 0;\n showResult();\n \n highlightHack = null;\n};\n\n\nvar myMacroSearchHandler = function(place,macroName,params)\n{\n var lastSearchText = "";\n var searchTimeout = null;\n var doSearch = function(txt)\n {\n if (config.options.chkUseYourSearch)\n myStorySearch(txt.value,config.options.chkCaseSensitiveSearch,config.options.chkRegExpSearch);\n else\n story.search(txt.value,config.options.chkCaseSensitiveSearch,config.options.chkRegExpSearch);\n lastSearchText = txt.value;\n };\n var clickHandler = function(e)\n {\n doSearch(searchInputField);\n return false;\n };\n var keyHandler = function(e)\n {\n if (!e) var e = window.event;\n switch(e.keyCode)\n {\n case 13:\n doSearch(this);\n break;\n case 27:\n // When the result is open, close it, \n // otherwise clear the content of the input field\n if (isResultOpen()) {\n closeResult();\n } else {\n this.value = "";\n clearMessage();\n }\n break;\n }\n if (String.fromCharCode(e.keyCode) == this.accessKey || e.altKey) \n {\n reopenResultIfApplicable();\n }\n\n if(this.value.length<3 && searchTimeout) clearTimeout(searchTimeout);\n if((this.value.length > 2) && (this.value != lastSearchText))\n if (!config.options.chkUseYourSearch || config.options.chkSearchAsYouType)\n {\n if(searchTimeout)\n clearTimeout(searchTimeout);\n var txt = this;\n searchTimeout = setTimeout(function() {doSearch(txt);},500);\n }\n if (this.value.length == 0) \n {\n closeResult();\n }\n };\n\n\n var focusHandler = function(e)\n {\n this.select();\n reopenResultIfApplicable();\n };\n\n var btn = createTiddlyButton(place,this.label,this.prompt,clickHandler);\n var txt = createTiddlyElement(place,"input",null,null,null);\n if(params[0])\n txt.value = params[0];\n txt.onkeyup = keyHandler;\n txt.onfocus = focusHandler;\n txt.setAttribute("size",this.sizeTextbox);\n txt.setAttribute("accessKey",this.accessKey);\n txt.setAttribute("autocomplete","off");\n if(config.browser.isSafari)\n {\n txt.setAttribute("type","search");\n txt.setAttribute("results","5");\n }\n else\n txt.setAttribute("type","text");\n\n searchInputField = txt;\n searchButton = btn;\n};\n\nvar isResultOpen = function() {\n return resultElement != null && resultElement.parentNode == document.body;\n};\n\nvar closeResult = function() {\n if (isResultOpen()) {\n document.body.removeChild(resultElement);\n }\n};\n\n\nvar openAllFoundTiddlers = function() {\n closeResult();\n if (lastResults) {\n var titles=[];\n for(var i = 0; i<lastResults.length; i++)\n titles.push(lastResults[i].title);\n story.displayTiddlers(null,titles);\n }\n};\n\n// Refreshes the content of the result with the current search result\n// of the selected page.\n//\n// Assumes that the result is already open. \n//\nvar refreshResult = function() {\n if (!resultElement || !searchInputField) return;\n\n // Load the template for the YourSearchResult\n var html = store.getTiddlerText("YourSearchResultTemplate");\n if (!html) html = "<b>Tiddler YourSearchResultTemplate not found</b>";\n resultElement.innerHTML = html;\n\n // Ensure that the firstIndexOnPage is really a page start. \n // This may have become violated when the ItemsPerPage are changed,\n // e.g. when switching between previewText and simple mode.\n firstIndexOnPage = Math.floor(firstIndexOnPage / getItemsPerPage()) * getItemsPerPage();\n \n // Expand the template macros etc.\n applyHtmlMacros(resultElement,null);\n refreshElements(resultElement,null);\n \n // When there are items found add them to the result page (pagewise)\n if (lastResults && lastResults.length > 0) {\n // Load the template how to display the items that represent a found tiddler\n var itemHtml = store.getTiddlerText("YourSearchItemTemplate");\n if (!itemHtml) alertAndThrow("YourSearchItemTemplate not found");\n \n // Locate the node that shall contain the list of found tiddlers\n var items = document.getElementById(yourSearchResultItemsID);\n if(!items)\n items = createTiddlyElement(resultElement,"div",yourSearchResultItemsID);\n\n // Add the items of the current page\n var endIndex = Math.min(firstIndexOnPage+getItemsPerPage(), lastResults.length);\n indexInPage = -1;\n for (var i=firstIndexOnPage; i < endIndex; i++) {\n currentTiddler = lastResults[i];\n indexInPage++;\n indexInResult = i;\n\n var item = createTiddlyElement(items,"div",null, "yourSearchItem");\n item.innerHTML = itemHtml;\n applyHtmlMacros(item,null);\n refreshElements(item,null);\n }\n }\n \n // The currentTiddler must only be defined while rendering the found tiddlers\n currentTiddler = null;\n\n ensureResultIsDisplayedNicely();\n};\n\n// Makes sure the result page has a good size and position and visible\n// (may scroll the window)\n//\nvar ensureResultIsDisplayedNicely = function() {\n adjustResultPositionAndSize();\n scrollVisible();\n};\n\nvar scrollVisible = function() {\n // Scroll the window to make the result page (and the search Input field) visible.\n if (resultElement) window.scrollTo(0,ensureVisible(resultElement));\n if (searchInputField) window.scrollTo(0,ensureVisible(searchInputField));\n};\n\n// Adjusts the resultElement's size and position, relative to the search input field.\n//\nvar adjustResultPositionAndSize = function() {\n if (!searchInputField) return;\n \n var root = searchInputField;\n \n // Position the result below the root and resize it if necessary.\n var rootLeft = findPosX(root);\n var rootTop = findPosY(root);\n var rootHeight = root.offsetHeight;\n var popupLeft = rootLeft;\n var popupTop = rootTop + rootHeight;\n\n // Make sure the result is not wider than the window\n var winWidth = findWindowWidth();\n if (winWidth < resultElement.offsetWidth) {\n resultElement.style.width = (winWidth - 100)+"px";\n winWidth = findWindowWidth();\n }\n\n // Ensure that the left and right of the result are not\n // clipped by the window. Move it to the left or right, if necessary. \n var popupWidth = resultElement.offsetWidth;\n if(popupLeft + popupWidth > winWidth)\n popupLeft = winWidth - popupWidth-30;\n if (popupLeft < 0) popupLeft = 0;\n \n // Do the actual moving\n resultElement.style.left = popupLeft + "px";\n resultElement.style.top = popupTop + "px";\n resultElement.style.display = "block";\n};\n\nvar showResult = function() {\n if (!resultElement) {\n resultElement = createTiddlyElement(document.body,"div",yourSearchResultID,"yourSearchResult");\n } else if (resultElement.parentNode != document.body) {\n document.body.appendChild(resultElement);\n }\n\n refreshResult();\n};\n\nvar reopenResultIfApplicable = function() {\n if (searchInputField == null || !config.options.chkUseYourSearch) return;\n \n if ((searchInputField.value == lastSearchText) && lastSearchText && !isResultOpen()) {\n // For speedup we check re-use the previously created resultElement, if possible.\n if (resultElement && (resultElement.parentNode != document.body)) {\n document.body.appendChild(resultElement);\n ensureResultIsDisplayedNicely();\n } else {\n showResult();\n }\n }\n};\n\nvar setFirstIndexOnPage = function(index) {\n if (!lastResults || lastResults.length == 0) return;\n\n firstIndexOnPage = Math.min(Math.max(0, index), lastResults.length-1);\n refreshResult(); \n};\n\n\nvar onDocumentClick = function(e) {\n // Close the search result page when the user clicks on the document\n // (and not into the searchInputField, on the search button or in the result)\n if (e.target == searchInputField) return; \n if (e.target == searchButton) return; \n if (resultElement && isDescendantOrSelf(resultElement, e.target)) return; \n \n closeResult();\n};\n\nvar onDocumentKeyup = function(e) {\n // Close the search result page when the user presses "ESC"\n if (e.keyCode == 27) closeResult();\n};\naddEvent(document,"click",onDocumentClick);\naddEvent(document,"keyup",onDocumentKeyup);\n\n\n//----------------------------------------------------------------------------\n// Macros\n//----------------------------------------------------------------------------\n\n// ====Macro yourSearch ================================================\n\nconfig.macros.yourSearch = {\n // Standard Properties\n label: "yourSearch",\n prompt: "Gives access to the current/last YourSearch result",\n\n funcs: {},\n \n tests: {\n "true" : function() {return true;},\n "false" : function() {return false;},\n "found" : function() {return lastResults && lastResults.length > 0;},\n "previewText" : function() {return config.options.chkPreviewText;}\n }\n};\n\nconfig.macros.yourSearch.handler = function(place,macroName,params,wikifier,paramString,tiddler) {\n if (params.length == 0) return;\n\n var name = params[0];\n var func = config.macros.yourSearch.funcs[name];\n if (func) func(place,macroName,params,wikifier,paramString,tiddler);\n};\n\nconfig.macros.yourSearch.funcs.itemRange = function(place) {\n if (lastResults) {\n var endIndex = Math.min(firstIndexOnPage+getItemsPerPage(), lastResults.length);\n var s = "%0 - %1".format([firstIndexOnPage+1,endIndex]);\n createTiddlyText(place, s);\n }\n};\n\nconfig.macros.yourSearch.funcs.count = function(place) {\n if (lastSearchText) {\n createTiddlyText(place, lastResults.length.toString());\n }\n};\n\nconfig.macros.yourSearch.funcs.query = function(place) {\n if (lastResults) {\n createTiddlyText(place, lastSearchText);\n }\n};\n\nconfig.macros.yourSearch.funcs.version = function(place) {\n var t = "YourSearch %0.%1.%2".format(\n [version.extensions.YourSearchPlugin.major, \n version.extensions.YourSearchPlugin.minor, \n version.extensions.YourSearchPlugin.revision]);\n var e = createTiddlyElement(place, "a");\n e.setAttribute("href", "http://tiddlywiki.abego-software.de/#YourSearchPlugin");\n e.innerHTML = '<font color="black" face="Arial, Helvetica, sans-serif">'+t+'<font>';\n};\n\nconfig.macros.yourSearch.funcs.copyright = function(place) {\n var e = createTiddlyElement(place, "a");\n e.setAttribute("href", "http://tiddlywiki.abego-software.de");\n e.innerHTML = '<font color="black" face="Arial, Helvetica, sans-serif">&copy; 2005-2006 <b><font color="red">abego</font></b> Software<font>';\n};\n\n\nconfig.macros.yourSearch.funcs.linkButton = function(place,macroName,params,wikifier,paramString,tiddler) {\n if (params < 2) return;\n \n var tiddlyLink = params[1];\n var text = params < 3 ? tiddlyLink : params[2];\n var tooltip = params < 4 ? text : params[3];\n var accessKey = params < 5 ? null : params[4];\n \n var btn = createTiddlyButton(place,text,tooltip,closeResultAndDisplayTiddler,null,null, accessKey);\n btn.setAttribute("tiddlyLink",tiddlyLink);\n};\n\nconfig.macros.yourSearch.funcs.closeButton = function(place,macroName,params,wikifier,paramString,tiddler) {\n var button = createTiddlyButton(place, "close", "Close the Search Results (Shortcut: ESC)", closeResult);\n};\n\nconfig.macros.yourSearch.funcs.openAllButton = function(place,macroName,params,wikifier,paramString,tiddler) {\n if (!lastResults) return;\n var n = lastResults.length;\n if (n == 0) return;\n\n var title = n == 1 ? "open tiddler" : "open all %0 tiddlers".format([n]);\n var button = createTiddlyButton(place, title, "Open all found tiddlers (Shortcut: Alt-O)", openAllFoundTiddlers);\n button.setAttribute("accessKey","O");\n};\n\nvar onNaviButtonClick = function(e) {\n if (!e) var e = window.event;\n var pageIndex = getIntAttribute(this, "page");\n setFirstIndexOnPage(pageIndex * getItemsPerPage(), 0);\n};\n\nconfig.macros.yourSearch.funcs.naviBar = function(place,macroName,params,wikifier,paramString,tiddler) {\n if (!lastResults || lastResults.length == 0) return;\n\n var button;\n var currentPageIndex = Math.floor(firstIndexOnPage / getItemsPerPage());\n var lastPageIndex = Math.floor((lastResults.length-1) / getItemsPerPage());\n if (currentPageIndex > 0) {\n button = createTiddlyButton(place, "Previous", "Go to previous page (Shortcut: Alt-'<')", onNaviButtonClick, "prev");\n button.setAttribute("page",(currentPageIndex-1).toString());\n button.setAttribute("accessKey","<");\n }\n\n for (var i = -maxPagesInNaviBar; i < maxPagesInNaviBar; i++) {\n var pageIndex = currentPageIndex+i;\n if (pageIndex < 0) continue;\n if (pageIndex > lastPageIndex) break;\n\n var pageNo = (i+currentPageIndex+1).toString();\n var buttonClass = pageIndex == currentPageIndex ? "currentPage" : "otherPage";\n button = createTiddlyButton(place, pageNo, "Go to page %0".format([pageNo]), onNaviButtonClick, buttonClass);\n button.setAttribute("page",(pageIndex).toString());\n }\n \n if (currentPageIndex < lastPageIndex) {\n button = createTiddlyButton(place, "Next", "Go to next page (Shortcut: Alt-'>')", onNaviButtonClick, "next");\n button.setAttribute("page",(currentPageIndex+1).toString());\n button.setAttribute("accessKey",">");\n }\n};\n\n\nconfig.macros.yourSearch.funcs["if"] = function(place,macroName,params,wikifier,paramString,tiddler) {\n if (params.length < 2) return;\n \n var testName = params[1];\n var negate = (testName == "not");\n if (negate) {\n if (params.length < 3) return;\n testName = params[2];\n }\n \n var test = config.macros.yourSearch.tests[testName];\n var showIt = false;\n try {\n if (test) {\n showIt = test(place,macroName,params,wikifier,paramString,tiddler) != negate;\n } else {\n // When no predefined test is specified try to evaluate it as a JavaScript expression.\n showIt = (!eval(testName)) == negate;\n }\n } catch (ex) {\n }\n \n if (!showIt) {\n place.style.display="none";\n }\n};\n\nvar createOptionWithRefresh = function(place, optionParams, wikifier,tiddler) {\n invokeMacro(place,"option",optionParams,wikifier,tiddler);\n // The option macro appended the component at the end of the place.\n var elem = place.lastChild;\n var oldOnClick = elem.onclick;\n elem.onclick = function(e) {\n var result = oldOnClick.apply(this, arguments);\n refreshResult();\n return result;\n };\n return elem;\n};\n\nconfig.macros.yourSearch.funcs.chkPreviewText = function(place,macroName,params,wikifier,paramString,tiddler) {\n var optionParams = params.slice(1).join(" ");\n \n var elem = createOptionWithRefresh(place, "chkPreviewText", wikifier,tiddler);\n elem.setAttribute("accessKey", "P");\n elem.title = "Show text preview of found tiddlers (Shortcut: Alt-P)"; \n return elem;\n};\n\n// ====Macro foundTiddler ================================================\n\nconfig.macros.foundTiddler = {\n // Standard Properties\n label: "foundTiddler",\n prompt: "Provides information on the tiddler currently processed on the YourSearch result page",\n \n funcs: {}\n};\n\n\nconfig.macros.foundTiddler.handler = function(place,macroName,params,wikifier,paramString,tiddler) {\n if (!currentTiddler) return;\n var name = params[0];\n var func = config.macros.foundTiddler.funcs[name];\n if (func) func(place,macroName,params,wikifier,paramString,tiddler);\n};\n\n// Closes the Search Result window and displays the tiddler \n// defined by the "tiddlyLink" attribute of this element\n//\nvar closeResultAndDisplayTiddler = function(e)\n{\n closeResult();\n \n var title = this.getAttribute("tiddlyLink");\n if(title) {\n var withHilite = this.getAttribute("withHilite");\n var oldHighlightHack = highlightHack;\n if (withHilite && withHilite=="true" && lastQuery) {\n highlightHack = lastQuery.getMarkRegExp();\n }\n story.displayTiddler(this,title);\n highlightHack = oldHighlightHack;\n }\n return(false);\n};\n\n// Returns the "shortcut number" of the currentTiddler. \n// I.e. When the user presses Alt-n the given tiddler is opened/display.\n//\n// @return 0-9 or -1 when no number is defined\n//\nvar getShortCutNumber = function() {\n if (!currentTiddler) return -1;\n \n if (indexInPage >= 0 && indexInPage <= 9) {\n return indexInPage < 9 ? (indexInPage+1) : 0;\n } else {\n return -1;\n }\n};\n\nconfig.macros.foundTiddler.funcs.title = function(place,macroName,params,wikifier,paramString,tiddler) {\n if (!currentTiddler) return;\n \n var shortcutNumber = getShortCutNumber();\n var tooltip = shortcutNumber >= 0 \n ? "Open tiddler (Shortcut: Alt-%0)".format([shortcutNumber.toString()])\n : "Open tiddler";\n\n var btn = createTiddlyButton(place,null,tooltip,closeResultAndDisplayTiddler,null);\n btn.setAttribute("tiddlyLink",currentTiddler.title);\n btn.setAttribute("withHilite","true");\n \n createLimitedTextWithMarks(btn, currentTiddler.title, maxCharsInTitle);\n\n if (shortcutNumber >= 0) {\n btn.setAttribute("accessKey",shortcutNumber.toString());\n }\n};\n\nconfig.macros.foundTiddler.funcs.tags = function(place,macroName,params,wikifier,paramString,tiddler) {\n if (!currentTiddler) return;\n\n createLimitedTextWithMarks(place, currentTiddler.getTags(), maxCharsInTags);\n};\n\nconfig.macros.foundTiddler.funcs.text = function(place,macroName,params,wikifier,paramString,tiddler) {\n if (!currentTiddler) return;\n\n createLimitedTextWithMarks(place, removeTextDecoration(currentTiddler.text), maxCharsInText);\n};\n\n\n// Renders the "shortcut number" of the current tiddler, to indicate to the user\n// what number to "Alt-press" to open the tiddler.\n//\nconfig.macros.foundTiddler.funcs.number = function(place,macroName,params,wikifier,paramString,tiddler) {\n var numberToDisplay = getShortCutNumber();\n if (numberToDisplay >= 0) {\n var text = "%0)".format([numberToDisplay.toString()]);\n createTiddlyElement(place,"span",null,"shortcutNumber",text);\n }\n};\n\nfunction scrollToAnchor(name) {\n return false;\n}\n//----------------------------------------------------------------------------\n// Configuration Stuff\n//----------------------------------------------------------------------------\n\nif (config.options.chkUseYourSearch == undefined) config.options.chkUseYourSearch = true;\nif (config.options.chkPreviewText == undefined) config.options.chkPreviewText = true;\nif (config.options.chkSearchAsYouType == undefined) config.options.chkSearchAsYouType=true;\nif (config.options.chkSearchInTitle == undefined) config.options.chkSearchInTitle=true;\nif (config.options.chkSearchInText == undefined) config.options.chkSearchInText=true;\nif (config.options.chkSearchInTags == undefined) config.options.chkSearchInTags=true;\nif (config.options.txtItemsPerPage == undefined) config.options.txtItemsPerPage =itemsPerPageDefault;\nif (config.options.txtItemsPerPageWithPreview == undefined) config.options.txtItemsPerPageWithPreview=itemsPerPageWithPreviewDefault;\n\nconfig.shadowTiddlers.AdvancedOptions += "\sn<<option chkUseYourSearch>> Use 'Your Search' //([[more options|YourSearch Options]])//";\n\n//----------------------------------------------------------------------------\n// Shadow Tiddlers\n//----------------------------------------------------------------------------\n\nconfig.shadowTiddlers["YourSearch Introduction"] = \n "!About YourSearch\sn"+\n "\sn"+\n "YourSearch gives you a bunch of new features to simplify and speed up your daily searches in TiddlyWiki. It seamlessly integrates into the standard TiddlyWiki search: just start typing into the 'search' field and explore!\sn"+\n "\sn"+\n "''May the '~Alt-F' be with you.''\sn"+\n "\sn"+\n "\sn"+\n "!Features\sn"+\n "* YourSearch searches for tiddlers that match your query ''as you type'' into the 'search' field. It presents a list of the ''\s"Top Ten\s"'' tiddlers in a ''popup-like window'': the ''[[YourSearch Result]]''. The tiddlers currently displayed in your TiddlyWiki are not affected.\sn"+\n "* Using ''~TiddlerRank technology'' the [[YourSearch Result]] lists the ''most interesting tiddlers first''.\sn"+\n "* Through ''Filtered Search'' and ''Boolean Search'' you can easily refining your search, like excluding words or searching for multiple words. This way less tiddlers are displayed in the [[YourSearch Result]] and you can faster scan the result for the tiddler you are looking for.\sn"+\n "* The [[YourSearch Result]] lists the found tiddlers ''page-wise'', e.g. 10 per page. Use the ''Result Page Navigation Bar'' to navigate between pages if the result does not fit on one page.\sn"+\n "* The [[YourSearch Result]] states the ''total number of found tiddlers''. This way you can quickly decide if you want to browse the result list or if you want to refine your search first to shorten the result list.\sn"+\n "* Beside the ''title of the found tiddlers'' the [[YourSearch Result]] also ''displays tags'' and ''tiddler text previews''. The ''tiddler text preview'' is an extract of the tiddler's content, showing the most interesting parts related to your query (e.g. the texts around the words you are looking for).\sn"+\n "* The words you are looking for are hilited in the titles, tags and text previews of the [[YourSearch Result]].\sn"+\n "* If you are not interested in the tiddler text previews but prefer to get longer lists of tiddlers on one result page you may ''switch of the text preview''.\sn"+\n "* If the [[YourSearch Result]] contains the tiddler you are looking for you can just ''click its title to display'' it in your TiddlyWiki. Alternatively you may also ''open all found tiddlers'' at once. \sn"+\n "* Use [[YourSearch Options]] to customize YourSearch to your needs. E.g. depending on the size of your screen you may change the number of tiddlers displayed in the [[YourSearch Result]]. In the [[YourSearch Options]] and the AdvancedOptions you may also switch off YourSearch in case you temporarily want to use the standard search.\sn"+\n "* For the most frequently actions ''access keys'' are defined so you can perform your search without using the mouse.\sn"+\n "\sn"\n ;\n\nconfig.shadowTiddlers["YourSearch Help"] = \n// "<html><a name='Top'/>"+\n// "<a href='javascript:scrollToAnchor(\s"Filtered\s");'>[Filtered Search] </a>"+\n// "<a href='#Boolean'>[Boolean Search] </a>"+\n// "<a href='#Exact'>['Exact Word' Search] </a>"+\n// "<a href='#Combined'>[Combined Search] </a>"+\n// "<a href='#Case'>[CaseSensitiveSearch and RegExpSearch] </a>"+\n// "<a href='#Access'>[Access Keys] </a>"+\n// "</html>"+\n "<<tiddler [[YourSearch Introduction]]>>"+\n// "<html><sub><a href='#Top'>[Top]</a></sub></html>\sn"+\n "\sn"+\n "!Filtered Search<html><a name='Filtered'/></html>\sn"+\n "Using the Filtered Search you can restrict your search to certain parts of a tiddler, e.g only search the tags or only the titles.\sn"+\n "|!What you want|!What you type|!Example|\sn"+\n "|Search ''titles only''|start word with ''!''|{{{!jonny}}}|\sn"+\n "|Search ''contents only''|start word with ''%''|{{{%football}}}|\sn"+\n "|Search ''tags only''|start word with ''#''|{{{#Plugin}}}|\sn"+\n "\sn"+\n "You may use more than one filter for a word. E.g. {{{!#Plugin}}} finds tiddlers containing \s"Plugin\s" either in the title or in the tags (but does not look for \s"Plugin\s" in the content).\sn"+\n// "<html><sub><a href='#Top'>[Top]</a></sub></html>\sn"+\n "\sn"+\n "!Boolean Search<html><a name='Boolean'/></html>\sn"+\n "The Boolean Search is useful when searching for multiple words.\sn"+\n "|!What you want|!What you type|!Example|\sn"+\n "|''All words'' must exist|List of words|{{{jonny jeremy}}}|\sn"+\n "|''At least one word'' must exist|Separate words by ''or''|{{{jonny or jeremy}}}|\sn"+\n "|A word ''must not exist''|Start word with ''-''|{{{-jonny}}}|\sn"+\n "\sn"+\n "''Note:'' When you specify two words, separated with a space, YourSearch finds all tiddlers that contain both words, but not necessarily next to each other. If you want to find a sequence of word, e.g. '{{{John Brown}}}', you need to put the words into quotes. I.e. you type: {{{\s"john brown\s"}}}.\sn"+\n// "<html><sub><a href='#Top'>[Top]</a></sub></html>\sn"+\n "\sn"+\n "!'Exact Word' Search<html><a name='Exact'/></html>\sn"+\n "By default a search result all matches that 'contain' the searched text. \sn"+\n " E.g. if you search for 'Task' you will get all tiddlers containing 'Task', but also 'CompletedTask', 'TaskForce' etc.\sn"+\n "\sn"+\n "If you only want to get the tiddlers that contain 'exactly the word' you need to prefix it with a '='. E.g. typing '=Task' will the tiddlers that contain the word 'Task', ignoring words that just contain 'Task' as a substring.\sn"+\n// "<html><sub><a href='#Top'>[Top]</a></sub></html>\sn"+\n "\sn"+\n "!Combined Search<html><a name='Combined'/></html>\sn"+\n "You are free to combine the various search options. \sn"+\n "\sn"+\n "''Examples''\sn"+\n "|!What you type|!Result|\sn"+\n "|{{{!jonny !jeremy -%football}}}| all tiddlers with both {{{jonny}}} and {{{jeremy}}} in its titles, but no {{{football}}} in content.|\sn"+\n "|{{{#=Task}}}|All tiddlers tagged with 'Task' (the exact word). Tags named 'CompletedTask', 'TaskForce' etc. are not considered.|\sn"+\n// "<html><sub><a href='#Top'>[Top]</a></sub></html>\sn"+\n "\sn"+\n "!~CaseSensitiveSearch and ~RegExpSearch<html><a name='Case'/></html>\sn"+\n "The standard search options ~CaseSensitiveSearch and ~RegExpSearch are fully supported by YourSearch. However when ''~RegExpSearch'' is on Filtered and Boolean Search are disabled.\sn"+\n// "<html><sub><a href='#Top'>[Top]</a></sub></html>\sn"+\n "\sn"+\n "!Access Keys<html><a name='Access'/></html>\sn"+\n "You are encouraged to use the access keys (also called \s"shortcut\s" keys) for the most frequently used operations. For quick reference these shortcuts are also mentioned in the tooltip for the various buttons etc.\sn"+\n "\sn"+\n "|!Key|!Operation|\sn"+\n "|{{{Alt-F}}}|''The most important keystroke'': It moves the cursor to the search input field so you can directly start typing your query. Pressing {{{Alt-F}}} will also display the previous search result. This way you can quickly display multiple tiddlers using \s"Press {{{Alt-F}}}. Select tiddler.\s" sequences.|\sn"+\n "|{{{ESC}}}|Closes the [[YourSearch Result]]. When the [[YourSearch Result]] is already closed and the cursor is in the search input field the field's content is cleared so you start a new query.|\sn"+\n "|{{{Alt-1}}}, {{{Alt-2}}},... |Pressing these keys opens the first, second etc. tiddler from the result list.|\sn"+\n "|{{{Alt-O}}}|Opens all found tiddlers.|\sn"+\n "|{{{Alt-P}}}|Toggles the 'Preview Text' mode.|\sn"+\n "|{{{Alt-'<'}}}, {{{Alt-'>'}}}|Displays the previous or next page in the [[YourSearch Result]].|\sn"+\n "|{{{Return}}}|When you have turned off the 'as you type' search mode pressing the {{{Return}}} key actually starts the search (as does pressing the 'search' button).|\sn"+\n// "<html><sub><a href='#Top'>[Top]</a></sub></html>\sn"+\n "\sn"\n ;\n\nconfig.shadowTiddlers["YourSearch Options"] = \n "|>|!YourSearch Options|\sn"+\n "|>|<<option chkUseYourSearch>> Use 'Your Search'|\sn"+\n "|!|<<option chkPreviewText>> Show Text Preview|\sn"+\n "|!|<<option chkSearchAsYouType>> 'Search As You Type' Mode (No RETURN required to start search)|\sn"+\n "|!|Default Search Filter:<<option chkSearchInTitle>>Titles ('!') <<option chkSearchInText>>Texts ('%') <<option chkSearchInTags>>Tags ('#') <html><br><font size=\s"-2\s">The parts of a tiddlers that are searched when you don't explicitly specify a filter in the search text (using a '!', '%' or '#' prefix).</font></html>|\sn"+\n "|!|Number of items on search result page: <<option txtItemsPerPage>>|\sn"+\n "|!|Number of items on search result page with preview text: <<option txtItemsPerPageWithPreview>>|\sn"\n ;\n \nconfig.shadowTiddlers["YourSearchStyleSheet"] = \n "/***\sn"+\n "!~YourSearchResult Stylesheet\sn"+\n "***/\sn"+\n "/*{{{*/\sn"+\n ".yourSearchResult {\sn"+\n "\stposition: absolute;\sn"+\n "\stwidth: 800px;\sn"+\n "\sn"+\n "\stpadding: 0.2em;\sn"+\n "\stlist-style: none;\sn"+\n "\stmargin: 0;\sn"+\n "\sn"+\n "\stbackground: White;\sn"+\n "\stborder: 1px solid DarkGray;\sn"+\n "}\sn"+\n "\sn"+\n "/*}}}*/\sn"+\n "/***\sn"+\n "!!Summary Section\sn"+\n "***/\sn"+\n "/*{{{*/\sn"+\n ".yourSearchResult .summary {\sn"+\n "\stborder-bottom-width: thin;\sn"+\n "\stborder-bottom-style: solid;\sn"+\n "\stborder-bottom-color: #999999;\sn"+\n "\stpadding-bottom: 4px;\sn"+\n "}\sn"+\n "\sn"+\n ".yourSearchRange, .yourSearchCount, .yourSearchQuery {\sn"+\n "\stfont-weight: bold;\sn"+\n "}\sn"+\n "\sn"+\n ".yourSearchResult .summary .button {\sn"+\n "\stfont-size: 10px;\sn"+\n "\sn"+\n "\stpadding-left: 0.3em;\sn"+\n "\stpadding-right: 0.3em;\sn"+\n "}\sn"+\n "\sn"+\n ".yourSearchResult .summary .chkBoxLabel {\sn"+\n "\stfont-size: 10px;\sn"+\n "\sn"+\n "\stpadding-right: 0.3em;\sn"+\n "}\sn"+\n "\sn"+\n "/*}}}*/\sn"+\n "/***\sn"+\n "!!Items Area\sn"+\n "***/\sn"+\n "/*{{{*/\sn"+\n ".yourSearchResult .marked {\sn"+\n "\stbackground: none;\sn"+\n "\stfont-weight: bold;\sn"+\n "}\sn"+\n "\sn"+\n ".yourSearchItem {\sn"+\n "\stmargin-top: 2px;\sn"+\n "}\sn"+\n "\sn"+\n ".yourSearchNumber {\sn"+\n "\stcolor: #808080;\sn"+\n "}\sn"+\n "\sn"+\n "\sn"+\n ".yourSearchTags {\sn"+\n "\stcolor: #008000;\sn"+\n "}\sn"+\n "\sn"+\n ".yourSearchText {\sn"+\n "\stcolor: #808080;\sn"+\n "\stmargin-bottom: 6px;\sn"+\n "}\sn"+\n "\sn"+\n "/*}}}*/\sn"+\n "/***\sn"+\n "!!Footer\sn"+\n "***/\sn"+\n "/*{{{*/\sn"+\n ".yourSearchFooter {\sn"+\n "\stmargin-top: 8px;\sn"+\n "\stborder-top-width: thin;\sn"+\n "\stborder-top-style: solid;\sn"+\n "\stborder-top-color: #999999;\sn"+\n "}\sn"+\n "\sn"+\n ".yourSearchFooter a:hover{\sn"+\n "\stbackground: none;\sn"+\n "\stcolor: none;\sn"+\n "}\sn"+\n "/*}}}*/\sn"+\n "/***\sn"+\n "!!Navigation Bar\sn"+\n "***/\sn"+\n "/*{{{*/\sn"+\n ".yourSearchNaviBar a {\sn"+\n "\stfont-size: 16px;\sn"+\n "\stmargin-left: 4px;\sn"+\n "\stmargin-right: 4px;\sn"+\n "\stcolor: black;\sn"+\n "\sttext-decoration: underline;\sn"+\n "}\sn"+\n "\sn"+\n ".yourSearchNaviBar a:hover {\sn"+\n "\stbackground-color: none;\sn"+\n "}\sn"+\n "\sn"+\n ".yourSearchNaviBar .prev {\sn"+\n "\stfont-weight: bold;\sn"+\n "\stcolor: blue;\sn"+\n "}\sn"+\n "\sn"+\n ".yourSearchNaviBar .currentPage {\sn"+\n "\stcolor: #FF0000;\sn"+\n "\stfont-weight: bold;\sn"+\n "\sttext-decoration: none;\sn"+\n "}\sn"+\n "\sn"+\n ".yourSearchNaviBar .next {\sn"+\n "\stfont-weight: bold;\sn"+\n "\stcolor: blue;\sn"+\n "}\sn"+\n "/*}}}*/\sn"\n ;\n\nconfig.shadowTiddlers["YourSearchResultTemplate"] = \n "<!--\sn"+\n "{{{\sn"+\n "-->\sn"+\n "<span macro=\s"yourSearch if found\s">\sn"+\n "<!-- The Summary Header ============================================ -->\sn"+\n "<table class=\s"summary\s" border=\s"0\s" width=\s"100%\s" cellspacing=\s"0\s" cellpadding=\s"0\s"><tbody>\sn"+\n " <tr>\sn"+\n "\st<td align=\s"left\s">\sn"+\n "\st\stYourSearch Result <span class=\s"yourSearchRange\s" macro=\s"yourSearch itemRange\s"></span>\sn"+\n "\st\st&nbsp;of&nbsp;<span class=\s"yourSearchCount\s" macro=\s"yourSearch count\s"></span>\sn"+\n "\st\stfor&nbsp;<span class=\s"yourSearchQuery\s" macro=\s"yourSearch query\s"></span>\sn"+\n "\st</td>\sn"+\n "\st<td class=\s"yourSearchButtons\s" align=\s"right\s">\sn"+\n "\st\st<span macro=\s"yourSearch chkPreviewText\s"></span><span class=\s"chkBoxLabel\s">preview text</span>\sn"+\n "\st\st<span macro=\s"yourSearch openAllButton\s"></span>\sn"+\n "\st\st<span macro=\s"yourSearch linkButton 'YourSearch Options' options 'Configure YourSearch'\s"></span>\sn"+\n "\st\st<span macro=\s"yourSearch linkButton 'YourSearch Help' help 'Get help how to use YourSearch'\s"></span>\sn"+\n "\st\st<span macro=\s"yourSearch closeButton\s"></span>\sn"+\n "\st</td>\sn"+\n " </tr>\sn"+\n "</tbody></table>\sn"+\n "\sn"+\n "<!-- The List of Found Tiddlers ============================================ -->\sn"+\n "<div id=\s"yourSearchResultItems\s" itemsPerPage=\s"25\s" itemsPerPageWithPreview=\s"10\s"></div>\sn"+\n "\sn"+\n "<!-- The Footer (with the Navigation) ============================================ -->\sn"+\n "<table class=\s"yourSearchFooter\s" border=\s"0\s" width=\s"100%\s" cellspacing=\s"0\s" cellpadding=\s"0\s"><tbody>\sn"+\n " <tr>\sn"+\n "\st<td align=\s"left\s">\sn"+\n "\st\stResult page: <span class=\s"yourSearchNaviBar\s" macro=\s"yourSearch naviBar\s"></span>\sn"+\n "\st</td>\sn"+\n "\st<td align=\s"right\s"><span macro=\s"yourSearch version\s"></span>, <span macro=\s"yourSearch copyright\s"></span>\sn"+\n "\st</td>\sn"+\n " </tr>\sn"+\n "</tbody></table>\sn"+\n "<!-- end of the 'tiddlers found' case =========================================== -->\sn"+\n "</span>\sn"+\n "\sn"+\n "\sn"+\n "<!-- The \s"No tiddlers found\s" case =========================================== -->\sn"+\n "<span macro=\s"yourSearch if not found\s">\sn"+\n "<table class=\s"summary\s" border=\s"0\s" width=\s"100%\s" cellspacing=\s"0\s" cellpadding=\s"0\s"><tbody>\sn"+\n " <tr>\sn"+\n "\st<td align=\s"left\s">\sn"+\n "\st\stYourSearch Result: No tiddlers found for <span class=\s"yourSearchQuery\s" macro=\s"yourSearch query\s"></span>.\sn"+\n "\st</td>\sn"+\n "\st<td class=\s"yourSearchButtons\s" align=\s"right\s">\sn"+\n "\st\st<span macro=\s"yourSearch linkButton 'YourSearch Options' options 'Configure YourSearch'\s"></span>\sn"+\n "\st\st<span macro=\s"yourSearch linkButton 'YourSearch Help' help 'Get help how to use YourSearch'\s"></span>\sn"+\n "\st\st<span macro=\s"yourSearch closeButton\s"></span>\sn"+\n "\st</td>\sn"+\n " </tr>\sn"+\n "</tbody></table>\sn"+\n "</span>\sn"+\n "\sn"+\n "\sn"+\n "<!--\sn"+\n "}}}\sn"+\n "-->\sn"\n ;\n\nconfig.shadowTiddlers["YourSearchItemTemplate"] = \n "<!--\sn"+\n "{{{\sn"+\n "-->\sn"+\n "<span class='yourSearchNumber' macro='foundTiddler number'></span>\sn"+\n "<span class='yourSearchTitle' macro='foundTiddler title'/></span>&nbsp;-&nbsp;\sn"+\n "<span class='yourSearchTags' macro='foundTiddler tags'/></span>\sn"+\n "<span macro=\s"yourSearch if previewText\s"><div class='yourSearchText' macro='foundTiddler text'/></div></span>\sn"+\n "<!--\sn"+\n "}}}\sn"+\n "-->"\n ;\nconfig.shadowTiddlers["YourSearch"] = "<<tiddler [[YourSearch Help]]>>";\n\nconfig.shadowTiddlers["YourSearch Result"] = "The popup-like window displaying the result of a YourSearch query.";\n\n\nsetStylesheet(\n store.getTiddlerText("YourSearchStyleSheet"),\n "yourSearch");\n\n//----------------------------------------------------------------------------\n// Install YourSearch\n//----------------------------------------------------------------------------\n\n// Overwrite the TiddlyWiki search handler and verify after a while \n// that nobody else has overwritten it.\n\nvar origMacros_search_handler = config.macros.search.handler;\nconfig.macros.search.handler = myMacroSearchHandler;\n\n\nvar ownsOverwrittenFunctions = function() {\n var result = (config.macros.search.handler == myMacroSearchHandler);\n return result;\n};\n\nvar checkForOtherHijacker = function() {\n if (!ownsOverwrittenFunctions()) {\n alert("Message from YourSearchPlugin:\sn\sn\sn"+\n "Another plugin has disabled the 'Your Search' features.\sn\sn\sn"+\n "You may disable the other plugin or change the load order of \sn"+\n "the plugins (by changing the names of the tiddlers)\sn"+ \n "to enable the 'Your Search' features.");\n }\n};\n\nsetTimeout(checkForOtherHijacker, 5000);\n\n\n// === Public API =================================\n\nabego.YourSearch.getStandardRankFunction = function() {\n return standardRankFunction;\n};\n\nabego.YourSearch.getRankFunction = function() {\n return abego.YourSearch.getStandardRankFunction();\n};\n\nabego.YourSearch.getCurrentTiddler = function() {\n return currentTiddler;\n};\n\n} // of "install only once"\n//}}}\n// Used Globals (for JSLint) ==============\n\n// ... JavaScript Core\n/*global alert,clearTimeout,confirm */\n// ... TiddlyWiki Core\n/*global Tiddler, applyHtmlMacros, clearMessage, createTiddlyElement, createTiddlyButton, createTiddlyText, ensureVisible ,findPosX, highlightHack, findPosY,findWindowWidth, invokeMacro, saveChanges, refreshElements, story */\n\n/***\n%/\n!Licence and Copyright\nCopyright (c) abego Software ~GmbH, 2005-2006 ([[www.abego-software.de|http://www.abego-software.de]])\n\nRedistribution and use in source and binary forms, with or without modification,\nare permitted provided that the following conditions are met:\n\nRedistributions of source code must retain the above copyright notice, this\nlist of conditions and the following disclaimer.\n\nRedistributions in binary form must reproduce the above copyright notice, this\nlist of conditions and the following disclaimer in the documentation and/or other\nmaterials provided with the distribution.\n\nNeither the name of abego Software nor the names of its contributors may be\nused to endorse or promote products derived from this software without specific\nprior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY\nEXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\nOF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\nSHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\nINCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\nTO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR\nBUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\nANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH\nDAMAGE.\n***/\n\n
<div class='toolbar' macro='toolbar collapseTiddler collapseOthers -closeTiddler closeOthers +editTiddler permalink references jump'><span macro='encrypt'></span><span macro='decrypt'></span><span macro='tagger'></span></div>\n<div class='title' macro='view title'></div>\n<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date [[DD MMM YYYY]]'></span> (created <span macro='view created date [[DD MMM YYYY]]'></span>)</div>\n<div class='tagging' macro='tagging'></div>\n<div class='tagged' macro='tags'></div>\n<div class='viewer' macro='view text wikified'></div>\n<div class='tagClear'></div>
/***\n|''Name:''|~TaggerPlugin|\n|''Version:''|1.0.1 (2006-06-01)|\n|''Source:''|http://lewcid.googlepages.com/lewcid.html/#TaggerPlugin|\n|''Author:''|SaqImtiaz|\n|''Description:''|Provides a drop down listing current tiddler tags, and allowing toggling of tags.|\n|''Documentation:''|[[TaggerPluginDocumentation]]|\n|''Source Code:''|[[TaggerPluginSource]]|\n|''~TiddlyWiki:''|Version 2.0.8 or better|\n***/\n//{{{\n\nconfig.tagger={\n defaults:{\n label: 'Tags: ',\n tooltip: 'Manage tiddler tags',\n taglist: 'true',\n excludeTags: '',\n notags: 'tiddler has no tags',\n aretags: 'current tiddler tags:',\n toggletext: 'add tags:'\n }\n};\n\nconfig.macros.tagger={};\nconfig.macros.tagger.arrow = (document.all?"▼":"▾"); // the fat one is the only one that works in IE\nconfig.macros.tagger.handler = function(place,macroName,params,wikifier,paramString,tiddler) {\n var defaults = config.tagger.defaults;\n var nAV = paramString.parseParams('tagman', null, true);\n var label = ((nAV[0].label)&&(nAV[0].label[0])!='.')?nAV[0].label[0]+this.arrow: defaults.label+this.arrow;\n var tooltip = ((nAV[0].tooltip)&&(nAV[0].tooltip[0])!='.')?nAV[0].tooltip[0]: defaults.tooltip;\n var taglist = ((nAV[0].taglist)&&(nAV[0].taglist[0])!='.')?nAV[0].taglist[0]: defaults.taglist;\n var exclude = ((nAV[0].exclude)&&(nAV[0].exclude[0])!='.')?(nAV[0].exclude[0]).readBracketedList(): defaults.excludeTags.readBracketedList();\n if ((nAV[0].source)&&(nAV[0].source[0])!='.')var source = nAV[0].source[0];\n if (source&&!store.getTiddler(source)) return false;\n\n var onclick = function(e) {\n if (!e) var e = window.event;\n var popup = Popup.create(this);\n var tagsarray = store.getTags();\n var tags=new Array();\n\n for (var i=0; i<tagsarray.length; i++){\n tags.push(tagsarray[i][0]);}\n\n if (source)\n {var sourcetiddler=store.getTiddler(source);\n tags=sourcetiddler.tags.sort();}\n\n var currentTags = tiddler.tags.sort();\n\n var createButtons=function(text,theTag,tooltipPrefix){\n var sp = createTiddlyElement(createTiddlyElement(popup,"li"),"span",null,"tagger");\n var theToggle = createTiddlyButton(sp,text,tooltipPrefix+" '"+theTag+"'",taggerOnToggle,"button","toggleButton");\n theToggle.setAttribute("tiddler",tiddler.title);\n theToggle.setAttribute("tag",theTag);\n insertSpacer(sp);\n if (window.createTagButton_orig_mptw)\n createTagButton_orig_mptw(sp,theTag);\n else\n createTagButton(sp,theTag);\n }\n\n createTiddlyElement(popup,"li",null,"listTitle",(tiddler.tags.length == 0 ? defaults.notags : defaults.aretags));\n\n for (var t=0; t<currentTags.length; t++){\n createButtons("[x]",currentTags[t],"remove tag ");\n }\n\n createTiddlyElement(createTiddlyElement(popup,"li"),"hr");\n\n if (taglist!='false')\n { createTiddlyElement(popup,"li",null,"listTitle",defaults.toggletext);\n for (var i=0; i<tags.length; i++){\n if (!tiddler.tags.contains(tags[i])&&!exclude.contains(tags[i]))\n {createButtons("[ ]",tags[i],"add tag ");\n }\n }\n createTiddlyElement(createTiddlyElement(popup,"li"),"hr");\n }\n\n var newTagButton = createTiddlyButton(createTiddlyElement(popup,"li"),("Create new tag"),null,taggerOnToggle);\n newTagButton.setAttribute("tiddler",tiddler.title);\n if (source) newTagButton.setAttribute("source",source);\n\n Popup.show(popup,false);\n e.cancelBubble = true;\n if (e.stopPropagation) e.stopPropagation();\n return(false);\n };\n\n createTiddlyButton(place,label,tooltip,onclick,"button","taggerDrpBtn");\n};\n\nwindow.taggerOnToggle = function(e) {\n var tag = this.getAttribute("tag");\n var title = this.getAttribute("tiddler");\n var tiddler = store.getTiddler(title);\n if (!tag)\n {\n var newtag=prompt("Enter new tag:","");\n if (newtag!=''&&newtag!=null)\n {\n var tag=newtag;\n if (this.getAttribute("source"))\n {var sourcetiddler = store.getTiddler(this.getAttribute("source"));\n sourcetiddler.tags.pushUnique(newtag);}\n }\n else\n {return false;};\n }\n if (!tiddler || !tiddler.tags)\n {store.saveTiddler(title,title,'',config.options.txtUserName,new Date(),tag);}\n else\n {if (tiddler.tags.find(tag)==null)\n {tiddler.tags.push(tag)}\n else if(!newtag)\n {tiddler.tags.splice(tiddler.tags.find(tag),1)};\n store.saveTiddler(tiddler.title,tiddler.title,tiddler.text,tiddler.modifier,tiddler.modified,tiddler.tags);};\n story.refreshTiddler(title,null,true);\n if(config.options.chkAutoSave)\n saveChanges();\n return false;\n};\n\nsetStylesheet(\n ".tagger a.button {font-weight: bold;display:inline; padding:0px;}\sn"+\n ".tagger #toggleButton {padding-left:2px; padding-right:2px; margin-right:1px; font-size:110%;}\sn"+\n "#nestedtagger {background:#2E5ADF; border: 1px solid #0331BF;}\sn"+\n ".popup .listTitle {color:#000;}\sn"+\n "",\n"TaggerStyles");\n\nwindow.lewcidTiddlerSwapTag = function (tiddler, oldTag, newTag){\n for (var i = 0; i < tiddler.tags.length; i++)\n if (tiddler.tags[i] == oldTag) {\n tiddler.tags[i] = newTag;\n return true;}\n return false;\n}\n\nwindow.lewcidRenameTag = function(e) {\n var tag=this.getAttribute("tag");\n var newtag=prompt("Rename tag '"+tag+"' to:",tag);\n\n if ((newtag==tag)||(newtag==null)) {return false;}\n\n if(store.tiddlerExists(newtag))\n {if(confirm(config.messages.overwriteWarning.format([newtag.toString()])))\n story.closeTiddler(newtag,false,false);\n else\n return null;}\n\n tagged=store.getTaggedTiddlers(tag);\n if (tagged.length!=0){\n for (var j = 0; j < tagged.length; j++)\n lewcidTiddlerSwapTag(tagged[j],tag,newtag);}\n\n if (store.tiddlerExists(tag))\n {store.saveTiddler(tag,newtag);}\n if (document.getElementById("tiddler"+tag))\n {var oldTagTiddler = document.getElementById(story.idPrefix + tag);\n var before= story.positionTiddler(oldTagTiddler);\n var place = document.getElementById(story.container);\n story.closeTiddler(tag,false,false);\n story.createTiddler(place,before,newtag,null);\n story.saveTiddler(newtag);}\n if(config.options.chkAutoSave)\n saveChanges();\n return false;\n}\n\n\nwindow.onClickTag=function(e)\n{\n if (!e) var e = window.event;\n var theTarget = resolveTarget(e);\n\n var nested = (!isNested(theTarget));\n if ((Popup.stack.length > 1)&&(nested==true)) {Popup.removeFrom(1);}\n else if(Popup.stack.length > 0 && nested==false) {Popup.removeFrom(0);};\n\n var theId = (nested==false)? "popup" : "nestedtagger";\n var popup = createTiddlyElement(document.body,"ol",theId,"popup",null);\n Popup.stack.push({root: this, popup: popup});\n\n var tag = this.getAttribute("tag");\n var title = this.getAttribute("tiddler");\n if(popup && tag)\n {\n var tagged = store.getTaggedTiddlers(tag);\n var titles = [];\n var li,r;\n for(r=0;r<tagged.length;r++)\n if(tagged[r].title != title)\n titles.push(tagged[r].title);\n var lingo = config.views.wikified.tag;\n if(titles.length > 0)\n {\n var openAll = createTiddlyButton(createTiddlyElement(popup,"li"),lingo.openAllText.format([tag]),lingo.openAllTooltip,onClickTagOpenAll);\n openAll.setAttribute("tag",tag);\n createTiddlyElement(createTiddlyElement(popup,"li"),"hr");\n for(r=0; r<titles.length; r++)\n {\n createTiddlyLink(createTiddlyElement(popup,"li"),titles[r],true);\n }\n }\n else\n createTiddlyText(createTiddlyElement(popup,"li",null,"disabled"),lingo.popupNone.format([tag]));\n createTiddlyElement(createTiddlyElement(popup,"li"),"hr");\n var h = createTiddlyLink(createTiddlyElement(popup,"li"),tag,false);\n createTiddlyText(h,lingo.openTag.format([tag]));\n\n createTiddlyElement(createTiddlyElement(popup,"li"),"hr");\n\n var renameTagButton = createTiddlyButton(createTiddlyElement(popup,"li"),("Rename tag '"+tag+"'"),null,lewcidRenameTag);\n renameTagButton.setAttribute("tag",tag)\n }\n Popup.show(popup,false);\n e.cancelBubble = true;\n if (e.stopPropagation) e.stopPropagation();\n return(false);\n}\n\nif (!window.isNested)\n window.isNested = function(e) {\n while (e != null) {\n var contentWrapper = document.getElementById("contentWrapper");\n if (contentWrapper == e) return true;\n e = e.parentNode;\n }\n return false;\n };\n\nconfig.shadowTiddlers.TaggerPluginDocumentation="The documentation is available [[here.|http://lewcid.googlepages.com/lewcid.html#TaggerPluginDocumentation]]";\n\nconfig.shadowTiddlers.TaggerPluginSource="The uncompressed source code is available [[here.|http://lewcid.googlepages.com/lewcid.html#TaggerPluginSource]]";\n//}}}
// These are some of the options that I (Sitaram Chamarty) like\n// step 1: change, delete, or comment out whatever options you don't like\n// step 2: add the "systemConfig" tag to this tiddler\n// step 3: save the tiddler, save the tiddlywiki, and reload\n\n// Please, please set your name here!\nconfig.options.txtUserName="Not Sitaram!";\n\n// I prefer to see the Tags tab rather than the default Timeline tab\nconfig.options.txtMainTab="Tags";\n\n// if you want, set a backup folder RELATIVE TO the folder in which this file lives\nconfig.options.txtBackupFolder="bkp-tw";\n\n// I hate the animation when you click a tiddler\nconfig.options.chkAnimate=false;\n\n// convenience shadow tiddler; nice to put into MainMenu as {{{<<tiddler lastModified>>}}}\nconfig.shadowTiddlers.lastModified = document.lastModified;\n
/***\n|''Name:''|betterFormatterPlugin|\n|''Version:''|2006-04-10 - 1.0.4|\n|''Source:''|http://knighjm.googlepages.com/knightnet-default-tw.html#betterFormatterPlugin|\n\n!!Sitaram's comments and changes\n# it's a kludge\n ## you have to override a core fn\n ## view and edit may look different for code blocks!\n# but the code is short and sweet :-)\n# added\n ## leading space handling for {{{<<<}}} also\n# changed\n ## leading dash stuff; no negative lookahead -- just assume a space follows the dash\n ## the name oldwikify changed to ldspOldWikify\n# removed\n ## the <hr> stuff\n ## the alt num stuff\n\n!Description\nMake the formatters more flexible:\n* Allows white-space before the block formatters\n* Allows more than 4 dashes to make an HR\n* Handles number lists pasted from the web - these have " 1." etc. at the start of each line and this changes that into a level 1 ordered list.\n* Allows a leading dash as an unordered list (only 1 level though to avoid clash with HR rule\n\n!Tests\n !! hdg 2\n !!! Heading 3 with leading spaces\n* Standard list entry\n * With leading spaces\n ** sub-list with leading spaces\n *** sub sub list leading spcs\n- Standard numbered list entry\n - With leading spaces\n -- sub-list with leading spaces\n --- sub sub list leading spcs\n----Not a list (4 leading dashes with text after), <hr> comes next\n----\n\n<<<\nmulti line\nblock quote\n<<<\n\n> normal single line bq\n > ldsp slbq\n >> twolevels\n\n\n!Code\n***/\n//{{{\nversion.extensions.betterFormatterPlugin = {\n major: 1, minor: 0, revision: 4, date: new Date("Apr 10, 2006"), type: 'macro',\n source: 'http://knighjm.googlepages.com/knightnet-default-tw.html#betterFormatterPlugin'\n};\n\nldspOldWikify = wikify;\nwikify = function(text,parent,highlightText,highlightCaseSensitive) {\n\n text = text.replace( /^\ss*(!{1,5})/mg, "$1" ); // Allow leading white-space in headings\n\n text = text.replace( /^\ss*\s*/mg, "*" ); // Allow leading white-space in unordered lists\n text = text.replace( /^\ss*\s#/mg, "#" ); // Allow leading white-space in ordered lists\n\n text = text.replace( /^\ss*\s- /mg, "* " ); // expect a space after the dash, no neg lookaheads!\n text = text.replace( /^\ss*\s-\s- /mg, "** " ); // ditto, for 2 dashes\n text = text.replace( /^\ss*\s-\s-\s- /mg, "*** " ); // and 3\n\n text = text.replace( /^\ss*(>+)/mg, "$1" ); // Allow leading white-space in block quotes\n text = text.replace( /^\ss*(<<<) *$/mg, "$1" ); // ditto for the ''block'' block quotes!\n\n ldspOldWikify(text,parent,highlightText,highlightCaseSensitive);\n}\n//}}}
/***\n''UnformattedTextPlugin for TiddlyWiki version 1.2.x and 2.0''\n^^author: Eric Shulman - ELS Design Studios\nsource: http://www.TiddlyTools.com/#UnformattedTextPlugin \n\n!!!!!Examples\n<<<\nContent containing TiddlyWiki formatting syntax can be shown with the syntax unchanged:\n{{{\n"""this text is //not italic// and <<not a macro>> and [[not a link]]"""\n}}}\n"""this text is //not italic// and <<not a macro>> and [[not a link]]"""\n\n{{{\n__"""this text is //not italic// and <<not a macro>> and [[not a link]], but it IS underlined"""__\n}}}\n__"""this text is //not italic// and <<not a macro>> and [[not a link]], but it IS underlined"""__\n<<<\n!!!!!Code\n***/\n//{{{\nversion.extensions.unformattedText = {major: 0, minor: 5, revision: 0, date: new Date(2005,11,07)};\n\nconfig.formatters.push( {\n name: "rawText",\n match: "\s\s\s"{3}",\n lookahead: "\s\s\s"{3}((?:.|\s\sn)*?)\s\s\s"{3}",\n handler: function(w)\n {\n var lookaheadRegExp = new RegExp(this.lookahead,"mg");\n lookaheadRegExp.lastIndex = w.matchStart;\n var lookaheadMatch = lookaheadRegExp.exec(w.source)\n if(lookaheadMatch && lookaheadMatch.index == w.matchStart)\n {\n var e = createTiddlyElement(w.output,"span",null,null,lookaheadMatch[1]);\n w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;\n }\n }\n }\n)\n//}}}\n
/***\n<<tiddler EncryptionPluginDocumentation>>\n!Code\n***/\n//{{{\nversion.extensions.EncryptionPlugin = { major: 1, minor: 0, revision: 1, date: new Date(2006,18,3),\n source: "http://yann.perrin.googlepages.com/twkd.html#EncryptionPlugin"\n};\n//}}}\n/***\n// // Encrypt Command Definition\n***/\n//{{{\nconfig.macros.encrypt = {\n label: '§',\n tooltip: 'Encrypt this tiddler',\n getkeydialog: 'Enter encryption key',\n cryptedtag: 'crypted',\n donotcrypttag: 'encable' //sita -- strictly speaking it is now "cryptonlythistag"\n};\nconfig.macros.encrypt.action = function(tiddler) {\n var key = prompt(this.getkeydialog,'');\n if (key)\n {\n tiddler.text = TEAencrypt(tiddler.text,key);\n tiddler.tags.push(this.cryptedtag);\n if (version.major < 2)\n store.tiddlers[tiddler.title] = tiddler;\n else\n store.addTiddler(tiddler);\n story.refreshTiddler(tiddler.title,1,true);\n store.notifyAll();\n }\n};\nconfig.macros.encrypt.handler = function (place,macroName,params,wikifier,paramString,tiddler) {\n// sita -- == changes to != in second cond below\nif (tiddler.tags.find(this.cryptedtag)==null && tiddler.tags.find(this.donotcrypttag)!=null)\ncreateTiddlyButton(place, this.label, this.tooltip, function () {config.macros.encrypt.action(tiddler); return false;}, null, null, null);\n}\n//}}}\n// // Decrypt Command Definition\n//{{{\nconfig.macros.decrypt = {\n label: '-§-',\n tooltip: 'Decrypt this tiddler',\n cryptedtag:'crypted',\n donotdecrypttag:'encable', // sita; see above\n getkeydialog: 'Enter encryption key'\n};\nconfig.macros.decrypt.action = function(tiddler) {\n var key = prompt(this.getkeydialog,'');\n if (key)\n {\n tiddler.text = TEAdecrypt(tiddler.text,key);\n tiddler.tags.splice(tiddler.tags.find(this.cryptedtag),1);\n if (version.major < 2)\n store.tiddlers[tiddler.title] = tiddler;\n else\n store.addTiddler(tiddler);\n story.refreshTiddler(tiddler.title,1,true);\n store.notifyAll();\n }\n};\nconfig.macros.decrypt.handler = function (place,macroName,params,wikifier,paramString,tiddler) {\n// sita; see above\nif (tiddler.tags.find(this.cryptedtag)!=null && tiddler.tags.find(this.donotdecrypttag)!=null)\ncreateTiddlyButton(place, this.label, this.tooltip, function () {config.macros.decrypt.action(tiddler); return false;}, null, null, null);\n}\n//}}}\n// //Shadow tiddlers definition\n//{{{\nconfig.shadowTiddlers.ViewTemplate="<div class='toolbar' macro='toolbar -closeTiddler closeOthers +editTiddler permalink references jump'><span macro='encrypt'></span><span macro='decrypt'></span></div>\sn<div class='title' macro='view title'></div>\sn<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date [[DD MMM YYYY]]'></span> (created <span macro='view created date [[DD MMM YYYY]]'></span>)</div>\sn<div class='tagging' macro='tagging'></div>\sn<div class='tagged' macro='tags'></div>\sn<div class='viewer' macro='view text wikified'></div>\sn<div class='tagClear'></div>";\nconfig.shadowTiddlers.EncryptionPluginDocumentation="Documentation for this plugin is available [[here|" + version.extensions.EncryptionPlugin.source +"Documentation]]";\n//}}}
// // ''Installation:''\n// // Copy this tiddler to your TiddlyWiki (copy the text in edit mode).\n// // Also copy the the TabMore and TabMoreUntagged tiddlers.\n\n// // ''Code:''\n//{{{\nconfig.macros.list["untagged"] = {prompt: "Untagged tiddlers"};\n\nconfig.macros.list.untagged.handler = function(params)\n{\n var results = [];\n\n store.forEachTiddler(function (title,tiddler) {\n if(!tiddler.tags || tiddler.tags.length == 0){\n results.push(title);\n }\n });\n results.sort();\n return results;\n}\n//}}}
<<list untagged>>\n<<allTags>>
/***\nJavascript implementation of ''T''iny ''E''ncryption ''A''lgorythm\nTaken from [[Movable Type Script|http://www.movable-type.co.uk/scripts/TEAblock.html]]\n***/\n//{{{\n//\n// TEAencrypt: Use Corrected Block TEA to encrypt plaintext using password\n// (note plaintext & password must be strings not string objects)\n//\n// Return encrypted text as string\n//\nfunction TEAencrypt(plaintext, password)\n{\n if (plaintext.length == 0) return(''); // nothing to encrypt\n // 'escape' plaintext so chars outside ISO-8859-1 work in single-byte packing, but \n // keep spaces as spaces (not '%20') so encrypted text doesn't grow too long, and \n // convert result to longs\n var v = strToLongs(escape(plaintext).replace(/%20/g,' '));\n if (v.length == 1) v[1] = 0; // algorithm doesn't work for n<2 so fudge by adding nulls\n var k = strToLongs(password.slice(0,16)); // simply convert first 16 chars of password as key\n var n = v.length;\n\n var z = v[n-1], y = v[0], delta = 0x9E3779B9;\n var mx, e, q = Math.floor(6 + 52/n), sum = 0;\n\n while (q-- > 0) { // 6 + 52/n operations gives between 6 & 32 mixes on each word\n sum += delta;\n e = sum>>>2 & 3;\n for (var p = 0; p < n-1; p++) {\n y = v[p+1];\n mx = (z>>>5 ^ y<<2) + (y>>>3 ^ z<<4) ^ (sum^y) + (k[p&3 ^ e] ^ z)\n z = v[p] += mx;\n }\n y = v[0];\n mx = (z>>>5 ^ y<<2) + (y>>>3 ^ z<<4) ^ (sum^y) + (k[p&3 ^ e] ^ z)\n z = v[n-1] += mx;\n }\n // note use of >>> in place of >> due to lack of 'unsigned' type in JavaScript \n\n return escCtrlCh(longsToStr(v));\n}\n\n//\n// TEAdecrypt: Use Corrected Block TEA to decrypt ciphertext using password\n//\nfunction TEAdecrypt(ciphertext, password)\n{\n if (ciphertext.length == 0) return('');\n var v = strToLongs(unescCtrlCh(ciphertext));\n var k = strToLongs(password.slice(0,16)); \n var n = v.length;\n\n var z = v[n-1], y = v[0], delta = 0x9E3779B9;\n var mx, e, q = Math.floor(6 + 52/n), sum = q*delta;\n\n while (sum != 0) {\n e = sum>>>2 & 3;\n for (var p = n-1; p > 0; p--) {\n z = v[p-1];\n mx = (z>>>5 ^ y<<2) + (y>>>3 ^ z<<4) ^ (sum^y) + (k[p&3 ^ e] ^ z)\n y = v[p] -= mx;\n }\n z = v[n-1];\n mx = (z>>>5 ^ y<<2) + (y>>>3 ^ z<<4) ^ (sum^y) + (k[p&3 ^ e] ^ z)\n y = v[0] -= mx;\n sum -= delta;\n }\n\n var plaintext = longsToStr(v);\n // strip trailing null chars resulting from filling 4-char blocks:\n if (plaintext.search(/\s0/) != -1) plaintext = plaintext.slice(0, plaintext.search(/\s0/));\n\n return unescape(plaintext);\n}\n\n\n// supporting functions\n\nfunction strToLongs(s) { // convert string to array of longs, each containing 4 chars\n // note chars must be within ISO-8859-1 (with Unicode code-point < 256) to fit 4/long\n var l = new Array(Math.ceil(s.length/4))\n for (var i=0; i<l.length; i++) {\n // note little-endian encoding - endianness is irrelevant as long as \n // it is the same in longsToStr() \n l[i] = s.charCodeAt(i*4) + (s.charCodeAt(i*4+1)<<8) + \n (s.charCodeAt(i*4+2)<<16) + (s.charCodeAt(i*4+3)<<24);\n }\n return l; // note running off the end of the string generates nulls since \n} // bitwise operators treat NaN as 0\n\nfunction longsToStr(l) { // convert array of longs back to string\n var a = new Array(l.length);\n for (var i=0; i<l.length; i++) {\n a[i] = String.fromCharCode(l[i] & 0xFF, l[i]>>>8 & 0xFF, \n l[i]>>>16 & 0xFF, l[i]>>>24 & 0xFF);\n }\n return a.join(''); // use Array.join() rather than repeated string appends for efficiency\n}\n\nfunction escCtrlCh(str) { // escape control chars which might cause problems with encrypted texts\n return str.replace(/[\s0\sn\sv\sf\sr\sxa0!]/g, function(c) { return '!' + c.charCodeAt(0) + '!'; });\n}\n\nfunction unescCtrlCh(str) { // unescape potentially problematic nulls and control characters\n return str.replace(/!\sd\sd?\sd?!/g, function(c) { return String.fromCharCode(c.slice(1,-1)); });\n}\n//}}}\n
<<search>><<closeAll>><<permaview>><<newTiddler>><<newJournal 'DD MMM YYYY'>><<importTiddlers>><<exportTiddlers>><<saveChanges>><<slider chkSliderOptionsPanel OptionsPanel 'options »' 'Change TiddlyWiki advanced options'>>
single-file information management!
/***\nsource: http://www.TiddlyTools.com/#ExportTiddlersPlugin\nthis is version ''2006.05.11 [2.2.2]''\n!!!!!Credits\n<<<\nThis feature was developed by EricShulman from [[ELS Design Studios|http:/www.elsdesign.com]]\n<<<\n!!!!!Code\n***/\n// // +++[version]\n//{{{\nversion.extensions.exportTiddlers = {major: 2, minor: 2, revision: 2, date: new Date(2006,5,2)};\n//}}}\n// //===\n\n// // +++[macro handler]\n//{{{\nconfig.macros.exportTiddlers = {\n label: "export tiddlers",\n prompt: "Copy selected tiddlers to an export document",\n datetimefmt: "0MM/0DD/YYYY 0hh:0mm:0ss" // for "filter date/time" edit fields\n};\n\nconfig.macros.exportTiddlers.handler = function(place,macroName,params) {\n if (params[0]!="inline")\n { createTiddlyButton(place,this.label,this.prompt,onClickExportMenu); return; }\n var panel=createExportPanel(place);\n panel.style.position="static";\n panel.style.display="block";\n}\n\nfunction createExportPanel(place) {\n var panel=document.getElementById("exportPanel");\n if (panel) { panel.parentNode.removeChild(panel); }\n setStylesheet(config.macros.exportTiddlers.css,"exportTiddlers");\n panel=createTiddlyElement(place,"span","exportPanel",null,null)\n panel.innerHTML=config.macros.exportTiddlers.html;\n exportShowPanel(document.location.protocol);\n exportInitFilter();\n refreshExportList(0);\n return panel;\n}\n\nfunction onClickExportMenu(e)\n{\n if (!e) var e = window.event;\n var parent=resolveTarget(e).parentNode;\n var panel = document.getElementById("exportPanel");\n if (panel==undefined || panel.parentNode!=parent)\n panel=createExportPanel(parent);\n var isOpen = panel.style.display=="block";\n if(config.options.chkAnimate)\n anim.startAnimating(new Slider(panel,!isOpen,e.shiftKey || e.altKey,"none"));\n else\n panel.style.display = isOpen ? "none" : "block" ;\n if (panel.style.display!="none") refreshExportList(0); // update list when panel is made visible\n e.cancelBubble = true;\n if (e.stopPropagation) e.stopPropagation();\n return(false);\n}\n//}}}\n// //===\n\n// // +++[Hijack saveChanges] diverts 'notFileUrlError' to display export control panel instead\n//{{{\nwindow.coreSaveChanges=window.saveChanges;\nwindow.saveChanges = function()\n{\n if (document.location.protocol=="file:") { coreSaveChanges(); return; }\n var e = window.event;\n var parent=e?resolveTarget(e).parentNode:document.body;\n var panel = document.getElementById("exportPanel");\n if (panel==undefined || panel.parentNode!=parent) panel=createExportPanel(parent);\n exportShowPanel(document.location.protocol);\n if (parent==document.body) { panel.style.left="30%"; panel.style.top="30%"; }\n panel.style.display = "block" ;\n}\n//}}}\n// //===\n\n// // +++[IE needs explicit scoping] for functions called by browser events\n//{{{\nwindow.onClickExportMenu=onClickExportMenu;\nwindow.onClickExportButton=onClickExportButton;\nwindow.exportShowPanel=exportShowPanel;\nwindow.exportShowFilterFields=exportShowFilterFields;\nwindow.refreshExportList=refreshExportList;\n//}}}\n// //===\n\n// // +++[CSS] for floating export control panel\n//{{{\nconfig.macros.exportTiddlers.css = '\s\n#exportPanel {\s\n display: none; position:absolute; z-index:12; width:35em; right:105%; top:6em;\s\n background-color: #eee; color:#000; font-size: 8pt; line-height:110%;\s\n border:1px solid black; border-bottom-width: 3px; border-right-width: 3px;\s\n padding: 0.5em; margin:0em; -moz-border-radius:1em;\s\n}\s\n#exportPanel a, #exportPanel td a { color:#009; display:inline; margin:0px; padding:1px; }\s\n#exportPanel table { width:100%; border:0px; padding:0px; margin:0px; font-size:8pt; line-height:110%; background:transparent; }\s\n#exportPanel tr { border:0px;padding:0px;margin:0px; background:transparent; }\s\n#exportPanel td { color:#000; border:0px;padding:0px;margin:0px; background:transparent; }\s\n#exportPanel select { width:98%;margin:0px;font-size:8pt;line-height:110%;}\s\n#exportPanel input { width:98%;padding:0px;margin:0px;font-size:8pt;line-height:110%; }\s\n#exportPanel textarea { width:98%;padding:0px;margin:0px;overflow:auto;font-size:8pt; }\s\n#exportPanel .box { border:1px solid black; padding:3px; margin-bottom:5px; background:#f8f8f8; -moz-border-radius:5px; }\s\n#exportPanel .topline { border-top:2px solid black; padding-top:3px; margin-bottom:5px; }\s\n#exportPanel .rad { width:auto;border:0 }\s\n#exportPanel .chk { width:auto;border:0 }\s\n#exportPanel .btn { width:auto; }\s\n#exportPanel .btn1 { width:98%; }\s\n#exportPanel .btn2 { width:48%; }\s\n#exportPanel .btn3 { width:32%; }\s\n#exportPanel .btn4 { width:24%; }\s\n#exportPanel .btn5 { width:19%; }\s\n';\n//}}}\n// //===\n\n// // +++[HTML] for export control panel interface\n//{{{\nconfig.macros.exportTiddlers.html = '\s\n<!-- output target and format -->\s\n<table cellpadding="0" cellspacing="0"><tr><td width=50%>\s\n export to\s\n <select size=1 id="exportTo" onchange="exportShowPanel(this.value);">\s\n <option value="file:" SELECTED>this computer</option>\s\n <option value="http:">web server (http)</option>\s\n <option value="https:">secure web server (https)</option>\s\n <option value="ftp:">file server (ftp)</option>\s\n </select>\s\n</td><td width=50%>\s\n output format\s\n <select id="exportFormat" size=1>\s\n <option value="DIV">TiddlyWiki export file</option>\s\n <option value="TW">TiddlyWiki document</option>\s\n <option value="XML">RSS feed (XML)</option>\s\n </select>\s\n</td></tr></table>\s\n\s\n<!-- export to local file -->\s\n<div id="exportLocalPanel" style="margin-top:5px;">\s\nlocal path/filename<br>\s\n<input type="file" id="exportFilename" size=57 style="width:100%"><br>\s\n</div><!--panel-->\s\n\s\n<!-- export to http server -->\s\n<div id="exportHTTPPanel" style="display:none;margin-top:5px;">\s\n<table><tr><td align=left>\s\n server location, script, and parameters<br>\s\n</td><td align=right>\s\n <input type="checkbox" class="chk" id="exportNotify"\s\n onClick="document.getElementById(\s'exportSetNotifyPanel\s').style.display=this.checked?\s'block\s':\s'none\s'"> notify\s\n</td></tr></table>\s\n<input type="text" id="exportHTTPServerURL" onfocus="this.select()"><br>\s\n<div id="exportSetNotifyPanel" style="display:none">\s\n send email notices to<br>\s\n <input type="text" id="exportNotifyTo" onfocus="this.select()"><br>\s\n</div>\s\n</div><!--panel-->\s\n\s\n<!-- export to ftp server -->\s\n<div id="exportFTPPanel" style="display:none;margin-top:5px;">\s\n<table cellpadding="0" cellspacing="0" width="32%"><tr valign="top"><td>\s\n host server<br>\s\n <input type="text" id="exportFTPHost" onfocus="this.select()"><br>\s\n</td><td width="32%">\s\n username<br>\s\n <input type="text" id="exportFTPID" onfocus="this.select()"><br>\s\n</td><td width="32%">\s\n password<br>\s\n <input type="password" id="exportFTPPW" onfocus="this.select()"><br>\s\n</td></tr></table>\s\nFTP path/filename<br>\s\n<input type="text" id="exportFTPFilename" onfocus="this.select()"><br>\s\n</div><!--panel-->\s\n\s\n<!-- notes -->\s\nnotes<br>\s\n<textarea id="exportNotes" rows=3 cols=40 style="height:4em;margin-bottom:5px;" onfocus="this.select()"></textarea> \s\n\s\n<!-- list of tiddlers -->\s\n<table><tr align="left"><td>\s\n select:\s\n <a href="JavaScript:;" id="exportSelectAll"\s\n onclick="onClickExportButton(this)" title="select all tiddlers">\s\n &nbsp;all&nbsp;</a>\s\n <a href="JavaScript:;" id="exportSelectChanges"\s\n onclick="onClickExportButton(this)" title="select tiddlers changed since last save">\s\n &nbsp;changes&nbsp;</a> \s\n <a href="JavaScript:;" id="exportSelectOpened"\s\n onclick="onClickExportButton(this)" title="select tiddlers currently being displayed">\s\n &nbsp;opened&nbsp;</a> \s\n <a href="JavaScript:;" id="exportToggleFilter"\s\n onclick="onClickExportButton(this)" title="show/hide selection filter">\s\n &nbsp;filter&nbsp;</a> \s\n</td><td align="right">\s\n <a href="JavaScript:;" id="exportListSmaller"\s\n onclick="onClickExportButton(this)" title="reduce list size">\s\n &nbsp;&#150;&nbsp;</a>\s\n <a href="JavaScript:;" id="exportListLarger"\s\n onclick="onClickExportButton(this)" title="increase list size">\s\n &nbsp;+&nbsp;</a>\s\n</td></tr></table>\s\n<select id="exportList" multiple size="10" style="margin-bottom:5px;"\s\n onchange="refreshExportList(this.selectedIndex)">\s\n</select><br>\s\n</div><!--box-->\s\n\s\n<!-- selection filter -->\s\n<div id="exportFilterPanel" style="display:none">\s\n<table><tr align="left"><td>\s\n selection filter\s\n</td><td align="right">\s\n <a href="JavaScript:;" id="exportHideFilter"\s\n onclick="onClickExportButton(this)" title="hide selection filter">hide</a>\s\n</td></tr></table>\s\n<div class="box">\s\n<input type="checkbox" class="chk" id="exportFilterStart" value="1"\s\n onclick="exportShowFilterFields(this)"> starting date/time<br>\s\n<table cellpadding="0" cellspacing="0"><tr valign="center"><td width="50%">\s\n <select size=1 id="exportFilterStartBy" onchange="exportShowFilterFields(this);">\s\n <option value="0">today</option>\s\n <option value="1">yesterday</option>\s\n <option value="7">a week ago</option>\s\n <option value="30">a month ago</option>\s\n <option value="site">SiteDate</option>\s\n <option value="file">file date</option>\s\n <option value="other">other (mm/dd/yyyy hh:mm)</option>\s\n </select>\s\n</td><td width="50%">\s\n <input type="text" id="exportStartDate" onfocus="this.select()"\s\n onchange="document.getElementById(\s'exportFilterStartBy\s').value=\s'other\s';">\s\n</td></tr></table>\s\n<input type="checkbox" class="chk" id="exportFilterEnd" value="1"\s\n onclick="exportShowFilterFields(this)"> ending date/time<br>\s\n<table cellpadding="0" cellspacing="0"><tr valign="center"><td width="50%">\s\n <select size=1 id="exportFilterEndBy" onchange="exportShowFilterFields(this);">\s\n <option value="0">today</option>\s\n <option value="1">yesterday</option>\s\n <option value="7">a week ago</option>\s\n <option value="30">a month ago</option>\s\n <option value="site">SiteDate</option>\s\n <option value="file">file date</option>\s\n <option value="other">other (mm/dd/yyyy hh:mm)</option>\s\n </select>\s\n</td><td width="50%">\s\n <input type="text" id="exportEndDate" onfocus="this.select()"\s\n onchange="document.getElementById(\s'exportFilterEndBy\s').value=\s'other\s';">\s\n</td></tr></table>\s\n<input type="checkbox" class="chk" id=exportFilterTags value="1"\s\n onclick="exportShowFilterFields(this)"> match tags<br>\s\n<input type="text" id="exportTags" onfocus="this.select()">\s\n<input type="checkbox" class="chk" id=exportFilterText value="1"\s\n onclick="exportShowFilterFields(this)"> match titles/tiddler text<br>\s\n<input type="text" id="exportText" onfocus="this.select()">\s\n</div> <!--box-->\s\n</div> <!--panel-->\s\n\s\n<!-- action buttons -->\s\n<div style="text-align:center">\s\n<input type=button class="btn3" onclick="onClickExportButton(this)"\s\n id="exportFilter" value="apply filter">\s\n<input type=button class="btn3" onclick="onClickExportButton(this)"\s\n id="exportStart" value="export tiddlers">\s\n<input type=button class="btn3" onclick="onClickExportButton(this)"\s\n id="exportClose" value="close">\s\n</div><!--center-->\s\n';\n//}}}\n// //===\n\n// // +++[initialize interface]>\n// // +++[exportShowPanel(which)]\n//{{{\nfunction exportShowPanel(which) {\n var index=0; var panel='exportLocalPanel';\n switch (which) {\n case 'file:':\n case undefined:\n index=0; panel='exportLocalPanel'; break;\n case 'http:':\n index=1; panel='exportHTTPPanel'; break;\n case 'https:':\n index=2; panel='exportHTTPPanel'; break;\n case 'ftp:':\n index=3; panel='exportFTPPanel'; break;\n default:\n alert("Sorry, export to "+which+" is not yet available");\n break;\n }\n exportInitPanel(which);\n document.getElementById('exportTo').selectedIndex=index;\n document.getElementById('exportLocalPanel').style.display='none';\n document.getElementById('exportHTTPPanel').style.display='none';\n document.getElementById('exportFTPPanel').style.display='none';\n document.getElementById(panel).style.display='block';\n}\n//}}}\n// //===\n\n// // +++[exportInitPanel(which)]\n//{{{\nfunction exportInitPanel(which) {\n switch (which) {\n case "file:": // LOCAL EXPORT PANEL: file/path:\n // ** no init - security issues in IE **\n break;\n case "http:": // WEB EXPORT PANEL\n case "https:": // SECURE WEB EXPORT PANEL\n // url\n if (store.tiddlerExists("unawiki_download")) {\n var theURL=store.getTiddlerText("unawiki_download");\n theURL=theURL.replace(/\s[\s[download\s|/,'').replace(/\s]\s]/,'');\n var title=(store.tiddlerExists("unawiki_host"))?"unawiki_host":"SiteHost";\n var theHost=store.getTiddlerText(title);\n if (!theHost || !theHost.length) theHost=document.location.host;\n if (!theHost || !theHost.length) theHost=title;\n }\n // server script/params\n var title=(store.tiddlerExists("unawiki_host"))?"unawiki_host":"SiteHost";\n var theHost=store.getTiddlerText(title);\n if (!theHost || !theHost.length) theHost=document.location.host;\n if (!theHost || !theHost.length) theHost=title;\n // get POST\n var title=(store.tiddlerExists("unawiki_post"))?"unawiki_post":"SitePost";\n var thePost=store.getTiddlerText(title);\n if (!thePost || !thePost.length) thePost="/"+title;\n // get PARAMS\n var title=(store.tiddlerExists("unawiki_params"))?"unawiki_params":"SiteParams";\n var theParams=store.getTiddlerText(title);\n if (!theParams|| !theParams.length) theParams=title;\n var serverURL = which+"//"+theHost+thePost+"?"+theParams;\n document.getElementById("exportHTTPServerURL").value=serverURL;\n // get NOTIFY\n var theAddresses=store.getTiddlerText("SiteNotify");\n if (!theAddresses|| !theAddresses.length) theAddresses="SiteNotify";\n document.getElementById("exportNotifyTo").value=theAddresses;\n break;\n case "ftp:": // FTP EXPORT PANEL\n // host\n var siteHost=store.getTiddlerText("SiteHost");\n if (!siteHost || !siteHost.length) siteHost=document.location.host;\n if (!siteHost || !siteHost.length) siteHost="SiteHost";\n document.getElementById("exportFTPHost").value=siteHost;\n // username\n var siteID=store.getTiddlerText("SiteID");\n if (!siteID || !siteID.length) siteID=config.options.txtUserName;\n document.getElementById("exportFTPID").value=siteID;\n // password\n document.getElementById("exportFTPPW").value="";\n // file/path\n document.getElementById("exportFTPFilename").value="";\n break;\n }\n}\n//}}}\n// //===\n\n// // +++[exportInitFilter()]\n//{{{\nfunction exportInitFilter() {\n // start date\n document.getElementById("exportFilterStart").checked=false;\n document.getElementById("exportStartDate").value="";\n // end date\n document.getElementById("exportFilterEnd").checked=false;\n document.getElementById("exportEndDate").value="";\n // tags\n document.getElementById("exportFilterTags").checked=false;\n document.getElementById("exportTags").value="";\n // text\n document.getElementById("exportFilterText").checked=false;\n document.getElementById("exportText").value="";\n // show/hide filter input fields\n exportShowFilterFields();\n}\n//}}}\n// //===\n\n// // +++[exportShowFilterFields(which)]\n//{{{\nfunction exportShowFilterFields(which) {\n var show;\n\n show=document.getElementById('exportFilterStart').checked;\n document.getElementById('exportFilterStartBy').style.display=show?"block":"none";\n document.getElementById('exportStartDate').style.display=show?"block":"none";\n var val=document.getElementById('exportFilterStartBy').value;\n document.getElementById('exportStartDate').value\n =getFilterDate(val,'exportStartDate').formatString(config.macros.exportTiddlers.datetimefmt);\n if (which && (which.id=='exportFilterStartBy') && (val=='other'))\n document.getElementById('exportStartDate').focus();\n\n show=document.getElementById('exportFilterEnd').checked;\n document.getElementById('exportFilterEndBy').style.display=show?"block":"none";\n document.getElementById('exportEndDate').style.display=show?"block":"none";\n var val=document.getElementById('exportFilterEndBy').value;\n document.getElementById('exportEndDate').value\n =getFilterDate(val,'exportEndDate').formatString(config.macros.exportTiddlers.datetimefmt);\n if (which && (which.id=='exportFilterEndBy') && (val=='other'))\n document.getElementById('exportEndDate').focus();\n\n show=document.getElementById('exportFilterTags').checked;\n document.getElementById('exportTags').style.display=show?"block":"none";\n\n show=document.getElementById('exportFilterText').checked;\n document.getElementById('exportText').style.display=show?"block":"none";\n}\n//}}}\n// //===\n// //===\n\n// // +++[onClickExportButton(which): control interactions]\n//{{{\nfunction onClickExportButton(which)\n{\n // DEBUG alert(which.id);\n var theList=document.getElementById('exportList'); if (!theList) return;\n var count = 0;\n var total = store.getTiddlers('title').length;\n switch (which.id)\n {\n case 'exportFilter':\n count=filterExportList();\n var panel=document.getElementById('exportFilterPanel');\n if (count==-1) { panel.style.display='block'; break; }\n document.getElementById("exportStart").disabled=(count==0);\n clearMessage(); displayMessage("filtered "+formatExportMessage(count,total));\n if (count==0) { alert("No tiddlers were selected"); panel.style.display='block'; }\n break;\n case 'exportStart':\n exportTiddlers();\n break;\n case 'exportHideFilter':\n case 'exportToggleFilter':\n var panel=document.getElementById('exportFilterPanel')\n panel.style.display=(panel.style.display=='block')?'none':'block';\n break;\n case 'exportSelectChanges':\n var lastmod=new Date(document.lastModified);\n for (var t = 0; t < theList.options.length; t++) {\n if (theList.options[t].value=="") continue;\n var tiddler=store.getTiddler(theList.options[t].value); if (!tiddler) continue;\n theList.options[t].selected=(tiddler.modified>lastmod);\n count += (tiddler.modified>lastmod)?1:0;\n }\n document.getElementById("exportStart").disabled=(count==0);\n clearMessage(); displayMessage(formatExportMessage(count,total));\n if (count==0) alert("There are no unsaved changes");\n break;\n case 'exportSelectAll':\n for (var t = 0; t < theList.options.length; t++) {\n if (theList.options[t].value=="") continue;\n theList.options[t].selected=true;\n count += 1;\n }\n document.getElementById("exportStart").disabled=(count==0);\n clearMessage(); displayMessage(formatExportMessage(count,count));\n break;\n case 'exportSelectOpened':\n for (var t = 0; t < theList.options.length; t++) theList.options[t].selected=false;\n var tiddlerDisplay = document.getElementById("tiddlerDisplay");\n for (var t=0;t<tiddlerDisplay.childNodes.length;t++) {\n var tiddler=tiddlerDisplay.childNodes[t].id.substr(7);\n for (var i = 0; i < theList.options.length; i++) {\n if (theList.options[i].value!=tiddler) continue;\n theList.options[i].selected=true; count++; break;\n }\n }\n document.getElementById("exportStart").disabled=(count==0);\n clearMessage(); displayMessage(formatExportMessage(count,total));\n if (count==0) alert("There are no tiddlers currently opened");\n break;\n case 'exportListSmaller': // decrease current listbox size\n var min=5;\n theList.size-=(theList.size>min)?1:0;\n break;\n case 'exportListLarger': // increase current listbox size\n var max=(theList.options.length>25)?theList.options.length:25;\n theList.size+=(theList.size<max)?1:0;\n break;\n case 'exportClose':\n document.getElementById('exportPanel').style.display='none';\n break;\n }\n}\n//}}}\n// //===\n\n// // +++[list display]\n//{{{\nfunction formatExportMessage(count,total)\n{\n var txt=total+' tiddler'+((total!=1)?'s':'')+" - ";\n txt += (count==0)?"none":(count==total)?"all":count;\n txt += " selected for export";\n return txt;\n}\n\nfunction refreshExportList(selectedIndex)\n{\n var theList = document.getElementById("exportList");\n var sort;\n if (!theList) return;\n // get the sort order\n if (!selectedIndex) selectedIndex=0;\n if (selectedIndex==0) sort='modified';\n if (selectedIndex==1) sort='title';\n if (selectedIndex==2) sort='modified';\n if (selectedIndex==3) sort='modifier';\n\n // get the alphasorted list of tiddlers\n var tiddlers = store.getTiddlers('title');\n // unselect headings and count number of tiddlers actually selected\n var count=0;\n for (var i=0; i<theList.options.length; i++) {\n if (theList.options[i].value=="") theList.options[i].selected=false;\n count+=theList.options[i].selected?1:0;\n }\n // disable "export" button if no tiddlers selected\n document.getElementById("exportStart").disabled=(count==0);\n // update listbox heading to show selection count\n if (theList.options.length) { clearMessage(); displayMessage(formatExportMessage(count,tiddlers.length)); }\n\n // if a [command] item, reload list... otherwise, no further refresh needed\n if (selectedIndex>3) return;\n\n // clear current list contents\n while (theList.length > 0) { theList.options[0] = null; }\n // add heading and control items to list\n var i=0;\n var indent=String.fromCharCode(160)+String.fromCharCode(160);\n theList.options[i++]=\n new Option(tiddlers.length+" tiddlers in document", "",false,false);\n theList.options[i++]=\n new Option(((sort=="title" )?">":indent)+' [by title]', "",false,false);\n theList.options[i++]=\n new Option(((sort=="modified")?">":indent)+' [by date]', "",false,false);\n theList.options[i++]=\n new Option(((sort=="modifier")?">":indent)+' [by author]', "",false,false);\n // output the tiddler list\n switch(sort)\n {\n case "title":\n for(var t = 0; t < tiddlers.length; t++)\n theList.options[i++] = new Option(tiddlers[t].title,tiddlers[t].title,false,false);\n break;\n case "modifier":\n case "modified":\n var tiddlers = store.getTiddlers(sort);\n // sort descending for newest date first\n tiddlers.sort(function (a,b) {if(a[sort] == b[sort]) return(0); else return (a[sort] > b[sort]) ? -1 : +1; });\n var lastSection = "";\n for(var t = 0; t < tiddlers.length; t++)\n {\n var tiddler = tiddlers[t];\n var theSection = "";\n if (sort=="modified") theSection=tiddler.modified.toLocaleDateString();\n if (sort=="modifier") theSection=tiddler.modifier;\n if (theSection != lastSection)\n {\n theList.options[i++] = new Option(theSection,"",false,false);\n lastSection = theSection;\n }\n theList.options[i++] = new Option(indent+indent+tiddler.title,tiddler.title,false,false);\n }\n break;\n }\n theList.selectedIndex=selectedIndex; // select current control item\n}\n//}}}\n// //===\n\n// // +++[list filtering]\n//{{{\nfunction getFilterDate(val,id)\n{\n var result=0;\n switch (val) {\n case 'site':\n var timestamp=store.getTiddlerText("SiteDate");\n if (!timestamp) timestamp=document.lastModified;\n result=new Date(timestamp);\n break;\n case 'file':\n result=new Date(document.lastModified);\n break;\n case 'other':\n result=new Date(document.getElementById(id).value);\n break;\n default: // today=0, yesterday=1, one week=7, two weeks=14, a month=31\n var now=new Date(); var tz=now.getTimezoneOffset()*60000; now-=tz;\n var oneday=86400000;\n if (id=='exportStartDate')\n result=new Date((Math.floor(now/oneday)-val)*oneday+tz);\n else\n result=new Date((Math.floor(now/oneday)-val+1)*oneday+tz-1);\n break;\n }\n // DEBUG alert('getFilterDate('+val+','+id+')=='+result+"\snnow="+now);\n return result;\n}\n\nfunction filterExportList()\n{\n var theList = document.getElementById("exportList"); if (!theList) return -1;\n\n var filterStart=document.getElementById("exportFilterStart").checked;\n var val=document.getElementById("exportFilterStartBy").value;\n var startDate=getFilterDate(val,'exportStartDate');\n\n var filterEnd=document.getElementById("exportFilterEnd").checked;\n var val=document.getElementById("exportFilterEndBy").value;\n var endDate=getFilterDate(val,'exportEndDate');\n\n var filterTags=document.getElementById("exportFilterTags").checked;\n var tags=document.getElementById("exportTags").value;\n\n var filterText=document.getElementById("exportFilterText").checked;\n var text=document.getElementById("exportText").value;\n\n if (!(filterStart||filterEnd||filterTags||filterText)) {\n alert("Please set the selection filter");\n document.getElementById('exportFilterPanel').style.display="block";\n return -1;\n }\n if (filterStart&&filterEnd&&(startDate>endDate)) {\n var msg="starting date/time:\sn"\n msg+=startDate.toLocaleString()+"\sn";\n msg+="is later than ending date/time:\sn"\n msg+=endDate.toLocaleString()\n alert(msg);\n return -1;\n }\n\n // scan list and select tiddlers that match all applicable criteria\n var total=0;\n var count=0;\n for (var i=0; i<theList.options.length; i++) {\n // get item, skip non-tiddler list items (section headings)\n var opt=theList.options[i]; if (opt.value=="") continue;\n // get tiddler, skip missing tiddlers (this should NOT happen)\n var tiddler=store.getTiddler(opt.value); if (!tiddler) continue; \n var sel=true;\n if ( (filterStart && tiddler.modified<startDate)\n || (filterEnd && tiddler.modified>endDate)\n || (filterTags && !matchTags(tiddler,tags))\n || (filterText && (tiddler.text.indexOf(text)==-1) && (tiddler.title.indexOf(text)==-1)))\n sel=false;\n opt.selected=sel;\n count+=sel?1:0;\n total++;\n }\n return count;\n}\n//}}}\n\n//{{{\nfunction matchTags(tiddler,cond)\n{\n if (!cond||!cond.trim().length) return false;\n\n // build a regex of all tags as a big-old regex that \n // OR's the tags together (tag1|tag2|tag3...) in length order\n var tgs = store.getTags();\n if ( tgs.length == 0 ) return results ;\n var tags = tgs.sort( function(a,b){return (a[0].length<b[0].length)-(a[0].length>b[0].length);});\n var exp = "(" + tags.join("|") + ")" ;\n exp = exp.replace( /(,[\sd]+)/g, "" ) ;\n var regex = new RegExp( exp, "ig" );\n\n // build a string such that an expression that looks like this: tag1 AND tag2 OR NOT tag3\n // turns into : /tag1/.test(...) && /tag2/.test(...) || ! /tag2/.test(...)\n cond = cond.replace( regex, "/$1\s\s|/.test(tiddlerTags)" );\n cond = cond.replace( /\ssand\ss/ig, " && " ) ;\n cond = cond.replace( /\ssor\ss/ig, " || " ) ;\n cond = cond.replace( /\ss?not\ss/ig, " ! " ) ;\n\n // if a boolean uses a tag that doesn't exist - it will get left alone \n // (we only turn existing tags into actual tests).\n // replace anything that wasn't found as a tag, AND, OR, or NOT with the string "false"\n // if the tag doesn't exist then /tag/.test(...) will always return false.\n cond = cond.replace( /(\ss|^)+[^\s/\s|&!][^\ss]*/g, "false" ) ;\n\n // make a string of the tags in the tiddler and eval the 'cond' string against that string \n // if it's TRUE then the tiddler qualifies!\n var tiddlerTags = (tiddler.tags?tiddler.tags.join("|"):"")+"|" ;\n try { if ( eval( cond ) ) return true; }\n catch( e ) { displayMessage("Error in tag filter '" + e + "'" ); }\n return false;\n}\n//}}}\n// //===\n\n// // +++[output data formatting]>\n// // +++[exportHeader(format)]\n//{{{\nfunction exportHeader(format)\n{\n switch (format) {\n case "TW": return exportTWHeader();\n case "DIV": return exportDIVHeader();\n case "XML": return exportXMLHeader();\n }\n}\n//}}}\n// //===\n\n// // +++[exportFooter(format)]\n//{{{\nfunction exportFooter(format)\n{\n switch (format) {\n case "TW": return exportDIVFooter();\n case "DIV": return exportDIVFooter();\n case "XML": return exportXMLFooter();\n }\n}\n//}}}\n// //===\n\n// // +++[exportTWHeader()]\n//{{{\nfunction exportTWHeader()\n{\n // Get the URL of the document\n var originalPath = document.location.toString();\n // Check we were loaded from a file URL\n if(originalPath.substr(0,5) != "file:")\n { alert(config.messages.notFileUrlError); return; }\n // Remove any location part of the URL\n var hashPos = originalPath.indexOf("#"); if(hashPos != -1) originalPath = originalPath.substr(0,hashPos);\n // Convert to a native file format assuming\n // "file:///x:/path/path/path..." - pc local file --> "x:\spath\spath\spath..."\n // "file://///server/share/path/path/path..." - FireFox pc network file --> "\s\sserver\sshare\spath\spath\spath..."\n // "file:///path/path/path..." - mac/unix local file --> "/path/path/path..."\n // "file://server/share/path/path/path..." - pc network file --> "\s\sserver\sshare\spath\spath\spath..."\n var localPath;\n if(originalPath.charAt(9) == ":") // pc local file\n localPath = unescape(originalPath.substr(8)).replace(new RegExp("/","g"),"\s\s");\n else if(originalPath.indexOf("file://///") == 0) // FireFox pc network file\n localPath = "\s\s\s\s" + unescape(originalPath.substr(10)).replace(new RegExp("/","g"),"\s\s");\n else if(originalPath.indexOf("file:///") == 0) // mac/unix local file\n localPath = unescape(originalPath.substr(7));\n else if(originalPath.indexOf("file:/") == 0) // mac/unix local file\n localPath = unescape(originalPath.substr(5));\n else // pc network file\n localPath = "\s\s\s\s" + unescape(originalPath.substr(7)).replace(new RegExp("/","g"),"\s\s");\n // Load the original file\n var original = loadFile(localPath);\n if(original == null)\n { alert(config.messages.cantSaveError); return; }\n // Locate the storeArea div's\n var posOpeningDiv = original.indexOf(startSaveArea);\n var posClosingDiv = original.lastIndexOf(endSaveArea);\n if((posOpeningDiv == -1) || (posClosingDiv == -1))\n { alert(config.messages.invalidFileError.format([localPath])); return; }\n return original.substr(0,posOpeningDiv+startSaveArea.length)\n}\n//}}}\n// //===\n\n// // +++[exportDIVHeader()]\n//{{{\nfunction exportDIVHeader()\n{\n var out=[];\n var now = new Date();\n var title = convertUnicodeToUTF8(wikifyPlain("SiteTitle").htmlEncode());\n var subtitle = convertUnicodeToUTF8(wikifyPlain("SiteSubtitle").htmlEncode());\n var user = convertUnicodeToUTF8(config.options.txtUserName.htmlEncode());\n var twver = version.major+"."+version.minor+"."+version.revision;\n var pver = version.extensions.exportTiddlers.major+"."\n +version.extensions.exportTiddlers.minor+"."+version.extensions.exportTiddlers.revision;\n out.push("<html><body>");\n out.push("<style type=\s"text/css\s">");\n out.push("#storeArea {display:block;margin:1em;}");\n out.push("#storeArea div");\n out.push("{padding:0.5em;margin:1em;border:2px solid black;height:10em;overflow:auto;}");\n out.push("#javascriptWarning");\n out.push("{width:100%;text-align:left;background-color:#eeeeee;padding:1em;}");\n out.push("</style>");\n out.push("<div id=\s"javascriptWarning\s">");\n out.push("TiddlyWiki export file<br>");\n out.push("Source: <b>"+convertUnicodeToUTF8(document.location.toString())+"</b><br>");\n out.push("Title: <b>"+title+"</b><br>");\n out.push("Subtitle: <b>"+subtitle+"</b><br>");\n out.push("Created: <b>"+now.toLocaleString()+"</b> by <b>"+user+"</b><br>");\n out.push("TiddlyWiki "+twver+" / "+"ExportTiddlersPlugin "+pver+"<br>");\n out.push("Notes:<hr><pre>"+document.getElementById("exportNotes").value.replace(regexpNewLine,"<br>")+"</pre>");\n out.push("</div>");\n out.push("<div id=\s"storeArea\s">");\n return out;\n}\n//}}}\n// //===\n\n// // +++[exportDIVFooter()]\n//{{{\nfunction exportDIVFooter()\n{\n var out=[];\n out.push("</div></body></html>");\n return out;\n}\n//}}}\n// //===\n\n// // +++[exportXMLHeader()]\n//{{{\nfunction exportXMLHeader()\n{\n var out=[];\n var now = new Date();\n var u = store.getTiddlerText("SiteUrl",null);\n var title = convertUnicodeToUTF8(wikifyPlain("SiteTitle").htmlEncode());\n var subtitle = convertUnicodeToUTF8(wikifyPlain("SiteSubtitle").htmlEncode());\n var user = convertUnicodeToUTF8(config.options.txtUserName.htmlEncode());\n var twver = version.major+"."+version.minor+"."+version.revision;\n var pver = version.extensions.exportTiddlers.major+"."\n +version.extensions.exportTiddlers.minor+"."+version.extensions.exportTiddlers.revision;\n out.push("<" + "?xml version=\s"1.0\s"?" + ">");\n out.push("<rss version=\s"2.0\s">");\n out.push("<channel>");\n out.push("<title>" + title + "</title>");\n if(u) out.push("<link>" + convertUnicodeToUTF8(u.htmlEncode()) + "</link>");\n out.push("<description>" + subtitle + "</description>");\n out.push("<language>en-us</language>");\n out.push("<copyright>Copyright " + now.getFullYear() + " " + user + "</copyright>");\n out.push("<pubDate>" + now.toGMTString() + "</pubDate>");\n out.push("<lastBuildDate>" + now.toGMTString() + "</lastBuildDate>");\n out.push("<docs>http://blogs.law.harvard.edu/tech/rss</docs>");\n out.push("<generator>TiddlyWiki "+twver+" plus ExportTiddlersPlugin "+pver+"</generator>");\n return out;\n}\n//}}}\n// //===\n\n// // +++[exportXMLFooter()]\n//{{{\nfunction exportXMLFooter()\n{\n var out=[];\n out.push("</channel></rss>");\n return out;\n}\n//}}}\n// //===\n\n// // +++[exportData()]\n//{{{\nfunction exportData(theList,theFormat)\n{\n // scan export listbox and collect DIVs or XML for selected tiddler content\n var out=[];\n for (var i=0; i<theList.options.length; i++) {\n // get item, skip non-selected items and section headings\n var opt=theList.options[i]; if (!opt.selected||(opt.value=="")) continue;\n // get tiddler, skip missing tiddlers (this should NOT happen)\n var thisTiddler=store.getTiddler(opt.value); if (!thisTiddler) continue; \n if (theFormat=="TW") out.push(convertUnicodeToUTF8(thisTiddler.saveToDiv()));\n if (theFormat=="DIV") out.push(convertUnicodeToUTF8(thisTiddler.title+"\sn"+thisTiddler.saveToDiv()));\n if (theFormat=="XML") out.push(convertUnicodeToUTF8(thisTiddler.saveToRss()));\n }\n return out;\n}\n//}}}\n// //===\n// //===\n\n// // +++[exportTiddlers(): output selected data to local or server]\n//{{{\nfunction exportTiddlers()\n{\n var theList = document.getElementById("exportList"); if (!theList) return;\n\n // get the export settings\n var theProtocol = document.getElementById("exportTo").value;\n var theFormat = document.getElementById("exportFormat").value;\n\n // assemble output: header + tiddlers + footer\n var theData=exportData(theList,theFormat);\n var count=theData.length;\n var out=[]; var txt=out.concat(exportHeader(theFormat),theData,exportFooter(theFormat)).join("\sn");\n var msg="";\n switch (theProtocol) {\n case "file:":\n var theTarget = document.getElementById("exportFilename").value.trim();\n if (!theTarget.length) msg = "A local path/filename is required\sn";\n if (!msg && saveFile(theTarget,txt))\n msg=count+" tiddler"+((count!=1)?"s":"")+" exported to local file";\n else if (!msg)\n msg+="An error occurred while saving to "+theTarget;\n break;\n case "http:":\n case "https:":\n var theTarget = document.getElementById("exportHTTPServerURL").value.trim();\n if (!theTarget.length) msg = "A server URL is required\sn";\n if (document.getElementById('exportNotify').checked)\n theTarget+="&notify="+encodeURIComponent(document.getElementById('exportNotifyTo').value);\n if (document.getElementById('exportNotes').value.trim().length)\n theTarget+="&notes="+encodeURIComponent(document.getElementById('exportNotes').value);\n if (!msg && exportPost(theTarget+encodeURIComponent(txt)))\n msg=count+" tiddler"+((count!=1)?"s":"")+" exported to "+theProtocol+" server";\n else if (!msg)\n msg+="An error occurred while saving to "+theTarget;\n break;\n case "ftp:":\n default:\n msg="Sorry, export to "+theLocation+" is not yet available";\n break;\n }\n clearMessage(); displayMessage(msg,theTarget);\n}\n//}}}\n// //===\n\n// // +++[exportPost(url): cross-domain post] uses hidden iframe to submit url and capture responses\n//{{{\nfunction exportPost(url)\n{\n var f=document.getElementById("exportFrame"); if (f) document.body.removeChild(f);\n f=document.createElement("iframe"); f.id="exportFrame";\n f.style.width="0px"; f.style.height="0px"; f.style.border="0px";\n document.body.appendChild(f);\n var d=f.document;\n if (f.contentDocument) d=f.contentDocument; // For NS6\n else if (f.contentWindow) d=f.contentWindow.document; // For IE5.5 and IE6\n d.location.replace(url);\n return true;\n}\n//}}}\n// //===\n
/***\nsource: http://www.TiddlyTools.com/#ImportTiddlersPlugin\n\nthis version is ''2006.08.16 [3.0.6]'\n!!!!!Credits\n<<<\nThis feature was developed by EricShulman from [[ELS Design Studios|http:/www.elsdesign.com]]\n<<<\n!!!!!Code\n\n***/\n\n// // ''MACRO DEFINITION''\n//{{{\n// Version\nversion.extensions.importTiddlers = {major: 3, minor: 0, revision: 6, date: new Date(2006,8,16)};\n\n// IE needs explicit global scoping for functions/vars called from browser events\nwindow.onClickImportButton=onClickImportButton;\nwindow.refreshImportList=refreshImportList;\n\n// default cookie/option values\nif (!config.options.chkImportReport) config.options.chkImportReport=true;\n\nconfig.macros.importTiddlers = { };\nconfig.macros.importTiddlers = {\n label: "import tiddlers",\n prompt: "Copy tiddlers from another document",\n foundMsg: "Found %0 tiddlers in %1",\n countMsg: "%0 tiddlers selected for import",\n importedMsg: "Imported %0 of %1 tiddlers from %2",\n src: "", // path/filename or URL of document to import (retrieved from SiteUrl tiddler)\n proxy: "", // URL for remote proxy script (retrieved from SiteProxy tiddler)\n useProxy: false, // use specific proxy script in front of remote URL\n inbound: null, // hash-indexed array of tiddlers from other document\n newTags: "", // text of tags added to imported tiddlers\n addTags: true, // add new tags to imported tiddlers\n listsize: 8, // # of lines to show in imported tiddler list\n importTags: true, // include tags from remote source document when importing a tiddler\n keepTags: true, // retain existing tags when replacing a tiddler\n index: 0, // current processing index in import list\n sort: "" // sort order for imported tiddler listbox\n};\n\nconfig.macros.importTiddlers.handler = function(place,macroName,params) {\n if (!config.macros.loadTiddlers.handler)\n { alert("importTiddlers error: this plugin requires LoadTiddlersPlugin or TiddlyWiki 2.1+"); return; }\n if (!params[0]) // LINK TO FLOATING PANEL\n createTiddlyButton(place,this.label,this.prompt,onClickImportMenu);\n else if (params[0]=="inline") {// // INLINE TIDDLER CONTENT\n createImportPanel(place);\n document.getElementById("importPanel").style.position="static";\n document.getElementById("importPanel").style.display="block";\n }\n else config.macros.loadTiddlers.handler(place,macroName,params); // FALLBACK: PASS TO LOADTIDDLERS\n}\n//}}}\n\n// // ''INTERFACE DEFINITION''\n\n// // Handle link click to create/show/hide control panel\n//{{{\nfunction onClickImportMenu(e)\n{\n if (!e) var e = window.event;\n var parent=resolveTarget(e).parentNode;\n var panel = document.getElementById("importPanel");\n if (panel==undefined || panel.parentNode!=parent)\n panel=createImportPanel(parent);\n var isOpen = panel.style.display=="block";\n if(config.options.chkAnimate)\n anim.startAnimating(new Slider(panel,!isOpen,e.shiftKey || e.altKey,"none"));\n else\n panel.style.display = isOpen ? "none" : "block" ;\n e.cancelBubble = true;\n if (e.stopPropagation) e.stopPropagation();\n return(false);\n}\n//}}}\n\n// // Create control panel: HTML, CSS\n//{{{\nfunction createImportPanel(place) {\n var panel=document.getElementById("importPanel");\n if (panel) { panel.parentNode.removeChild(panel); }\n setStylesheet(config.macros.importTiddlers.css,"importTiddlers");\n panel=createTiddlyElement(place,"span","importPanel",null,null)\n panel.innerHTML=config.macros.importTiddlers.html;\n refreshImportList();\n var siteURL=store.getTiddlerText("SiteUrl"); if (!siteURL) siteURL="";\n document.getElementById("importSourceURL").value=siteURL;\n config.macros.importTiddlers.src=siteURL;\n var siteProxy=store.getTiddlerText("SiteProxy"); if (!siteProxy) siteProxy="SiteProxy";\n document.getElementById("importSiteProxy").value=siteProxy;\n config.macros.importTiddlers.proxy=siteProxy;\n return panel;\n}\n//}}}\n\n// // CSS\n//{{{\nconfig.macros.importTiddlers.css = '\s\n#importPanel {\s\n display: none; position:absolute; z-index:11; width:35em; right:105%; top:3em;\s\n background-color: #eee; color:#000; font-size: 8pt; line-height:110%;\s\n border:1px solid black; border-bottom-width: 3px; border-right-width: 3px;\s\n padding: 0.5em; margin:0em; -moz-border-radius:1em;\s\n}\s\n#importPanel a, #importPanel td a { color:#009; display:inline; margin:0px; padding:1px; }\s\n#importPanel table { width:100%; border:0px; padding:0px; margin:0px; font-size:8pt; line-height:110%; background:transparent; }\s\n#importPanel tr { border:0px;padding:0px;margin:0px; background:transparent; }\s\n#importPanel td { color:#000; border:0px;padding:0px;margin:0px; background:transparent; }\s\n#importPanel select { width:98%;margin:0px;font-size:8pt;line-height:110%;}\s\n#importPanel input { width:98%;padding:0px;margin:0px;font-size:8pt;line-height:110%}\s\n#importPanel .box { border:1px solid black; padding:3px; margin-bottom:5px; background:#f8f8f8; -moz-border-radius:5px;}\s\n#importPanel .topline { border-top:2px solid black; padding-top:3px; margin-bottom:5px; }\s\n#importPanel .rad { width:auto; }\s\n#importPanel .chk { width:auto; margin:1px;border:0; }\s\n#importPanel .btn { width:auto; }\s\n#importPanel .btn1 { width:98%; }\s\n#importPanel .btn2 { width:48%; }\s\n#importPanel .btn3 { width:32%; }\s\n#importPanel .btn4 { width:24%; }\s\n#importPanel .btn5 { width:19%; }\s\n#importPanel .importButton { padding: 0em; margin: 0px; font-size:8pt; }\s\n#importPanel .importListButton { padding:0em 0.25em 0em 0.25em; color: #000000; display:inline }\s\n#importCollisionPanel { display:none; margin:0.5em 0em 0em 0em; }\s\n';\n//}}}\n\n// // HTML \n//{{{\nconfig.macros.importTiddlers.html = '\s\n<!-- source and report -->\s\n<table><tr><td align=left>\s\n import from\s\n <input type="radio" class="rad" name="importFrom" value="file" CHECKED\s\n onClick="document.getElementById(\s'importLocalPanel\s').style.display=this.checked?\s'block\s':\s'none\s';\s\n document.getElementById(\s'importHTTPPanel\s').style.display=!this.checked?\s'block\s':\s'none\s'"> local file\s\n <input type="radio" class="rad" name="importFrom" value="http"\s\n onClick="document.getElementById(\s'importLocalPanel\s').style.display=!this.checked?\s'block\s':\s'none\s';\s\n document.getElementById(\s'importHTTPPanel\s').style.display=this.checked?\s'block\s':\s'none\s'"> web server\s\n</td><td align=right>\s\n <input type=checkbox class="chk" id="chkImportReport" checked\s\n onClick="config.options[\s'chkImportReport\s']=this.checked;"> create a report\s\n</td></tr></table>\s\n<!-- import from local file -->\s\n<div id="importLocalPanel" style="display:block;margin-bottom:5px;margin-top:5px;padding-top:3px;border-top:1px solid #999">\s\nlocal document path/filename:<br>\s\n<input type="file" id="fileImportSource" size=57 style="width:100%"\s\n onKeyUp="config.macros.importTiddlers.src=this.value"\s\n onChange="config.macros.importTiddlers.src=this.value;">\s\n</div><!--panel-->\s\n\s\n<!-- import from http server -->\s\n<div id="importHTTPPanel" style="display:none;margin-bottom:5px;margin-top:5px;padding-top:3px;border-top:1px solid #999">\s\n<table><tr><td align=left>\s\n remote document URL:<br>\s\n</td><td align=right>\s\n <input type="checkbox" class="chk" id="importUseProxy"\s\n onClick="config.macros.importTiddlers.useProxy=this.checked;\s\n document.getElementById(\s'importSiteProxy\s').style.display=this.checked?\s'block\s':\s'none\s'"> use a proxy script\s\n</td></tr></table>\s\n<input type="text" id="importSiteProxy" style="display:none;margin-bottom:1px" onfocus="this.select()" value="SiteProxy"\s\n onKeyUp="config.macros.importTiddlers.proxy=this.value"\s\n onChange="config.macros.importTiddlers.proxy=this.value;">\s\n<input type="text" id="importSourceURL" onfocus="this.select()" value="SiteUrl"\s\n onKeyUp="config.macros.importTiddlers.src=this.value"\s\n onChange="config.macros.importTiddlers.src=this.value;">\s\n</div><!--panel-->\s\n\s\n<table><tr><td align=left>\s\n select:\s\n <a href="JavaScript:;" id="importSelectAll"\s\n onclick="onClickImportButton(this)" title="select all tiddlers">\s\n &nbsp;all&nbsp;</a>\s\n <a href="JavaScript:;" id="importSelectNew"\s\n onclick="onClickImportButton(this)" title="select tiddlers not already in destination document">\s\n &nbsp;added&nbsp;</a> \s\n <a href="JavaScript:;" id="importSelectChanges"\s\n onclick="onClickImportButton(this)" title="select tiddlers that have been updated in source document">\s\n &nbsp;changes&nbsp;</a> \s\n <a href="JavaScript:;" id="importSelectDifferences"\s\n onclick="onClickImportButton(this)" title="select tiddlers that have been added or are different from existing tiddlers">\s\n &nbsp;differences&nbsp;</a> \s\n <a href="JavaScript:;" id="importToggleFilter"\s\n onclick="onClickImportButton(this)" title="show/hide selection filter">\s\n &nbsp;filter&nbsp;</a> \s\n</td><td align=right>\s\n <a href="JavaScript:;" id="importListSmaller"\s\n onclick="onClickImportButton(this)" title="reduce list size">\s\n &nbsp;&#150;&nbsp;</a>\s\n <a href="JavaScript:;" id="importListLarger"\s\n onclick="onClickImportButton(this)" title="increase list size">\s\n &nbsp;+&nbsp;</a>\s\n <a href="JavaScript:;" id="importListMaximize"\s\n onclick="onClickImportButton(this)" title="maximize/restore list size">\s\n &nbsp;=&nbsp;</a>\s\n</td></tr></table>\s\n<select id="importList" size=8 multiple\s\n onchange="setTimeout(\s'refreshImportList(\s'+this.selectedIndex+\s')\s',1)">\s\n <!-- NOTE: delay refresh so list is updated AFTER onchange event is handled -->\s\n</select>\s\n<input type=checkbox class="chk" id="chkAddTags" checked\s\n onClick="config.macros.importTiddlers.addTags=this.checked;">add new tags &nbsp;\s\n<input type=checkbox class="chk" id="chkImportTags" checked\s\n onClick="config.macros.importTiddlers.importTags=this.checked;">import source tags &nbsp;\s\n<input type=checkbox class="chk" id="chkKeepTags" checked\s\n onClick="config.macros.importTiddlers.keepTags=this.checked;">keep existing tags<br>\s\n<input type=text id="txtNewTags" size=15 onKeyUp="config.macros.importTiddlers.newTags=this.value" autocomplete=off>\s\n<div align=center>\s\n <input type=button id="importOpen" class="importButton" style="width:32%" value="open"\s\n onclick="onClickImportButton(this)">\s\n <input type=button id="importStart" class="importButton" style="width:32%" value="import"\s\n onclick="onClickImportButton(this)">\s\n <input type=button id="importClose" class="importButton" style="width:32%" value="close"\s\n onclick="onClickImportButton(this)">\s\n</div>\s\n<div id="importCollisionPanel">\s\n tiddler already exists:\s\n <input type=text id="importNewTitle" size=15 autocomplete=off">\s\n <div align=center>\s\n <input type=button id="importSkip" class="importButton" style="width:23%" value="skip"\s\n onclick="onClickImportButton(this)">\s\n <input type=button id="importRename" class="importButton" style="width:23%" value="rename"\s\n onclick="onClickImportButton(this)">\s\n <input type=button id="importMerge" class="importButton" style="width:23%" value="merge"\s\n onclick="onClickImportButton(this)">\s\n <input type=button id="importReplace" class="importButton" style="width:23%" value="replace"\s\n onclick="onClickImportButton(this)">\s\n </div>\s\n</div>\s\n';\n//}}}\n\n// // Control interactions\n//{{{\nfunction onClickImportButton(which)\n{\n // DEBUG alert(which.id);\n var theList = document.getElementById('importList');\n if (!theList) return;\n var thePanel = document.getElementById('importPanel');\n var theCollisionPanel = document.getElementById('importCollisionPanel');\n var theNewTitle = document.getElementById('importNewTitle');\n var count=0;\n switch (which.id)\n {\n case 'fileImportSource':\n case 'importOpen': // load import source into hidden frame\n importReport(); // if an import was in progress, generate a report\n config.macros.importTiddlers.inbound=null; // clear the imported tiddler buffer\n refreshImportList(); // reset/resize the listbox\n if (config.macros.importTiddlers.src=="") break;\n // Load document into hidden iframe so we can read it's DOM and fill the list\n loadRemoteFile(config.macros.importTiddlers.src, function(src,txt) {\n var tiddlers = readTiddlersFromHTML(txt);\n var count=tiddlers?tiddlers.length:0;\n displayMessage(config.macros.importTiddlers.foundMsg.format([count,src]));\n config.macros.importTiddlers.inbound=tiddlers;\n window.refreshImportList(0);\n });\n break;\n case 'importSelectAll': // select all tiddler list items (i.e., not headings)\n importReport(); // if an import was in progress, generate a report\n for (var t=0,count=0; t < theList.options.length; t++) {\n if (theList.options[t].value=="") continue;\n theList.options[t].selected=true;\n count++;\n }\n clearMessage(); displayMessage(config.macros.importTiddlers.countMsg.format([count]));\n break;\n case 'importSelectNew': // select tiddlers not in current document\n importReport(); // if an import was in progress, generate a report\n for (var t=0,count=0; t < theList.options.length; t++) {\n theList.options[t].selected=false;\n if (theList.options[t].value=="") continue;\n theList.options[t].selected=!store.tiddlerExists(theList.options[t].value);\n count+=theList.options[t].selected?1:0;\n }\n clearMessage(); displayMessage(config.macros.importTiddlers.countMsg.format([count]));\n break;\n case 'importSelectChanges': // select tiddlers that are updated from existing tiddlers\n importReport(); // if an import was in progress, generate a report\n for (var t=0,count=0; t < theList.options.length; t++) {\n theList.options[t].selected=false;\n if (theList.options[t].value==""||!store.tiddlerExists(theList.options[t].value)) continue;\n for (var i=0; i<config.macros.importTiddlers.inbound.length; i++) // find matching inbound tiddler\n { var inbound=config.macros.importTiddlers.inbound[i]; if (inbound.title==theList.options[t].value) break; }\n theList.options[t].selected=(inbound.modified-store.getTiddler(theList.options[t].value).modified>0); // updated tiddler\n count+=theList.options[t].selected?1:0;\n }\n clearMessage(); displayMessage(config.macros.importTiddlers.countMsg.format([count]));\n break;\n case 'importSelectDifferences': // select tiddlers that are new or different from existing tiddlers\n importReport(); // if an import was in progress, generate a report\n for (var t=0,count=0; t < theList.options.length; t++) {\n theList.options[t].selected=false;\n if (theList.options[t].value=="") continue;\n if (!store.tiddlerExists(theList.options[t].value)) { theList.options[t].selected=true; count++; continue; }\n for (var i=0; i<config.macros.importTiddlers.inbound.length; i++) // find matching inbound tiddler\n { var inbound=config.macros.importTiddlers.inbound[i]; if (inbound.title==theList.options[t].value) break; }\n theList.options[t].selected=(inbound.modified-store.getTiddler(theList.options[t].value).modified!=0); // changed tiddler\n count+=theList.options[t].selected?1:0;\n }\n clearMessage(); displayMessage(config.macros.importTiddlers.countMsg.format([count]));\n break;\n case 'importToggleFilter': // show/hide filter\n case 'importFilter': // apply filter\n alert("coming soon!");\n break;\n case 'importStart': // initiate the import processing\n importReport(); // if an import was in progress, generate a report\n config.macros.importTiddlers.index=0;\n config.macros.importTiddlers.index=importTiddlers(0);\n importStopped();\n break;\n case 'importClose': // unload imported tiddlers or hide the import control panel\n // if imported tiddlers not loaded, close the import control panel\n if (!config.macros.importTiddlers.inbound) { thePanel.style.display='none'; break; }\n importReport(); // if an import was in progress, generate a report\n config.macros.importTiddlers.inbound=null; // clear the imported tiddler buffer\n refreshImportList(); // reset/resize the listbox\n break;\n case 'importSkip': // don't import the tiddler\n var theItem = theList.options[config.macros.importTiddlers.index];\n for (var j=0;j<config.macros.importTiddlers.inbound.length;j++)\n if (config.macros.importTiddlers.inbound[j].title==theItem.value) break;\n var theImported = config.macros.importTiddlers.inbound[j];\n theImported.status='skipped after asking'; // mark item as skipped\n theCollisionPanel.style.display='none';\n config.macros.importTiddlers.index=importTiddlers(config.macros.importTiddlers.index+1); // resume with NEXT item\n importStopped();\n break;\n case 'importRename': // change name of imported tiddler\n var theItem = theList.options[config.macros.importTiddlers.index];\n for (var j=0;j<config.macros.importTiddlers.inbound.length;j++)\n if (config.macros.importTiddlers.inbound[j].title==theItem.value) break;\n var theImported = config.macros.importTiddlers.inbound[j];\n theImported.status = 'renamed from '+theImported.title; // mark item as renamed\n theImported.set(theNewTitle.value,null,null,null,null); // change the tiddler title\n theItem.value = theNewTitle.value; // change the listbox item text\n theItem.text = theNewTitle.value; // change the listbox item text\n theCollisionPanel.style.display='none';\n config.macros.importTiddlers.index=importTiddlers(config.macros.importTiddlers.index); // resume with THIS item\n importStopped();\n break;\n case 'importMerge': // join existing and imported tiddler content\n var theItem = theList.options[config.macros.importTiddlers.index];\n for (var j=0;j<config.macros.importTiddlers.inbound.length;j++)\n if (config.macros.importTiddlers.inbound[j].title==theItem.value) break;\n var theImported = config.macros.importTiddlers.inbound[j];\n var theExisting = store.getTiddler(theItem.value);\n var theText = theExisting.text+'\sn----\sn^^merged from: ';\n theText +='[['+config.macros.importTiddlers.src+'#'+theItem.value+'|'+config.macros.importTiddlers.src+'#'+theItem.value+']]^^\sn';\n theText +='^^'+theImported.modified.toLocaleString()+' by '+theImported.modifier+'^^\sn'+theImported.text;\n var theDate = new Date();\n var theTags = theExisting.getTags()+' '+theImported.getTags();\n theImported.set(null,theText,null,theDate,theTags);\n theImported.status = 'merged with '+theExisting.title; // mark item as merged\n theImported.status += ' - '+theExisting.modified.formatString("MM/DD/YYYY 0hh:0mm:0ss");\n theImported.status += ' by '+theExisting.modifier;\n theCollisionPanel.style.display='none';\n config.macros.importTiddlers.index=importTiddlers(config.macros.importTiddlers.index); // resume with this item\n importStopped();\n break;\n case 'importReplace': // substitute imported tiddler for existing tiddler\n var theItem = theList.options[config.macros.importTiddlers.index];\n for (var j=0;j<config.macros.importTiddlers.inbound.length;j++)\n if (config.macros.importTiddlers.inbound[j].title==theItem.value) break;\n var theImported = config.macros.importTiddlers.inbound[j];\n var theExisting = store.getTiddler(theItem.value);\n theImported.status = 'replaces '+theExisting.title; // mark item for replace\n theImported.status += ' - '+theExisting.modified.formatString("MM/DD/YYYY 0hh:0mm:0ss");\n theImported.status += ' by '+theExisting.modifier;\n theCollisionPanel.style.display='none';\n config.macros.importTiddlers.index=importTiddlers(config.macros.importTiddlers.index); // resume with THIS item\n importStopped();\n break;\n case 'importListSmaller': // decrease current listbox size, minimum=5\n if (theList.options.length==1) break;\n theList.size-=(theList.size>5)?1:0;\n config.macros.importTiddlers.listsize=theList.size;\n break;\n case 'importListLarger': // increase current listbox size, maximum=number of items in list\n if (theList.options.length==1) break;\n theList.size+=(theList.size<theList.options.length)?1:0;\n config.macros.importTiddlers.listsize=theList.size;\n break;\n case 'importListMaximize': // toggle listbox size between current and maximum\n if (theList.options.length==1) break;\n theList.size=(theList.size==theList.options.length)?config.macros.importTiddlers.listsize:theList.options.length;\n break;\n }\n}\n//}}}\n\n// // refresh listbox\n//{{{\nfunction refreshImportList(selectedIndex)\n{\n var theList = document.getElementById("importList");\n if (!theList) return;\n // if nothing to show, reset list content and size\n if (!config.macros.importTiddlers.inbound) \n {\n while (theList.length > 0) { theList.options[0] = null; }\n theList.options[0]=new Option('please open a document...',"",false,false);\n theList.size=config.macros.importTiddlers.listsize;\n return;\n }\n // get the sort order\n if (!selectedIndex) selectedIndex=0;\n if (selectedIndex==0) config.macros.importTiddlers.sort='title'; // heading\n if (selectedIndex==1) config.macros.importTiddlers.sort='title';\n if (selectedIndex==2) config.macros.importTiddlers.sort='modified';\n if (selectedIndex==3) config.macros.importTiddlers.sort='tags';\n if (selectedIndex>3) {\n // display selected tiddler count\n for (var t=0,count=0; t < theList.options.length; t++) count+=(theList.options[t].selected&&theList.options[t].value!="")?1:0;\n clearMessage(); displayMessage(config.macros.importTiddlers.countMsg.format([count]));\n return; // no refresh needed\n }\n\n // get the alphasorted list of tiddlers (optionally, filter out unchanged tiddlers)\n var tiddlers=config.macros.importTiddlers.inbound;\n tiddlers.sort(function (a,b) {if(a['title'] == b['title']) return(0); else return (a['title'] < b['title']) ? -1 : +1; });\n // clear current list contents\n while (theList.length > 0) { theList.options[0] = null; }\n // add heading and control items to list\n var i=0;\n var indent=String.fromCharCode(160)+String.fromCharCode(160);\n theList.options[i++]=new Option(tiddlers.length+' tiddler'+((tiddlers.length!=1)?'s are':' is')+' in the document',"",false,false);\n theList.options[i++]=new Option(((config.macros.importTiddlers.sort=="title" )?">":indent)+' [by title]',"",false,false);\n theList.options[i++]=new Option(((config.macros.importTiddlers.sort=="modified")?">":indent)+' [by date]',"",false,false);\n theList.options[i++]=new Option(((config.macros.importTiddlers.sort=="tags")?">":indent)+' [by tags]',"",false,false);\n // output the tiddler list\n switch(config.macros.importTiddlers.sort)\n {\n case "title":\n for(var t = 0; t < tiddlers.length; t++)\n theList.options[i++] = new Option(tiddlers[t].title,tiddlers[t].title,false,false);\n break;\n case "modified":\n // sort descending for newest date first\n tiddlers.sort(function (a,b) {if(a['modified'] == b['modified']) return(0); else return (a['modified'] > b['modified']) ? -1 : +1; });\n var lastSection = "";\n for(var t = 0; t < tiddlers.length; t++) {\n var tiddler = tiddlers[t];\n var theSection = tiddler.modified.toLocaleDateString();\n if (theSection != lastSection) {\n theList.options[i++] = new Option(theSection,"",false,false);\n lastSection = theSection;\n }\n theList.options[i++] = new Option(indent+indent+tiddler.title,tiddler.title,false,false);\n }\n break;\n case "tags":\n var theTitles = {}; // all tiddler titles, hash indexed by tag value\n var theTags = new Array();\n for(var t=0; t<tiddlers.length; t++) {\n var title=tiddlers[t].title;\n var tags=tiddlers[t].tags;\n if (!tags || !tags.length) {\n if (theTitles["untagged"]==undefined) { theTags.push("untagged"); theTitles["untagged"]=new Array(); }\n theTitles["untagged"].push(title);\n }\n else for(var s=0; s<tags.length; s++) {\n if (theTitles[tags[s]]==undefined) { theTags.push(tags[s]); theTitles[tags[s]]=new Array(); }\n theTitles[tags[s]].push(title);\n }\n }\n theTags.sort();\n for(var tagindex=0; tagindex<theTags.length; tagindex++) {\n var theTag=theTags[tagindex];\n theList.options[i++]=new Option(theTag,"",false,false);\n for(var t=0; t<theTitles[theTag].length; t++)\n theList.options[i++]=new Option(indent+indent+theTitles[theTag][t],theTitles[theTag][t],false,false);\n }\n break;\n }\n theList.selectedIndex=selectedIndex; // select current control item\n if (theList.size<config.macros.importTiddlers.listsize) theList.size=config.macros.importTiddlers.listsize;\n if (theList.size>theList.options.length) theList.size=theList.options.length;\n}\n//}}}\n\n// // re-entrant processing for handling import with interactive collision prompting\n//{{{\nfunction importTiddlers(startIndex)\n{\n if (!config.macros.importTiddlers.inbound) return -1;\n\n var theList = document.getElementById('importList');\n if (!theList) return;\n var t;\n // if starting new import, reset import status flags\n if (startIndex==0)\n for (var t=0;t<config.macros.importTiddlers.inbound.length;t++)\n config.macros.importTiddlers.inbound[t].status="";\n for (var i=startIndex; i<theList.options.length; i++)\n {\n // if list item is not selected or is a heading (i.e., has no value), skip it\n if ((!theList.options[i].selected) || ((t=theList.options[i].value)==""))\n continue;\n for (var j=0;j<config.macros.importTiddlers.inbound.length;j++)\n if (config.macros.importTiddlers.inbound[j].title==t) break;\n var inbound = config.macros.importTiddlers.inbound[j];\n var theExisting = store.getTiddler(inbound.title);\n // avoid redundant import for tiddlers that are listed multiple times (when 'by tags')\n if (inbound.status=="added")\n continue;\n // don't import the "ImportedTiddlers" history from the other document...\n if (inbound.title=='ImportedTiddlers')\n continue;\n // if tiddler exists and import not marked for replace or merge, stop importing\n if (theExisting && (inbound.status.substr(0,7)!="replace") && (inbound.status.substr(0,5)!="merge"))\n return i;\n // assemble tags (remote + existing + added)\n var newTags = "";\n if (config.macros.importTiddlers.importTags)\n newTags+=inbound.getTags() // import remote tags\n if (config.macros.importTiddlers.keepTags && theExisting)\n newTags+=" "+theExisting.getTags(); // keep existing tags\n if (config.macros.importTiddlers.addTags && config.macros.importTiddlers.newTags.trim().length)\n newTags+=" "+config.macros.importTiddlers.newTags; // add new tags\n inbound.set(null,null,null,null,newTags.trim());\n // set the status to 'added' (if not already set by the 'ask the user' UI)\n inbound.status=(inbound.status=="")?'added':inbound.status;\n // do the import!\n // OLD: store.addTiddler(in); store.setDirty(true);\n store.saveTiddler(inbound.title, inbound.title, inbound.text, inbound.modifier, inbound.modified, inbound.tags);\n store.fetchTiddler(inbound.title).created = inbound.created; // force creation date to imported value\n }\n return(-1); // signals that we really finished the entire list\n}\n//}}}\n\n//{{{\nfunction importStopped()\n{\n var theList = document.getElementById('importList');\n var theNewTitle = document.getElementById('importNewTitle');\n if (!theList) return;\n if (config.macros.importTiddlers.index==-1)\n importReport(); // import finished... generate the report\n else\n {\n // DEBUG alert('import stopped at: '+config.macros.importTiddlers.index);\n // import collision... show the collision panel and set the title edit field\n document.getElementById('importCollisionPanel').style.display='block';\n theNewTitle.value=theList.options[config.macros.importTiddlers.index].value;\n }\n}\n//}}}\n\n// // ''REPORT GENERATOR''\n//{{{\nfunction importReport(quiet)\n{\n if (!config.macros.importTiddlers.inbound) return;\n // DEBUG alert('importReport: start');\n\n // if import was not completed, the collision panel will still be open... close it now.\n var panel=document.getElementById('importCollisionPanel'); if (panel) panel.style.display='none';\n\n // get the alphasorted list of tiddlers\n var tiddlers = config.macros.importTiddlers.inbound;\n // gather the statistics\n var count=0;\n for (var t=0; t<tiddlers.length; t++)\n if (tiddlers[t].status && tiddlers[t].status.trim().length && tiddlers[t].status.substr(0,7)!="skipped") count++;\n\n // generate a report\n if (count && config.options.chkImportReport) {\n // get/create the report tiddler\n var theReport = store.getTiddler('ImportedTiddlers');\n if (!theReport) { theReport= new Tiddler(); theReport.title = 'ImportedTiddlers'; theReport.text = ""; }\n // format the report content\n var now = new Date();\n var newText = "On "+now.toLocaleString()+", "+config.options.txtUserName\n newText +=" imported "+count+" tiddler"+(count==1?"":"s")+" from\sn[["+config.macros.importTiddlers.src+"|"+config.macros.importTiddlers.src+"]]:\sn";\n if (config.macros.importTiddlers.addTags && config.macros.importTiddlers.newTags.trim().length)\n newText += "imported tiddlers were tagged with: \s""+config.macros.importTiddlers.newTags+"\s"\sn";\n newText += "<<<\sn";\n for (var t=0; t<tiddlers.length; t++) if (tiddlers[t].status) newText += "#[["+tiddlers[t].title+"]] - "+tiddlers[t].status+"\sn";\n newText += "<<<\sn";\n newText += "<html><input type=\s"button\s" href=\s"javascript:;\s" ";\n newText += "onclick=\s"story.closeTiddler('"+theReport.title+"'); store.deleteTiddler('"+theReport.title+"');\s" ";\n newText += "value=\s"discard report\s"></html>";\n // update the ImportedTiddlers content and show the tiddler\n theReport.text = newText+((theReport.text!="")?'\sn----\sn':"")+theReport.text;\n theReport.modifier = config.options.txtUserName;\n theReport.modified = new Date();\n // OLD: store.addTiddler(theReport);\n store.saveTiddler(theReport.title, theReport.title, theReport.text, theReport.modifier, theReport.modified, theReport.tags);\n if (!quiet) { story.displayTiddler(null,theReport.title,1,null,null,false); story.refreshTiddler(theReport.title,1,true); }\n }\n\n // reset status flags\n for (var t=0; t<config.macros.importTiddlers.inbound.length; t++) config.macros.importTiddlers.inbound[t].status="";\n\n // refresh display if tiddlers have been loaded\n if (count) { store.setDirty(true); store.notifyAll(); }\n\n // always show final message when tiddlers were actually loaded\n if (count) displayMessage(config.macros.importTiddlers.importedMsg.format([count,tiddlers.length,config.macros.importTiddlers.src]));\n}\n//}}}\n\n/***\n!!!!!TW 2.1beta Core Code Candidate\n//The following section is a preliminary 'code candidate' for incorporation of non-interactive 'load tiddlers' functionality into TW2.1beta. //\n***/\n//{{{\n// default cookie/option values\nif (!config.options.chkImportReport) config.options.chkImportReport=true;\n\nconfig.macros.loadTiddlers = {\n label: "",\n prompt: "add/update tiddlers from '%0'",\n askMsg: "Please enter a local path/filename or a remote URL",\n openMsg: "Opening %0",\n openErrMsg: "Could not open %0 - error=%1",\n readMsg: "Read %0 bytes from %1",\n foundMsg: "Found %0 tiddlers in %1",\n nochangeMsg: "'%0' is up-to-date... skipped.",\n loadedMsg: "Loaded %0 of %1 tiddlers from %2"\n};\n\nconfig.macros.loadTiddlers.handler = function(place,macroName,params) {\n var label=(params[0] && params[0].substr(0,6)=='label:')?params.shift().substr(6):this.label;\n var prompt=(params[0] && params[0].substr(0,7)=='prompt:')?params.shift().substr(7):this.prompt;\n var filter="updates";\n if (params[0] && (params[0]=='all' || params[0]=='new' || params[0]=='changes' || params[0]=='updates'\n || params[0].substr(0,8)=='tiddler:' || params[0].substr(0,4)=='tag:'))\n filter=params.shift();\n var src=params.shift(); if (!src || !src.length) return; // filename is required\n var quiet=(params[0]=="quiet"); if (quiet) params.shift();\n var ask=(params[0]=="confirm"); if (ask) params.shift();\n var force=(params[0]=="force"); if (force) params.shift();\n if (label.trim().length) {\n // link triggers load tiddlers from another file/URL and then applies filtering rules to add/replace tiddlers in the store\n createTiddlyButton(place,label.format([src]),prompt.format([src]), function() {\n if (src=="ask") src=prompt(config.macros.loadTiddlers.askMsg);\n loadRemoteFile(src,loadTiddlers,quiet,ask,filter,force);\n })\n }\n else {\n // load tiddlers from another file/URL and then apply filtering rules to add/replace tiddlers in the store\n if (src=="ask") src=prompt(config.macros.loadTiddlers.askMsg);\n loadRemoteFile(src,loadTiddlers,quiet,ask,filter,force);\n }\n}\n\nfunction loadTiddlers(src,html,quiet,ask,filter,force)\n{\n var tiddlers = readTiddlersFromHTML(html);\n var count=tiddlers?tiddlers.length:0;\n if (!quiet) displayMessage(config.macros.loadTiddlers.foundMsg.format([count,src]));\n var count=0;\n if (tiddlers) for (var t=0;t<tiddlers.length;t++) {\n var inbound = tiddlers[t];\n var theExisting = store.getTiddler(inbound.title);\n if (inbound.title=='ImportedTiddlers')\n continue; // skip "ImportedTiddlers" history from the other document...\n\n // apply the all/new/changes/updates filter (if any)\n if (filter && filter!="all") {\n if ((filter=="new") && theExisting) // skip existing tiddlers\n continue;\n if ((filter=="changes") && !theExisting) // skip new tiddlers\n continue;\n if ((filter.substr(0,4)=="tag:") && inbound.tags.find(filter.substr(4))==null) // must match specific tag value\n continue;\n if ((filter.substr(0,8)=="tiddler:") && inbound.title!=filter.substr(8)) // must match specific tiddler name\n continue;\n if (!force && store.tiddlerExists(inbound.title) && ((theExisting.modified.getTime()-inbound.modified.getTime())>=0))\n { if (!quiet) displayMessage(config.macros.loadTiddlers.nochangeMsg.format([inbound.title])); continue; }\n }\n // get confirmation if required\n if (ask && !confirm((theExisting?"Update":"Add")+" tiddler '"+inbound.title+"'\snfrom "+src))\n { tiddlers[t].status="skipped - cancelled by user"; continue; }\n // DO IT!\n // OLD: store.addTiddler(in);\n store.saveTiddler(inbound.title, inbound.title, inbound.text, inbound.modifier, inbound.modified, inbound.tags);\n store.fetchTiddler(inbound.title).created = inbound.created; // force creation date to imported value\n tiddlers[t].status=theExisting?"updated":"added"\n count++;\n }\n if (count) {\n // refresh display\n store.setDirty(true);\n store.notifyAll();\n // generate a report\n if (config.options.chkImportReport) {\n // get/create the report tiddler\n var theReport = store.getTiddler('ImportedTiddlers');\n if (!theReport) { theReport= new Tiddler(); theReport.title = 'ImportedTiddlers'; theReport.text = ""; }\n // format the report content\n var now = new Date();\n var newText = "On "+now.toLocaleString()+", "+config.options.txtUserName+" loaded "+count+" tiddlers from\sn[["+src+"|"+src+"]]:\sn";\n newText += "<<<\sn";\n for (var t=0; t<tiddlers.length; t++) if (tiddlers[t].status) newText += "#[["+tiddlers[t].title+"]] - "+tiddlers[t].status+"\sn";\n newText += "<<<\sn";\n newText += "<html><input type=\s"button\s" href=\s"javascript:;\s" ";\n newText += "onclick=\s"story.closeTiddler('"+theReport.title+"'); store.deleteTiddler('"+theReport.title+"');\s" ";\n newText += "value=\s"discard report\s"></html>";\n // update the ImportedTiddlers content and show the tiddler\n theReport.text = newText+((theReport.text!="")?'\sn----\sn':"")+theReport.text;\n theReport.modifier = config.options.txtUserName;\n theReport.modified = new Date();\n // OLD: store.addTiddler(theReport);\n store.saveTiddler(theReport.title, theReport.title, theReport.text, theReport.modifier, theReport.modified, theReport.tags);\n if (!quiet) { story.displayTiddler(null,theReport.title,1,null,null,false); story.refreshTiddler(theReport.title,1,true); }\n }\n }\n // always show final message when tiddlers were actually loaded\n if (!quiet||count) displayMessage(config.macros.loadTiddlers.loadedMsg.format([count,tiddlers.length,src]));\n}\n\nfunction loadRemoteFile(src,callback,quiet,ask,filter,force) {\n if (src==undefined || !src.length) return null; // filename is required\n if (!quiet) clearMessage();\n if (!quiet) displayMessage(config.macros.loadTiddlers.openMsg.format([src]));\n if (src.substr(0,4)!="http" && src.substr(0,4)!="file") { // if not a URL, fallback to read from local filesystem\n var txt=loadFile(src);\n if ((txt==null)||(txt==false)) // file didn't load\n { if (!quiet) displayMessage(config.macros.loadTiddlers.openErrMsg.format([src,"(unknown)"])); }\n else {\n if (!quiet) displayMessage(config.macros.loadTiddlers.readMsg.format([txt.length,src]));\n if (callback) callback(src,convertUTF8ToUnicode(txt),quiet,ask,filter,force);\n }\n }\n else {\n var x; // get an request object\n try {x = new XMLHttpRequest()} // moz\n catch(e) {\n try {x = new ActiveXObject("Msxml2.XMLHTTP")} // IE 6\n catch (e) {\n try {x = new ActiveXObject("Microsoft.XMLHTTP")} // IE 5\n catch (e) { return }\n }\n }\n // setup callback function to handle server response(s)\n x.onreadystatechange = function() {\n if (x.readyState == 4) {\n if (x.status==0 || x.status == 200) {\n if (!quiet) displayMessage(config.macros.loadTiddlers.readMsg.format([x.responseText.length,src]));\n if (callback) callback(src,x.responseText,quiet,ask,filter,force);\n }\n else {\n if (!quiet) displayMessage(config.macros.loadTiddlers.openErrMsg.format([src,x.status]));\n }\n }\n }\n // get privileges to read another document's DOM via http:// or file:// (moz-only)\n if (typeof(netscape)!="undefined") {\n try { netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead"); }\n catch (e) { if (!quiet) displayMessage(e.description?e.description:e.toString()); }\n }\n // send the HTTP request\n try {\n var url=src+(src.indexOf('?')<0?'?':'&')+'nocache='+Math.random();\n x.open("GET",src,true);\n if (x.overrideMimeType) x.overrideMimeType('text/html');\n x.send(null);\n }\n catch (e) {\n if (!quiet) {\n displayMessage(config.macros.loadTiddlers.openErrMsg.format([src,"(unknown)"]));\n displayMessage(e.description?e.description:e.toString());\n }\n }\n }\n}\n\nfunction readTiddlersFromHTML(html)\n{\n // extract store area from html \n var start=html.indexOf('<div id="storeArea">');\n var end=html.indexOf('</body>',start);\n var sa="<html><body>"+html.substring(start,end)+"</body></html>";\n\n // load html into iframe document\n var f=document.getElementById("loaderFrame"); if (f) document.body.removeChild(f);\n f=document.createElement("iframe"); f.id="loaderFrame";\n f.style.width="0px"; f.style.height="0px"; f.style.border="0px";\n document.body.appendChild(f);\n var d=f.document;\n if (f.contentDocument) d=f.contentDocument; // For NS6\n else if (f.contentWindow) d=f.contentWindow.document; // For IE5.5 and IE6\n d.open(); d.writeln(sa); d.close();\n\n // read tiddler DIVs from storeArea DOM element \n var sa = d.getElementById("storeArea");\n if (!sa) return null;\n sa.normalize();\n var nodes = sa.childNodes;\n if (!nodes || !nodes.length) return null;\n var tiddlers = [];\n for(var t = 0; t < nodes.length; t++) {\n var title = null;\n if(nodes[t].getAttribute)\n title = nodes[t].getAttribute("tiddler");\n if(!title && nodes[t].id && (nodes[t].id.substr(0,5) == "store"))\n title = nodes[t].id.substr(5);\n if(title && title != "")\n tiddlers.push((new Tiddler()).loadFromDiv(nodes[t],title));\n }\n return tiddlers;\n}\n//}}}
<div class='toolbar' macro='toolbar expandTiddler collapseOthers -closeTiddler closeOthers +editTiddler permalink references jump'></div>\n<div class='title' macro='view title'></div><span macro='tiddler DoubleClickForFocus'></span>
/***\n!! CollapseTiddlersPlugin\n^^Author: Bradley Meck^^\n^^Source: http://gensoft.revhost.net/Collapse.html^^\n\n|ELS 2/24/2006: added fallback to "CollapsedTemplate if "WebCollapsedTemplate" is not found |\n|ELS 2/6/2006: added check for 'readOnly' flag to use alternative "WebCollapsedTemplate" |\n\n***/\n\nconfig.commands.collapseTiddler = {\ntext: "fold",\ntooltip: "Collapse this tiddler",\nhandler: function(event,src,title)\n{\nvar e = story.findContainingTiddler(src);\nif(e.getAttribute("template") != config.tiddlerTemplates[DEFAULT_EDIT_TEMPLATE]){\nvar t = (readOnly&&store.tiddlerExists("WebCollapsedTemplate"))?"WebCollapsedTemplate":"CollapsedTemplate";\nif (!store.tiddlerExists(t)) { alert("Can't find 'CollapsedTemplate'"); return; }\nif(e.getAttribute("template") != t ){\ne.setAttribute("oldTemplate",e.getAttribute("template"));\nstory.displayTiddler(null,title,t);\n}\n}\n}\n}\n\nconfig.commands.expandTiddler = {\ntext: "unfold",\ntooltip: "Expand this tiddler",\nhandler: function(event,src,title)\n{\nvar e = story.findContainingTiddler(src);\nstory.displayTiddler(null,title,e.getAttribute("oldTemplate"));\n}\n}\n\nconfig.macros.collapseAll = {\nhandler: function(place,macroName,params,wikifier,paramString,tiddler){\ncreateTiddlyButton(place,"Collapse All","",function(){\nstory.forEachTiddler(function(title,tiddler){\nif(tiddler.getAttribute("template") != config.tiddlerTemplates[DEFAULT_EDIT_TEMPLATE])\nvar t = (readOnly&&store.tiddlerExists("WebCollapsedTemplate"))?"WebCollapsedTemplate":"CollapsedTemplate";\nif (!store.tiddlerExists(t)) { alert("Can't find 'CollapsedTemplate'"); return; }\nstory.displayTiddler(null,title,t);\n})})\n}\n}\n\nconfig.macros.expandAll = {\nhandler: function(place,macroName,params,wikifier,paramString,tiddler){\ncreateTiddlyButton(place,"Expand All","",function(){\nstory.forEachTiddler(function(title,tiddler){\nvar t = (readOnly&&store.tiddlerExists("WebCollapsedTemplate"))?"WebCollapsedTemplate":"CollapsedTemplate";\nif (!store.tiddlerExists(t)) { alert("Can't find 'CollapsedTemplate'"); return; }\nif(tiddler.getAttribute("template") == t) story.displayTiddler(null,title,tiddler.getAttribute("oldTemplate"));\n})})\n}\n}\n\nconfig.commands.collapseOthers = {\ntext: "focus",\ntooltip: "Expand this tiddler and collapse all others",\nhandler: function(event,src,title)\n{\nvar e = story.findContainingTiddler(src);\nstory.forEachTiddler(function(title,tiddler){\nif(tiddler.getAttribute("template") != config.tiddlerTemplates[DEFAULT_EDIT_TEMPLATE]){\nvar t = (readOnly&&store.tiddlerExists("WebCollapsedTemplate"))?"WebCollapsedTemplate":"CollapsedTemplate";\nif (!store.tiddlerExists(t)) { alert("Can't find 'CollapsedTemplate'"); return; }\nif (e==tiddler) t=e.getAttribute("oldTemplate");\n//////////\n// ELS 2006.02.22 - removed this line. if t==null, then the *current* view template, not the default "ViewTemplate", will be used.\n// if (!t||!t.length) t=!readOnly?"ViewTemplate":"WebViewTemplate";\n//////////\nstory.displayTiddler(null,title,t);\n}\n})\n}\n}
Sitaram's tiddlywiki