mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2024-11-26 11:37:20 +00:00
Make it easier to subclass the wikitext parser with a custom rule set
We can now pass arrays of rule classes to the parser constructor, overriding the rules that would normally be used by the parser. This allows us to create custom variants of the wikitext parser with their own content type. It could also provide a basis for a new Markdown parser based on our existing wikitext parser but with new rules.
This commit is contained in:
parent
12f1847475
commit
9f9ce6595b
19
boot/boot.js
19
boot/boot.js
@ -893,19 +893,26 @@ $tw.modules.applyMethods = function(moduleType,targetObject) {
|
||||
};
|
||||
|
||||
/*
|
||||
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
|
||||
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.createClassesFromModules = function(moduleType,subType,baseClass) {
|
||||
var classes = Object.create(null);
|
||||
$tw.modules.forEachModuleOfType(moduleType,function(title,moduleExports) {
|
||||
if(!subType || moduleExports.types[subType]) {
|
||||
$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);
|
||||
classes[moduleExports.name] = newClass;
|
||||
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
|
||||
*/
|
||||
$tw.modules.createClassesFromModules = function(moduleType,subType,baseClass) {
|
||||
var classes = Object.create(null);
|
||||
$tw.modules.forEachModuleOfType(moduleType,function(title,moduleExports) {
|
||||
if(!subType || moduleExports.types[subType]) {
|
||||
classes[moduleExports.name] = $tw.modules.createClassFromModule(moduleExports,baseClass);
|
||||
}
|
||||
});
|
||||
return classes;
|
||||
|
@ -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) {
|
||||
|
42
editions/dev/tiddlers/new/ParserSubclassingMechanism.tid
Normal file
42
editions/dev/tiddlers/new/ParserSubclassingMechanism.tid
Normal file
@ -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;
|
||||
|
||||
})();
|
||||
```
|
Loading…
Reference in New Issue
Block a user