{"title":"$:/plugins/tiddlywiki/freelinks","name":"Freelinks","description":"Freelinking of tiddler titles","list":"readme settings","version":"5.1.22","plugin-type":"plugin","dependents":"","type":"application/json","tiddlers":{"$:/config/Freelinks/Enable":{"title":"$:/config/Freelinks/Enable","text":"yes"},"$:/plugins/tiddlywiki/freelinks/macros/view":{"title":"$:/plugins/tiddlywiki/freelinks/macros/view","tags":"$:/tags/Macro/View","text":"<$set name=\"tv-freelinks\" value={{$:/config/Freelinks/Enable}}/>\n"},"$:/core/modules/widgets/plain-text.js":{"title":"$:/core/modules/widgets/plain-text.js","text":"/*\\\ntitle: $:/core/modules/widgets/plain-text.js\ntype: application/javascript\nmodule-type: widget\n\nA copy of the core text widget under a different name\n\n\\*/\n(function(){\n\n/*jslint node: true, browser: true */\n/*global $tw: false */\n\"use strict\";\n\nvar Widget = require(\"$:/core/modules/widgets/widget.js\").widget;\n\nvar PlainTextNodeWidget = function(parseTreeNode,options) {\n\tthis.initialise(parseTreeNode,options);\n};\n\n/*\nInherit from the base widget class\n*/\nPlainTextNodeWidget.prototype = new Widget();\n\n/*\nRender this widget into the DOM\n*/\nPlainTextNodeWidget.prototype.render = function(parent,nextSibling) {\n\tthis.parentDomNode = parent;\n\tthis.computeAttributes();\n\tthis.execute();\n\tvar text = this.getAttribute(\"text\",this.parseTreeNode.text || \"\");\n\ttext = text.replace(/\\r/mg,\"\");\n\tvar textNode = this.document.createTextNode(text);\n\tparent.insertBefore(textNode,nextSibling);\n\tthis.domNodes.push(textNode);\n};\n\n/*\nCompute the internal state of the widget\n*/\nPlainTextNodeWidget.prototype.execute = function() {\n\t// Nothing to do for a text node\n};\n\n/*\nSelectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering\n*/\nPlainTextNodeWidget.prototype.refresh = function(changedTiddlers) {\n\tvar changedAttributes = this.computeAttributes();\n\tif(changedAttributes.text) {\n\t\tthis.refreshSelf();\n\t\treturn true;\n\t} else {\n\t\treturn false;\t\n\t}\n};\n\nexports[\"plain-text\"] = PlainTextNodeWidget;\n\n})();\n","type":"application/javascript","module-type":"widget"},"$:/plugins/tiddlywiki/freelinks/readme":{"title":"$:/plugins/tiddlywiki/freelinks/readme","text":"This plugin adds automatic generation of links to tiddler titles.\n\n''Note that automatic link generation can be very slow when there are a large number of tiddlers''.\n\nFreelinking is activated for runs of text that have the following variables set:\n\n* `tv-wikilinks` is NOT equal to `no`\n* `tv-freelinks` is set to `yes`\n\nFreelinks are case sensitive.\n\nWithin view templates, the variable `tv-freelinks` is automatically set to the content of $:/config/Freelinks/Enable, which can be set via the settings panel of this plugin.\n\n!! Notes\n\nTo change within which tiddlers freelinking occurs requires customising the shadow tiddler $:/plugins/tiddlywiki/freelinks/macros/view. This tiddler is tagged $:/tags/Macro/View  which means that it will be included as a local macro in each view template. By default, its content is:\n\n```\n<$set name=\"tv-freelinks\" value={{$:/config/Freelinks/Enable}}/>\n```\n\nThat means that for each tiddler the variable tv-freelinks will be set to the tiddler $:/config/Freelinks/Enable, which is set to \"yes\" or \"no\" by the settings in control panel.\n\nInstead, we can use a filter expression to, say, only freelink within the tiddler with the title \"HelloThere\":\n\n```\n<$set name=\"tv-freelinks\" value={{{ [<currentTiddler>match[HelloThere]then[yes]else[no]] }}}/>\n```\n\nOr, we can make a filter that will only freelink within tiddlers with the tag \"MyTag\":\n\n```\n<$set name=\"tv-freelinks\" value={{{ [<currentTiddler>tag[MyTags]then[yes]else[no]] }}}/>\n```\n\nOr we can combine both approaches:\n\n```\n<$set name=\"tv-freelinks\" value={{{ [<currentTiddler>match[HelloThere]] ~[<currentTiddler>tag[MyTag]] +[then[yes]else[no]] }}}/>\n```\n"},"$:/plugins/tiddlywiki/freelinks/settings":{"title":"$:/plugins/tiddlywiki/freelinks/settings","text":"<$checkbox tiddler=\"$:/config/Freelinks/Enable\" field=\"text\" checked=\"yes\" unchecked=\"no\" default=\"no\"> <$link to=\"$:/config/Freelinks/Enable\">Enable freelinking within tiddler view templates</$link> </$checkbox>\n"},"$:/plugins/tiddlywiki/freelinks/styles":{"title":"$:/plugins/tiddlywiki/freelinks/styles","tags":"[[$:/tags/Stylesheet]]","text":"\\rules only filteredtranscludeinline transcludeinline macrodef macrocallinline\n\nbutton.tc-tiddlylink.tc-freelink, a.tc-tiddlylink.tc-freelink {\n\tbackground-color: #5777d91c;\n}\n"},"$:/core/modules/widgets/text.js":{"title":"$:/core/modules/widgets/text.js","text":"/*\\\ntitle: $:/core/modules/widgets/text.js\ntype: application/javascript\nmodule-type: widget\n\nAn override of the core text widget that automatically linkifies the text\n\n\\*/\n(function(){\n\n/*jslint node: true, browser: true */\n/*global $tw: false */\n\"use strict\";\n\nvar Widget = require(\"$:/core/modules/widgets/widget.js\").widget,\n\tLinkWidget = require(\"$:/core/modules/widgets/link.js\").link,\n\tButtonWidget = require(\"$:/core/modules/widgets/button.js\").button;\n\nvar TextNodeWidget = function(parseTreeNode,options) {\n\tthis.initialise(parseTreeNode,options);\n};\n\n/*\nInherit from the base widget class\n*/\nTextNodeWidget.prototype = new Widget();\n\n/*\nRender this widget into the DOM\n*/\nTextNodeWidget.prototype.render = function(parent,nextSibling) {\n\tthis.parentDomNode = parent;\n\tthis.computeAttributes();\n\tthis.execute();\n\tthis.renderChildren(parent,nextSibling);\n};\n\n/*\nCompute the internal state of the widget\n*/\nTextNodeWidget.prototype.execute = function() {\n\tvar self = this;\n\t// Get our parameters\n\tvar childParseTree = [{\n\t\t\ttype: \"plain-text\",\n\t\t\ttext: this.getAttribute(\"text\",this.parseTreeNode.text || \"\")\n\t\t}];\n\t// Only process links if not disabled and we're not within a button or link widget\n\tif(this.getVariable(\"tv-wikilinks\",{defaultValue:\"yes\"}).trim() !== \"no\" && this.getVariable(\"tv-freelinks\",{defaultValue:\"no\"}).trim() === \"yes\" && !this.isWithinButtonOrLink()) {\n\t\t// Get the information about the current tiddler titles, and construct a regexp\n\t\tthis.tiddlerTitleInfo = this.wiki.getGlobalCache(\"tiddler-title-info\",function() {\n\t\t\tvar titles = [],\n\t\t\t\treparts = [],\n\t\t\t\tsortedTitles = self.wiki.allTitles().sort(function(a,b) {\n\t\t\t\t\tvar lenA = a.length,\n\t\t\t\t\t\tlenB = b.length;\n\t\t\t\t\t// First sort by length, so longer titles are first\n\t\t\t\t\tif(lenA !== lenB) {\n\t\t\t\t\t\tif(lenA < lenB) {\n\t\t\t\t\t\t\treturn +1;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn -1;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t// Then sort alphabetically within titles of the same length\n\t\t\t\t\t\tif(a < b) {\n\t\t\t\t\t\t\treturn -1;\n\t\t\t\t\t\t} else if(a > b) {\n\t\t\t\t\t\t\treturn +1;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t$tw.utils.each(sortedTitles,function(title) {\n\t\t\t\tif(title.substring(0,3) !== \"$:/\") {\n\t\t\t\t\ttitles.push(title);\n\t\t\t\t\treparts.push(\"(\\\\b\" + $tw.utils.escapeRegExp(title) + \"\\\\b)\");\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn {\n\t\t\t\ttitles: titles,\n\t\t\t\tregexp: new RegExp(reparts.join(\"|\"),\"\")\n\t\t\t};\n\t\t});\n\t\t// Repeatedly linkify\n\t\tif(this.tiddlerTitleInfo.titles.length > 0) {\n\t\t\tvar index,text,match,matchEnd;\n\t\t\tdo {\n\t\t\t\tindex = childParseTree.length - 1;\n\t\t\t\ttext = childParseTree[index].text;\n\t\t\t\tmatch = this.tiddlerTitleInfo.regexp.exec(text);\n\t\t\t\tif(match) {\n\t\t\t\t\t// Make a text node for any text before the match\n\t\t\t\t\tif(match.index > 0) {\n\t\t\t\t\t\tchildParseTree[index].text = text.substring(0,match.index);\n\t\t\t\t\t\tindex += 1;\n\t\t\t\t\t}\n\t\t\t\t\t// Make a link node for the match\n\t\t\t\t\tchildParseTree[index] = {\n\t\t\t\t\t\ttype: \"link\",\n\t\t\t\t\t\tattributes: {\n\t\t\t\t\t\t\tto: {type: \"string\", value: match[0]},\n\t\t\t\t\t\t\t\"class\": {type: \"string\", value: \"tc-freelink\"}\n\t\t\t\t\t\t},\n\t\t\t\t\t\tchildren: [{\n\t\t\t\t\t\t\ttype: \"plain-text\", text: match[0]\n\t\t\t\t\t\t}]\n\t\t\t\t\t};\n\t\t\t\t\tindex += 1;\n\t\t\t\t\t// Make a text node for any text after the match\n\t\t\t\t\tmatchEnd = match.index + match[0].length;\n\t\t\t\t\tif(matchEnd < text.length) {\n\t\t\t\t\t\tchildParseTree[index] = {\n\t\t\t\t\t\t\ttype: \"plain-text\",\n\t\t\t\t\t\t\ttext: text.substring(matchEnd)\n\t\t\t\t\t\t};\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} while(match && childParseTree[childParseTree.length - 1].type === \"plain-text\");\t\t\t\n\t\t}\n\t}\n\t// Make the child widgets\n\tthis.makeChildWidgets(childParseTree);\n};\n\nTextNodeWidget.prototype.isWithinButtonOrLink = function() {\n\tvar withinButtonOrLink = false,\n\t\twidget = this.parentWidget;\n\twhile(!withinButtonOrLink && widget) {\n\t\twithinButtonOrLink = widget instanceof ButtonWidget || widget instanceof LinkWidget;\n\t\twidget = widget.parentWidget;\n\t}\n\treturn withinButtonOrLink;\n};\n\n/*\nSelectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering\n*/\nTextNodeWidget.prototype.refresh = function(changedTiddlers) {\n\tvar self = this,\n\t\tchangedAttributes = this.computeAttributes(),\n\t\ttitlesHaveChanged = false;\n\t$tw.utils.each(changedTiddlers,function(change,title) {\n\t\tif(change.isDeleted) {\n\t\t\ttitlesHaveChanged = true\n\t\t} else {\n\t\t\ttitlesHaveChanged = titlesHaveChanged || !self.tiddlerTitleInfo || self.tiddlerTitleInfo.titles.indexOf(title) === -1;\n\t\t}\n\t});\n\tif(changedAttributes.text || titlesHaveChanged) {\n\t\tthis.refreshSelf();\n\t\treturn true;\n\t} else {\n\t\treturn false;\t\n\t}\n};\n\nexports.text = TextNodeWidget;\n\n})();\n","type":"application/javascript","module-type":"widget"}}}