mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2024-09-18 18:29:42 +00:00
b7562f0c7b
* Initial Commit * Update docs * Add support for elseif blocks * Another test * WIP * Change from `{%if%}` to `<%if%>` See discussion here - https://talk.tiddlywiki.org/t/proposed-if-widget/7882/64 * Don't use the widget body as the template if a list-empty widget is present See discussion here - https://github.com/Jermolene/TiddlyWiki5/pull/7710#issuecomment-1717193296 * List widget should search recursively for list-template and list-empty * Allow block mode content within an if/then/else clause * Update docs * Add from-version tag to docs
121 lines
3.8 KiB
JavaScript
121 lines
3.8 KiB
JavaScript
/*\
|
|
title: $:/core/modules/parsers/wikiparser/rules/conditional.js
|
|
type: application/javascript
|
|
module-type: wikirule
|
|
|
|
Conditional shortcut syntax
|
|
|
|
```
|
|
This is a <% if [{something}] %>Elephant<% elseif [{else}] %>Pelican<% else %>Crocodile<% endif %>
|
|
```
|
|
|
|
\*/
|
|
(function(){
|
|
|
|
/*jslint node: true, browser: true */
|
|
/*global $tw: false */
|
|
"use strict";
|
|
|
|
exports.name = "conditional";
|
|
exports.types = {inline: true, block: true};
|
|
|
|
exports.init = function(parser) {
|
|
this.parser = parser;
|
|
// Regexp to match
|
|
this.matchRegExp = /\<\%\s*if\s+/mg;
|
|
this.terminateIfRegExp = /\%\>/mg;
|
|
};
|
|
|
|
exports.findNextMatch = function(startPos) {
|
|
// Look for the next <% if shortcut
|
|
this.matchRegExp.lastIndex = startPos;
|
|
this.match = this.matchRegExp.exec(this.parser.source);
|
|
// If not found then return no match
|
|
if(!this.match) {
|
|
return undefined;
|
|
}
|
|
// Check for the next %>
|
|
this.terminateIfRegExp.lastIndex = this.match.index;
|
|
this.terminateIfMatch = this.terminateIfRegExp.exec(this.parser.source);
|
|
// If not found then return no match
|
|
if(!this.terminateIfMatch) {
|
|
return undefined;
|
|
}
|
|
// Return the position at which the construction was found
|
|
return this.match.index;
|
|
};
|
|
|
|
/*
|
|
Parse the most recent match
|
|
*/
|
|
exports.parse = function() {
|
|
// Get the filter condition
|
|
var filterCondition = this.parser.source.substring(this.match.index + this.match[0].length,this.terminateIfMatch.index);
|
|
// Advance the parser position to past the %>
|
|
this.parser.pos = this.terminateIfMatch.index + this.terminateIfMatch[0].length;
|
|
// Parse the if clause
|
|
return this.parseIfClause(filterCondition);
|
|
};
|
|
|
|
exports.parseIfClause = function(filterCondition) {
|
|
// Create the list widget
|
|
var listWidget = {
|
|
type: "list",
|
|
tag: "$list",
|
|
isBlock: this.is.block,
|
|
children: [
|
|
{
|
|
type: "list-template",
|
|
tag: "$list-template"
|
|
},
|
|
{
|
|
type: "list-empty",
|
|
tag: "$list-empty"
|
|
}
|
|
]
|
|
};
|
|
$tw.utils.addAttributeToParseTreeNode(listWidget,"filter",filterCondition);
|
|
$tw.utils.addAttributeToParseTreeNode(listWidget,"variable","condition");
|
|
$tw.utils.addAttributeToParseTreeNode(listWidget,"limit","1");
|
|
// Check for an immediately following double linebreak
|
|
var hasLineBreak = !!$tw.utils.parseTokenRegExp(this.parser.source,this.parser.pos,/([^\S\n\r]*\r?\n(?:[^\S\n\r]*\r?\n|$))/g);
|
|
// Parse the body looking for else or endif
|
|
var reEndString = "\\<\\%\\s*(endif)\\s*\\%\\>|\\<\\%\\s*(else)\\s*\\%\\>|\\<\\%\\s*(elseif)\\s+([\\s\\S]+?)\\%\\>",
|
|
ex;
|
|
if(hasLineBreak) {
|
|
ex = this.parser.parseBlocksTerminatedExtended(reEndString);
|
|
} else {
|
|
var reEnd = new RegExp(reEndString,"mg");
|
|
ex = this.parser.parseInlineRunTerminatedExtended(reEnd,{eatTerminator: true});
|
|
}
|
|
// Put the body into the list template
|
|
listWidget.children[0].children = ex.tree;
|
|
// Check for an else or elseif
|
|
if(ex.match) {
|
|
if(ex.match[1] === "endif") {
|
|
// Nothing to do if we just found an endif
|
|
} else if(ex.match[2] === "else") {
|
|
// Check for an immediately following double linebreak
|
|
hasLineBreak = !!$tw.utils.parseTokenRegExp(this.parser.source,this.parser.pos,/([^\S\n\r]*\r?\n(?:[^\S\n\r]*\r?\n|$))/g);
|
|
// If we found an else then we need to parse the body looking for the endif
|
|
var reEndString = "\\<\\%\\s*(endif)\\s*\\%\\>",
|
|
ex;
|
|
if(hasLineBreak) {
|
|
ex = this.parser.parseBlocksTerminatedExtended(reEndString);
|
|
} else {
|
|
var reEnd = new RegExp(reEndString,"mg");
|
|
ex = this.parser.parseInlineRunTerminatedExtended(reEnd,{eatTerminator: true});
|
|
}
|
|
// Put the parsed content inside the list empty template
|
|
listWidget.children[1].children = ex.tree;
|
|
} else if(ex.match[3] === "elseif") {
|
|
// Parse the elseif clause by reusing this parser, passing the new filter condition
|
|
listWidget.children[1].children = this.parseIfClause(ex.match[4]);
|
|
}
|
|
}
|
|
// Return the parse tree node
|
|
return [listWidget];
|
|
};
|
|
|
|
})();
|