373 lines
18 KiB
C#
373 lines
18 KiB
C#
using System.Text;
|
|
using NTDLS.Helpers;
|
|
using ZelWiki.Engine.Function;
|
|
using ZelWiki.Engine.Implementation.Utility;
|
|
using ZelWiki.Engine.Library;
|
|
using ZelWiki.Engine.Library.Interfaces;
|
|
using static ZelWiki.Engine.Library.Constants;
|
|
|
|
namespace ZelWiki.Engine.Implementation
|
|
{
|
|
/// <summary>
|
|
/// Handled scope function calls.
|
|
/// </summary>
|
|
public class ScopeFunctionHandler : IScopeFunctionHandler
|
|
{
|
|
private static FunctionPrototypeCollection? _collection;
|
|
|
|
public FunctionPrototypeCollection Prototypes
|
|
{
|
|
get
|
|
{
|
|
if (_collection == null)
|
|
{
|
|
_collection = new FunctionPrototypeCollection(FunctionPrototypeCollection.WikiFunctionType.Scoped);
|
|
|
|
#region Prototypes.
|
|
|
|
_collection.Add("$$Code: <string>{language(auto,wiki,cpp,lua,graphql,swift,r,yaml,kotlin,scss,shell,vbnet,json,objectivec,perl,diff,wasm,php,xml,bash,csharp,css,go,ini,javascript,less,makefile,markdown,plaintext,python,python-repl,ruby,rust,sql,typescript)}='auto'");
|
|
_collection.Add("$$Bullets: <string>{type(unordered,ordered)}='unordered'");
|
|
_collection.Add("$$Order: <string>{direction(ascending,descending)}='ascending'");
|
|
_collection.Add("$$Jumbotron:");
|
|
_collection.Add("$$Callout: <string>{styleName(default,primary,secondary,success,info,warning,danger)}='default' | <string>{titleText}=''");
|
|
_collection.Add("$$Background: <string>{styleName(default,primary,secondary,light,dark,success,info,warning,danger,muted)}='default'");
|
|
_collection.Add("$$Foreground: <string>{styleName(default,primary,secondary,light,dark,success,info,warning,danger,muted)}='default'");
|
|
_collection.Add("$$Alert: <string>{styleName(default,primary,secondary,light,dark,success,info,warning,danger)}='default' | <string>{titleText}=''");
|
|
_collection.Add("$$Card: <string>{styleName(default,primary,secondary,light,dark,success,info,warning,danger)}='default' | <string>{titleText}=''");
|
|
_collection.Add("$$Collapse: <string>{linkText}='Show'");
|
|
_collection.Add("$$Table: <boolean>{hasBorder}='true' | <boolean>{isFirstRowHeader}='true'");
|
|
_collection.Add("$$StripedTable: <boolean>{hasBorder}='true' | <boolean>{isFirstRowHeader}='true'");
|
|
_collection.Add("$$DefineSnippet: <string>[name]");
|
|
|
|
#endregion
|
|
}
|
|
|
|
return _collection;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called to handle function calls when proper prototypes are matched.
|
|
/// </summary>
|
|
/// <param name="state">Reference to the wiki state object</param>
|
|
/// <param name="function">The parsed function call and all its parameters and their values.</param>
|
|
/// <param name="scopeBody">The the text that the function is designed to affect.</param>
|
|
public HandlerResult Handle(IZelEngineState state, FunctionCall function, string? scopeBody = null)
|
|
{
|
|
scopeBody.EnsureNotNull($"The function '{function.Name}' scope body can not be null");
|
|
|
|
switch (function.Name.ToLower())
|
|
{
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
case "code":
|
|
{
|
|
var html = new StringBuilder();
|
|
|
|
string language = function.Parameters.Get<string>("language");
|
|
if (string.IsNullOrEmpty(language) || language?.ToLower() == "auto")
|
|
{
|
|
html.Append($"<pre>");
|
|
html.Append($"<code>{scopeBody.Replace("\r\n", "\n").Replace("\n", SoftBreak)}</code></pre>");
|
|
}
|
|
else
|
|
{
|
|
html.Append($"<pre class=\"language-{language}\">");
|
|
html.Append($"<code>{scopeBody.Replace("\r\n", "\n").Replace("\n", SoftBreak)}</code></pre>");
|
|
}
|
|
|
|
return new HandlerResult(html.ToString())
|
|
{
|
|
Instructions = [Constants.HandlerResultInstruction.DisallowNestedProcessing]
|
|
};
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
case "stripedtable":
|
|
case "table":
|
|
{
|
|
var html = new StringBuilder();
|
|
|
|
var hasBorder = function.Parameters.Get<bool>("hasBorder");
|
|
var isFirstRowHeader = function.Parameters.Get<bool>("isFirstRowHeader");
|
|
|
|
html.Append($"<table class=\"table");
|
|
|
|
if (function.Name.Equals("stripedtable", StringComparison.InvariantCultureIgnoreCase))
|
|
{
|
|
html.Append(" table-striped");
|
|
}
|
|
if (hasBorder)
|
|
{
|
|
html.Append(" table-bordered");
|
|
}
|
|
|
|
html.Append($"\">");
|
|
|
|
var lines = scopeBody.Split(['\n'], StringSplitOptions.RemoveEmptyEntries).Select(o => o.Trim()).Where(o => o.Length > 0);
|
|
|
|
int rowNumber = 0;
|
|
|
|
foreach (var lineText in lines)
|
|
{
|
|
var columns = lineText.Split("||");
|
|
|
|
if (rowNumber == 0 && isFirstRowHeader)
|
|
{
|
|
html.Append($"<thead>");
|
|
}
|
|
else if (rowNumber == 1 && isFirstRowHeader || rowNumber == 0 && isFirstRowHeader == false)
|
|
{
|
|
html.Append($"<tbody>");
|
|
}
|
|
|
|
html.Append($"<tr>");
|
|
foreach (var columnText in columns)
|
|
{
|
|
if (rowNumber == 0 && isFirstRowHeader)
|
|
{
|
|
html.Append($"<td><strong>{columnText}</strong></td>");
|
|
}
|
|
else
|
|
{
|
|
html.Append($"<td>{columnText}</td>");
|
|
}
|
|
}
|
|
|
|
if (rowNumber == 0 && isFirstRowHeader)
|
|
{
|
|
html.Append($"</thead>");
|
|
}
|
|
html.Append($"</tr>");
|
|
|
|
rowNumber++;
|
|
}
|
|
|
|
html.Append($"</tbody>");
|
|
html.Append($"</table>");
|
|
|
|
return new HandlerResult(html.ToString());
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
case "bullets":
|
|
{
|
|
var html = new StringBuilder();
|
|
|
|
string type = function.Parameters.Get<string>("type");
|
|
|
|
if (type == "unordered")
|
|
{
|
|
var lines = scopeBody.Split(['\n'], StringSplitOptions.RemoveEmptyEntries).Select(o => o.Trim()).Where(o => o.Length > 0);
|
|
|
|
int currentLevel = 0;
|
|
|
|
foreach (var line in lines)
|
|
{
|
|
int newIndent = 0;
|
|
for (; newIndent < line.Length && line[newIndent] == '>'; newIndent++)
|
|
{
|
|
//Count how many '>' are at the start of the line.
|
|
}
|
|
newIndent++;
|
|
|
|
if (newIndent < currentLevel)
|
|
{
|
|
for (; currentLevel != newIndent; currentLevel--)
|
|
{
|
|
html.Append($"</ul>");
|
|
}
|
|
}
|
|
else if (newIndent > currentLevel)
|
|
{
|
|
for (; currentLevel != newIndent; currentLevel++)
|
|
{
|
|
html.Append($"<ul>");
|
|
}
|
|
}
|
|
|
|
html.Append($"<li>{line.Trim(['>'])}</li>");
|
|
}
|
|
|
|
for (; currentLevel > 0; currentLevel--)
|
|
{
|
|
html.Append($"</ul>");
|
|
}
|
|
}
|
|
else if (type == "ordered")
|
|
{
|
|
var lines = scopeBody.Split(['\n'], StringSplitOptions.RemoveEmptyEntries).Select(o => o.Trim()).Where(o => o.Length > 0);
|
|
|
|
int currentLevel = 0;
|
|
|
|
foreach (var line in lines)
|
|
{
|
|
int newIndent = 0;
|
|
for (; newIndent < line.Length && line[newIndent] == '>'; newIndent++)
|
|
{
|
|
//Count how many '>' are at the start of the line.
|
|
}
|
|
newIndent++;
|
|
|
|
if (newIndent < currentLevel)
|
|
{
|
|
for (; currentLevel != newIndent; currentLevel--)
|
|
{
|
|
html.Append($"</ol>");
|
|
}
|
|
}
|
|
else if (newIndent > currentLevel)
|
|
{
|
|
for (; currentLevel != newIndent; currentLevel++)
|
|
{
|
|
html.Append($"<ol>");
|
|
}
|
|
}
|
|
|
|
html.Append($"<li>{line.Trim(['>'])}</li>");
|
|
}
|
|
|
|
for (; currentLevel > 0; currentLevel--)
|
|
{
|
|
html.Append($"</ol>");
|
|
}
|
|
}
|
|
return new HandlerResult(html.ToString());
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
case "definesnippet":
|
|
{
|
|
var html = new StringBuilder();
|
|
|
|
string name = function.Parameters.Get<string>("name");
|
|
|
|
if (!state.Snippets.TryAdd(name, scopeBody))
|
|
{
|
|
state.Snippets[name] = scopeBody;
|
|
}
|
|
|
|
return new HandlerResult(html.ToString());
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
case "alert":
|
|
{
|
|
var html = new StringBuilder();
|
|
|
|
string titleText = function.Parameters.Get<string>("titleText");
|
|
string style = function.Parameters.Get<string>("styleName").ToLower();
|
|
style = style == "default" ? "" : $"alert-{style}";
|
|
|
|
if (!string.IsNullOrEmpty(titleText)) scopeBody = $"<h1>{titleText}</h1>{scopeBody}";
|
|
html.Append($"<div class=\"alert {style}\">{scopeBody}</div>");
|
|
return new HandlerResult(html.ToString());
|
|
}
|
|
|
|
case "order":
|
|
{
|
|
var html = new StringBuilder();
|
|
|
|
string direction = function.Parameters.Get<string>("direction");
|
|
var lines = scopeBody.Split("\n").Select(o => o.Trim()).ToList();
|
|
|
|
if (direction == "ascending")
|
|
{
|
|
html.Append(string.Join("\r\n", lines.OrderBy(o => o)));
|
|
}
|
|
else
|
|
{
|
|
html.Append(string.Join("\r\n", lines.OrderByDescending(o => o)));
|
|
}
|
|
return new HandlerResult(html.ToString());
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
case "jumbotron":
|
|
{
|
|
var html = new StringBuilder();
|
|
|
|
string titleText = function.Parameters.Get("titleText", "");
|
|
html.Append($"<div class=\"mt-4 p-5 bg-secondary text-white rounded\">");
|
|
if (!string.IsNullOrEmpty(titleText)) html.Append($"<h1>{titleText}</h1>");
|
|
html.Append($"<p>{scopeBody}</p>");
|
|
html.Append($"</div>");
|
|
return new HandlerResult(html.ToString());
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
case "foreground":
|
|
{
|
|
var html = new StringBuilder();
|
|
|
|
var style = BGFGStyle.GetForegroundStyle(function.Parameters.Get("styleName", "default")).Swap();
|
|
html.Append($"<p class=\"{style.ForegroundStyle} {style.BackgroundStyle}\">{scopeBody}</p>");
|
|
return new HandlerResult(html.ToString());
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
case "background":
|
|
{
|
|
var html = new StringBuilder();
|
|
|
|
var style = BGFGStyle.GetBackgroundStyle(function.Parameters.Get("styleName", "default"));
|
|
html.Append($"<div class=\"p-3 mb-2 {style.ForegroundStyle} {style.BackgroundStyle}\">{scopeBody}</div>");
|
|
return new HandlerResult(html.ToString());
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
case "collapse":
|
|
{
|
|
var html = new StringBuilder();
|
|
|
|
string linkText = function.Parameters.Get<string>("linktext");
|
|
string uid = "A" + Guid.NewGuid().ToString().Replace("-", "");
|
|
html.Append($"<a data-bs-toggle=\"collapse\" href=\"#{uid}\" role=\"button\" aria-expanded=\"false\" aria-controls=\"{uid}\">{linkText}</a>");
|
|
html.Append($"<div class=\"collapse\" id=\"{uid}\">");
|
|
html.Append($"<div class=\"card card-body\"><p class=\"card-text\">{scopeBody}</p></div></div>");
|
|
return new HandlerResult(html.ToString());
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
case "callout":
|
|
{
|
|
var html = new StringBuilder();
|
|
|
|
string titleText = function.Parameters.Get<string>("titleText");
|
|
string style = function.Parameters.Get<string>("styleName").ToLower();
|
|
style = style == "default" ? "" : style;
|
|
|
|
html.Append($"<div class=\"bd-callout bd-callout-{style}\">");
|
|
if (string.IsNullOrWhiteSpace(titleText) == false) html.Append($"<h4>{titleText}</h4>");
|
|
html.Append($"{scopeBody}");
|
|
html.Append($"</div>");
|
|
return new HandlerResult(html.ToString());
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
case "card":
|
|
{
|
|
var html = new StringBuilder();
|
|
|
|
string titleText = function.Parameters.Get<string>("titleText");
|
|
var style = BGFGStyle.GetBackgroundStyle(function.Parameters.Get("styleName", "default"));
|
|
|
|
html.Append($"<div class=\"card {style.ForegroundStyle} {style.BackgroundStyle} mb-3\">");
|
|
if (string.IsNullOrEmpty(titleText) == false)
|
|
{
|
|
html.Append($"<div class=\"card-header\">{titleText}</div>");
|
|
}
|
|
html.Append("<div class=\"card-body\">");
|
|
html.Append($"<p class=\"card-text\">{scopeBody}</p>");
|
|
html.Append("</div>");
|
|
html.Append("</div>");
|
|
return new HandlerResult(html.ToString());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return new HandlerResult() { Instructions = [Constants.HandlerResultInstruction.Skip] };
|
|
}
|
|
}
|
|
}
|