diff --git a/boot/boot.js b/boot/boot.js index 353e5e0f6..fbac37d77 100644 --- a/boot/boot.js +++ b/boot/boot.js @@ -892,6 +892,19 @@ $tw.modules.applyMethods = function(moduleType,targetObject) { return targetObject; }; +/* +Return a class created from a modules. The module should export the properties to be added to those of the optional base class +*/ +$tw.modules.createClassFromModule = function(moduleExports,baseClass) { + var newClass = function() {}; + if(baseClass) { + newClass.prototype = new baseClass(); + newClass.prototype.constructor = baseClass; + } + $tw.utils.extend(newClass.prototype,moduleExports); + return newClass; +}; + /* Return an array of classes created from the modules of a specified type. Each module should export the properties to be added to those of the optional base class */ @@ -899,13 +912,7 @@ $tw.modules.createClassesFromModules = function(moduleType,subType,baseClass) { var classes = Object.create(null); $tw.modules.forEachModuleOfType(moduleType,function(title,moduleExports) { if(!subType || moduleExports.types[subType]) { - var newClass = function() {}; - if(baseClass) { - newClass.prototype = new baseClass(); - newClass.prototype.constructor = baseClass; - } - $tw.utils.extend(newClass.prototype,moduleExports); - classes[moduleExports.name] = newClass; + classes[moduleExports.name] = $tw.modules.createClassFromModule(moduleExports,baseClass); } }); return classes; diff --git a/core/modules/parsers/wikiparser/wikiparser.js b/core/modules/parsers/wikiparser/wikiparser.js index dbeed9de2..e6f860a91 100644 --- a/core/modules/parsers/wikiparser/wikiparser.js +++ b/core/modules/parsers/wikiparser/wikiparser.js @@ -25,6 +25,14 @@ Attributes are stored as hashmaps of the following objects: /*global $tw: false */ "use strict"; +/* +type: content type of text +text: text to be parsed +options: see below: + parseAsInline: true to parse text as inline instead of block + wiki: reference to wiki to use + _canonical_uri: optional URI of content if text is missing or empty +*/ var WikiParser = function(type,text,options) { this.wiki = options.wiki; var self = this; @@ -33,19 +41,6 @@ var WikiParser = function(type,text,options) { this.loadRemoteTiddler(options._canonical_uri); text = $tw.language.getRawString("LazyLoadingWarning"); } - // Initialise the classes if we don't have them already - if(!this.pragmaRuleClasses) { - WikiParser.prototype.pragmaRuleClasses = $tw.modules.createClassesFromModules("wikirule","pragma",$tw.WikiRuleBase); - this.setupRules(WikiParser.prototype.pragmaRuleClasses,"$:/config/WikiParserRules/Pragmas/"); - } - if(!this.blockRuleClasses) { - WikiParser.prototype.blockRuleClasses = $tw.modules.createClassesFromModules("wikirule","block",$tw.WikiRuleBase); - this.setupRules(WikiParser.prototype.blockRuleClasses,"$:/config/WikiParserRules/Block/"); - } - if(!this.inlineRuleClasses) { - WikiParser.prototype.inlineRuleClasses = $tw.modules.createClassesFromModules("wikirule","inline",$tw.WikiRuleBase); - this.setupRules(WikiParser.prototype.inlineRuleClasses,"$:/config/WikiParserRules/Inline/"); - } // Save the parse text this.type = type || "text/vnd.tiddlywiki"; this.source = text || ""; @@ -54,13 +49,38 @@ var WikiParser = function(type,text,options) { this.configTrimWhiteSpace = false; // Set current parse position this.pos = 0; - // Instantiate the pragma parse rules - this.pragmaRules = this.instantiateRules(this.pragmaRuleClasses,"pragma",0); - // Instantiate the parser block and inline rules - this.blockRules = this.instantiateRules(this.blockRuleClasses,"block",0); - this.inlineRules = this.instantiateRules(this.inlineRuleClasses,"inline",0); - // Parse any pragmas + // Start with empty output this.tree = []; + // Assemble the rule classes we're going to use + var pragmaRuleClasses, blockRuleClasses, inlineRuleClasses; + if(options.rules) { + pragmaRuleClasses = options.rules.pragma; + blockRuleClasses = options.rules.block; + inlineRuleClasses = options.rules.inline; + } else { + // Setup the rule classes if we don't have them already + if(!this.pragmaRuleClasses) { + WikiParser.prototype.pragmaRuleClasses = $tw.modules.createClassesFromModules("wikirule","pragma",$tw.WikiRuleBase); + this.setupRules(WikiParser.prototype.pragmaRuleClasses,"$:/config/WikiParserRules/Pragmas/"); + } + pragmaRuleClasses = this.pragmaRuleClasses; + if(!this.blockRuleClasses) { + WikiParser.prototype.blockRuleClasses = $tw.modules.createClassesFromModules("wikirule","block",$tw.WikiRuleBase); + this.setupRules(WikiParser.prototype.blockRuleClasses,"$:/config/WikiParserRules/Block/"); + } + blockRuleClasses = this.blockRuleClasses; + if(!this.inlineRuleClasses) { + WikiParser.prototype.inlineRuleClasses = $tw.modules.createClassesFromModules("wikirule","inline",$tw.WikiRuleBase); + this.setupRules(WikiParser.prototype.inlineRuleClasses,"$:/config/WikiParserRules/Inline/"); + } + inlineRuleClasses = this.inlineRuleClasses; + } + // Instantiate the pragma parse rules + this.pragmaRules = this.instantiateRules(pragmaRuleClasses,"pragma",0); + // Instantiate the parser block and inline rules + this.blockRules = this.instantiateRules(blockRuleClasses,"block",0); + this.inlineRules = this.instantiateRules(inlineRuleClasses,"inline",0); + // Parse any pragmas var topBranch = this.parsePragmas(); // Parse the text into inline runs or blocks if(options.parseAsInline) { diff --git a/editions/dev/tiddlers/new/ParserSubclassingMechanism.tid b/editions/dev/tiddlers/new/ParserSubclassingMechanism.tid new file mode 100644 index 000000000..c4aab295e --- /dev/null +++ b/editions/dev/tiddlers/new/ParserSubclassingMechanism.tid @@ -0,0 +1,42 @@ +created: 20210203150855206 +modified: 20210203150855206 +title: ParserSubclassingMechanism + +!! Introduction + +The wikitext parser subclassing mechanism makes it possible for custom parsers to use the wiki text parsing engine, but to customise the rules that are used. + +!! Example + +Here is an example of a subclass of the checkbox widget that adds logging to the event handler: + +```js +(function(){ + +/*jslint node: true, browser: true */ +/*global $tw: false */ +"use strict"; + +var WikiParser = require("$:/core/modules/parsers/wikiparser/wikiparser.js")["text/vnd.tiddlywiki"], + HtmlParser = $tw.modules.createClassFromModule(require("$:/core/modules/parsers/wikiparser/rules/html.js"),$tw.WikiRuleBase), + EntityParser = $tw.modules.createClassFromModule(require("$:/core/modules/parsers/wikiparser/rules/entity.js"),$tw.WikiRuleBase); + +var MyCustomWikiParser = function(type,text,options) { + var parser = new WikiParser(type,text,$tw.utils.extend({},options,{ + // Force the parser to parse in inline mode + parseAsInline: true, + // Specify which rules will be used + rules: { + pragma: [], + block: [], + inline: [HtmlParser,EntityParser] + } + })); + this.tree = parser.tree; + this.prototype = parser.prototype; +}; + +exports["text/vnd.my-custom-type"] = MyCustomWikiParser; + +})(); +```