diff --git a/core/modules/filters/backtranscludes.js b/core/modules/filters/backtranscludes.js new file mode 100644 index 000000000..7d4215073 --- /dev/null +++ b/core/modules/filters/backtranscludes.js @@ -0,0 +1,26 @@ +/*\ +title: $:/core/modules/filters/backtranscludes.js +type: application/javascript +module-type: filteroperator + +Filter operator for returning all the backtranscludes from a tiddler + +\*/ +(function(){ + +/*jslint node: true, browser: true */ +/*global $tw: false */ +"use strict"; + +/* +Export our filter function +*/ +exports.backtranscludes = function(source,operator,options) { + var results = []; + source(function(tiddler,title) { + $tw.utils.pushTop(results,options.wiki.getTiddlerBacktranscludes(title)); + }); + return results; +}; + +})(); diff --git a/core/modules/filters/transcludes.js b/core/modules/filters/transcludes.js new file mode 100644 index 000000000..bd618296b --- /dev/null +++ b/core/modules/filters/transcludes.js @@ -0,0 +1,26 @@ +/*\ +title: $:/core/modules/filters/transcludes.js +type: application/javascript +module-type: filteroperator + +Filter operator for returning all the transcludes from a tiddler + +\*/ +(function(){ + +/*jslint node: true, browser: true */ +/*global $tw: false */ +"use strict"; + +/* +Export our filter function +*/ +exports.transcludes = function(source,operator,options) { + var results = new $tw.utils.LinkedList(); + source(function(tiddler,title) { + results.pushTop(options.wiki.getTiddlerTranscludes(title)); + }); + return results.toArray(); +}; + +})(); diff --git a/core/modules/indexers/back-indexer.js b/core/modules/indexers/back-indexer.js new file mode 100644 index 000000000..609d62bfc --- /dev/null +++ b/core/modules/indexers/back-indexer.js @@ -0,0 +1,119 @@ +/*\ +title: $:/core/modules/indexers/back-indexer.js +type: application/javascript +module-type: indexer + +By parsing the tiddler text, indexes the tiddlers' back links, back transclusions, block level back links. + +\*/ +function BackIndexer(wiki) { + this.wiki = wiki; +} + +BackIndexer.prototype.init = function() { + this.subIndexers = { + link: new BackSubIndexer(this,"extractLinks"), + transclude: new BackSubIndexer(this,"extractTranscludes"), + }; +}; + +BackIndexer.prototype.rebuild = function() { + $tw.utils.each(this.subIndexers,function(subIndexer) { + subIndexer.rebuild(); + }); +}; + +BackIndexer.prototype.update = function(updateDescriptor) { + $tw.utils.each(this.subIndexers,function(subIndexer) { + subIndexer.update(updateDescriptor); + }); +}; +function BackSubIndexer(indexer,extractor) { + this.wiki = indexer.wiki; + this.indexer = indexer; + this.extractor = extractor; + /** + * { + * [target title, e.g. tiddler title being linked to]: + * { + * [source title, e.g. tiddler title that has link syntax in its text]: true + * } + * } + */ + this.index = null; +} + +BackSubIndexer.prototype.init = function() { + // lazy init until first lookup + this.index = null; +} + +BackSubIndexer.prototype._init = function() { + this.index = Object.create(null); + var self = this; + this.wiki.forEachTiddler(function(sourceTitle,tiddler) { + var newTargets = self._getTarget(tiddler); + $tw.utils.each(newTargets, function(target) { + if(!self.index[target]) { + self.index[target] = Object.create(null); + } + self.index[target][sourceTitle] = true; + }); + }); +} + +BackSubIndexer.prototype.rebuild = function() { + this.index = null; +} + +/* +* Get things that is being referenced in the text, e.g. tiddler names in the link syntax. +*/ +BackSubIndexer.prototype._getTarget = function(tiddler) { + var parser = this.wiki.parseText(tiddler.fields.type, tiddler.fields.text, {}); + if(parser) { + return this.wiki[this.extractor](parser.tree); + } + return []; +} + +BackSubIndexer.prototype.update = function(updateDescriptor) { + // lazy init/update until first lookup + if(!this.index) { + return; + } + var newTargets = [], + oldTargets = [], + self = this; + if(updateDescriptor.old.exists) { + oldTargets = this._getTarget(updateDescriptor.old.tiddler); + } + if(updateDescriptor.new.exists) { + newTargets = this._getTarget(updateDescriptor.new.tiddler); + } + + $tw.utils.each(oldTargets,function(target) { + if(self.index[target]) { + delete self.index[target][updateDescriptor.old.tiddler.fields.title]; + } + }); + $tw.utils.each(newTargets,function(target) { + if(!self.index[target]) { + self.index[target] = Object.create(null); + } + self.index[target][updateDescriptor.new.tiddler.fields.title] = true; + }); +} + +BackSubIndexer.prototype.lookup = function(title) { + if(!this.index) { + this._init(); + } + if(this.index[title]) { + return Object.keys(this.index[title]); + } else { + return []; + } +} + +exports.BackIndexer = BackIndexer; diff --git a/core/modules/indexers/backlinks-index.js b/core/modules/indexers/backlinks-index.js deleted file mode 100644 index 5902e2829..000000000 --- a/core/modules/indexers/backlinks-index.js +++ /dev/null @@ -1,86 +0,0 @@ -/*\ -title: $:/core/modules/indexers/backlinks-indexer.js -type: application/javascript -module-type: indexer - -Indexes the tiddlers' backlinks - -\*/ -(function(){ - -/*jslint node: true, browser: true */ -/*global modules: false */ -"use strict"; - - -function BacklinksIndexer(wiki) { - this.wiki = wiki; -} - -BacklinksIndexer.prototype.init = function() { - this.index = null; -} - -BacklinksIndexer.prototype.rebuild = function() { - this.index = null; -} - -BacklinksIndexer.prototype._getLinks = function(tiddler) { - var parser = this.wiki.parseText(tiddler.fields.type, tiddler.fields.text, {}); - if(parser) { - return this.wiki.extractLinks(parser.tree); - } - return []; -} - -BacklinksIndexer.prototype.update = function(updateDescriptor) { - if(!this.index) { - return; - } - var newLinks = [], - oldLinks = [], - self = this; - if(updateDescriptor.old.exists) { - oldLinks = this._getLinks(updateDescriptor.old.tiddler); - } - if(updateDescriptor.new.exists) { - newLinks = this._getLinks(updateDescriptor.new.tiddler); - } - - $tw.utils.each(oldLinks,function(link) { - if(self.index[link]) { - delete self.index[link][updateDescriptor.old.tiddler.fields.title]; - } - }); - $tw.utils.each(newLinks,function(link) { - if(!self.index[link]) { - self.index[link] = Object.create(null); - } - self.index[link][updateDescriptor.new.tiddler.fields.title] = true; - }); -} - -BacklinksIndexer.prototype.lookup = function(title) { - if(!this.index) { - this.index = Object.create(null); - var self = this; - this.wiki.forEachTiddler(function(title,tiddler) { - var links = self._getLinks(tiddler); - $tw.utils.each(links, function(link) { - if(!self.index[link]) { - self.index[link] = Object.create(null); - } - self.index[link][title] = true; - }); - }); - } - if(this.index[title]) { - return Object.keys(this.index[title]); - } else { - return []; - } -} - -exports.BacklinksIndexer = BacklinksIndexer; - -})(); diff --git a/core/modules/wiki.js b/core/modules/wiki.js index 430c46466..96e40a708 100755 --- a/core/modules/wiki.js +++ b/core/modules/wiki.js @@ -534,8 +534,8 @@ Return an array of tiddler titles that link to the specified tiddler */ exports.getTiddlerBacklinks = function(targetTitle) { var self = this, - backlinksIndexer = this.getIndexer("BacklinksIndexer"), - backlinks = backlinksIndexer && backlinksIndexer.lookup(targetTitle); + backIndexer = this.getIndexer("BackIndexer"), + backlinks = backIndexer && backIndexer.subIndexers.link.lookup(targetTitle); if(!backlinks) { backlinks = []; @@ -549,6 +549,68 @@ exports.getTiddlerBacklinks = function(targetTitle) { return backlinks; }; + +/* +Return an array of tiddler titles that are directly transcluded within the given parse tree + */ +exports.extractTranscludes = function(parseTreeRoot) { + // Count up the transcludes + var transcludes = [], + checkParseTree = function(parseTree, parentNode) { + for(var t=0; t> diff --git a/editions/tw5.com/tiddlers/filters/examples/backtransclude.tid b/editions/tw5.com/tiddlers/filters/examples/backtransclude.tid new file mode 100644 index 000000000..e70648576 --- /dev/null +++ b/editions/tw5.com/tiddlers/filters/examples/backtransclude.tid @@ -0,0 +1,7 @@ +tags: [[backtranscludes Operator]] [[Operator Examples]] +title: backtranscludes Operator (Examples) +type: text/vnd.tiddlywiki + +<<.operator-example 1 "[[Motovun Jack.jpg]backtranscludes[]]">> + +<<.operator-example 2 "[[Transclusion]backtranscludes[]]">> diff --git a/editions/tw5.com/tiddlers/filters/examples/transclude.tid b/editions/tw5.com/tiddlers/filters/examples/transclude.tid new file mode 100644 index 000000000..eefea2a57 --- /dev/null +++ b/editions/tw5.com/tiddlers/filters/examples/transclude.tid @@ -0,0 +1,5 @@ +tags: [[transcludes Operator]] [[Operator Examples]] +title: transcludes Operator (Examples) +type: text/vnd.tiddlywiki + +<<.operator-example 1 "[[Images in WikiText]transcludes[]]">> diff --git a/editions/tw5.com/tiddlers/filters/transcludes.tid b/editions/tw5.com/tiddlers/filters/transcludes.tid new file mode 100644 index 000000000..29b90eb54 --- /dev/null +++ b/editions/tw5.com/tiddlers/filters/transcludes.tid @@ -0,0 +1,13 @@ +created: 20211002204500000 +tags: [[Filter Operators]] [[Common Operators]] +title: transcludes Operator +type: text/vnd.tiddlywiki +caption: transcludes +op-purpose: find the titles linked to by each input title +op-input: a [[selection of titles|Title Selection]] +op-parameter: none +op-output: the titles to which the input tiddlers [[transcludes|Transclusion]] + +Each input title is processed in turn. The corresponding tiddler's list of transcludes is generated, in the order in which they appear in the tiddler's text, and [[dominantly appended|Dominant Append]] to the operator's overall output. + +<<.operator-examples "transcludes">> diff --git a/languages/zh-Hans/Docs/ModuleTypes.multids b/languages/zh-Hans/Docs/ModuleTypes.multids index e86baa57f..6f33a3fe0 100644 --- a/languages/zh-Hans/Docs/ModuleTypes.multids +++ b/languages/zh-Hans/Docs/ModuleTypes.multids @@ -9,7 +9,7 @@ config: 加入 `$tw.config` 的数据。 filteroperator: 个别筛选器算子方法。 global: 加入 `$tw` 的全域数据。 info: 透过 [[$:/temp/info-plugin]] 伪插件,发布系统信息。 -isfilteroperator: ''is'' 筛选器算子的运算符。 +isfilteroperator: ''is'' 筛选器运算子的参数。 library: 一般用途的 JavaScript 模块的通用模块类型。 macro: JavaScript ''宏''定义。 parser: 不同内容类型的解析器。 diff --git a/languages/zh-Hans/Misc.multids b/languages/zh-Hans/Misc.multids index 51e6a2ca0..edd508ecd 100644 --- a/languages/zh-Hans/Misc.multids +++ b/languages/zh-Hans/Misc.multids @@ -31,7 +31,7 @@ Error/Filter: 筛选器错误 Error/FilterRunPrefix: 筛选器错误:筛选器 run 的未知首码 Error/FilterSyntax: 筛选器运算式中的语法错误 Error/FormatFilterOperator: 筛选器错误:`format` 筛选器运算符的未知尾码 -Error/IsFilterOperator: 筛选器错误︰'is' 筛选器运算符的未知操作数 +Error/IsFilterOperator: 筛选器错误︰'is' 筛选器运算子的未知参数 Error/LoadingPluginLibrary: 加载插件库时,发生错误 Error/NetworkErrorAlert: `

''网络错误''

与服务器的连缐似乎已中断。这可能表示您的网络连缐有问题。请尝试恢复网路连缐才能继续。

''恢复连缐时,所有未保存的更改,将自动同步''。` Error/PutEditConflict: 服务器上的文件已更改 diff --git a/languages/zh-Hant/Docs/ModuleTypes.multids b/languages/zh-Hant/Docs/ModuleTypes.multids index baba51100..620615248 100644 --- a/languages/zh-Hant/Docs/ModuleTypes.multids +++ b/languages/zh-Hant/Docs/ModuleTypes.multids @@ -9,7 +9,7 @@ config: 加入 `$tw.config` 的資料。 filteroperator: 個別篩選器運算元方法。 global: 加入 `$tw` 的全域資料。 info: 透過 [[$:/temp/info-plugin]] 偽插件,發佈系統資訊。 -isfilteroperator: ''is'' 篩選器運算元的運算子。 +isfilteroperator: ''is'' 篩選器運算子的參數。 library: 一般用途的 JavaScript 模組的通用的模組類型。 macro: JavaScript ''巨集''定義。 parser: 不同內容類型的解析器。 diff --git a/languages/zh-Hant/Misc.multids b/languages/zh-Hant/Misc.multids index e38900415..5ddb9f1a3 100644 --- a/languages/zh-Hant/Misc.multids +++ b/languages/zh-Hant/Misc.multids @@ -31,7 +31,7 @@ Error/Filter: 篩選器錯誤 Error/FilterRunPrefix: 篩選器錯誤:篩選器 run 的未知首碼 Error/FilterSyntax: 篩選器運算式中的語法錯誤 Error/FormatFilterOperator: 篩選器錯誤:`format` 篩選器運算子的未知尾碼 -Error/IsFilterOperator: 篩選器錯誤︰'is' 篩選器運算子的未知運算元 +Error/IsFilterOperator: 篩選器錯誤︰'is' 篩選器運算子的未知參數 Error/LoadingPluginLibrary: 載入插件程式庫時,發生錯誤 Error/NetworkErrorAlert: `

''網路錯誤''

與伺服器的連線似乎已中斷。這可能表示您的網路連線有問題。請嘗試恢復網路連線才能繼續。

''恢復連線時,所有未儲存的變更,將自動同步''。` Error/PutEditConflict: 伺服器上的檔案已更改