123123
This commit is contained in:
@@ -47,7 +47,8 @@ namespace DummyPageGenerator
|
|||||||
{
|
{
|
||||||
for (int i = 0; i < 1124 - _users.Count; i++)
|
for (int i = 0; i < 1124 - _users.Count; i++)
|
||||||
{
|
{
|
||||||
string emailAddress = WordsRepository.GetRandomWords(1).First() + "@" + WordsRepository.GetRandomWords(1).First() + ".com";
|
string emailAddress = WordsRepository.GetRandomWords(1).First() + "@" +
|
||||||
|
WordsRepository.GetRandomWords(1).First() + ".com";
|
||||||
CreateUserAndProfile(emailAddress);
|
CreateUserAndProfile(emailAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,7 +69,7 @@ namespace DummyPageGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a user and the associated profile with claims and such.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="emailAddress"></param>
|
/// <param name="emailAddress"></param>
|
||||||
/// <exception cref="Exception"></exception>
|
/// <exception cref="Exception"></exception>
|
||||||
@@ -80,7 +81,8 @@ namespace DummyPageGenerator
|
|||||||
Email = emailAddress
|
Email = emailAddress
|
||||||
};
|
};
|
||||||
|
|
||||||
var result = _userManager.CreateAsync(user, WordsRepository.GetRandomWords(1).First() + Guid.NewGuid().ToString()).Result;
|
var result = _userManager
|
||||||
|
.CreateAsync(user, WordsRepository.GetRandomWords(1).First() + Guid.NewGuid().ToString()).Result;
|
||||||
if (!result.Succeeded)
|
if (!result.Succeeded)
|
||||||
{
|
{
|
||||||
throw new Exception(string.Join("\r\n", result.Errors.Select(o => o.Description)));
|
throw new Exception(string.Join("\r\n", result.Errors.Select(o => o.Description)));
|
||||||
@@ -103,7 +105,7 @@ namespace DummyPageGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a paragraph/sentence structure.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="words"></param>
|
/// <param name="words"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
@@ -118,7 +120,7 @@ namespace DummyPageGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a paragraph/sentence structure with links and wiki markup.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="wordCount"></param>
|
/// <param name="wordCount"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
@@ -135,18 +137,19 @@ namespace DummyPageGenerator
|
|||||||
|
|
||||||
switch (_random.Next(0, 7))
|
switch (_random.Next(0, 7))
|
||||||
{
|
{
|
||||||
case 2: //Dead link.
|
case 2:
|
||||||
paragraph = paragraph.Replace(token, $"[[{token}]]");
|
paragraph = paragraph.Replace(token, $"[[{token}]]");
|
||||||
break;
|
break;
|
||||||
case 4: //Wiki markup.
|
case 4:
|
||||||
paragraph = paragraph.Replace(token, AddWikiMarkup(token));
|
paragraph = paragraph.Replace(token, AddWikiMarkup(token));
|
||||||
break;
|
break;
|
||||||
case 6: //Good link.
|
case 6:
|
||||||
var recentPage = GetRandomRecentPageName();
|
var recentPage = GetRandomRecentPageName();
|
||||||
if (recentPage != null)
|
if (recentPage != null)
|
||||||
{
|
{
|
||||||
paragraph = paragraph.Replace(token, $"[[{recentPage}]]");
|
paragraph = paragraph.Replace(token, $"[[{recentPage}]]");
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -163,7 +166,7 @@ namespace DummyPageGenerator
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_recentPageNames.Count > 200) //Shuffle and limit the recent page names.
|
if (_recentPageNames.Count > 200)
|
||||||
{
|
{
|
||||||
_recentPageNames = ShuffleList(_recentPageNames).Take(100).ToList();
|
_recentPageNames = ShuffleList(_recentPageNames).Take(100).ToList();
|
||||||
}
|
}
|
||||||
@@ -176,7 +179,7 @@ namespace DummyPageGenerator
|
|||||||
{
|
{
|
||||||
lock (_pagePool)
|
lock (_pagePool)
|
||||||
{
|
{
|
||||||
if (_recentPageNames.Count > 200) //Shuffle and limit the recent page names.
|
if (_recentPageNames.Count > 200)
|
||||||
{
|
{
|
||||||
_recentPageNames = ShuffleList(_recentPageNames).Take(100).ToList();
|
_recentPageNames = ShuffleList(_recentPageNames).Take(100).ToList();
|
||||||
}
|
}
|
||||||
@@ -186,6 +189,7 @@ namespace DummyPageGenerator
|
|||||||
{
|
{
|
||||||
pageNames.Add(_recentPageNames[_random.Next(0, _recentPageNames.Count)]);
|
pageNames.Add(_recentPageNames[_random.Next(0, _recentPageNames.Count)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return pageNames;
|
return pageNames;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -199,8 +203,9 @@ namespace DummyPageGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a random page on the wiki.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="engine"></param>
|
||||||
/// <param name="userId"></param>
|
/// <param name="userId"></param>
|
||||||
public void GeneratePage(IZelEngine engine, Guid userId)
|
public void GeneratePage(IZelEngine engine, Guid userId)
|
||||||
{
|
{
|
||||||
@@ -216,7 +221,8 @@ namespace DummyPageGenerator
|
|||||||
|
|
||||||
var body = new StringBuilder();
|
var body = new StringBuilder();
|
||||||
|
|
||||||
body.AppendLine($"##title ##Tag(" + string.Join(' ', ShuffleList(_tags).Take(_random.Next(1, 4))) + ")");
|
body.AppendLine($"##title ##Tag(" + string.Join(' ', ShuffleList(_tags).Take(_random.Next(1, 4))) +
|
||||||
|
")");
|
||||||
body.AppendLine($"##toc");
|
body.AppendLine($"##toc");
|
||||||
|
|
||||||
body.AppendLine($"==Overview");
|
body.AppendLine($"==Overview");
|
||||||
@@ -232,7 +238,6 @@ namespace DummyPageGenerator
|
|||||||
|
|
||||||
if (_random.Next(100) >= 95)
|
if (_random.Next(100) >= 95)
|
||||||
{
|
{
|
||||||
//Add dead links (missing pages).
|
|
||||||
textWithLinks.AddRange(WordsRepository.GetRandomWords(_random.Next(1, 2)).Select(o => $"[[{o}]]"));
|
textWithLinks.AddRange(WordsRepository.GetRandomWords(_random.Next(1, 2)).Select(o => $"[[{o}]]"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,7 +263,8 @@ namespace DummyPageGenerator
|
|||||||
|
|
||||||
if (_random.Next(100) >= 70)
|
if (_random.Next(100) >= 70)
|
||||||
{
|
{
|
||||||
var fileName = _fileNames[_random.Next(_fileNames.Count)] + ".txt"; ;
|
var fileName = _fileNames[_random.Next(_fileNames.Count)] + ".txt";
|
||||||
|
;
|
||||||
var fileData = Encoding.UTF8.GetBytes(page.Body);
|
var fileData = Encoding.UTF8.GetBytes(page.Body);
|
||||||
AttachFile(newPageId, userId, fileName, fileData);
|
AttachFile(newPageId, userId, fileName, fileData);
|
||||||
}
|
}
|
||||||
@@ -288,7 +294,7 @@ namespace DummyPageGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Modifies a random page on the wiki.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="userId"></param>
|
/// <param name="userId"></param>
|
||||||
public void ModifyRandomPages(IZelEngine engine, Guid userId)
|
public void ModifyRandomPages(IZelEngine engine, Guid userId)
|
||||||
@@ -328,12 +334,13 @@ namespace DummyPageGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attaches a file to a wiki page.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pageId"></param>
|
/// <param name="pageId"></param>
|
||||||
/// <param name="userId"></param>
|
/// <param name="userId"></param>
|
||||||
/// <param name="fileName"></param>
|
/// <param name="fileName"></param>
|
||||||
/// <param name="fileData"></param>
|
/// <param name="fileData"></param>
|
||||||
|
/// <exception cref="Exception"></exception>
|
||||||
private void AttachFile(int pageId, Guid userId, string fileName, byte[] fileData)
|
private void AttachFile(int pageId, Guid userId, string fileName, byte[] fileData)
|
||||||
{
|
{
|
||||||
if (fileData.Length > GlobalConfiguration.MaxAttachmentFileSize)
|
if (fileData.Length > GlobalConfiguration.MaxAttachmentFileSize)
|
||||||
@@ -372,6 +379,7 @@ namespace DummyPageGenerator
|
|||||||
newList[k] = newList[n];
|
newList[k] = newList[n];
|
||||||
newList[n] = value;
|
newList[n] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return newList;
|
return newList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ using System.Runtime.Caching;
|
|||||||
|
|
||||||
namespace ZelWiki.Caching
|
namespace ZelWiki.Caching
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 缓存
|
||||||
|
/// </summary>
|
||||||
public class WikiCache
|
public class WikiCache
|
||||||
{
|
{
|
||||||
public enum Category
|
public enum Category
|
||||||
@@ -24,7 +27,7 @@ namespace ZelWiki.Caching
|
|||||||
public static int CacheItemCount => MemCache.Count();
|
public static int CacheItemCount => MemCache.Count();
|
||||||
public static double CacheMemoryLimit => MemCache.CacheMemoryLimit;
|
public static double CacheMemoryLimit => MemCache.CacheMemoryLimit;
|
||||||
|
|
||||||
public static MemoryCache MemCache => _memCache ?? throw new Exception("Cache has not been initialized.");
|
public static MemoryCache MemCache => _memCache ?? throw new Exception("缓存尚未初始化");
|
||||||
|
|
||||||
public static void Initialize(int cacheMemoryLimitMB, int defaultCacheSeconds)
|
public static void Initialize(int cacheMemoryLimitMB, int defaultCacheSeconds)
|
||||||
{
|
{
|
||||||
@@ -40,7 +43,7 @@ namespace ZelWiki.Caching
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets an item from the cache.
|
/// 获取缓存
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T"></typeparam>
|
/// <typeparam name="T"></typeparam>
|
||||||
/// <param name="cacheKey"></param>
|
/// <param name="cacheKey"></param>
|
||||||
@@ -60,9 +63,8 @@ namespace ZelWiki.Caching
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines if the cache contains a given key.
|
/// 确定缓存是否包含给定的key
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
/// <param name="cacheKey"></param>
|
/// <param name="cacheKey"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static bool Contains(IWikiCacheKey cacheKey)
|
public static bool Contains(IWikiCacheKey cacheKey)
|
||||||
@@ -79,7 +81,7 @@ namespace ZelWiki.Caching
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets an item from the cache.
|
/// 获取缓存
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T"></typeparam>
|
/// <typeparam name="T"></typeparam>
|
||||||
/// <param name="cacheKey"></param>
|
/// <param name="cacheKey"></param>
|
||||||
@@ -98,7 +100,7 @@ namespace ZelWiki.Caching
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds an item to the cache. If the item is already in the cache, this will reset its expiration.
|
///添加缓存
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="cacheKey"></param>
|
/// <param name="cacheKey"></param>
|
||||||
/// <param name="value"></param>
|
/// <param name="value"></param>
|
||||||
@@ -127,7 +129,7 @@ namespace ZelWiki.Caching
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Removes all entries from the cache.
|
/// 清理
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static void Clear()
|
public static void Clear()
|
||||||
{
|
{
|
||||||
@@ -144,9 +146,9 @@ namespace ZelWiki.Caching
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Removes cache entries that begin with the given cache key.
|
/// 删除某个
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="category"></param>
|
/// <param name="cacheKey"></param>
|
||||||
public static void ClearCategory(WikiCacheKey cacheKey)
|
public static void ClearCategory(WikiCacheKey cacheKey)
|
||||||
{
|
{
|
||||||
var keys = new List<string>();
|
var keys = new List<string>();
|
||||||
@@ -163,7 +165,7 @@ namespace ZelWiki.Caching
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Removes cache entries in a given category.
|
/// 删除给定类别中的缓存条目
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="category"></param>
|
/// <param name="category"></param>
|
||||||
public static void ClearCategory(Category category)
|
public static void ClearCategory(Category category)
|
||||||
|
|||||||
@@ -3,17 +3,17 @@
|
|||||||
namespace ZelWiki.Caching
|
namespace ZelWiki.Caching
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Contains a verbatim cache key.
|
/// 包含逐字缓存键
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="key"></param>
|
/// <param name="key"></param>
|
||||||
public class WikiCacheKey(string key) : IWikiCacheKey
|
public class WikiCacheKey(string key) : IWikiCacheKey
|
||||||
{
|
{
|
||||||
public string Key { get; set; } = key;
|
public string Key { get; set; } = key;
|
||||||
|
|
||||||
public static WikiCacheKey Build(WikiCache.Category category, object?[] segments)
|
public static WikiCacheKey Build(Category category, object?[] segments)
|
||||||
=> new($"[{category}]:[{string.Join("]:[", segments)}]");
|
=> new($"[{category}]:[{string.Join("]:[", segments)}]");
|
||||||
|
|
||||||
public static WikiCacheKey Build(WikiCache.Category category)
|
public static WikiCacheKey Build(Category category)
|
||||||
=> new($"[{category}]");
|
=> new($"[{category}]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,22 +3,18 @@ using static ZelWiki.Caching.WikiCache;
|
|||||||
|
|
||||||
namespace ZelWiki.Caching
|
namespace ZelWiki.Caching
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Contains a verbatim cache key which also includes the calling function name.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="key"></param>
|
|
||||||
public class WikiCacheKeyFunction(string key) : IWikiCacheKey
|
public class WikiCacheKeyFunction(string key) : IWikiCacheKey
|
||||||
{
|
{
|
||||||
public string Key { get; set; } = key;
|
public string Key { get; set; } = key;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Builds a cache key which includes the calling function name.
|
/// 生成一个包含调用函数名称的缓存键。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static WikiCacheKeyFunction Build(WikiCache.Category category, object?[] segments, [CallerMemberName] string callingFunction = "")
|
public static WikiCacheKeyFunction Build(WikiCache.Category category, object?[] segments, [CallerMemberName] string callingFunction = "")
|
||||||
=> new($"[{category}]:[{string.Join("]:[", segments)}]:[{callingFunction}]");
|
=> new($"[{category}]:[{string.Join("]:[", segments)}]:[{callingFunction}]");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Builds a cache key which includes the calling function name.
|
/// 生成一个包含调用函数名称的缓存键。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static WikiCacheKeyFunction Build(WikiCache.Category category, [CallerMemberName] string callingFunction = "")
|
public static WikiCacheKeyFunction Build(WikiCache.Category category, [CallerMemberName] string callingFunction = "")
|
||||||
=> new($"[{category}]:[{callingFunction}]");
|
=> new($"[{category}]:[{callingFunction}]");
|
||||||
|
|||||||
@@ -11,6 +11,10 @@ namespace ZelWiki.Email
|
|||||||
{
|
{
|
||||||
private readonly ILogger<WikiEmailSender> _logger;
|
private readonly ILogger<WikiEmailSender> _logger;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="logger"></param>
|
||||||
public WikiEmailSender(ILogger<WikiEmailSender> logger)
|
public WikiEmailSender(ILogger<WikiEmailSender> logger)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
|||||||
@@ -1,17 +1,19 @@
|
|||||||
namespace ZelWiki.Engine.Function
|
namespace ZelWiki.Engine.Function
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Contains information about an actual function call, its supplied parameters, and is matched with a defined function.
|
/// 包含有关实际函数调用及其提供的参数的信息,并与定义的函数相匹配。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class FunctionCall
|
public class FunctionCall
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The name of the function being called.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Name { get; private set; }
|
public string Name { get; private set; }
|
||||||
|
|
||||||
public FunctionPrototype Prototype { get; set; }
|
public FunctionPrototype Prototype { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The arguments supplied by the caller.
|
/// T
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public FunctionParameters Parameters { get; private set; }
|
public FunctionParameters Parameters { get; private set; }
|
||||||
|
|
||||||
@@ -25,7 +27,7 @@
|
|||||||
{
|
{
|
||||||
if (arg.StartsWith(':') && arg.Contains('='))
|
if (arg.StartsWith(':') && arg.Contains('='))
|
||||||
{
|
{
|
||||||
var parsed = arg.Substring(1); //Skip the colon.
|
var parsed = arg.Substring(1);
|
||||||
int index = parsed.IndexOf('=');
|
int index = parsed.IndexOf('=');
|
||||||
var name = parsed.Substring(0, index).Trim().ToLower();
|
var name = parsed.Substring(0, index).Trim().ToLower();
|
||||||
var value = parsed.Substring(index + 1).Trim();
|
var value = parsed.Substring(index + 1).Trim();
|
||||||
@@ -42,9 +44,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks the passed value against the function prototype to ensure that the variable is the correct type, value, etc.
|
/// 对照函数原型检查传递的值,以确保变量的类型,值等正确
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="segment"></param>
|
/// <param name="param"></param>
|
||||||
/// <param name="value"></param>
|
/// <param name="value"></param>
|
||||||
/// <exception cref="Exception"></exception>
|
/// <exception cref="Exception"></exception>
|
||||||
private void EnforcePrototypeParamValue(PrototypeParameter param, string value)
|
private void EnforcePrototypeParamValue(PrototypeParameter param, string value)
|
||||||
@@ -53,21 +55,25 @@
|
|||||||
{
|
{
|
||||||
if (bool.TryParse(value, out bool _) == false)
|
if (bool.TryParse(value, out bool _) == false)
|
||||||
{
|
{
|
||||||
throw new Exception($"Function [{Name}], the value [{value}] passed to parameter [{param.Name}] could not be converted to boolean.");
|
throw new Exception(
|
||||||
|
$"函数 [{Name}] 传递给 [{param.Name}] 的值 [{value}] 无法转化成布尔");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (param.Type == "integer")
|
if (param.Type == "integer")
|
||||||
{
|
{
|
||||||
if (int.TryParse(value, out int _) == false)
|
if (int.TryParse(value, out int _) == false)
|
||||||
{
|
{
|
||||||
throw new Exception($"Function [{Name}], the value [{value}] passed to parameter [{param.Name}] could not be converted to integer.");
|
throw new Exception(
|
||||||
|
$"函数 [{Name}] 传递给 [{param.Name}] 的值 [{value}] 无法转化成整数.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (param.Type == "float")
|
else if (param.Type == "float")
|
||||||
{
|
{
|
||||||
if (double.TryParse(value, out double _) == false)
|
if (double.TryParse(value, out double _) == false)
|
||||||
{
|
{
|
||||||
throw new Exception($"Function [{Name}], the value [{value}] passed to parameter [{param.Name}] could not be converted to float.");
|
throw new Exception(
|
||||||
|
$"函数 [{Name}] 传递给 [{param.Name}] 的值 [{value}] 无法转化成小数.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,24 +81,22 @@
|
|||||||
{
|
{
|
||||||
if (param.AllowedValues.Contains(value.ToLower()) == false)
|
if (param.AllowedValues.Contains(value.ToLower()) == false)
|
||||||
{
|
{
|
||||||
throw new Exception($"Function [{Name}], the value [{value}] passed to parameter [{param.Name}] is not allowed. Allowed values are [{string.Join(",", param.AllowedValues)}].");
|
throw new Exception(
|
||||||
|
$"函数 [{Name}] 传递给 [{param.Name}] 的值 [{value}] 为非法数据. 合法值为 [{string.Join(",", param.AllowedValues)}].");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Rolls through the supplied arguments and applies them to the prototype. Also identifies which supplied arguments are associated with each
|
///
|
||||||
/// prototype argument and adds the ordinal based arguments to the name based collection. Ensures that each argument conforms with the prototype.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <exception cref="Exception"></exception>
|
/// <exception cref="Exception"></exception>
|
||||||
private void ApplyPrototype()
|
private void ApplyPrototype()
|
||||||
{
|
{
|
||||||
int index = 0;
|
var index = 0;
|
||||||
|
|
||||||
//Keep a list of the arguments as they are associated with the prototype so that we can later reference them by name.
|
|
||||||
var namedToAddLater = new List<NamedParameter>();
|
var namedToAddLater = new List<NamedParameter>();
|
||||||
|
|
||||||
//Handle non-infinite ordinal based required parameters:
|
|
||||||
for (; index < Prototype.Parameters.Count; index++)
|
for (; index < Prototype.Parameters.Count; index++)
|
||||||
{
|
{
|
||||||
var param = Prototype.Parameters[index];
|
var param = Prototype.Parameters[index];
|
||||||
@@ -101,15 +105,15 @@
|
|||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (param.IsInfinite == true)
|
|
||||||
|
if (param.IsInfinite)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Parameters.Ordinals.Count > index)
|
if (Parameters.Ordinals.Count > index)
|
||||||
{
|
{
|
||||||
//Good, we have a value.
|
var value = Parameters.Ordinals[index].Value;
|
||||||
string value = Parameters.Ordinals[index].Value;
|
|
||||||
Parameters.Ordinals[index].AssociateWithPrototypeParam(param.Name);
|
Parameters.Ordinals[index].AssociateWithPrototypeParam(param.Name);
|
||||||
EnforcePrototypeParamValue(param, value.ToLower());
|
EnforcePrototypeParamValue(param, value.ToLower());
|
||||||
|
|
||||||
@@ -123,33 +127,30 @@
|
|||||||
|
|
||||||
bool hasEncounteredOptionalParameter = false;
|
bool hasEncounteredOptionalParameter = false;
|
||||||
|
|
||||||
//Handle remaining optional parameters:
|
|
||||||
for (; index < Prototype.Parameters.Count; index++)
|
for (; index < Prototype.Parameters.Count; index++)
|
||||||
{
|
{
|
||||||
var param = Prototype.Parameters[index];
|
var param = Prototype.Parameters[index];
|
||||||
|
|
||||||
if (param.IsInfinite == true)
|
if (param.IsInfinite)
|
||||||
{
|
{
|
||||||
if (param.IsRequired == true)
|
if (param.IsRequired)
|
||||||
{
|
{
|
||||||
//Make sure we have at least one of these required infinite parameters passed.
|
|
||||||
if (Parameters.Ordinals.Count > index)
|
if (Parameters.Ordinals.Count > index)
|
||||||
{
|
{
|
||||||
//Good, we have a value.
|
var value = Parameters.Ordinals[index].Value;
|
||||||
string value = Parameters.Ordinals[index].Value;
|
|
||||||
Parameters.Ordinals[index].AssociateWithPrototypeParam(param.Name);
|
Parameters.Ordinals[index].AssociateWithPrototypeParam(param.Name);
|
||||||
EnforcePrototypeParamValue(param, value.ToLower());
|
EnforcePrototypeParamValue(param, value.ToLower());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new Exception($"Function [{Name}], the required infinite parameter [{param.Name}] was not passed.");
|
throw new Exception(
|
||||||
|
$"函数 [{Name}], 参数 [{param.Name}] 未通过.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Now that we have encountered an infinite parameter, it will swallow up all other ordinal based arguments. Might as well check the types and exit the loop.
|
|
||||||
for (; index < Parameters.Ordinals.Count; index++)
|
for (; index < Parameters.Ordinals.Count; index++)
|
||||||
{
|
{
|
||||||
string value = Parameters.Ordinals[index].Value;
|
var value = Parameters.Ordinals[index].Value;
|
||||||
Parameters.Ordinals[index].AssociateWithPrototypeParam(param.Name);
|
Parameters.Ordinals[index].AssociateWithPrototypeParam(param.Name);
|
||||||
EnforcePrototypeParamValue(param, value.ToLower());
|
EnforcePrototypeParamValue(param, value.ToLower());
|
||||||
namedToAddLater.Add(new NamedParameter(param.Name, value));
|
namedToAddLater.Add(new NamedParameter(param.Name, value));
|
||||||
@@ -163,18 +164,20 @@
|
|||||||
hasEncounteredOptionalParameter = true;
|
hasEncounteredOptionalParameter = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (param.IsRequired == true && hasEncounteredOptionalParameter)
|
if (param.IsRequired && hasEncounteredOptionalParameter)
|
||||||
{
|
{
|
||||||
throw new Exception($"Function [{Name}], the required parameter [{param.Name}] was found after other optional parameters.");
|
throw new Exception(
|
||||||
|
$"函数 [{Name}], 所必参数 [{param.Name}] 在其他可选参数之后找到.");
|
||||||
}
|
}
|
||||||
else if (param.IsInfinite == true)
|
else if (param.IsInfinite)
|
||||||
{
|
{
|
||||||
throw new Exception($"Function [{Name}], encountered an unexpected number of infinite parameters in prototype for [{param.Name}].");
|
throw new Exception(
|
||||||
|
$"函数 [{Name}], 参数溢出 [{param.Name}].");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Parameters.Ordinals.Count > index)
|
if (Parameters.Ordinals.Count > index)
|
||||||
{
|
{
|
||||||
string value = Parameters.Ordinals[index].Value;
|
var value = Parameters.Ordinals[index].Value;
|
||||||
Parameters.Ordinals[index].AssociateWithPrototypeParam(param.Name);
|
Parameters.Ordinals[index].AssociateWithPrototypeParam(param.Name);
|
||||||
EnforcePrototypeParamValue(param, value.ToLower());
|
EnforcePrototypeParamValue(param, value.ToLower());
|
||||||
namedToAddLater.Add(new NamedParameter(param.Name, value));
|
namedToAddLater.Add(new NamedParameter(param.Name, value));
|
||||||
@@ -183,8 +186,10 @@
|
|||||||
|
|
||||||
foreach (var named in Parameters.Named)
|
foreach (var named in Parameters.Named)
|
||||||
{
|
{
|
||||||
var param = Prototype.Parameters.Where(o => o.Name.Equals(named.Name, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault()
|
var param = Prototype.Parameters
|
||||||
?? throw new Exception($"Function [{Name}], the named parameter [{named.Name}] is not defined in the function prototype.");
|
.FirstOrDefault(o => o.Name.Equals(named.Name, StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
?? throw new Exception(
|
||||||
|
$"函数 [{Name}], 命名参数 [{named.Name}] 未在函数原型中定义.");
|
||||||
|
|
||||||
EnforcePrototypeParamValue(param, named.Value);
|
EnforcePrototypeParamValue(param, named.Value);
|
||||||
}
|
}
|
||||||
@@ -194,16 +199,19 @@
|
|||||||
var unmatchedParams = Parameters.Ordinals.Where(o => o.IsMatched == false).ToList();
|
var unmatchedParams = Parameters.Ordinals.Where(o => o.IsMatched == false).ToList();
|
||||||
if (unmatchedParams.Count != 0)
|
if (unmatchedParams.Count != 0)
|
||||||
{
|
{
|
||||||
throw new Exception($"Function [{Name}], unmatched parameter value [{unmatchedParams.First().Value}].");
|
throw new Exception($"函数 [{Name}], 不匹配的参数值 [{unmatchedParams.First().Value}].");
|
||||||
}
|
}
|
||||||
|
|
||||||
var nonInfiniteParams = Prototype.Parameters.Where(o => o.IsInfinite == false).Select(o => o.Name.ToLower());
|
var nonInfiniteParams =
|
||||||
var groups = Parameters.Named.Where(o => nonInfiniteParams.Contains(o.Name.ToLower())).GroupBy(o => o.Name.ToLower()).Where(o => o.Count() > 1);
|
Prototype.Parameters.Where(o => o.IsInfinite == false).Select(o => o.Name.ToLower());
|
||||||
|
var groups = Parameters.Named.Where(o => nonInfiniteParams.Contains(o.Name.ToLower()))
|
||||||
|
.GroupBy(o => o.Name.ToLower()).Where(o => o.Count() > 1);
|
||||||
|
|
||||||
if (groups.Any())
|
if (groups.Any())
|
||||||
{
|
{
|
||||||
var group = groups.First();
|
var group = groups.First();
|
||||||
throw new Exception($"Function [{Name}], non-infinite parameter specified more than once: [{group.Key}].");
|
throw new Exception(
|
||||||
|
$"函数 [{Name}], 多次指定参数: [{group.Key}].");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,38 +4,42 @@ namespace ZelWiki.Engine.Function
|
|||||||
{
|
{
|
||||||
public class FunctionParameters
|
public class FunctionParameters
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Variables set by ordinal.
|
|
||||||
/// </summary>
|
|
||||||
public List<OrdinalParameter> Ordinals { get; set; } = new();
|
|
||||||
/// <summary>
|
|
||||||
/// Variables set by name.
|
|
||||||
/// </summary>
|
|
||||||
public List<NamedParameter> Named { get; private set; } = new();
|
|
||||||
|
|
||||||
private readonly FunctionCall _owner;
|
private readonly FunctionCall _owner;
|
||||||
|
|
||||||
public FunctionParameters(FunctionCall owner)
|
public FunctionParameters(FunctionCall owner)
|
||||||
{
|
{
|
||||||
_owner = owner;
|
_owner = owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public List<OrdinalParameter> Ordinals { get; set; } = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public List<NamedParameter> Named { get; private set; } = new();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public T Get<T>(string name)
|
public T Get<T>(string name)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var value = Named.Where(o => o.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault()?.Value;
|
var value = Named
|
||||||
|
.FirstOrDefault(o => o.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase))?.Value;
|
||||||
if (value == null)
|
if (value == null)
|
||||||
{
|
{
|
||||||
var prototype = _owner.Prototype.Parameters.Where(o => o.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase)).First();
|
var prototype = _owner.Prototype.Parameters.First(o => o.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase));
|
||||||
return Converters.ConvertTo<T>(prototype.DefaultValue) ?? throw new Exception("Value cannot be null");
|
return Converters.ConvertTo<T>(prototype.DefaultValue) ??
|
||||||
|
throw new Exception("值不能为空");
|
||||||
}
|
}
|
||||||
|
|
||||||
return Converters.ConvertTo<T>(value) ?? throw new Exception("Value cannot be null");
|
return Converters.ConvertTo<T>(value) ?? throw new Exception("值不能为空");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
throw new Exception($"Function [{_owner.Name}], {ex.Message}");
|
throw new Exception($"函数 [{_owner.Name}], {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,17 +47,18 @@ namespace ZelWiki.Engine.Function
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var value = Named.Where(o => o.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault()?.Value;
|
var value = Named
|
||||||
|
.FirstOrDefault(o => o.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase))?.Value;
|
||||||
if (value == null)
|
if (value == null)
|
||||||
{
|
{
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Converters.ConvertTo<T>(value) ?? throw new Exception("Value cannot be null");
|
return Converters.ConvertTo<T>(value) ?? throw new Exception("值不能为空");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
throw new Exception($"Function [{_owner.Name}], {ex.Message}");
|
throw new Exception($"函数 [{_owner.Name}], {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,13 +67,14 @@ namespace ZelWiki.Engine.Function
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var values = Named.Where(o => o.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase))?
|
var values = Named.Where(o => o.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase))?
|
||||||
.Select(o => Converters.ConvertTo<T>(o.Value) ?? throw new Exception("Value cannot be null"))?.ToList();
|
.Select(o => Converters.ConvertTo<T>(o.Value) ?? throw new Exception("值不能为空"))
|
||||||
|
?.ToList();
|
||||||
|
|
||||||
return values ?? new List<T>();
|
return values ?? new List<T>();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
throw new Exception($"Function [{_owner.Name}], {ex.Message}");
|
throw new Exception($"函数 [{_owner.Name}], {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,13 +10,15 @@ namespace ZelWiki.Engine.Function
|
|||||||
private static partial Regex FunctionCallParser();
|
private static partial Regex FunctionCallParser();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Parsed a function call, its parameters and matches it to a defined function and its prototype.
|
/// 解析函数调用及其参数,并将其与已定义的函数及其原型进行匹配
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="prototypes"></param>
|
||||||
/// <param name="functionCall"></param>
|
/// <param name="functionCall"></param>
|
||||||
/// <param name="parseEndIndex"></param>
|
/// <param name="parseEndIndex"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
/// <exception cref="Exception"></exception>
|
/// <exception cref="WikiFunctionPrototypeNotDefinedException"></exception>
|
||||||
public static FunctionCall ParseAndGetFunctionCall(FunctionPrototypeCollection prototypes, string functionCall, out int parseEndIndex)
|
public static FunctionCall ParseAndGetFunctionCall(FunctionPrototypeCollection prototypes, string functionCall,
|
||||||
|
out int parseEndIndex)
|
||||||
{
|
{
|
||||||
var rawArguments = new List<string>();
|
var rawArguments = new List<string>();
|
||||||
|
|
||||||
@@ -25,7 +27,8 @@ namespace ZelWiki.Engine.Function
|
|||||||
var prototype = prototypes.Get(parsed.Prefix, parsed.Name);
|
var prototype = prototypes.Get(parsed.Prefix, parsed.Name);
|
||||||
if (prototype == null)
|
if (prototype == null)
|
||||||
{
|
{
|
||||||
throw new WikiFunctionPrototypeNotDefinedException($"Function ({parsed.Name}) does not have a defined prototype.");
|
throw new WikiFunctionPrototypeNotDefinedException(
|
||||||
|
$"函数 ({parsed.Name}) 没有定义的原型.");
|
||||||
}
|
}
|
||||||
|
|
||||||
parseEndIndex = parsed.EndIndex;
|
parseEndIndex = parsed.EndIndex;
|
||||||
@@ -35,18 +38,18 @@ namespace ZelWiki.Engine.Function
|
|||||||
|
|
||||||
public static ParsedFunctionCall ParseFunctionCall(FunctionPrototypeCollection prototypes, string functionCall)
|
public static ParsedFunctionCall ParseFunctionCall(FunctionPrototypeCollection prototypes, string functionCall)
|
||||||
{
|
{
|
||||||
string functionName = string.Empty;
|
var functionName = string.Empty;
|
||||||
int parseEndIndex = 0;
|
var parseEndIndex = 0;
|
||||||
var rawArguments = new List<string>();
|
var rawArguments = new List<string>();
|
||||||
|
|
||||||
var firstLine = functionCall.Split('\n')?.FirstOrDefault();
|
var firstLine = functionCall.Split('\n')?.FirstOrDefault();
|
||||||
|
|
||||||
if (firstLine == null || firstLine.Where(x => x == '(').Count() != firstLine.Where(x => x == ')').Count())
|
if (firstLine == null || firstLine.Count(x => x == '(') != firstLine.Count(x => x == ')'))
|
||||||
{
|
{
|
||||||
throw new WikiFunctionPrototypeSyntaxError($"Function parentheses mismatch.");
|
throw new WikiFunctionPrototypeSyntaxError($"函数括号不匹配.");
|
||||||
}
|
}
|
||||||
|
|
||||||
string functionPrefix = functionCall.Substring(0, 2);
|
var functionPrefix = functionCall.Substring(0, 2);
|
||||||
|
|
||||||
var parameterMatches = FunctionCallParser().Matches(firstLine);
|
var parameterMatches = FunctionCallParser().Matches(firstLine);
|
||||||
if (parameterMatches.Count > 0)
|
if (parameterMatches.Count > 0)
|
||||||
@@ -57,12 +60,15 @@ namespace ZelWiki.Engine.Function
|
|||||||
functionName = match.Value[..paramStartIndex].ToLower().TrimStart(['{', '#', '@']).Trim();
|
functionName = match.Value[..paramStartIndex].ToLower().TrimStart(['{', '#', '@']).Trim();
|
||||||
parseEndIndex = match.Index + match.Length;
|
parseEndIndex = match.Index + match.Length;
|
||||||
|
|
||||||
string rawArgTrimmed = match.ToString().Substring(paramStartIndex, (match.ToString().Length - paramStartIndex));
|
string rawArgTrimmed = match.ToString()
|
||||||
|
.Substring(paramStartIndex, (match.ToString().Length - paramStartIndex));
|
||||||
rawArguments = ParseRawArguments(rawArgTrimmed);
|
rawArguments = ParseRawArguments(rawArgTrimmed);
|
||||||
}
|
}
|
||||||
else //The function call has no parameters.
|
else //函数调用没有参数.
|
||||||
{
|
{
|
||||||
int endOfLine = functionCall.Substring(2).TakeWhile(c => char.IsLetterOrDigit(c)).Count(); //Find the first non-alphanumeric after the function identifier (##, @@, etc).
|
var endOfLine =
|
||||||
|
functionCall.Substring(2).TakeWhile(c => char.IsLetterOrDigit(c))
|
||||||
|
.Count();
|
||||||
functionName = functionCall.Substring(2, endOfLine).ToLower().TrimStart(['{', '#', '@']).Trim();
|
functionName = functionCall.Substring(2, endOfLine).ToLower().TrimStart(['{', '#', '@']).Trim();
|
||||||
parseEndIndex = endOfLine + 2;
|
parseEndIndex = endOfLine + 2;
|
||||||
}
|
}
|
||||||
@@ -71,12 +77,11 @@ namespace ZelWiki.Engine.Function
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Parses function parameters into a list of arguments based on comma separation.
|
///
|
||||||
/// String do not need to be enclosed in double-quotes unless they contain commas.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="paramString"></param>
|
/// <param name="paramString"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
/// <exception cref="Exception"></exception>
|
/// <exception cref="WikiFunctionPrototypeSyntaxError"></exception>
|
||||||
public static List<string> ParseRawArgumentsAddParenthesis(string paramString)
|
public static List<string> ParseRawArgumentsAddParenthesis(string paramString)
|
||||||
{
|
{
|
||||||
if (paramString.StartsWith('(') || paramString.EndsWith(')'))
|
if (paramString.StartsWith('(') || paramString.EndsWith(')'))
|
||||||
@@ -88,17 +93,16 @@ namespace ZelWiki.Engine.Function
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Parses function parameters into a list of arguments based on comma separation.
|
///
|
||||||
/// String do not need to be enclosed in double-quotes unless they contain commas.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="paramString"></param>
|
/// <param name="paramString"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
/// <exception cref="Exception"></exception>
|
/// <exception cref="WikiFunctionPrototypeSyntaxError"></exception>
|
||||||
public static List<string> ParseRawArguments(string paramString)
|
public static List<string> ParseRawArguments(string paramString)
|
||||||
{
|
{
|
||||||
List<string> ps = new();
|
List<string> ps = new();
|
||||||
|
|
||||||
int readPos = 0;
|
var readPos = 0;
|
||||||
|
|
||||||
var singleParam = new StringBuilder();
|
var singleParam = new StringBuilder();
|
||||||
|
|
||||||
@@ -109,7 +113,7 @@ namespace ZelWiki.Engine.Function
|
|||||||
|
|
||||||
int parenNest = 1;
|
int parenNest = 1;
|
||||||
|
|
||||||
readPos++; //Skip the (
|
readPos++;
|
||||||
|
|
||||||
while (readPos < paramString.Length && char.IsWhiteSpace(paramString[readPos])) readPos++;
|
while (readPos < paramString.Length && char.IsWhiteSpace(paramString[readPos])) readPos++;
|
||||||
|
|
||||||
@@ -130,7 +134,7 @@ namespace ZelWiki.Engine.Function
|
|||||||
}
|
}
|
||||||
else if (paramString[readPos] == ')' && parenNest == 0)
|
else if (paramString[readPos] == ')' && parenNest == 0)
|
||||||
{
|
{
|
||||||
readPos++; //Skip the )
|
readPos++;
|
||||||
|
|
||||||
if (parenNest == 0 && readPos != paramString.Length)
|
if (parenNest == 0 && readPos != paramString.Length)
|
||||||
{
|
{
|
||||||
@@ -141,6 +145,7 @@ namespace ZelWiki.Engine.Function
|
|||||||
{
|
{
|
||||||
ps.Add(singleParam.ToString());
|
ps.Add(singleParam.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
singleParam.Clear();
|
singleParam.Clear();
|
||||||
|
|
||||||
if (parenNest == 0)
|
if (parenNest == 0)
|
||||||
@@ -150,9 +155,9 @@ namespace ZelWiki.Engine.Function
|
|||||||
}
|
}
|
||||||
else if (paramString[readPos] == '\"')
|
else if (paramString[readPos] == '\"')
|
||||||
{
|
{
|
||||||
readPos++; //Skip the ".
|
readPos++;
|
||||||
|
|
||||||
bool escapeChar = false;
|
var escapeChar = false;
|
||||||
for (;; readPos++)
|
for (;; readPos++)
|
||||||
{
|
{
|
||||||
if (readPos == paramString.Length)
|
if (readPos == paramString.Length)
|
||||||
@@ -166,14 +171,14 @@ namespace ZelWiki.Engine.Function
|
|||||||
}
|
}
|
||||||
else if (paramString[readPos] == '\"' && escapeChar == false)
|
else if (paramString[readPos] == '\"' && escapeChar == false)
|
||||||
{
|
{
|
||||||
//Found the end of the string:
|
readPos++;
|
||||||
readPos++; //Skip the ".
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
singleParam.Append(paramString[readPos]);
|
singleParam.Append(paramString[readPos]);
|
||||||
}
|
}
|
||||||
|
|
||||||
escapeChar = false;
|
escapeChar = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,7 +186,7 @@ namespace ZelWiki.Engine.Function
|
|||||||
}
|
}
|
||||||
else if (paramString[readPos] == ',')
|
else if (paramString[readPos] == ',')
|
||||||
{
|
{
|
||||||
readPos++; //Skip the ,
|
readPos++;
|
||||||
while (readPos < paramString.Length && char.IsWhiteSpace(paramString[readPos])) readPos++;
|
while (readPos < paramString.Length && char.IsWhiteSpace(paramString[readPos])) readPos++;
|
||||||
|
|
||||||
ps.Add(singleParam.ToString());
|
ps.Add(singleParam.ToString());
|
||||||
@@ -209,7 +214,7 @@ namespace ZelWiki.Engine.Function
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < ps.Count; i++)
|
for (var i = 0; i < ps.Count; i++)
|
||||||
{
|
{
|
||||||
ps[i] = ps[i].Trim();
|
ps[i] = ps[i].Trim();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,14 +2,19 @@
|
|||||||
{
|
{
|
||||||
public class FunctionPrototype
|
public class FunctionPrototype
|
||||||
{
|
{
|
||||||
public string FunctionPrefix { get; set; } = string.Empty;
|
/// <summary>
|
||||||
public string ProperName { get; set; } = string.Empty;
|
///
|
||||||
public string FunctionName { get; set; } = string.Empty;
|
/// </summary>
|
||||||
public List<PrototypeParameter> Parameters { get; set; }
|
|
||||||
|
|
||||||
public FunctionPrototype()
|
public FunctionPrototype()
|
||||||
{
|
{
|
||||||
Parameters = new List<PrototypeParameter>();
|
FunctionPrefix = string.Empty;
|
||||||
}
|
ProperName = string.Empty;
|
||||||
|
FunctionName = string.Empty;
|
||||||
|
Parameters = new();
|
||||||
|
}
|
||||||
|
public string FunctionPrefix { get; set; }
|
||||||
|
public string ProperName { get; set; }
|
||||||
|
public string FunctionName { get; set; }
|
||||||
|
public List<PrototypeParameter> Parameters { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,10 @@ namespace ZelWiki.Engine.Function
|
|||||||
public WikiFunctionType FunctionTypes { get; private set; }
|
public WikiFunctionType FunctionTypes { get; private set; }
|
||||||
public List<PrototypeSet> Items { get; set; } = new();
|
public List<PrototypeSet> Items { get; set; } = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="functionTypes"></param>
|
||||||
public FunctionPrototypeCollection(WikiFunctionType functionTypes)
|
public FunctionPrototypeCollection(WikiFunctionType functionTypes)
|
||||||
{
|
{
|
||||||
FunctionTypes = functionTypes;
|
FunctionTypes = functionTypes;
|
||||||
@@ -36,40 +40,40 @@ namespace ZelWiki.Engine.Function
|
|||||||
{
|
{
|
||||||
functionName = functionName.ToLower();
|
functionName = functionName.ToLower();
|
||||||
|
|
||||||
//$$ are scope functions and are not called by prefix, we only have prefixes to make it easier to parse
|
return Items.Any(o =>
|
||||||
// the functions in the wikiText and scope functions are easy enough since they start with curly braces.
|
(o.FunctionPrefix == functionPrefix || o.FunctionPrefix == "$$") && o.FunctionName == functionName);
|
||||||
return Items.Any(o => (o.FunctionPrefix == functionPrefix || o.FunctionPrefix == "$$") && o.FunctionName == functionName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public FunctionPrototype Get(string functionPrefix, string functionName)
|
public FunctionPrototype Get(string functionPrefix, string functionName)
|
||||||
{
|
{
|
||||||
functionName = functionName.ToLower();
|
functionName = functionName.ToLower();
|
||||||
|
|
||||||
//$$ are scope functions and are not called by prefix, we only have prefixes to make it easier to parse
|
var functionPrototype = Items.FirstOrDefault(o =>
|
||||||
// the functions in the wikiText and scope functions are easy enough since they start with curly braces.
|
(o.FunctionPrefix == functionPrefix || o.FunctionPrefix == "$$") && o.FunctionName == functionName)
|
||||||
var functionPrototype = Items.Where(o => (o.FunctionPrefix == functionPrefix || o.FunctionPrefix == "$$") && o.FunctionName == functionName).FirstOrDefault()?.Value;
|
?.Value;
|
||||||
|
|
||||||
return functionPrototype
|
return functionPrototype
|
||||||
?? throw new WikiFunctionPrototypeNotDefinedException($"Function ({functionName}) does not have a defined prototype.");
|
?? throw new WikiFunctionPrototypeNotDefinedException(
|
||||||
|
$"函数 ({functionName}) 没有定义的原型.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region Private
|
||||||
|
|
||||||
private FunctionPrototype ParsePrototype(string prototypeString)
|
private FunctionPrototype ParsePrototype(string prototypeString)
|
||||||
{
|
{
|
||||||
int nameStartIndex = prototypeString.TakeWhile(c => char.IsLetterOrDigit(c) == false).Count();
|
var nameStartIndex = prototypeString.TakeWhile(c => char.IsLetterOrDigit(c) == false).Count();
|
||||||
int nameEndIndex = prototypeString.IndexOf(':');
|
var nameEndIndex = prototypeString.IndexOf(':');
|
||||||
string properName = prototypeString.Substring(nameStartIndex, nameEndIndex - nameStartIndex).Trim();
|
var properName = prototypeString.Substring(nameStartIndex, nameEndIndex - nameStartIndex).Trim();
|
||||||
string functionName = properName.ToLower();
|
var functionName = properName.ToLower();
|
||||||
string functionPrefix = prototypeString.Substring(0, nameStartIndex).Trim();
|
var functionPrefix = prototypeString.Substring(0, nameStartIndex).Trim();
|
||||||
|
|
||||||
prototypeString = prototypeString.Substring(nameEndIndex + 1).Trim();
|
prototypeString = prototypeString.Substring(nameEndIndex + 1).Trim();
|
||||||
|
|
||||||
var prototype = new FunctionPrototype() { FunctionPrefix = functionPrefix, ProperName = properName, FunctionName = functionName };
|
var prototype = new FunctionPrototype()
|
||||||
|
{ FunctionPrefix = functionPrefix, ProperName = properName, FunctionName = functionName };
|
||||||
|
|
||||||
if (prototypeString.Length == 0)
|
if (prototypeString.Length == 0)
|
||||||
{
|
|
||||||
//No parameters.
|
|
||||||
return prototype;
|
return prototype;
|
||||||
}
|
|
||||||
|
|
||||||
var segments = prototypeString.Trim().Split('|').Select(o => o.Trim());
|
var segments = prototypeString.Trim().Split('|').Select(o => o.Trim());
|
||||||
|
|
||||||
@@ -77,13 +81,13 @@ namespace ZelWiki.Engine.Function
|
|||||||
{
|
{
|
||||||
var prototypeSegment = new PrototypeParameter();
|
var prototypeSegment = new PrototypeParameter();
|
||||||
|
|
||||||
int index = 0;
|
var index = 0;
|
||||||
|
|
||||||
if (segment[index] == '<')
|
if (segment[index] == '<')
|
||||||
{
|
{
|
||||||
index++; //Skip the '<'
|
index++;
|
||||||
prototypeSegment.Type = Tok(segment, ref index);
|
prototypeSegment.Type = Tok(segment, ref index);
|
||||||
index++; //Skip the '>'
|
index++;
|
||||||
|
|
||||||
if (prototypeSegment.Type.Contains(':'))
|
if (prototypeSegment.Type.Contains(':'))
|
||||||
{
|
{
|
||||||
@@ -94,12 +98,14 @@ namespace ZelWiki.Engine.Function
|
|||||||
prototypeSegment.IsInfinite = true;
|
prototypeSegment.IsInfinite = true;
|
||||||
if (prototype.Parameters.Any(o => o.IsInfinite))
|
if (prototype.Parameters.Any(o => o.IsInfinite))
|
||||||
{
|
{
|
||||||
throw new Exception($"Function [{functionName}], prototype error: cannot contain more than one [infinite] parameter.");
|
throw new Exception(
|
||||||
|
$"函数 [{functionName}], 原型错误: cannot contain more than one [infinite] parameter.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new Exception($"Function [{functionName}], prototype error: expected [infinite] got [{splitSeg[1]}].");
|
throw new Exception(
|
||||||
|
$"函数 [{functionName}], 原型错误: expected [infinite] got [{splitSeg[1]}].");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,41 +118,42 @@ namespace ZelWiki.Engine.Function
|
|||||||
prototypeSegment.IsRequired = true;
|
prototypeSegment.IsRequired = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
index++; //Skip the '[' or '{'
|
index++;
|
||||||
|
|
||||||
prototypeSegment.Name = Tok(segment, ref index);
|
prototypeSegment.Name = Tok(segment, ref index);
|
||||||
|
|
||||||
if (index < segment.Length && segment[index] == '(') //Parse allowed values.
|
if (index < segment.Length && segment[index] == '(')
|
||||||
{
|
{
|
||||||
int allowedValueEndIndex = segment.IndexOf(')', index);
|
int allowedValueEndIndex = segment.IndexOf(')', index);
|
||||||
string roteRequiredValues = segment.Substring(index + 1, allowedValueEndIndex - index - 1);
|
string roteRequiredValues = segment.Substring(index + 1, allowedValueEndIndex - index - 1);
|
||||||
prototypeSegment.AllowedValues = roteRequiredValues.Trim().Split(',').Select(o => o.Trim().ToLower()).ToList();
|
prototypeSegment.AllowedValues = roteRequiredValues.Trim().Split(',')
|
||||||
|
.Select(o => o.Trim().ToLower()).ToList();
|
||||||
|
|
||||||
index = allowedValueEndIndex;
|
index = allowedValueEndIndex;
|
||||||
index++; //Skip the ')'
|
index++;
|
||||||
SkipWhiteSpace(segment, ref index);
|
SkipWhiteSpace(segment, ref index);
|
||||||
}
|
}
|
||||||
|
|
||||||
index++; //Skip the ']' or '}'
|
index++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new Exception($"Function [{functionName}], prototype error: expected [{{] or [[].");
|
throw new Exception($"函数 [{functionName}], 原型错误: expected [{{] or [[].");
|
||||||
}
|
}
|
||||||
|
|
||||||
SkipWhiteSpace(segment, ref index);
|
SkipWhiteSpace(segment, ref index);
|
||||||
|
|
||||||
if (index < segment.Length && segment[index] == '=')
|
if (index < segment.Length && segment[index] == '=')
|
||||||
{
|
{
|
||||||
index++; //Skip the '='
|
index++;
|
||||||
SkipWhiteSpace(segment, ref index);
|
SkipWhiteSpace(segment, ref index);
|
||||||
|
|
||||||
if (segment[index] != '\'')
|
if (segment[index] != '\'')
|
||||||
{
|
{
|
||||||
throw new Exception($"Function [{functionName}], prototype error: expected [\'].");
|
throw new Exception($"函数 [{functionName}], 原型错误: expected [\'].");
|
||||||
}
|
}
|
||||||
|
|
||||||
index++; //Skip the '''
|
index++;
|
||||||
|
|
||||||
prototypeSegment.DefaultValue = segment.Substring(index, (segment.Length - index) - 1);
|
prototypeSegment.DefaultValue = segment.Substring(index, (segment.Length - index) - 1);
|
||||||
|
|
||||||
@@ -154,13 +161,13 @@ namespace ZelWiki.Engine.Function
|
|||||||
|
|
||||||
if (index < segment.Length && segment[index] != '\'')
|
if (index < segment.Length && segment[index] != '\'')
|
||||||
{
|
{
|
||||||
throw new Exception($"Function [{functionName}], prototype error: expected [\'].");
|
throw new Exception($"函数 [{functionName}], 原型错误: expected [\'].");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new Exception($"Function [{functionName}], prototype error: expected [<].");
|
throw new Exception($"函数 [{functionName}], 原型错误: expected [<].");
|
||||||
}
|
}
|
||||||
|
|
||||||
prototype.Parameters.Add(prototypeSegment);
|
prototype.Parameters.Add(prototypeSegment);
|
||||||
@@ -168,9 +175,8 @@ namespace ZelWiki.Engine.Function
|
|||||||
|
|
||||||
return prototype;
|
return prototype;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the next token in a string.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="str"></param>
|
/// <param name="str"></param>
|
||||||
/// <param name="index"></param>
|
/// <param name="index"></param>
|
||||||
@@ -203,5 +209,7 @@ namespace ZelWiki.Engine.Function
|
|||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,11 @@
|
|||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public string Value { get; set; }
|
public string Value { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name"></param>
|
||||||
|
/// <param name="value"></param>
|
||||||
public NamedParameter(string name, string value)
|
public NamedParameter(string name, string value)
|
||||||
{
|
{
|
||||||
Name = name;
|
Name = name;
|
||||||
|
|||||||
@@ -2,22 +2,27 @@
|
|||||||
{
|
{
|
||||||
public class OrdinalParameter
|
public class OrdinalParameter
|
||||||
{
|
{
|
||||||
public string Value { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Has been matched to a prototype parameter?
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsMatched { get; set; } = false;
|
/// <param name="value"></param>
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// If matched to a prototype parameter, this is the name of the parameter.
|
|
||||||
/// </summary>
|
|
||||||
public string ParameterName { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
public OrdinalParameter(string value)
|
public OrdinalParameter(string value)
|
||||||
{
|
{
|
||||||
Value = value;
|
Value = value;
|
||||||
|
IsMatched = false;
|
||||||
|
ParameterName = string.Empty;
|
||||||
}
|
}
|
||||||
|
public string Value { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public bool IsMatched { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public string ParameterName { get; set; }
|
||||||
|
|
||||||
public void AssociateWithPrototypeParam(string paramName)
|
public void AssociateWithPrototypeParam(string paramName)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,11 +2,13 @@
|
|||||||
{
|
{
|
||||||
public class ParsedFunctionCall
|
public class ParsedFunctionCall
|
||||||
{
|
{
|
||||||
public string Prefix { get; set; } = string.Empty;
|
/// <summary>
|
||||||
public string Name { get; set; } = string.Empty;
|
///
|
||||||
public int EndIndex { get; set; }
|
/// </summary>
|
||||||
public List<string> RawArguments { get; set; } = new List<string>();
|
/// <param name="prefix"></param>
|
||||||
|
/// <param name="name"></param>
|
||||||
|
/// <param name="endIndex"></param>
|
||||||
|
/// <param name="rawArguments"></param>
|
||||||
public ParsedFunctionCall(string prefix, string name, int endIndex, List<string> rawArguments)
|
public ParsedFunctionCall(string prefix, string name, int endIndex, List<string> rawArguments)
|
||||||
{
|
{
|
||||||
Prefix = prefix;
|
Prefix = prefix;
|
||||||
@@ -14,5 +16,9 @@
|
|||||||
EndIndex = endIndex;
|
EndIndex = endIndex;
|
||||||
RawArguments = rawArguments;
|
RawArguments = rawArguments;
|
||||||
}
|
}
|
||||||
|
public string Prefix { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public int EndIndex { get; set; }
|
||||||
|
public List<string> RawArguments { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,24 @@
|
|||||||
{
|
{
|
||||||
public class PrototypeParameter
|
public class PrototypeParameter
|
||||||
{
|
{
|
||||||
public string Type { get; set; } = string.Empty;
|
/// <summary>
|
||||||
public string Name { get; set; } = string.Empty;
|
///
|
||||||
public string DefaultValue { get; set; } = string.Empty;
|
/// </summary>
|
||||||
public bool IsRequired { get; set; } = false;
|
public PrototypeParameter()
|
||||||
public bool IsInfinite { get; set; } = false;
|
{
|
||||||
public List<string> AllowedValues { get; set; } = new();
|
Type = string.Empty;
|
||||||
|
Name = string.Empty;
|
||||||
|
DefaultValue = string.Empty;
|
||||||
|
IsRequired = false;
|
||||||
|
IsInfinite = false;
|
||||||
|
AllowedValues = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Type { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string DefaultValue { get; set; }
|
||||||
|
public bool IsRequired { get; set; }
|
||||||
|
public bool IsInfinite { get; set; }
|
||||||
|
public List<string> AllowedValues { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,9 +2,19 @@
|
|||||||
{
|
{
|
||||||
public class PrototypeSet
|
public class PrototypeSet
|
||||||
{
|
{
|
||||||
public string FunctionPrefix { get; set; } = string.Empty;
|
/// <summary>
|
||||||
public string ProperName { get; set; } = string.Empty;
|
///
|
||||||
public string FunctionName { get; set; } = string.Empty;
|
/// </summary>
|
||||||
public FunctionPrototype Value { get; set; } = new();
|
public PrototypeSet()
|
||||||
|
{
|
||||||
|
FunctionPrefix = string.Empty;
|
||||||
|
ProperName = string.Empty;
|
||||||
|
FunctionName = string.Empty;
|
||||||
|
Value = new();
|
||||||
|
}
|
||||||
|
public string FunctionPrefix { get; set; }
|
||||||
|
public string ProperName { get; set; }
|
||||||
|
public string FunctionName { get; set; }
|
||||||
|
public FunctionPrototype Value { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
namespace ZelWiki.Engine.Function
|
namespace ZelWiki.Engine.Function
|
||||||
{
|
{
|
||||||
|
[Obsolete("弃用了")]
|
||||||
public static class SelfDocument
|
public static class SelfDocument
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Don't ever look at this. :(
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Obsolete("弃用了")]
|
||||||
public static void CreateNotExisting()
|
public static void CreateNotExisting()
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -2,8 +2,13 @@
|
|||||||
{
|
{
|
||||||
public class AggregatedSearchToken
|
public class AggregatedSearchToken
|
||||||
{
|
{
|
||||||
public string Token { get; set; } = string.Empty;
|
public AggregatedSearchToken()
|
||||||
|
{
|
||||||
|
Token = string.Empty;
|
||||||
|
DoubleMetaphone = string.Empty;
|
||||||
|
}
|
||||||
|
public string Token { get; set; }
|
||||||
public double Weight { get; set; }
|
public double Weight { get; set; }
|
||||||
public string DoubleMetaphone { get; set; } = string.Empty;
|
public string DoubleMetaphone { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,15 +4,16 @@ using ZelWiki.Engine.Library.Interfaces;
|
|||||||
namespace ZelWiki.Engine.Implementation
|
namespace ZelWiki.Engine.Implementation
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles wiki comments. These are generally removed from the result.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class CommentHandler : ICommentHandler
|
public class CommentHandler : ICommentHandler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles a wiki comment.
|
/// 处理评论
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state">Reference to the wiki state object</param>
|
/// <param name="state"></param>
|
||||||
/// <param name="text">The comment text</param>
|
/// <param name="text"></param>
|
||||||
|
/// <returns></returns>
|
||||||
public HandlerResult Handle(IZelEngineState state, string text)
|
public HandlerResult Handle(IZelEngineState state, string text)
|
||||||
{
|
{
|
||||||
return new HandlerResult() { Instructions = [Constants.HandlerResultInstruction.TruncateTrailingLine] };
|
return new HandlerResult() { Instructions = [Constants.HandlerResultInstruction.TruncateTrailingLine] };
|
||||||
|
|||||||
@@ -5,14 +5,14 @@ using ZelWiki.Repository;
|
|||||||
namespace ZelWiki.Engine.Implementation
|
namespace ZelWiki.Engine.Implementation
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles wiki completion events.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class CompletionHandler : ICompletionHandler
|
public class CompletionHandler : ICompletionHandler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles wiki completion events. Is called when the wiki processing competes for a given page.
|
/// 完成事件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state">Reference to the wiki state object</param>
|
/// <param name="state"></param>
|
||||||
public void Complete(IZelEngineState state)
|
public void Complete(IZelEngineState state)
|
||||||
{
|
{
|
||||||
if (GlobalConfiguration.RecordCompilationMetrics)
|
if (GlobalConfiguration.RecordCompilationMetrics)
|
||||||
|
|||||||
@@ -5,16 +5,17 @@ using ZelWiki.Models;
|
|||||||
namespace ZelWiki.Engine.Implementation
|
namespace ZelWiki.Engine.Implementation
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles wiki emojis.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class EmojiHandler : IEmojiHandler
|
public class EmojiHandler : IEmojiHandler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles an emoji instruction.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state">Reference to the wiki state object</param>
|
/// <param name="state"></param>
|
||||||
/// <param name="key">The lookup key for the given emoji.</param>
|
/// <param name="key"></param>
|
||||||
/// <param name="scale">The desired 1-100 scale factor for the emoji.</param>
|
/// <param name="scale"></param>
|
||||||
|
/// <returns></returns>
|
||||||
public HandlerResult Handle(IZelEngineState state, string key, int scale)
|
public HandlerResult Handle(IZelEngineState state, string key, int scale)
|
||||||
{
|
{
|
||||||
var emoji = GlobalConfiguration.Emojis.FirstOrDefault(o => o.Shortcut == key);
|
var emoji = GlobalConfiguration.Emojis.FirstOrDefault(o => o.Shortcut == key);
|
||||||
@@ -23,20 +24,23 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
{
|
{
|
||||||
if (scale != 100 && scale > 0 && scale <= 500)
|
if (scale != 100 && scale > 0 && scale <= 500)
|
||||||
{
|
{
|
||||||
var emojiImage = $"<img src=\"{GlobalConfiguration.BasePath}/file/Emoji/{key.Trim('%')}?Scale={scale}\" alt=\"{emoji?.Name}\" />";
|
var emojiImage =
|
||||||
|
$"<img src=\"{GlobalConfiguration.BasePath}/file/Emoji/{key.Trim('%')}?Scale={scale}\" alt=\"{emoji?.Name}\" />";
|
||||||
|
|
||||||
return new HandlerResult(emojiImage);
|
return new HandlerResult(emojiImage);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var emojiImage = $"<img src=\"{GlobalConfiguration.BasePath}/file/Emoji/{key.Trim('%')}\" alt=\"{emoji?.Name}\" />";
|
var emojiImage =
|
||||||
|
$"<img src=\"{GlobalConfiguration.BasePath}/file/Emoji/{key.Trim('%')}\" alt=\"{emoji?.Name}\" />";
|
||||||
|
|
||||||
return new HandlerResult(emojiImage);
|
return new HandlerResult(emojiImage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return new HandlerResult(key) { Instructions = [Constants.HandlerResultInstruction.DisallowNestedProcessing] };
|
return new HandlerResult(key)
|
||||||
|
{ Instructions = [Constants.HandlerResultInstruction.DisallowNestedProcessing] };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,16 +4,16 @@ using ZelWiki.Repository;
|
|||||||
namespace ZelWiki.Engine.Implementation
|
namespace ZelWiki.Engine.Implementation
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles exceptions thrown by the wiki engine.
|
/// 异常处理.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ExceptionHandler : IExceptionHandler
|
public class ExceptionHandler : IExceptionHandler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called when an exception is thrown by the wiki engine.
|
/// 日志处理
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state">Reference to the wiki state object</param>
|
/// <param name="state"></param>
|
||||||
/// <param name="ex">Optional exception, in the case that this was an actual exception.</param>
|
/// <param name="ex"></param>
|
||||||
/// <param name="customText">Text that accompanies the exception.</param>
|
/// <param name="customText"></param>
|
||||||
public void Log(IZelEngineState state, Exception? ex, string customText)
|
public void Log(IZelEngineState state, Exception? ex, string customText)
|
||||||
{
|
{
|
||||||
if (ex != null)
|
if (ex != null)
|
||||||
|
|||||||
@@ -4,18 +4,18 @@ using ZelWiki.Engine.Library.Interfaces;
|
|||||||
namespace ZelWiki.Engine.Implementation
|
namespace ZelWiki.Engine.Implementation
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles links the wiki to another site.
|
/// 处理链接
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ExternalLinkHandler : IExternalLinkHandler
|
public class ExternalLinkHandler : IExternalLinkHandler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles an internal wiki link.
|
/// 处理内链
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state">Reference to the wiki state object</param>
|
/// <param name="state"></param>
|
||||||
/// <param name="link">The address of the external site being linked to.</param>
|
/// <param name="link"></param>
|
||||||
/// <param name="text">The text which should be show in the absence of an image.</param>
|
/// <param name="text"></param>
|
||||||
/// <param name="image">The image that should be shown.</param>
|
/// <param name="image"></param>
|
||||||
/// <param name="imageScale">The 0-100 image scale factor for the given image.</param>
|
/// <returns></returns>
|
||||||
public HandlerResult Handle(IZelEngineState state, string link, string? text, string? image)
|
public HandlerResult Handle(IZelEngineState state, string link, string? text, string? image)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(image))
|
if (string.IsNullOrEmpty(image))
|
||||||
@@ -25,8 +25,7 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
Instructions = [Constants.HandlerResultInstruction.DisallowNestedProcessing]
|
Instructions = [Constants.HandlerResultInstruction.DisallowNestedProcessing]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
return new HandlerResult($"<a href=\"{link}\"><img src=\"{image}\" border =\"0\"></a>")
|
return new HandlerResult($"<a href=\"{link}\"><img src=\"{image}\" border =\"0\"></a>")
|
||||||
{
|
{
|
||||||
Instructions = [Constants.HandlerResultInstruction.DisallowNestedProcessing]
|
Instructions = [Constants.HandlerResultInstruction.DisallowNestedProcessing]
|
||||||
@@ -34,4 +33,3 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
@@ -3,18 +3,16 @@ using ZelWiki.Engine.Library.Interfaces;
|
|||||||
|
|
||||||
namespace ZelWiki.Engine.Implementation
|
namespace ZelWiki.Engine.Implementation
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Handles wiki headings. These are automatically added to the table of contents.
|
|
||||||
/// </summary>
|
|
||||||
public class HeadingHandler : IHeadingHandler
|
public class HeadingHandler : IHeadingHandler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles wiki headings. These are automatically added to the table of contents.
|
/// 处理白哦提
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state">Reference to the wiki state object</param>
|
/// <param name="state"></param>
|
||||||
/// <param name="depth">The size of the header, also used for table of table of contents indentation.</param>
|
/// <param name="depth"></param>
|
||||||
/// <param name="link">The self link reference.</param>
|
/// <param name="link"></param>
|
||||||
/// <param name="text">The text for the self link.</param>
|
/// <param name="text"></param>
|
||||||
|
/// <returns></returns>
|
||||||
public HandlerResult Handle(IZelEngineState state, int depth, string link, string text)
|
public HandlerResult Handle(IZelEngineState state, int depth, string link, string text)
|
||||||
{
|
{
|
||||||
if (depth >= 2 && depth <= 6)
|
if (depth >= 2 && depth <= 6)
|
||||||
@@ -22,7 +20,8 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
int fontSize = 8 - depth;
|
int fontSize = 8 - depth;
|
||||||
if (fontSize < 5) fontSize = 5;
|
if (fontSize < 5) fontSize = 5;
|
||||||
|
|
||||||
string html = "<font size=\"" + fontSize + "\"><a name=\"" + link + "\"><span class=\"WikiH" + (depth - 1).ToString() + "\">" + text + "</span></a></font>\r\n";
|
string html = "<font size=\"" + fontSize + "\"><a name=\"" + link + "\"><span class=\"WikiH" +
|
||||||
|
(depth - 1).ToString() + "\">" + text + "</span></a></font>\r\n";
|
||||||
return new HandlerResult(html);
|
return new HandlerResult(html);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,41 +9,41 @@ using ZelWiki.Repository;
|
|||||||
|
|
||||||
namespace ZelWiki.Engine.Implementation
|
namespace ZelWiki.Engine.Implementation
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
public class Helpers
|
public class Helpers
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Inserts a new page if Page.Id == 0, other wise updates the page. All metadata is written to the database.
|
/// 更新页面 如果Id为0则新增页面
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="sessionState"></param>
|
/// <param name="wikifier"></param>
|
||||||
/// <param name="query"></param>
|
|
||||||
/// <param name="page"></param>
|
/// <param name="page"></param>
|
||||||
|
/// <param name="sessionState"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static int UpsertPage(IZelEngine wikifier, Page page, ISessionState? sessionState = null)
|
public static int UpsertPage(IZelEngine wikifier, Page page, ISessionState? sessionState = null)
|
||||||
{
|
{
|
||||||
bool isNewlyCreated = page.Id == 0;
|
var isNewlyCreated = page.Id == 0;
|
||||||
|
|
||||||
page.Id = PageRepository.SavePage(page);
|
page.Id = PageRepository.SavePage(page);
|
||||||
|
|
||||||
RefreshPageMetadata(wikifier, page, sessionState);
|
RefreshPageMetadata(wikifier, page, sessionState);
|
||||||
|
|
||||||
if (isNewlyCreated)
|
if (isNewlyCreated)
|
||||||
{
|
|
||||||
//This will update the PageId of references that have been saved to the navigation link.
|
|
||||||
PageRepository.UpdateSinglePageReference(page.Navigation, page.Id);
|
PageRepository.UpdateSinglePageReference(page.Navigation, page.Id);
|
||||||
}
|
|
||||||
|
|
||||||
return page.Id;
|
return page.Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Rebuilds the page and writes all aspects to the database.
|
/// 重建页面并将所有方面写入数据库
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="sessionState"></param>
|
/// <param name="wikifier"></param>
|
||||||
/// <param name="query"></param>
|
|
||||||
/// <param name="page"></param>
|
/// <param name="page"></param>
|
||||||
|
/// <param name="sessionState"></param>
|
||||||
public static void RefreshPageMetadata(IZelEngine wikifier, Page page, ISessionState? sessionState = null)
|
public static void RefreshPageMetadata(IZelEngine wikifier, Page page, ISessionState? sessionState = null)
|
||||||
{
|
{
|
||||||
//We omit function calls from the tokenization process because they are too dynamic for static searching.
|
|
||||||
var state = wikifier.Transform(sessionState, page, null,
|
var state = wikifier.Transform(sessionState, page, null,
|
||||||
[Constants.WikiMatchType.StandardFunction]);
|
[Constants.WikiMatchType.StandardFunction]);
|
||||||
|
|
||||||
@@ -67,7 +67,13 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
WikiCache.ClearCategory(WikiCacheKey.Build(WikiCache.Category.Page, [page.Navigation]));
|
WikiCache.ClearCategory(WikiCacheKey.Build(WikiCache.Category.Page, [page.Navigation]));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<AggregatedSearchToken> ParsePageTokens(IZelEngineState state)
|
#region Private
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="state"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private static List<AggregatedSearchToken> ParsePageTokens(IZelEngineState state)
|
||||||
{
|
{
|
||||||
var parsedTokens = new List<WeightedSearchToken>();
|
var parsedTokens = new List<WeightedSearchToken>();
|
||||||
|
|
||||||
@@ -86,7 +92,7 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
return aggregatedTokens;
|
return aggregatedTokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static List<WeightedSearchToken> ComputeParsedPageTokens(string content, double weightMultiplier)
|
private static List<WeightedSearchToken> ComputeParsedPageTokens(string content, double weightMultiplier)
|
||||||
{
|
{
|
||||||
var searchConfig = ConfigurationRepository.GetConfigurationEntryValuesByGroupName("Search");
|
var searchConfig = ConfigurationRepository.GetConfigurationEntryValuesByGroupName("Search");
|
||||||
|
|
||||||
@@ -117,7 +123,8 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
tokens.RemoveAll(o => exclusionWords.Contains(o));
|
tokens.RemoveAll(o => exclusionWords.Contains(o));
|
||||||
|
|
||||||
var searchTokens = (from w in tokens
|
var searchTokens = (from w in tokens
|
||||||
group w by w into g
|
group w by w
|
||||||
|
into g
|
||||||
select new WeightedSearchToken
|
select new WeightedSearchToken
|
||||||
{
|
{
|
||||||
Token = g.Key,
|
Token = g.Key,
|
||||||
@@ -126,5 +133,7 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
|
|
||||||
return searchTokens.Where(o => string.IsNullOrWhiteSpace(o.Token) == false).ToList();
|
return searchTokens.Where(o => string.IsNullOrWhiteSpace(o.Token) == false).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,19 +8,21 @@ using Constants = ZelWiki.Engine.Library.Constants;
|
|||||||
namespace ZelWiki.Engine.Implementation
|
namespace ZelWiki.Engine.Implementation
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles links from one wiki page to another.
|
/// 内链处理.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class InternalLinkHandler : IInternalLinkHandler
|
public class InternalLinkHandler : IInternalLinkHandler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles an internal wiki link.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state">Reference to the wiki state object</param>
|
/// <param name="state"></param>
|
||||||
/// <param name="pageNavigation">The navigation for the linked page.</param>
|
/// <param name="pageNavigation"></param>
|
||||||
/// <param name="pageName">The name of the page being linked to.</param>
|
/// <param name="pageName"></param>
|
||||||
/// <param name="linkText">The text which should be show in the absence of an image.</param>
|
/// <param name="linkText"></param>
|
||||||
/// <param name="image">The image that should be shown.</param>
|
/// <param name="image"></param>
|
||||||
/// <param name="imageScale">The 0-100 image scale factor for the given image.</param>
|
/// <param name="imageScale"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <exception cref="Exception"></exception>
|
||||||
public HandlerResult Handle(IZelEngineState state, NamespaceNavigation pageNavigation,
|
public HandlerResult Handle(IZelEngineState state, NamespaceNavigation pageNavigation,
|
||||||
string pageName, string linkText, string? image, int imageScale)
|
string pageName, string linkText, string? image, int imageScale)
|
||||||
{
|
{
|
||||||
@@ -37,18 +39,21 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
if (image.StartsWith("http://", StringComparison.InvariantCultureIgnoreCase)
|
if (image.StartsWith("http://", StringComparison.InvariantCultureIgnoreCase)
|
||||||
|| image.StartsWith("https://", StringComparison.InvariantCultureIgnoreCase))
|
|| image.StartsWith("https://", StringComparison.InvariantCultureIgnoreCase))
|
||||||
{
|
{
|
||||||
//The image is external.
|
//外部图片.
|
||||||
href = $"<a href=\"{GlobalConfiguration.BasePath}/Page/Create?Name={pageName}\"><img src=\"{GlobalConfiguration.BasePath}{image}?Scale={imageScale}\" /></a>";
|
href =
|
||||||
|
$"<a href=\"{GlobalConfiguration.BasePath}/Page/Create?Name={pageName}\"><img src=\"{GlobalConfiguration.BasePath}{image}?Scale={imageScale}\" /></a>";
|
||||||
}
|
}
|
||||||
else if (image.Contains('/'))
|
else if (image.Contains('/'))
|
||||||
{
|
{
|
||||||
//The image is located on another page.
|
//图像位于另一页面.
|
||||||
href = $"<a href=\"{GlobalConfiguration.BasePath}/Page/Create?Name={pageName}\"><img src=\"{GlobalConfiguration.BasePath}/Page/Image/{image}?Scale={imageScale}\" /></a>";
|
href =
|
||||||
|
$"<a href=\"{GlobalConfiguration.BasePath}/Page/Create?Name={pageName}\"><img src=\"{GlobalConfiguration.BasePath}/Page/Image/{image}?Scale={imageScale}\" /></a>";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//The image is located on this page, but this page does not exist.
|
//图像位于此页面上,但此页面不存在.
|
||||||
href = $"<a href=\"{GlobalConfiguration.BasePath}/Page/Create?Name={pageName}\">{linkText}</a>";
|
href =
|
||||||
|
$"<a href=\"{GlobalConfiguration.BasePath}/Page/Create?Name={pageName}\">{linkText}</a>";
|
||||||
}
|
}
|
||||||
|
|
||||||
return new HandlerResult(href)
|
return new HandlerResult(href)
|
||||||
@@ -58,7 +63,8 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
}
|
}
|
||||||
else if (linkText != null)
|
else if (linkText != null)
|
||||||
{
|
{
|
||||||
var href = $"<a href=\"{GlobalConfiguration.BasePath}/Page/Create?Name={pageName}\">{linkText}</a>"
|
var href =
|
||||||
|
$"<a href=\"{GlobalConfiguration.BasePath}/Page/Create?Name={pageName}\">{linkText}</a>"
|
||||||
+ "<font color=\"#cc0000\" size=\"2\">?</font>";
|
+ "<font color=\"#cc0000\" size=\"2\">?</font>";
|
||||||
|
|
||||||
return new HandlerResult(href)
|
return new HandlerResult(href)
|
||||||
@@ -73,7 +79,7 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//The page does not exist and the user does not have permission to create it.
|
//该页面不存在,用户没有创建该页面的权限.
|
||||||
|
|
||||||
if (image != null)
|
if (image != null)
|
||||||
{
|
{
|
||||||
@@ -82,17 +88,18 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
if (image.StartsWith("http://", StringComparison.InvariantCultureIgnoreCase)
|
if (image.StartsWith("http://", StringComparison.InvariantCultureIgnoreCase)
|
||||||
|| image.StartsWith("https://", StringComparison.InvariantCultureIgnoreCase))
|
|| image.StartsWith("https://", StringComparison.InvariantCultureIgnoreCase))
|
||||||
{
|
{
|
||||||
//The image is external.
|
//外部图像.
|
||||||
mockHref = $"<img src=\"{GlobalConfiguration.BasePath}{image}?Scale={imageScale}\" />";
|
mockHref = $"<img src=\"{GlobalConfiguration.BasePath}{image}?Scale={imageScale}\" />";
|
||||||
}
|
}
|
||||||
else if (image.Contains('/'))
|
else if (image.Contains('/'))
|
||||||
{
|
{
|
||||||
//The image is located on another page.
|
//图像位于另一页.
|
||||||
mockHref = $"<img src=\"{GlobalConfiguration.BasePath}/Page/Image/{image}?Scale={imageScale}\" />";
|
mockHref =
|
||||||
|
$"<img src=\"{GlobalConfiguration.BasePath}/Page/Image/{image}?Scale={imageScale}\" />";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//The image is located on this page, but this page does not exist.
|
//图像位于此页面上,但此页面不存在.
|
||||||
mockHref = $"linkText";
|
mockHref = $"linkText";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,7 +117,7 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new Exception("No link or image was specified.");
|
throw new Exception("未指定链接或图像.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -123,23 +130,26 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
if (image.StartsWith("http://", StringComparison.InvariantCultureIgnoreCase)
|
if (image.StartsWith("http://", StringComparison.InvariantCultureIgnoreCase)
|
||||||
|| image.StartsWith("https://", StringComparison.InvariantCultureIgnoreCase))
|
|| image.StartsWith("https://", StringComparison.InvariantCultureIgnoreCase))
|
||||||
{
|
{
|
||||||
//The image is external.
|
//外部图像.
|
||||||
href = $"<a href=\"{GlobalConfiguration.BasePath}/{page.Navigation}\"><img src=\"{GlobalConfiguration.BasePath}{image}\" /></a>";
|
href =
|
||||||
|
$"<a href=\"{GlobalConfiguration.BasePath}/{page.Navigation}\"><img src=\"{GlobalConfiguration.BasePath}{image}\" /></a>";
|
||||||
}
|
}
|
||||||
else if (image.Contains('/'))
|
else if (image.Contains('/'))
|
||||||
{
|
{
|
||||||
//The image is located on another page.
|
//图像在另一页面.
|
||||||
href = $"<a href=\"{GlobalConfiguration.BasePath}/{page.Navigation}\"><img src=\"{GlobalConfiguration.BasePath}/Page/Image/{image}?Scale={imageScale}\" /></a>";
|
href =
|
||||||
|
$"<a href=\"{GlobalConfiguration.BasePath}/{page.Navigation}\"><img src=\"{GlobalConfiguration.BasePath}/Page/Image/{image}?Scale={imageScale}\" /></a>";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//The image is located on this page.
|
//图像在此页面
|
||||||
href = $"<a href=\"{GlobalConfiguration.BasePath}/{page.Navigation}\"><img src=\"{GlobalConfiguration.BasePath}/Page/Image/{state.Page.Navigation}/{image}?Scale={imageScale}\" /></a>";
|
href =
|
||||||
|
$"<a href=\"{GlobalConfiguration.BasePath}/{page.Navigation}\"><img src=\"{GlobalConfiguration.BasePath}/Page/Image/{state.Page.Navigation}/{image}?Scale={imageScale}\" /></a>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//Just a plain ol' internal page link.
|
//内链
|
||||||
href = $"<a href=\"{GlobalConfiguration.BasePath}/{page.Navigation}\">{linkText}</a>";
|
href = $"<a href=\"{GlobalConfiguration.BasePath}/{page.Navigation}\">{linkText}</a>";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,16 +4,17 @@ using ZelWiki.Engine.Library.Interfaces;
|
|||||||
namespace ZelWiki.Engine.Implementation
|
namespace ZelWiki.Engine.Implementation
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles basic markup/style instructions like bole, italic, underline, etc.
|
/// 处理基本的标记/样式指令,如粗体、斜体、下划线等.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MarkupHandler : IMarkupHandler
|
public class MarkupHandler : IMarkupHandler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles basic markup instructions like bole, italic, underline, etc.
|
/// 处理基本的标记指令,如粗体、斜体、下划线等
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state">Reference to the wiki state object</param>
|
/// <param name="state"></param>
|
||||||
/// <param name="sequence">The sequence of symbols that were found to denotate this markup instruction,</param>
|
/// <param name="sequence"></param>
|
||||||
/// <param name="scopeBody">The body of text to apply the style to.</param>
|
/// <param name="scopeBody"></param>
|
||||||
|
/// <returns></returns>
|
||||||
public HandlerResult Handle(IZelEngineState state, char sequence, string scopeBody)
|
public HandlerResult Handle(IZelEngineState state, char sequence, string scopeBody)
|
||||||
{
|
{
|
||||||
switch (sequence)
|
switch (sequence)
|
||||||
@@ -26,7 +27,6 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new HandlerResult() { Instructions = [Constants.HandlerResultInstruction.Skip] };
|
return new HandlerResult() { Instructions = [Constants.HandlerResultInstruction.Skip] };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ using ZelWiki.Models;
|
|||||||
namespace ZelWiki.Engine.Implementation
|
namespace ZelWiki.Engine.Implementation
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles post-processing function calls.
|
/// 处理后处理函数调用.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class PostProcessingFunctionHandler : IPostProcessingFunctionHandler
|
public class PostProcessingFunctionHandler : IPostProcessingFunctionHandler
|
||||||
{
|
{
|
||||||
@@ -20,9 +20,10 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
{
|
{
|
||||||
if (_collection == null)
|
if (_collection == null)
|
||||||
{
|
{
|
||||||
_collection = new FunctionPrototypeCollection(FunctionPrototypeCollection.WikiFunctionType.Standard);
|
_collection =
|
||||||
|
new FunctionPrototypeCollection(FunctionPrototypeCollection.WikiFunctionType.Standard);
|
||||||
|
|
||||||
#region Prototypes.
|
#region
|
||||||
|
|
||||||
_collection.Add("##Tags: <string>{styleName(Flat,List)}='List'");
|
_collection.Add("##Tags: <string>{styleName(Flat,List)}='List'");
|
||||||
_collection.Add("##TagCloud: <string>[pageTag] | <integer>{Top}='1000'");
|
_collection.Add("##TagCloud: <string>[pageTag] | <integer>{Top}='1000'");
|
||||||
@@ -37,20 +38,19 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called to handle function calls when proper prototypes are matched.
|
/// 当匹配到合适的原型时,调用它来处理函数调用。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state">Reference to the wiki state object</param>
|
/// <param name="state"></param>
|
||||||
/// <param name="function">The parsed function call and all its parameters and their values.</param>
|
/// <param name="function"></param>
|
||||||
/// <param name="scopeBody">This is not a scope function, this should always be null</param>
|
/// <param name="scopeBody"></param>
|
||||||
|
/// <returns></returns>
|
||||||
public HandlerResult Handle(IZelEngineState state, FunctionCall function, string? scopeBody = null)
|
public HandlerResult Handle(IZelEngineState state, FunctionCall function, string? scopeBody = null)
|
||||||
{
|
{
|
||||||
switch (function.Name.ToLower())
|
switch (function.Name.ToLower())
|
||||||
{
|
{
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
//Displays a tag link list.
|
|
||||||
case "tags": //##tags
|
case "tags": //##tags
|
||||||
{
|
{
|
||||||
string styleName = function.Parameters.Get<string>("styleName").ToLower();
|
var styleName = function.Parameters.Get<string>("styleName").ToLower();
|
||||||
var html = new StringBuilder();
|
var html = new StringBuilder();
|
||||||
|
|
||||||
if (styleName == "list")
|
if (styleName == "list")
|
||||||
@@ -60,6 +60,7 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
{
|
{
|
||||||
html.Append($"<li><a href=\"{GlobalConfiguration.BasePath}/Tag/Browse/{tag}\">{tag}</a>");
|
html.Append($"<li><a href=\"{GlobalConfiguration.BasePath}/Tag/Browse/{tag}\">{tag}</a>");
|
||||||
}
|
}
|
||||||
|
|
||||||
html.Append("</ul>");
|
html.Append("</ul>");
|
||||||
}
|
}
|
||||||
else if (styleName == "flat")
|
else if (styleName == "flat")
|
||||||
@@ -74,7 +75,6 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
return new HandlerResult(html.ToString());
|
return new HandlerResult(html.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
case "tagcloud":
|
case "tagcloud":
|
||||||
{
|
{
|
||||||
var top = function.Parameters.Get<int>("Top");
|
var top = function.Parameters.Get<int>("Top");
|
||||||
@@ -84,21 +84,19 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
return new HandlerResult(html);
|
return new HandlerResult(html);
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
case "searchcloud":
|
case "searchcloud":
|
||||||
{
|
{
|
||||||
var top = function.Parameters.Get<int>("Top");
|
var top = function.Parameters.Get<int>("Top");
|
||||||
var tokens = function.Parameters.Get<string>("searchPhrase").Split(" ", StringSplitOptions.RemoveEmptyEntries).ToList();
|
var tokens = function.Parameters.Get<string>("searchPhrase")
|
||||||
|
.Split(" ", StringSplitOptions.RemoveEmptyEntries).ToList();
|
||||||
|
|
||||||
string html = SearchCloud.Build(tokens, top);
|
string html = SearchCloud.Build(tokens, top);
|
||||||
return new HandlerResult(html);
|
return new HandlerResult(html);
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
//Displays a table of contents for the page based on the header tags.
|
|
||||||
case "toc":
|
case "toc":
|
||||||
{
|
{
|
||||||
bool alphabetized = function.Parameters.Get<bool>("alphabetized");
|
var alphabetized = function.Parameters.Get<bool>("alphabetized");
|
||||||
|
|
||||||
var html = new StringBuilder();
|
var html = new StringBuilder();
|
||||||
|
|
||||||
@@ -111,7 +109,7 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
|
|
||||||
if (alphabetized)
|
if (alphabetized)
|
||||||
{
|
{
|
||||||
int level = tags.FirstOrDefault()?.Level ?? 0;
|
var level = tags.FirstOrDefault()?.Level ?? 0;
|
||||||
|
|
||||||
foreach (var tag in tags)
|
foreach (var tag in tags)
|
||||||
{
|
{
|
||||||
@@ -131,7 +129,7 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
tags = ordered.ToList();
|
tags = ordered.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
int currentLevel = 0;
|
var currentLevel = 0;
|
||||||
|
|
||||||
foreach (var tag in tags)
|
foreach (var tag in tags)
|
||||||
{
|
{
|
||||||
@@ -147,7 +145,6 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
{
|
{
|
||||||
while (currentLevel > tag.Level)
|
while (currentLevel > tag.Level)
|
||||||
{
|
{
|
||||||
|
|
||||||
html.Append("</ul>");
|
html.Append("</ul>");
|
||||||
currentLevel--;
|
currentLevel--;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ using ZelWiki.Engine.Library.Interfaces;
|
|||||||
namespace ZelWiki.Engine.Implementation
|
namespace ZelWiki.Engine.Implementation
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles processing-instruction function calls, these functions affect the way the page is processed, but are not directly replaced with text.
|
/// 处理处理指令函数调用,这些函数会影响页面的处理方式,但不会直接替换为文本.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ProcessingInstructionFunctionHandler : IProcessingInstructionFunctionHandler
|
public class ProcessingInstructionFunctionHandler : IProcessingInstructionFunctionHandler
|
||||||
{
|
{
|
||||||
@@ -17,11 +17,11 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
{
|
{
|
||||||
if (_collection == null)
|
if (_collection == null)
|
||||||
{
|
{
|
||||||
_collection = new FunctionPrototypeCollection(FunctionPrototypeCollection.WikiFunctionType.Instruction);
|
_collection =
|
||||||
|
new FunctionPrototypeCollection(FunctionPrototypeCollection.WikiFunctionType.Instruction);
|
||||||
|
|
||||||
#region Prototypes.
|
#region
|
||||||
|
|
||||||
//Processing instructions:
|
|
||||||
_collection.Add("@@Deprecate:");
|
_collection.Add("@@Deprecate:");
|
||||||
_collection.Add("@@Protect:<bool>{isSilent}='false'");
|
_collection.Add("@@Protect:<bool>{isSilent}='false'");
|
||||||
_collection.Add("@@Tags: <string:infinite>[pageTags]");
|
_collection.Add("@@Tags: <string:infinite>[pageTags]");
|
||||||
@@ -42,19 +42,16 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called to handle function calls when proper prototypes are matched.
|
/// 处理各种页面
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state">Reference to the wiki state object</param>
|
/// <param name="state"></param>
|
||||||
/// <param name="function">The parsed function call and all its parameters and their values.</param>
|
/// <param name="function"></param>
|
||||||
/// <param name="scopeBody">This is not a scope function, this should always be null</param>
|
/// <param name="scopeBody"></param>
|
||||||
|
/// <returns></returns>
|
||||||
public HandlerResult Handle(IZelEngineState state, FunctionCall function, string? scopeBody = null)
|
public HandlerResult Handle(IZelEngineState state, FunctionCall function, string? scopeBody = null)
|
||||||
{
|
{
|
||||||
switch (function.Name.ToLower())
|
switch (function.Name.ToLower())
|
||||||
{
|
{
|
||||||
//We check wikifierSession.Factory.CurrentNestLevel here because we don't want to include the processing instructions on any parent pages that are injecting this one.
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
//Associates tags with a page. These are saved with the page and can also be displayed.
|
|
||||||
case "tags": //##tag(pipe|separated|list|of|tags)
|
case "tags": //##tag(pipe|separated|list|of|tags)
|
||||||
{
|
{
|
||||||
var tags = function.Parameters.GetList<string>("pageTags");
|
var tags = function.Parameters.GetList<string>("pageTags");
|
||||||
@@ -66,8 +63,6 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
Instructions = [Constants.HandlerResultInstruction.TruncateTrailingLine]
|
Instructions = [Constants.HandlerResultInstruction.TruncateTrailingLine]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
case "title":
|
case "title":
|
||||||
{
|
{
|
||||||
state.PageTitle = function.Parameters.Get<string>("pageTitle");
|
state.PageTitle = function.Parameters.Get<string>("pageTitle");
|
||||||
@@ -77,8 +72,6 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
Instructions = [Constants.HandlerResultInstruction.TruncateTrailingLine]
|
Instructions = [Constants.HandlerResultInstruction.TruncateTrailingLine]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
case "hidefooterlastmodified":
|
case "hidefooterlastmodified":
|
||||||
{
|
{
|
||||||
state.ProcessingInstructions.Add(ZelWiki.Library.Constants.WikiInstruction.HideFooterLastModified);
|
state.ProcessingInstructions.Add(ZelWiki.Library.Constants.WikiInstruction.HideFooterLastModified);
|
||||||
@@ -88,8 +81,6 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
Instructions = [Constants.HandlerResultInstruction.TruncateTrailingLine]
|
Instructions = [Constants.HandlerResultInstruction.TruncateTrailingLine]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
case "hidefootercomments":
|
case "hidefootercomments":
|
||||||
{
|
{
|
||||||
state.ProcessingInstructions.Add(ZelWiki.Library.Constants.WikiInstruction.HideFooterComments);
|
state.ProcessingInstructions.Add(ZelWiki.Library.Constants.WikiInstruction.HideFooterComments);
|
||||||
@@ -98,8 +89,6 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
Instructions = [Constants.HandlerResultInstruction.TruncateTrailingLine]
|
Instructions = [Constants.HandlerResultInstruction.TruncateTrailingLine]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
case "nocache":
|
case "nocache":
|
||||||
{
|
{
|
||||||
state.ProcessingInstructions.Add(ZelWiki.Library.Constants.WikiInstruction.NoCache);
|
state.ProcessingInstructions.Add(ZelWiki.Library.Constants.WikiInstruction.NoCache);
|
||||||
@@ -108,22 +97,20 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
Instructions = [Constants.HandlerResultInstruction.TruncateTrailingLine]
|
Instructions = [Constants.HandlerResultInstruction.TruncateTrailingLine]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
case "deprecate":
|
case "deprecate":
|
||||||
{
|
{
|
||||||
if (state.NestDepth == 0)
|
if (state.NestDepth == 0)
|
||||||
{
|
{
|
||||||
state.ProcessingInstructions.Add(ZelWiki.Library.Constants.WikiInstruction.Deprecate);
|
state.ProcessingInstructions.Add(ZelWiki.Library.Constants.WikiInstruction.Deprecate);
|
||||||
state.Headers.Add("<div class=\"alert alert-danger\">This page has been deprecated and will eventually be deleted.</div>");
|
state.Headers.Add(
|
||||||
|
"<div class=\"alert alert-danger\">此页面已被弃用,最终将被删除.</div>");
|
||||||
}
|
}
|
||||||
|
|
||||||
return new HandlerResult(string.Empty)
|
return new HandlerResult(string.Empty)
|
||||||
{
|
{
|
||||||
Instructions = [Constants.HandlerResultInstruction.TruncateTrailingLine]
|
Instructions = [Constants.HandlerResultInstruction.TruncateTrailingLine]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
case "protect":
|
case "protect":
|
||||||
{
|
{
|
||||||
if (state.NestDepth == 0)
|
if (state.NestDepth == 0)
|
||||||
@@ -132,65 +119,67 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
state.ProcessingInstructions.Add(ZelWiki.Library.Constants.WikiInstruction.Protect);
|
state.ProcessingInstructions.Add(ZelWiki.Library.Constants.WikiInstruction.Protect);
|
||||||
if (isSilent == false)
|
if (isSilent == false)
|
||||||
{
|
{
|
||||||
state.Headers.Add("<div class=\"alert alert-info\">This page has been protected and can not be changed by non-moderators.</div>");
|
state.Headers.Add(
|
||||||
|
"<div class=\"alert alert-info\">此页面已受到保护,非版主无法更改.</div>");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new HandlerResult(string.Empty)
|
return new HandlerResult(string.Empty)
|
||||||
{
|
{
|
||||||
Instructions = [Constants.HandlerResultInstruction.TruncateTrailingLine]
|
Instructions = [Constants.HandlerResultInstruction.TruncateTrailingLine]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
case "template":
|
case "template":
|
||||||
{
|
{
|
||||||
if (state.NestDepth == 0)
|
if (state.NestDepth == 0)
|
||||||
{
|
{
|
||||||
state.ProcessingInstructions.Add(ZelWiki.Library.Constants.WikiInstruction.Template);
|
state.ProcessingInstructions.Add(ZelWiki.Library.Constants.WikiInstruction.Template);
|
||||||
state.Headers.Add("<div class=\"alert alert-secondary\">This page is a template and will not appear in indexes or glossaries.</div>");
|
state.Headers.Add(
|
||||||
|
"<div class=\"alert alert-secondary\">此页面是一个模板,不会出现在索引或术语表中.</div>");
|
||||||
}
|
}
|
||||||
|
|
||||||
return new HandlerResult(string.Empty)
|
return new HandlerResult(string.Empty)
|
||||||
{
|
{
|
||||||
Instructions = [Constants.HandlerResultInstruction.TruncateTrailingLine]
|
Instructions = [Constants.HandlerResultInstruction.TruncateTrailingLine]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
case "review":
|
case "review":
|
||||||
{
|
{
|
||||||
if (state.NestDepth == 0)
|
if (state.NestDepth == 0)
|
||||||
{
|
{
|
||||||
state.ProcessingInstructions.Add(ZelWiki.Library.Constants.WikiInstruction.Review);
|
state.ProcessingInstructions.Add(ZelWiki.Library.Constants.WikiInstruction.Review);
|
||||||
state.Headers.Add("<div class=\"alert alert-warning\">This page has been flagged for review, its content may be inaccurate.</div>");
|
state.Headers.Add(
|
||||||
|
"<div class=\"alert alert-warning\">此页面已被标记为待审核,其内容可能不准确.</div>");
|
||||||
}
|
}
|
||||||
|
|
||||||
return new HandlerResult(string.Empty)
|
return new HandlerResult(string.Empty)
|
||||||
{
|
{
|
||||||
Instructions = [Constants.HandlerResultInstruction.TruncateTrailingLine]
|
Instructions = [Constants.HandlerResultInstruction.TruncateTrailingLine]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
case "include":
|
case "include":
|
||||||
{
|
{
|
||||||
if (state.NestDepth == 0)
|
if (state.NestDepth == 0)
|
||||||
{
|
{
|
||||||
state.ProcessingInstructions.Add(ZelWiki.Library.Constants.WikiInstruction.Include);
|
state.ProcessingInstructions.Add(ZelWiki.Library.Constants.WikiInstruction.Include);
|
||||||
state.Headers.Add("<div class=\"alert alert-secondary\">This page is an include and will not appear in indexes or glossaries.</div>");
|
state.Headers.Add(
|
||||||
|
"<div class=\"alert alert-secondary\">此页为包含页,不会出现在索引或术语表中.</div>");
|
||||||
}
|
}
|
||||||
|
|
||||||
return new HandlerResult(string.Empty)
|
return new HandlerResult(string.Empty)
|
||||||
{
|
{
|
||||||
Instructions = [Constants.HandlerResultInstruction.TruncateTrailingLine]
|
Instructions = [Constants.HandlerResultInstruction.TruncateTrailingLine]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
case "draft":
|
case "draft":
|
||||||
{
|
{
|
||||||
if (state.NestDepth == 0)
|
if (state.NestDepth == 0)
|
||||||
{
|
{
|
||||||
state.ProcessingInstructions.Add(ZelWiki.Library.Constants.WikiInstruction.Draft);
|
state.ProcessingInstructions.Add(ZelWiki.Library.Constants.WikiInstruction.Draft);
|
||||||
state.Headers.Add("<div class=\"alert alert-warning\">This page is a draft and may contain incorrect information and/or experimental styling.</div>");
|
state.Headers.Add(
|
||||||
|
"<div class=\"alert alert-warning\">本页为草稿,可能包含不正确的信息包括但不仅限于实验性样式.</div>");
|
||||||
}
|
}
|
||||||
|
|
||||||
return new HandlerResult(string.Empty)
|
return new HandlerResult(string.Empty)
|
||||||
{
|
{
|
||||||
Instructions = [Constants.HandlerResultInstruction.TruncateTrailingLine]
|
Instructions = [Constants.HandlerResultInstruction.TruncateTrailingLine]
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ using static ZelWiki.Engine.Library.Constants;
|
|||||||
namespace ZelWiki.Engine.Implementation
|
namespace ZelWiki.Engine.Implementation
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handled scope function calls.
|
///处理作用域函数调用.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ScopeFunctionHandler : IScopeFunctionHandler
|
public class ScopeFunctionHandler : IScopeFunctionHandler
|
||||||
{
|
{
|
||||||
@@ -23,17 +23,23 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
{
|
{
|
||||||
_collection = new FunctionPrototypeCollection(FunctionPrototypeCollection.WikiFunctionType.Scoped);
|
_collection = new FunctionPrototypeCollection(FunctionPrototypeCollection.WikiFunctionType.Scoped);
|
||||||
|
|
||||||
#region Prototypes.
|
#region
|
||||||
|
|
||||||
_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(
|
||||||
|
"$$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("$$Bullets: <string>{type(unordered,ordered)}='unordered'");
|
||||||
_collection.Add("$$Order: <string>{direction(ascending,descending)}='ascending'");
|
_collection.Add("$$Order: <string>{direction(ascending,descending)}='ascending'");
|
||||||
_collection.Add("$$Jumbotron:");
|
_collection.Add("$$Jumbotron:");
|
||||||
_collection.Add("$$Callout: <string>{styleName(default,primary,secondary,success,info,warning,danger)}='default' | <string>{titleText}=''");
|
_collection.Add(
|
||||||
_collection.Add("$$Background: <string>{styleName(default,primary,secondary,light,dark,success,info,warning,danger,muted)}='default'");
|
"$$Callout: <string>{styleName(default,primary,secondary,success,info,warning,danger)}='default' | <string>{titleText}=''");
|
||||||
_collection.Add("$$Foreground: <string>{styleName(default,primary,secondary,light,dark,success,info,warning,danger,muted)}='default'");
|
_collection.Add(
|
||||||
_collection.Add("$$Alert: <string>{styleName(default,primary,secondary,light,dark,success,info,warning,danger)}='default' | <string>{titleText}=''");
|
"$$Background: <string>{styleName(default,primary,secondary,light,dark,success,info,warning,danger,muted)}='default'");
|
||||||
_collection.Add("$$Card: <string>{styleName(default,primary,secondary,light,dark,success,info,warning,danger)}='default' | <string>{titleText}=''");
|
_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("$$Collapse: <string>{linkText}='Show'");
|
||||||
_collection.Add("$$Table: <boolean>{hasBorder}='true' | <boolean>{isFirstRowHeader}='true'");
|
_collection.Add("$$Table: <boolean>{hasBorder}='true' | <boolean>{isFirstRowHeader}='true'");
|
||||||
_collection.Add("$$StripedTable: <boolean>{hasBorder}='true' | <boolean>{isFirstRowHeader}='true'");
|
_collection.Add("$$StripedTable: <boolean>{hasBorder}='true' | <boolean>{isFirstRowHeader}='true'");
|
||||||
@@ -47,23 +53,23 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called to handle function calls when proper prototypes are matched.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state">Reference to the wiki state object</param>
|
/// <param name="state"></param>
|
||||||
/// <param name="function">The parsed function call and all its parameters and their values.</param>
|
/// <param name="function"></param>
|
||||||
/// <param name="scopeBody">The the text that the function is designed to affect.</param>
|
/// <param name="scopeBody"></param>
|
||||||
|
/// <returns></returns>
|
||||||
public HandlerResult Handle(IZelEngineState state, FunctionCall function, string? scopeBody = null)
|
public HandlerResult Handle(IZelEngineState state, FunctionCall function, string? scopeBody = null)
|
||||||
{
|
{
|
||||||
scopeBody.EnsureNotNull($"The function '{function.Name}' scope body can not be null");
|
scopeBody.EnsureNotNull($"函数'{function.Name}'作用域主题为空");
|
||||||
|
|
||||||
switch (function.Name.ToLower())
|
switch (function.Name.ToLower())
|
||||||
{
|
{
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
case "code":
|
case "code":
|
||||||
{
|
{
|
||||||
var html = new StringBuilder();
|
var html = new StringBuilder();
|
||||||
|
|
||||||
string language = function.Parameters.Get<string>("language");
|
var language = function.Parameters.Get<string>("language");
|
||||||
if (string.IsNullOrEmpty(language) || language?.ToLower() == "auto")
|
if (string.IsNullOrEmpty(language) || language?.ToLower() == "auto")
|
||||||
{
|
{
|
||||||
html.Append($"<pre>");
|
html.Append($"<pre>");
|
||||||
@@ -77,11 +83,9 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
|
|
||||||
return new HandlerResult(html.ToString())
|
return new HandlerResult(html.ToString())
|
||||||
{
|
{
|
||||||
Instructions = [Constants.HandlerResultInstruction.DisallowNestedProcessing]
|
Instructions = [HandlerResultInstruction.DisallowNestedProcessing]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
case "stripedtable":
|
case "stripedtable":
|
||||||
case "table":
|
case "table":
|
||||||
{
|
{
|
||||||
@@ -96,6 +100,7 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
{
|
{
|
||||||
html.Append(" table-striped");
|
html.Append(" table-striped");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasBorder)
|
if (hasBorder)
|
||||||
{
|
{
|
||||||
html.Append(" table-bordered");
|
html.Append(" table-bordered");
|
||||||
@@ -103,7 +108,8 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
|
|
||||||
html.Append($"\">");
|
html.Append($"\">");
|
||||||
|
|
||||||
var lines = scopeBody.Split(['\n'], StringSplitOptions.RemoveEmptyEntries).Select(o => o.Trim()).Where(o => o.Length > 0);
|
var lines = scopeBody.Split(['\n'], StringSplitOptions.RemoveEmptyEntries).Select(o => o.Trim())
|
||||||
|
.Where(o => o.Length > 0);
|
||||||
|
|
||||||
int rowNumber = 0;
|
int rowNumber = 0;
|
||||||
|
|
||||||
@@ -137,6 +143,7 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
{
|
{
|
||||||
html.Append($"</thead>");
|
html.Append($"</thead>");
|
||||||
}
|
}
|
||||||
|
|
||||||
html.Append($"</tr>");
|
html.Append($"</tr>");
|
||||||
|
|
||||||
rowNumber++;
|
rowNumber++;
|
||||||
@@ -147,27 +154,27 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
|
|
||||||
return new HandlerResult(html.ToString());
|
return new HandlerResult(html.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
case "bullets":
|
case "bullets":
|
||||||
{
|
{
|
||||||
var html = new StringBuilder();
|
var html = new StringBuilder();
|
||||||
|
|
||||||
string type = function.Parameters.Get<string>("type");
|
var type = function.Parameters.Get<string>("type");
|
||||||
|
|
||||||
if (type == "unordered")
|
if (type == "unordered")
|
||||||
{
|
{
|
||||||
var lines = scopeBody.Split(['\n'], StringSplitOptions.RemoveEmptyEntries).Select(o => o.Trim()).Where(o => o.Length > 0);
|
var lines = scopeBody.Split(['\n'], StringSplitOptions.RemoveEmptyEntries).Select(o => o.Trim())
|
||||||
|
.Where(o => o.Length > 0);
|
||||||
|
|
||||||
int currentLevel = 0;
|
int currentLevel = 0;
|
||||||
|
|
||||||
foreach (var line in lines)
|
foreach (var line in lines)
|
||||||
{
|
{
|
||||||
int newIndent = 0;
|
var newIndent = 0;
|
||||||
for (; newIndent < line.Length && line[newIndent] == '>'; newIndent++)
|
for (; newIndent < line.Length && line[newIndent] == '>'; newIndent++)
|
||||||
{
|
{
|
||||||
//Count how many '>' are at the start of the line.
|
//计算行开头有多少个“>”.
|
||||||
}
|
}
|
||||||
|
|
||||||
newIndent++;
|
newIndent++;
|
||||||
|
|
||||||
if (newIndent < currentLevel)
|
if (newIndent < currentLevel)
|
||||||
@@ -195,17 +202,19 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
}
|
}
|
||||||
else if (type == "ordered")
|
else if (type == "ordered")
|
||||||
{
|
{
|
||||||
var lines = scopeBody.Split(['\n'], StringSplitOptions.RemoveEmptyEntries).Select(o => o.Trim()).Where(o => o.Length > 0);
|
var lines = scopeBody.Split(['\n'], StringSplitOptions.RemoveEmptyEntries).Select(o => o.Trim())
|
||||||
|
.Where(o => o.Length > 0);
|
||||||
|
|
||||||
int currentLevel = 0;
|
var currentLevel = 0;
|
||||||
|
|
||||||
foreach (var line in lines)
|
foreach (var line in lines)
|
||||||
{
|
{
|
||||||
int newIndent = 0;
|
var newIndent = 0;
|
||||||
for (; newIndent < line.Length && line[newIndent] == '>'; newIndent++)
|
for (; newIndent < line.Length && line[newIndent] == '>'; newIndent++)
|
||||||
{
|
{
|
||||||
//Count how many '>' are at the start of the line.
|
//计算行开头有多少个“>”.
|
||||||
}
|
}
|
||||||
|
|
||||||
newIndent++;
|
newIndent++;
|
||||||
|
|
||||||
if (newIndent < currentLevel)
|
if (newIndent < currentLevel)
|
||||||
@@ -231,15 +240,14 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
html.Append($"</ol>");
|
html.Append($"</ol>");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new HandlerResult(html.ToString());
|
return new HandlerResult(html.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
case "definesnippet":
|
case "definesnippet":
|
||||||
{
|
{
|
||||||
var html = new StringBuilder();
|
var html = new StringBuilder();
|
||||||
|
|
||||||
string name = function.Parameters.Get<string>("name");
|
var name = function.Parameters.Get<string>("name");
|
||||||
|
|
||||||
if (!state.Snippets.TryAdd(name, scopeBody))
|
if (!state.Snippets.TryAdd(name, scopeBody))
|
||||||
{
|
{
|
||||||
@@ -248,14 +256,12 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
|
|
||||||
return new HandlerResult(html.ToString());
|
return new HandlerResult(html.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
case "alert":
|
case "alert":
|
||||||
{
|
{
|
||||||
var html = new StringBuilder();
|
var html = new StringBuilder();
|
||||||
|
|
||||||
string titleText = function.Parameters.Get<string>("titleText");
|
var titleText = function.Parameters.Get<string>("titleText");
|
||||||
string style = function.Parameters.Get<string>("styleName").ToLower();
|
var style = function.Parameters.Get<string>("styleName").ToLower();
|
||||||
style = style == "default" ? "" : $"alert-{style}";
|
style = style == "default" ? "" : $"alert-{style}";
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(titleText)) scopeBody = $"<h1>{titleText}</h1>{scopeBody}";
|
if (!string.IsNullOrEmpty(titleText)) scopeBody = $"<h1>{titleText}</h1>{scopeBody}";
|
||||||
@@ -267,34 +273,25 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
{
|
{
|
||||||
var html = new StringBuilder();
|
var html = new StringBuilder();
|
||||||
|
|
||||||
string direction = function.Parameters.Get<string>("direction");
|
var direction = function.Parameters.Get<string>("direction");
|
||||||
var lines = scopeBody.Split("\n").Select(o => o.Trim()).ToList();
|
var lines = scopeBody.Split("\n").Select(o => o.Trim()).ToList();
|
||||||
|
|
||||||
if (direction == "ascending")
|
html.Append(direction == "ascending"
|
||||||
{
|
? string.Join("\r\n", lines.OrderBy(o => o))
|
||||||
html.Append(string.Join("\r\n", lines.OrderBy(o => o)));
|
: string.Join("\r\n", lines.OrderByDescending(o => o)));
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
html.Append(string.Join("\r\n", lines.OrderByDescending(o => o)));
|
|
||||||
}
|
|
||||||
return new HandlerResult(html.ToString());
|
return new HandlerResult(html.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
case "jumbotron":
|
case "jumbotron":
|
||||||
{
|
{
|
||||||
var html = new StringBuilder();
|
var html = new StringBuilder();
|
||||||
|
|
||||||
string titleText = function.Parameters.Get("titleText", "");
|
var titleText = function.Parameters.Get("titleText", "");
|
||||||
html.Append($"<div class=\"mt-4 p-5 bg-secondary text-white rounded\">");
|
html.Append($"<div class=\"mt-4 p-5 bg-secondary text-white rounded\">");
|
||||||
if (!string.IsNullOrEmpty(titleText)) html.Append($"<h1>{titleText}</h1>");
|
if (!string.IsNullOrEmpty(titleText)) html.Append($"<h1>{titleText}</h1>");
|
||||||
html.Append($"<p>{scopeBody}</p>");
|
html.Append($"<p>{scopeBody}</p>");
|
||||||
html.Append($"</div>");
|
html.Append($"</div>");
|
||||||
return new HandlerResult(html.ToString());
|
return new HandlerResult(html.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
case "foreground":
|
case "foreground":
|
||||||
{
|
{
|
||||||
var html = new StringBuilder();
|
var html = new StringBuilder();
|
||||||
@@ -303,31 +300,27 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
html.Append($"<p class=\"{style.ForegroundStyle} {style.BackgroundStyle}\">{scopeBody}</p>");
|
html.Append($"<p class=\"{style.ForegroundStyle} {style.BackgroundStyle}\">{scopeBody}</p>");
|
||||||
return new HandlerResult(html.ToString());
|
return new HandlerResult(html.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
case "background":
|
case "background":
|
||||||
{
|
{
|
||||||
var html = new StringBuilder();
|
var html = new StringBuilder();
|
||||||
|
|
||||||
var style = BGFGStyle.GetBackgroundStyle(function.Parameters.Get("styleName", "default"));
|
var style = BGFGStyle.GetBackgroundStyle(function.Parameters.Get("styleName", "default"));
|
||||||
html.Append($"<div class=\"p-3 mb-2 {style.ForegroundStyle} {style.BackgroundStyle}\">{scopeBody}</div>");
|
html.Append(
|
||||||
|
$"<div class=\"p-3 mb-2 {style.ForegroundStyle} {style.BackgroundStyle}\">{scopeBody}</div>");
|
||||||
return new HandlerResult(html.ToString());
|
return new HandlerResult(html.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
case "collapse":
|
case "collapse":
|
||||||
{
|
{
|
||||||
var html = new StringBuilder();
|
var html = new StringBuilder();
|
||||||
|
|
||||||
string linkText = function.Parameters.Get<string>("linktext");
|
var linkText = function.Parameters.Get<string>("linktext");
|
||||||
string uid = "A" + Guid.NewGuid().ToString().Replace("-", "");
|
var 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(
|
||||||
|
$"<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=\"collapse\" id=\"{uid}\">");
|
||||||
html.Append($"<div class=\"card card-body\"><p class=\"card-text\">{scopeBody}</p></div></div>");
|
html.Append($"<div class=\"card card-body\"><p class=\"card-text\">{scopeBody}</p></div></div>");
|
||||||
return new HandlerResult(html.ToString());
|
return new HandlerResult(html.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
case "callout":
|
case "callout":
|
||||||
{
|
{
|
||||||
var html = new StringBuilder();
|
var html = new StringBuilder();
|
||||||
@@ -342,31 +335,26 @@ namespace ZelWiki.Engine.Implementation
|
|||||||
html.Append($"</div>");
|
html.Append($"</div>");
|
||||||
return new HandlerResult(html.ToString());
|
return new HandlerResult(html.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
case "card":
|
case "card":
|
||||||
{
|
{
|
||||||
var html = new StringBuilder();
|
var html = new StringBuilder();
|
||||||
|
|
||||||
string titleText = function.Parameters.Get<string>("titleText");
|
var titleText = function.Parameters.Get<string>("titleText");
|
||||||
var style = BGFGStyle.GetBackgroundStyle(function.Parameters.Get("styleName", "default"));
|
var style = BGFGStyle.GetBackgroundStyle(function.Parameters.Get("styleName", "default"));
|
||||||
|
|
||||||
html.Append($"<div class=\"card {style.ForegroundStyle} {style.BackgroundStyle} mb-3\">");
|
html.Append($"<div class=\"card {style.ForegroundStyle} {style.BackgroundStyle} mb-3\">");
|
||||||
if (string.IsNullOrEmpty(titleText) == false)
|
if (string.IsNullOrEmpty(titleText) == false)
|
||||||
{
|
|
||||||
html.Append($"<div class=\"card-header\">{titleText}</div>");
|
html.Append($"<div class=\"card-header\">{titleText}</div>");
|
||||||
}
|
|
||||||
html.Append("<div class=\"card-body\">");
|
html.Append("<div class=\"card-body\">");
|
||||||
html.Append($"<p class=\"card-text\">{scopeBody}</p>");
|
html.Append($"<p class=\"card-text\">{scopeBody}</p>");
|
||||||
html.Append("</div>");
|
html.Append("</div>");
|
||||||
html.Append("</div>");
|
html.Append("</div>");
|
||||||
return new HandlerResult(html.ToString());
|
return new HandlerResult(html.ToString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
return new HandlerResult() { Instructions = [HandlerResultInstruction.Skip] };
|
||||||
|
|
||||||
return new HandlerResult() { Instructions = [Constants.HandlerResultInstruction.Skip] };
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -2,8 +2,14 @@
|
|||||||
{
|
{
|
||||||
public class BGFGStyle
|
public class BGFGStyle
|
||||||
{
|
{
|
||||||
public string ForegroundStyle { get; set; } = String.Empty;
|
public BGFGStyle()
|
||||||
public string BackgroundStyle { get; set; } = String.Empty;
|
{
|
||||||
|
ForegroundStyle = string.Empty;
|
||||||
|
BackgroundStyle = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ForegroundStyle { get; set; }
|
||||||
|
public string BackgroundStyle { get; set; }
|
||||||
|
|
||||||
public BGFGStyle(string foregroundStyle, string backgroundStyle)
|
public BGFGStyle(string foregroundStyle, string backgroundStyle)
|
||||||
{
|
{
|
||||||
@@ -16,9 +22,6 @@
|
|||||||
return new BGFGStyle(BackgroundStyle, ForegroundStyle);
|
return new BGFGStyle(BackgroundStyle, ForegroundStyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BGFGStyle()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public static readonly Dictionary<string, BGFGStyle> ForegroundStyles = new(StringComparer.OrdinalIgnoreCase)
|
public static readonly Dictionary<string, BGFGStyle> ForegroundStyles = new(StringComparer.OrdinalIgnoreCase)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ namespace ZelWiki.Engine.Implementation.Utility
|
|||||||
public static class Differentiator
|
public static class Differentiator
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This leaves a lot to be desired.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="thisRev"></param>
|
/// <param name="thisRev"></param>
|
||||||
/// <param name="prevRev"></param>
|
/// <param name="prevRev"></param>
|
||||||
@@ -16,32 +16,32 @@ namespace ZelWiki.Engine.Implementation.Utility
|
|||||||
|
|
||||||
var thisRevLines = thisRev.Split('\n');
|
var thisRevLines = thisRev.Split('\n');
|
||||||
var prevRevLines = prevRev.Split('\n');
|
var prevRevLines = prevRev.Split('\n');
|
||||||
int thisRevLineCount = thisRevLines.Length;
|
var thisRevLineCount = thisRevLines.Length;
|
||||||
int prevRevLinesCount = prevRevLines.Length;
|
var prevRevLinesCount = prevRevLines.Length;
|
||||||
|
|
||||||
int linesAdded = prevRevLines.Except(thisRevLines).Count();
|
var linesAdded = prevRevLines.Except(thisRevLines).Count();
|
||||||
int linesDeleted = thisRevLines.Except(prevRevLines).Count();
|
var linesDeleted = thisRevLines.Except(prevRevLines).Count();
|
||||||
|
|
||||||
if (thisRevLineCount != prevRevLinesCount)
|
if (thisRevLineCount != prevRevLinesCount)
|
||||||
{
|
{
|
||||||
summary.Append($"{Math.Abs(thisRevLineCount - prevRevLinesCount):N0} lines changed.");
|
summary.Append($"{Math.Abs(thisRevLineCount - prevRevLinesCount):N0} 行修改.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (linesAdded > 0)
|
if (linesAdded > 0)
|
||||||
{
|
{
|
||||||
if (summary.Length > 0) summary.Append(' ');
|
if (summary.Length > 0) summary.Append(' ');
|
||||||
summary.Append($"{linesAdded:N0} lines added.");
|
summary.Append($"{linesAdded:N0} 行新增.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (linesDeleted > 0)
|
if (linesDeleted > 0)
|
||||||
{
|
{
|
||||||
if (summary.Length > 0) summary.Append(' ');
|
if (summary.Length > 0) summary.Append(' ');
|
||||||
summary.Append($"{linesDeleted:N0} lines deleted.");
|
summary.Append($"{linesDeleted:N0} 行删除.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (summary.Length == 0)
|
if (summary.Length == 0)
|
||||||
{
|
{
|
||||||
summary.Append($"No changes detected.");
|
summary.Append($"未修改.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return summary.ToString();
|
return summary.ToString();
|
||||||
|
|||||||
@@ -16,10 +16,10 @@ namespace ZelWiki.Engine.Implementation.Utility
|
|||||||
pages = pages.Take((int)maxCount).ToList();
|
pages = pages.Take((int)maxCount).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
int pageCount = pages.Count;
|
var pageCount = pages.Count;
|
||||||
int fontSize = 7;
|
var fontSize = 7;
|
||||||
int sizeStep = (pageCount > fontSize ? pageCount : (fontSize * 2)) / fontSize;
|
var sizeStep = (pageCount > fontSize ? pageCount : (fontSize * 2)) / fontSize;
|
||||||
int pageIndex = 0;
|
var pageIndex = 0;
|
||||||
|
|
||||||
var pageList = new List<TagCloudItem>();
|
var pageList = new List<TagCloudItem>();
|
||||||
|
|
||||||
|
|||||||
@@ -17,10 +17,10 @@ namespace ZelWiki.Engine.Implementation.Utility
|
|||||||
tags = tags.Take((int)maxCount).ToList();
|
tags = tags.Take((int)maxCount).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
int tagCount = tags.Count;
|
var tagCount = tags.Count;
|
||||||
int fontSize = 7;
|
var fontSize = 7;
|
||||||
int sizeStep = (tagCount > fontSize ? tagCount : (fontSize * 2)) / fontSize;
|
var sizeStep = (tagCount > fontSize ? tagCount : (fontSize * 2)) / fontSize;
|
||||||
int tagIndex = 0;
|
var tagIndex = 0;
|
||||||
|
|
||||||
var tagList = new List<TagCloudItem>();
|
var tagList = new List<TagCloudItem>();
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,14 @@
|
|||||||
{
|
{
|
||||||
public class WeightedSearchToken
|
public class WeightedSearchToken
|
||||||
{
|
{
|
||||||
public string Token { get; set; } = string.Empty;
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public WeightedSearchToken()
|
||||||
|
{
|
||||||
|
Token = string.Empty;
|
||||||
|
}
|
||||||
|
public string Token { get; set; }
|
||||||
public double Weight { get; set; }
|
public double Weight { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
namespace ZelWiki.Engine.Library
|
namespace ZelWiki.Engine.Library
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
public class Constants
|
public class Constants
|
||||||
{
|
{
|
||||||
public const string SoftBreak = "<!--SoftBreak-->"; //These will remain as \r\n in the final HTML.
|
public const string SoftBreak = "<!--SoftBreak-->";
|
||||||
public const string HardBreak = "<!--HardBreak-->"; //These will remain as <br /> in the final HTML.
|
public const string HardBreak = "<!--HardBreak-->";
|
||||||
|
|
||||||
public enum WikiMatchType
|
public enum WikiMatchType
|
||||||
{
|
{
|
||||||
@@ -23,20 +26,22 @@
|
|||||||
public enum HandlerResultInstruction
|
public enum HandlerResultInstruction
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Does not process the match, allowing it to be processed by another handler.
|
/// 不处理匹配,允许它由另一个处理程序处理
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Skip,
|
Skip,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Removes any single trailing newline after match.
|
/// 删除匹配后的任何单个尾随换行符
|
||||||
/// </summary>
|
/// </summary>
|
||||||
TruncateTrailingLine,
|
TruncateTrailingLine,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Will not continue to process content in this block.
|
/// 将不会继续处理此块中的内容
|
||||||
/// </summary>
|
/// </summary>
|
||||||
DisallowNestedProcessing,
|
DisallowNestedProcessing,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// As opposed to the default functionality of replacing all matches, this will cause ony the first match to be replaced.
|
///
|
||||||
/// This also means that each match will be processed individually, which can impact performance.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
OnlyReplaceFirstMatch
|
OnlyReplaceFirstMatch
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
namespace ZelWiki.Engine.Library.Interfaces
|
namespace ZelWiki.Engine.Library.Interfaces
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles wiki comments. These are generally removed from the result.
|
/// 处理评论.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ICommentHandler
|
public interface ICommentHandler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles a wiki comment.
|
/// 处理评论
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state">Reference to the wiki state object</param>
|
/// <param name="state"></param>
|
||||||
/// <param name="text">The comment text</param>
|
/// <param name="text"></param>
|
||||||
|
/// <returns></returns>
|
||||||
public HandlerResult Handle(IZelEngineState state, string text);
|
public HandlerResult Handle(IZelEngineState state, string text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
namespace ZelWiki.Engine.Library.Interfaces
|
namespace ZelWiki.Engine.Library.Interfaces
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles wiki completion events.
|
/// 处理完成事件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ICompletionHandler
|
public interface ICompletionHandler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles wiki completion events. Is called when the wiki processing competes for a given page.
|
/// 处理完成事件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state">Reference to the wiki state object</param>
|
/// <param name="state"></param>
|
||||||
public void Complete(IZelEngineState state);
|
public void Complete(IZelEngineState state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,16 +1,17 @@
|
|||||||
namespace ZelWiki.Engine.Library.Interfaces
|
namespace ZelWiki.Engine.Library.Interfaces
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles wiki emojis.
|
/// emoji
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IEmojiHandler
|
public interface IEmojiHandler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles an emoji instruction.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state">Reference to the wiki state object</param>
|
/// <param name="state"></param>
|
||||||
/// <param name="key">The lookup key for the given emoji.</param>
|
/// <param name="key"></param>
|
||||||
/// <param name="scale">The desired 1-100 scale factor for the emoji.</param>
|
/// <param name="scale"></param>
|
||||||
|
/// <returns></returns>
|
||||||
public HandlerResult Handle(IZelEngineState state, string key, int scale);
|
public HandlerResult Handle(IZelEngineState state, string key, int scale);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
namespace ZelWiki.Engine.Library.Interfaces
|
namespace ZelWiki.Engine.Library.Interfaces
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles exceptions thrown by the wiki engine.
|
/// 错误日志
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IExceptionHandler
|
public interface IExceptionHandler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called when an exception is thrown by the wiki engine.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state">Reference to the wiki state object</param>
|
/// <param name="state"></param>
|
||||||
/// <param name="ex">Optional exception, in the case that this was an actual exception.</param>
|
/// <param name="ex"></param>
|
||||||
/// <param name="customText">Text that accompanies the exception.</param>
|
/// <param name="customText"></param>
|
||||||
public void Log(IZelEngineState state, Exception? ex, string customText);
|
public void Log(IZelEngineState state, Exception? ex, string customText);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
namespace ZelWiki.Engine.Library.Interfaces
|
namespace ZelWiki.Engine.Library.Interfaces
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles links the wiki to another site.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IExternalLinkHandler
|
public interface IExternalLinkHandler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles an internal wiki link.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state">Reference to the wiki state object</param>
|
/// <param name="state"></param>
|
||||||
/// <param name="link">The address of the external site being linked to.</param>
|
/// <param name="link"></param>
|
||||||
/// <param name="text">The text which should be show in the absence of an image.</param>
|
/// <param name="text"></param>
|
||||||
/// <param name="image">The image that should be shown.</param>
|
/// <param name="image"></param>
|
||||||
/// <param name="imageScale">The 0-100 image scale factor for the given image.</param>
|
/// <returns></returns>
|
||||||
public HandlerResult Handle(IZelEngineState state, string link, string? text, string? image);
|
public HandlerResult Handle(IZelEngineState state, string link, string? text, string? image);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,22 +3,23 @@
|
|||||||
namespace ZelWiki.Engine.Library.Interfaces
|
namespace ZelWiki.Engine.Library.Interfaces
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Base function handler for standard, post-processing, scoped and processing-instruction functions.
|
/// 处理函数.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IFunctionHandler
|
public interface IFunctionHandler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a collection of function prototypes.
|
/// 回调.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public FunctionPrototypeCollection Prototypes { get; }
|
public FunctionPrototypeCollection Prototypes { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called to handle function calls when proper prototypes are matched.
|
/// 当匹配到合适的原型时,调用以处理函数调用
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state">Reference to the wiki state object</param>
|
/// <param name="state"></param>
|
||||||
/// <param name="function">The parsed function call and all its parameters and their values.</param>
|
/// <param name="function"></param>
|
||||||
/// <param name="scopeBody">For scope functions, this is the text that the function is designed to affect.</param>
|
/// <param name="scopeBody"></param>
|
||||||
|
/// <returns></returns>
|
||||||
public HandlerResult Handle(IZelEngineState state, FunctionCall function, string? scopeBody = null);
|
public HandlerResult Handle(IZelEngineState state, FunctionCall function, string? scopeBody = null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,17 +1,18 @@
|
|||||||
namespace ZelWiki.Engine.Library.Interfaces
|
namespace ZelWiki.Engine.Library.Interfaces
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles wiki headings. These are automatically added to the table of contents.
|
/// 处理标题
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IHeadingHandler
|
public interface IHeadingHandler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles wiki headings. These are automatically added to the table of contents.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state">Reference to the wiki state object</param>
|
/// <param name="state"></param>
|
||||||
/// <param name="depth">The size of the header, also used for table of table of contents indentation.</param>
|
/// <param name="depth"></param>
|
||||||
/// <param name="link">The self link reference.</param>
|
/// <param name="link"></param>
|
||||||
/// <param name="text">The text for the self link.</param>
|
/// <param name="text"></param>
|
||||||
|
/// <returns></returns>
|
||||||
public HandlerResult Handle(IZelEngineState state, int depth, string link, string text);
|
public HandlerResult Handle(IZelEngineState state, int depth, string link, string text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,19 +3,21 @@
|
|||||||
namespace ZelWiki.Engine.Library.Interfaces
|
namespace ZelWiki.Engine.Library.Interfaces
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles links from one wiki page to another.
|
/// 处理内链
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IInternalLinkHandler
|
public interface IInternalLinkHandler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles an internal wiki link.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state">Reference to the wiki state object</param>
|
/// <param name="state"></param>
|
||||||
/// <param name="pageNavigation">The navigation for the linked page.</param>
|
/// <param name="pageNavigation"></param>
|
||||||
/// <param name="pageName">The name of the page being linked to.</param>
|
/// <param name="pageName"></param>
|
||||||
/// <param name="linkText">The text which should be show in the absence of an image.</param>
|
/// <param name="linkText"></param>
|
||||||
/// <param name="image">The image that should be shown.</param>
|
/// <param name="image"></param>
|
||||||
/// <param name="imageScale">The 0-100 image scale factor for the given image.</param>
|
/// <param name="imageScale"></param>
|
||||||
public HandlerResult Handle(IZelEngineState state, NamespaceNavigation pageNavigation, string pageName, string linkText, string? image, int imageScale);
|
/// <returns></returns>
|
||||||
|
public HandlerResult Handle(IZelEngineState state, NamespaceNavigation pageNavigation, string pageName,
|
||||||
|
string linkText, string? image, int imageScale);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,16 +1,17 @@
|
|||||||
namespace ZelWiki.Engine.Library.Interfaces
|
namespace ZelWiki.Engine.Library.Interfaces
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles basic markup/style instructions like bole, italic, underline, etc.
|
/// 处理基本的标记/样式指令,如粗体、斜体、下划线等.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IMarkupHandler
|
public interface IMarkupHandler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles basic markup instructions like bole, italic, underline, etc.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state">Reference to the wiki state object</param>
|
/// <param name="state"></param>
|
||||||
/// <param name="sequence">The sequence of symbols that were found to denotate this markup instruction,</param>
|
/// <param name="sequence"></param>
|
||||||
/// <param name="scopeBody">The body of text to apply the style to.</param>
|
/// <param name="scopeBody"></param>
|
||||||
|
/// <returns></returns>
|
||||||
public HandlerResult Handle(IZelEngineState state, char sequence, string scopeBody);
|
public HandlerResult Handle(IZelEngineState state, char sequence, string scopeBody);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
namespace ZelWiki.Engine.Library.Interfaces
|
namespace ZelWiki.Engine.Library.Interfaces
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles post-processing function calls.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IPostProcessingFunctionHandler : IFunctionHandler
|
public interface IPostProcessingFunctionHandler : IFunctionHandler
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
namespace ZelWiki.Engine.Library.Interfaces
|
namespace ZelWiki.Engine.Library.Interfaces
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles processing-instruction function calls.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IProcessingInstructionFunctionHandler : IFunctionHandler
|
public interface IProcessingInstructionFunctionHandler : IFunctionHandler
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
namespace ZelWiki.Engine.Library.Interfaces
|
namespace ZelWiki.Engine.Library.Interfaces
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles scope function calls.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IScopeFunctionHandler : IFunctionHandler
|
public interface IScopeFunctionHandler : IFunctionHandler
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
namespace ZelWiki.Engine.Library.Interfaces
|
namespace ZelWiki.Engine.Library.Interfaces
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles standard function calls.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IStandardFunctionHandler : IFunctionHandler
|
public interface IStandardFunctionHandler : IFunctionHandler
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,68 +6,63 @@ namespace ZelWiki.Engine.Library.Interfaces
|
|||||||
{
|
{
|
||||||
public interface IZelEngineState
|
public interface IZelEngineState
|
||||||
{
|
{
|
||||||
#region Parameters.
|
#region 参数
|
||||||
|
|
||||||
ISessionState? Session { get; }
|
public ISessionState? Session { get; }
|
||||||
IQueryCollection QueryString { get; }
|
public IQueryCollection QueryString { get; }
|
||||||
|
public IZelEngine Engine { get; }
|
||||||
IZelEngine Engine { get; }
|
public IPage Page { get; }
|
||||||
IPage Page { get; }
|
public int? Revision { get; }
|
||||||
int? Revision { get; }
|
|
||||||
public HashSet<Constants.WikiMatchType> OmitMatches { get; }
|
public HashSet<Constants.WikiMatchType> OmitMatches { get; }
|
||||||
public int NestDepth { get; } //Used for recursion.
|
public int NestDepth { get; }
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region State.
|
#region 状态
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Custom page title set by a call to @@Title("...")
|
|
||||||
/// </summary>
|
|
||||||
public string? PageTitle { get; set; }
|
public string? PageTitle { get; set; }
|
||||||
|
|
||||||
Dictionary<string, string> Variables { get; }
|
public Dictionary<string, string> Variables { get; }
|
||||||
Dictionary<string, string> Snippets { get; }
|
public Dictionary<string, string> Snippets { get; }
|
||||||
List<string> Tags { get; set; }
|
public List<string> Tags { get; set; }
|
||||||
List<string> ProcessingInstructions { get; }
|
public List<string> ProcessingInstructions { get; }
|
||||||
List<PageReference> OutgoingLinks { get; }
|
public List<PageReference> OutgoingLinks { get; }
|
||||||
List<TableOfContentsTag> TableOfContents { get; }
|
public List<TableOfContentsTag> TableOfContents { get; }
|
||||||
List<string> Headers { get; }
|
public List<string> Headers { get; }
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Results.
|
#region 结果
|
||||||
|
|
||||||
string HtmlResult { get; }
|
public string HtmlResult { get; }
|
||||||
TimeSpan ProcessingTime { get; }
|
public TimeSpan ProcessingTime { get; }
|
||||||
int ErrorCount { get; }
|
public int ErrorCount { get; }
|
||||||
int MatchCount { get; }
|
public int MatchCount { get; }
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used to store values for handlers that needs to survive only a single wiki processing session.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void SetStateValue<T>(string key, T value);
|
public void SetStateValue<T>(string key, T value);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used to get values for handlers that needs to survive only a single wiki processing session.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool TryGetStateValue<T>(string key, [MaybeNullWhen(false)] out T? outValue);
|
public bool TryGetStateValue<T>(string key, [MaybeNullWhen(false)] out T? outValue);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used to get values for handlers that needs to survive only a single wiki processing session.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public T GetStateValue<T>(string key, T defaultValue);
|
public T GetStateValue<T>(string key, T defaultValue);
|
||||||
|
|
||||||
string GetNextQueryToken();
|
string GetNextQueryToken();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Transforms "included" wiki pages, for example if a wiki function
|
///
|
||||||
/// injected additional wiki markup, this 'could' be processed separately.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="page">The child page to process</param>
|
/// <param name="page"></param>
|
||||||
/// <param name="revision">The optional revision of the child page to process</param>
|
/// <param name="revision"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
IZelEngineState TransformChild(IPage page, int? revision = null);
|
IZelEngineState TransformChild(IPage page, int? revision = null);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,23 +2,29 @@
|
|||||||
{
|
{
|
||||||
public class PageReference
|
public class PageReference
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// The name of the page. Such as "Sand Box" or "Some Namespace : SandBox".
|
|
||||||
/// </summary>
|
|
||||||
public string Name { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The namespace part of the Name.
|
|
||||||
/// </summary>
|
|
||||||
public string Namespace { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
/// The cleaned up version of the name, safe for passing in URLs.
|
|
||||||
public string Navigation { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
public PageReference()
|
public PageReference()
|
||||||
{
|
{
|
||||||
|
Name = string.Empty;
|
||||||
|
Namespace = string.Empty;
|
||||||
|
Navigation = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public string Namespace { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public string Navigation { get; set; }
|
||||||
|
|
||||||
|
|
||||||
public override bool Equals(object? obj)
|
public override bool Equals(object? obj)
|
||||||
{
|
{
|
||||||
return obj is PageReference other
|
return obj is PageReference other
|
||||||
@@ -30,6 +36,12 @@
|
|||||||
return Navigation.GetHashCode();
|
return Navigation.GetHashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name"></param>
|
||||||
|
/// <param name="navigation"></param>
|
||||||
|
/// <exception cref="Exception"></exception>
|
||||||
public PageReference(string name, string navigation)
|
public PageReference(string name, string navigation)
|
||||||
{
|
{
|
||||||
var parts = name.Split("::");
|
var parts = name.Split("::");
|
||||||
@@ -45,7 +57,7 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new Exception($"Invalid page name {name}");
|
throw new Exception($"页面名称无效: {name}");
|
||||||
}
|
}
|
||||||
|
|
||||||
Navigation = navigation;
|
Navigation = navigation;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
namespace ZelWiki.Engine.Library
|
namespace ZelWiki.Engine.Library
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Table of contents tag.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class TableOfContentsTag
|
public class TableOfContentsTag
|
||||||
{
|
{
|
||||||
@@ -10,6 +10,13 @@
|
|||||||
public string Text;
|
public string Text;
|
||||||
public int StartingPosition;
|
public int StartingPosition;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="level"></param>
|
||||||
|
/// <param name="startingPosition"></param>
|
||||||
|
/// <param name="hrefTag"></param>
|
||||||
|
/// <param name="text"></param>
|
||||||
public TableOfContentsTag(int level, int startingPosition, string hrefTag, string text)
|
public TableOfContentsTag(int level, int startingPosition, string hrefTag, string text)
|
||||||
{
|
{
|
||||||
Level = level;
|
Level = level;
|
||||||
|
|||||||
@@ -5,18 +5,17 @@ namespace ZelWiki.Engine
|
|||||||
public class WikiMatchSet
|
public class WikiMatchSet
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The type of match that was found.
|
/// 找到的匹配类型.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Constants.WikiMatchType MatchType { get; set; }
|
public Constants.WikiMatchType MatchType { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The resulting content of the wiki processing.
|
/// 内容.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Content { get; set; } = string.Empty;
|
public string Content { get; set; } = string.Empty;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The content in this segment will be wikified. This is useful to disable on things like error messages
|
///
|
||||||
/// and literal blocks where the content may contain valid wiki markup but we want it to display verbatim.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool AllowNestedDecode { get; set; }
|
public bool AllowNestedDecode { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,17 @@
|
|||||||
{
|
{
|
||||||
public class WikiOrderedMatch
|
public class WikiOrderedMatch
|
||||||
{
|
{
|
||||||
public string Value { get; set; } = string.Empty;
|
public WikiOrderedMatch()
|
||||||
|
{
|
||||||
|
Value = string.Empty;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public string Value { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
public int Index { get; set; }
|
public int Index { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
namespace ZelWiki.Engine
|
namespace ZelWiki.Engine
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 一些正则
|
||||||
|
/// </summary>
|
||||||
internal static partial class PrecompiledRegex
|
internal static partial class PrecompiledRegex
|
||||||
{
|
{
|
||||||
[GeneratedRegex("\\#\\{([\\S\\s]*?)\\}\\#", RegexOptions.IgnoreCase)]
|
[GeneratedRegex("\\#\\{([\\S\\s]*?)\\}\\#", RegexOptions.IgnoreCase)]
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ namespace ZelWiki.Engine
|
|||||||
internal static class WikiUtility
|
internal static class WikiUtility
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Skips the namespace and returns just the page name part of the navigation.
|
/// 跳过命名空间,只返回导航的页面名称部分.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="navigation"></param>
|
/// <param name="navigation"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
@@ -50,7 +50,7 @@ namespace ZelWiki.Engine
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a list of symbols where the symbol occurs consecutively, more than once. (e.g. "##This##")
|
/// 获取符号连续出现多次的符号列表. ("##This##")
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="input"></param>
|
/// <param name="input"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ using ZelWiki.Models;
|
|||||||
namespace ZelWiki.Engine
|
namespace ZelWiki.Engine
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tiny wikifier (reduced feature-set) for things like comments and profile bios.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class WikifierLite
|
public class WikifierLite
|
||||||
{
|
{
|
||||||
@@ -17,9 +17,9 @@ namespace ZelWiki.Engine
|
|||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 100; i++) //We don't want to process nested wiki forever.
|
for (var i = 0; i < 100; i++)
|
||||||
{
|
{
|
||||||
bool processedMatches = false;
|
var processedMatches = false;
|
||||||
var matchStore = new Dictionary<string, string>();
|
var matchStore = new Dictionary<string, string>();
|
||||||
|
|
||||||
var content = new WikiString(unprocessedText);
|
var content = new WikiString(unprocessedText);
|
||||||
@@ -75,7 +75,8 @@ namespace ZelWiki.Engine
|
|||||||
{
|
{
|
||||||
if (scale != 100 && scale > 0 && scale <= 500)
|
if (scale != 100 && scale > 0 && scale <= 500)
|
||||||
{
|
{
|
||||||
var emojiImage = $"<img src=\"/file/Emoji/{key.Trim('%')}?Scale={scale}\" alt=\"{emoji?.Name}\" />";
|
var emojiImage =
|
||||||
|
$"<img src=\"/file/Emoji/{key.Trim('%')}?Scale={scale}\" alt=\"{emoji?.Name}\" />";
|
||||||
pageContent.Replace(match.Value, StoreMatch(matchStore, emojiImage));
|
pageContent.Replace(match.Value, StoreMatch(matchStore, emojiImage));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -92,7 +93,7 @@ namespace ZelWiki.Engine
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Transform basic markup such as bold, italics, underline, etc. for single and multi-line.
|
/// 转换单行和多行的基本标记,如粗体、斜体、下划线等.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pageContent"></param>
|
/// <param name="pageContent"></param>
|
||||||
private static void TransformMarkup(WikiString pageContent, Dictionary<string, string> matchStore)
|
private static void TransformMarkup(WikiString pageContent, Dictionary<string, string> matchStore)
|
||||||
@@ -126,12 +127,12 @@ namespace ZelWiki.Engine
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Transform links, these can be internal Wiki links or external links.
|
/// 转换链接,这些链接可以是内部Wiki链接或外部链接.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pageContent"></param>
|
/// <param name="pageContent"></param>
|
||||||
private static void TransformLinks(WikiString pageContent, Dictionary<string, string> matchStore)
|
private static void TransformLinks(WikiString pageContent, Dictionary<string, string> matchStore)
|
||||||
{
|
{
|
||||||
//Parse external explicit links. eg. [[http://test.net]].
|
//解析外部链接 [[http://test.net]].
|
||||||
var rgx = new Regex(@"(\[\[http\:\/\/.+?\]\])", RegexOptions.IgnoreCase);
|
var rgx = new Regex(@"(\[\[http\:\/\/.+?\]\])", RegexOptions.IgnoreCase);
|
||||||
var matches = WikiUtility.OrderMatchesByLengthDescending(rgx.Matches(pageContent.ToString()));
|
var matches = WikiUtility.OrderMatchesByLengthDescending(rgx.Matches(pageContent.ToString()));
|
||||||
foreach (var match in matches)
|
foreach (var match in matches)
|
||||||
@@ -149,7 +150,7 @@ namespace ZelWiki.Engine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Parse external explicit links. eg. [[https://test.net]].
|
//解析外部链接. [[https://test.net]].
|
||||||
rgx = new Regex(@"(\[\[https\:\/\/.+?\]\])", RegexOptions.IgnoreCase);
|
rgx = new Regex(@"(\[\[https\:\/\/.+?\]\])", RegexOptions.IgnoreCase);
|
||||||
matches = WikiUtility.OrderMatchesByLengthDescending(rgx.Matches(pageContent.ToString()));
|
matches = WikiUtility.OrderMatchesByLengthDescending(rgx.Matches(pageContent.ToString()));
|
||||||
foreach (var match in matches)
|
foreach (var match in matches)
|
||||||
@@ -167,7 +168,7 @@ namespace ZelWiki.Engine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Parse internal dynamic links. eg [[AboutUs|About Us]].
|
//解析内部链接 [[AboutUs|About Us]].
|
||||||
rgx = new Regex(@"(\[\[.+?\]\])", RegexOptions.IgnoreCase);
|
rgx = new Regex(@"(\[\[.+?\]\])", RegexOptions.IgnoreCase);
|
||||||
matches = WikiUtility.OrderMatchesByLengthDescending(rgx.Matches(pageContent.ToString()));
|
matches = WikiUtility.OrderMatchesByLengthDescending(rgx.Matches(pageContent.ToString()));
|
||||||
foreach (var match in matches)
|
foreach (var match in matches)
|
||||||
@@ -177,11 +178,13 @@ namespace ZelWiki.Engine
|
|||||||
|
|
||||||
if (args.Count == 1)
|
if (args.Count == 1)
|
||||||
{
|
{
|
||||||
pageContent.Replace(match.Value, StoreMatch(matchStore, $"<a href=\"{GlobalConfiguration.BasePath}/{args[0]}\">{args[0]}</a>"));
|
pageContent.Replace(match.Value,
|
||||||
|
StoreMatch(matchStore, $"<a href=\"{GlobalConfiguration.BasePath}/{args[0]}\">{args[0]}</a>"));
|
||||||
}
|
}
|
||||||
else if (args.Count > 1)
|
else if (args.Count > 1)
|
||||||
{
|
{
|
||||||
pageContent.Replace(match.Value, StoreMatch(matchStore, $"<a href=\"{GlobalConfiguration.BasePath}/{args[0]}\">{args[1]}</a>"));
|
pageContent.Replace(match.Value,
|
||||||
|
StoreMatch(matchStore, $"<a href=\"{GlobalConfiguration.BasePath}/{args[0]}\">{args[1]}</a>"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ namespace ZelWiki.Engine
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Transforms the content for the given page.
|
/// 转换给定页面的内容.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="session">The users current state, used for localization.</param>
|
/// <param name="session">The users current state, used for localization.</param>
|
||||||
/// <param name="page">The page that is being processed.</param>
|
/// <param name="page">The page that is being processed.</param>
|
||||||
|
|||||||
@@ -23,12 +23,13 @@ namespace ZelWiki.Engine
|
|||||||
private readonly string _tocName = "TOC_" + new Random().Next(0, 1000000).ToString();
|
private readonly string _tocName = "TOC_" + new Random().Next(0, 1000000).ToString();
|
||||||
private readonly Dictionary<string, object> _handlerState = new();
|
private readonly Dictionary<string, object> _handlerState = new();
|
||||||
|
|
||||||
#region Public properties.
|
#region 公共属性.
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Custom page title set by a call to @@Title("...")
|
/// 通过调用设置自定义页面标题 @@Title("...")
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? PageTitle { get; set; }
|
public string? PageTitle { get; set; }
|
||||||
|
|
||||||
public int ErrorCount { get; private set; }
|
public int ErrorCount { get; private set; }
|
||||||
public int MatchCount { get; private set; }
|
public int MatchCount { get; private set; }
|
||||||
public int TransformIterations { get; private set; }
|
public int TransformIterations { get; private set; }
|
||||||
@@ -45,19 +46,19 @@ namespace ZelWiki.Engine
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Input parameters.
|
#region 入参.
|
||||||
|
|
||||||
public IPage Page { get; }
|
public IPage Page { get; }
|
||||||
public int? Revision { get; }
|
public int? Revision { get; }
|
||||||
public IQueryCollection QueryString { get; }
|
public IQueryCollection QueryString { get; }
|
||||||
public ISessionState? Session { get; }
|
public ISessionState? Session { get; }
|
||||||
public HashSet<Constants.WikiMatchType> OmitMatches { get; private set; } = new();
|
public HashSet<Constants.WikiMatchType> OmitMatches { get; private set; } = new();
|
||||||
public int NestDepth { get; private set; } //Used for recursion.
|
public int NestDepth { get; private set; } //用于递归
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used to store values for handlers that needs to survive only a single wiki processing session.
|
/// 存储只需要在单个wiki处理会话中生存的处理程序的值.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void SetStateValue<T>(string key, T value)
|
public void SetStateValue<T>(string key, T value)
|
||||||
{
|
{
|
||||||
@@ -65,11 +66,12 @@ namespace ZelWiki.Engine
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_handlerState[key] = value;
|
_handlerState[key] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used to get values for handlers that needs to survive only a single wiki processing session.
|
/// 获取只需要在单个处理会话中生存的处理程序的值.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public T GetStateValue<T>(string key, T defaultValue)
|
public T GetStateValue<T>(string key, T defaultValue)
|
||||||
{
|
{
|
||||||
@@ -77,12 +79,13 @@ namespace ZelWiki.Engine
|
|||||||
{
|
{
|
||||||
return (T)value;
|
return (T)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetStateValue(key, defaultValue);
|
SetStateValue(key, defaultValue);
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used to get values for handlers that needs to survive only a single wiki processing session.
|
/// 尝试获取只需要在单个处理会话中生存的处理程序的值..
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool TryGetStateValue<T>(string key, [MaybeNullWhen(false)] out T? outValue)
|
public bool TryGetStateValue<T>(string key, [MaybeNullWhen(false)] out T? outValue)
|
||||||
{
|
{
|
||||||
@@ -97,13 +100,14 @@ namespace ZelWiki.Engine
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of the ZelEngineState class. Typically created by a call to ZelEngine.Transform().
|
/// 创建一个实例
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="session">The users current state, used for localization.</param>
|
/// <param name="engine"></param>
|
||||||
/// <param name="page">The page that is being processed.</param>
|
/// <param name="session"></param>
|
||||||
/// <param name="revision">The revision of the page that is being processed.</param>
|
/// <param name="page"></param>
|
||||||
/// <param name="omitMatches">The type of matches that we want to omit from processing.</param>
|
/// <param name="revision"></param>
|
||||||
/// <param name="nestDepth">The current depth of recursion.</param>
|
/// <param name="omitMatches"></param>
|
||||||
|
/// <param name="nestDepth"></param>
|
||||||
internal ZelEngineState(IZelEngine engine, ISessionState? session,
|
internal ZelEngineState(IZelEngine engine, ISessionState? session,
|
||||||
IPage page, int? revision = null, Constants.WikiMatchType[]? omitMatches = null, int nestDepth = 0)
|
IPage page, int? revision = null, Constants.WikiMatchType[]? omitMatches = null, int nestDepth = 0)
|
||||||
{
|
{
|
||||||
@@ -123,15 +127,15 @@ namespace ZelWiki.Engine
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Transforms "included" wiki pages, for example if a wiki function
|
///
|
||||||
/// injected additional wiki markup, this 'could' be processed separately.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="page">The child page to process</param>
|
/// <param name="page"></param>
|
||||||
/// <param name="revision">The optional revision of the child page to process</param>
|
/// <param name="revision"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public IZelEngineState TransformChild(IPage page, int? revision = null)
|
public IZelEngineState TransformChild(IPage page, int? revision = null)
|
||||||
{
|
{
|
||||||
return new ZelEngineState(Engine, Session, page, revision, OmitMatches.ToArray(), NestDepth + 1).Transform();
|
return new ZelEngineState(Engine, Session, page, revision, OmitMatches.ToArray(), NestDepth + 1)
|
||||||
|
.Transform();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal IZelEngineState Transform()
|
internal IZelEngineState Transform()
|
||||||
@@ -169,21 +173,15 @@ namespace ZelWiki.Engine
|
|||||||
foreach (var v in Matches)
|
foreach (var v in Matches)
|
||||||
{
|
{
|
||||||
if (OmitMatches.Contains(v.Value.MatchType))
|
if (OmitMatches.Contains(v.Value.MatchType))
|
||||||
{
|
|
||||||
/// When matches are omitted, the entire match will be removed from the resulting wiki text.
|
|
||||||
pageContent.Replace(v.Key, string.Empty);
|
pageContent.Replace(v.Key, string.Empty);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
pageContent.Replace(v.Key, v.Value.Content);
|
pageContent.Replace(v.Key, v.Value.Content);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} while (length != pageContent.Length);
|
} while (length != pageContent.Length);
|
||||||
|
|
||||||
pageContent.Replace(SoftBreak, "\r\n");
|
pageContent.Replace(SoftBreak, "\r\n");
|
||||||
pageContent.Replace(HardBreak, "<br />");
|
pageContent.Replace(HardBreak, "<br />");
|
||||||
|
|
||||||
//Prepend any headers that were added by wiki handlers.
|
|
||||||
foreach (var header in Headers)
|
foreach (var header in Headers)
|
||||||
{
|
{
|
||||||
pageContent.Insert(0, header);
|
pageContent.Insert(0, header);
|
||||||
@@ -223,7 +221,6 @@ namespace ZelWiki.Engine
|
|||||||
TransformStandardFunctions(pageContent, false);
|
TransformStandardFunctions(pageContent, false);
|
||||||
TransformProcessingInstructionFunctions(pageContent);
|
TransformProcessingInstructionFunctions(pageContent);
|
||||||
|
|
||||||
//We have to replace a few times because we could have replace tags (guids) nested inside others.
|
|
||||||
int length;
|
int length;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@@ -233,15 +230,10 @@ namespace ZelWiki.Engine
|
|||||||
if (v.Value.AllowNestedDecode)
|
if (v.Value.AllowNestedDecode)
|
||||||
{
|
{
|
||||||
if (OmitMatches.Contains(v.Value.MatchType))
|
if (OmitMatches.Contains(v.Value.MatchType))
|
||||||
{
|
|
||||||
/// When matches are omitted, the entire match will be removed from the resulting wiki text.
|
|
||||||
pageContent.Replace(v.Key, string.Empty);
|
pageContent.Replace(v.Key, string.Empty);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pageContent.Replace(v.Key, v.Value.Content);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
else
|
||||||
|
pageContent.Replace(v.Key, v.Value.Content);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (length != pageContent.Length);
|
} while (length != pageContent.Length);
|
||||||
@@ -250,7 +242,7 @@ namespace ZelWiki.Engine
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Transform basic markup such as bold, italics, underline, etc. for single and multi-line.
|
/// 转换单行和多行的基本标记,如粗体、斜体、下划线等.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pageContent"></param>
|
/// <param name="pageContent"></param>
|
||||||
private void TransformMarkup(WikiString pageContent)
|
private void TransformMarkup(WikiString pageContent)
|
||||||
@@ -270,7 +262,8 @@ namespace ZelWiki.Engine
|
|||||||
|
|
||||||
var result = Engine.MarkupHandler.Handle(this, symbol, body);
|
var result = Engine.MarkupHandler.Handle(this, symbol, body);
|
||||||
|
|
||||||
StoreHandlerResult(result, Constants.WikiMatchType.Markup, pageContent, match.Value, result.Content);
|
StoreHandlerResult(result, WikiMatchType.Markup, pageContent, match.Value,
|
||||||
|
result.Content);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,15 +272,17 @@ namespace ZelWiki.Engine
|
|||||||
|
|
||||||
foreach (var match in sizeUpOrderedMatches)
|
foreach (var match in sizeUpOrderedMatches)
|
||||||
{
|
{
|
||||||
int headingMarkers = 0;
|
var headingMarkers = 0;
|
||||||
foreach (char c in match.Value)
|
foreach (char c in match.Value)
|
||||||
{
|
{
|
||||||
if (c != '^')
|
if (c != '^')
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
headingMarkers++;
|
headingMarkers++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (headingMarkers >= 2 && headingMarkers <= 6)
|
if (headingMarkers >= 2 && headingMarkers <= 6)
|
||||||
{
|
{
|
||||||
string value = match.Value.Substring(headingMarkers, match.Value.Length - headingMarkers).Trim();
|
string value = match.Value.Substring(headingMarkers, match.Value.Length - headingMarkers).Trim();
|
||||||
@@ -295,44 +290,43 @@ namespace ZelWiki.Engine
|
|||||||
int fontSize = 1 + headingMarkers;
|
int fontSize = 1 + headingMarkers;
|
||||||
if (fontSize < 1) fontSize = 1;
|
if (fontSize < 1) fontSize = 1;
|
||||||
|
|
||||||
string markup = "<font size=\"" + fontSize + "\">" + value + "</font>\r\n";
|
var markup = "<font size=\"" + fontSize + "\">" + value + "</font>\r\n";
|
||||||
StoreMatch(Constants.WikiMatchType.Markup, pageContent, match.Value, markup);
|
StoreMatch(WikiMatchType.Markup, pageContent, match.Value, markup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Transform inline and multi-line literal blocks. These are blocks where the content will not be wikified and contain code that is encoded to display verbatim on the page.
|
/// 转换内联和多行文字块
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pageContent"></param>
|
/// <param name="pageContent"></param>
|
||||||
private void TransformLiterals(WikiString pageContent)
|
private void TransformLiterals(WikiString pageContent)
|
||||||
{
|
{
|
||||||
//TODO: May need to do the same thing we did with TransformBlocks() to match all these if they need to be nested.
|
|
||||||
|
|
||||||
//Transform literal strings, even encodes HTML so that it displays verbatim.
|
|
||||||
var orderedMatches = WikiUtility.OrderMatchesByLengthDescending(
|
var orderedMatches = WikiUtility.OrderMatchesByLengthDescending(
|
||||||
PrecompiledRegex.TransformLiterals().Matches(pageContent.ToString()));
|
PrecompiledRegex.TransformLiterals().Matches(pageContent.ToString()));
|
||||||
|
|
||||||
foreach (var match in orderedMatches)
|
foreach (var match in orderedMatches)
|
||||||
{
|
{
|
||||||
string value = match.Value.Substring(2, match.Value.Length - 4);
|
var value = match.Value.Substring(2, match.Value.Length - 4);
|
||||||
value = HttpUtility.HtmlEncode(value);
|
value = HttpUtility.HtmlEncode(value);
|
||||||
StoreMatch(Constants.WikiMatchType.Literal, pageContent, match.Value, value.Replace("\r", "").Trim().Replace("\n", "<br />\r\n"), false);
|
StoreMatch(WikiMatchType.Literal, pageContent, match.Value,
|
||||||
|
value.Replace("\r", "").Trim().Replace("\n", "<br />\r\n"), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Matching nested blocks with regex was hell, I escaped with a loop. ¯\_(ツ)_/¯
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pageContent"></param>
|
/// <param name="pageContent"></param>
|
||||||
private void TransformScopeFunctions(WikiString pageContent)
|
private void TransformScopeFunctions(WikiString pageContent)
|
||||||
{
|
{
|
||||||
var content = pageContent.ToString();
|
var content = pageContent.ToString();
|
||||||
|
|
||||||
string rawBlock = string.Empty;
|
var rawBlock = string.Empty;
|
||||||
|
|
||||||
int startPos = content.Length - 1;
|
var startPos = content.Length - 1;
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
@@ -341,18 +335,24 @@ namespace ZelWiki.Engine
|
|||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
int endPos = content.IndexOf("}}", startPos);
|
int endPos = content.IndexOf("}}", startPos);
|
||||||
|
|
||||||
if (endPos < 0 || endPos < startPos)
|
if (endPos < 0 || endPos < startPos)
|
||||||
{
|
{
|
||||||
var exception = new StringBuilder();
|
var exception = new StringBuilder();
|
||||||
exception.AppendLine($"<strong>A parsing error occurred after position {startPos}:<br /></strong> Unable to locate closing tag.<br /><br />");
|
exception.AppendLine(
|
||||||
|
$"<strong>定位后发生解析错误 {startPos}:<br /></strong> 无法找到结束标记.<br /><br />");
|
||||||
if (rawBlock?.Length > 0)
|
if (rawBlock?.Length > 0)
|
||||||
{
|
{
|
||||||
exception.AppendLine($"<strong>The last successfully parsed block was:</strong><br /> {rawBlock}");
|
exception.AppendLine(
|
||||||
|
$"<strong>最后一个成功解析的块是:</strong><br /> {rawBlock}");
|
||||||
}
|
}
|
||||||
exception.AppendLine($"<strong>The problem occurred after:</strong><br /> {pageContent.ToString().Substring(startPos)}<br /><br />");
|
|
||||||
exception.AppendLine($"<strong>The content the parser was working on is:</strong><br /> {pageContent}<br /><br />");
|
exception.AppendLine(
|
||||||
|
$"<strong>问题发生在:</strong><br /> {pageContent.ToString().Substring(startPos)}<br /><br />");
|
||||||
|
exception.AppendLine(
|
||||||
|
$"<strong>解析器正在处理的内容是:</strong><br /> {pageContent}<br /><br />");
|
||||||
|
|
||||||
throw new Exception(exception.ToString());
|
throw new Exception(exception.ToString());
|
||||||
}
|
}
|
||||||
@@ -369,10 +369,10 @@ namespace ZelWiki.Engine
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Transform blocks or sections of code, these are thinks like panels and alerts.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pageContent"></param>
|
/// <param name="pageContent"></param>
|
||||||
/// <param name="isFirstChance">Only process early functions (like code blocks)</param>
|
/// <param name="isFirstChance"></param>
|
||||||
private void TransformScopeFunctions(WikiString pageContent, bool isFirstChance)
|
private void TransformScopeFunctions(WikiString pageContent, bool isFirstChance)
|
||||||
{
|
{
|
||||||
// {{([\\S\\s]*)}}
|
// {{([\\S\\s]*)}}
|
||||||
@@ -387,14 +387,14 @@ namespace ZelWiki.Engine
|
|||||||
|
|
||||||
FunctionCall function;
|
FunctionCall function;
|
||||||
|
|
||||||
//We are going to mock up a function call:
|
|
||||||
string mockFunctionCall = "##" + match.Value.Trim([' ', '\t', '{', '}']);
|
string mockFunctionCall = "##" + match.Value.Trim([' ', '\t', '{', '}']);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
function = FunctionParser.ParseAndGetFunctionCall(functionHandler.Prototypes, mockFunctionCall, out paramEndIndex);
|
function = FunctionParser.ParseAndGetFunctionCall(functionHandler.Prototypes, mockFunctionCall,
|
||||||
|
out paramEndIndex);
|
||||||
|
|
||||||
var firstChanceFunctions = new string[] { "code" }; //Process these the first time through.
|
var firstChanceFunctions = new [] { "code" };
|
||||||
if (isFirstChance && firstChanceFunctions.Contains(function.Name.ToLower()) == false)
|
if (isFirstChance && firstChanceFunctions.Contains(function.Name.ToLower()) == false)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@@ -411,7 +411,8 @@ namespace ZelWiki.Engine
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = functionHandler.Handle(this, function, scopeBody);
|
var result = functionHandler.Handle(this, function, scopeBody);
|
||||||
StoreHandlerResult(result, Constants.WikiMatchType.ScopeFunction, pageContent, match.Value, scopeBody);
|
StoreHandlerResult(result, WikiMatchType.ScopeFunction, pageContent, match.Value,
|
||||||
|
scopeBody);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -421,7 +422,7 @@ namespace ZelWiki.Engine
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Transform headings. These are the basic HTML H1-H6 headings but they are saved for the building of the table of contents.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pageContent"></param>
|
/// <param name="pageContent"></param>
|
||||||
private void TransformHeadings(WikiString pageContent)
|
private void TransformHeadings(WikiString pageContent)
|
||||||
@@ -431,28 +432,32 @@ namespace ZelWiki.Engine
|
|||||||
|
|
||||||
foreach (var match in orderedMatches)
|
foreach (var match in orderedMatches)
|
||||||
{
|
{
|
||||||
int headingMarkers = 0;
|
var headingMarkers = 0;
|
||||||
foreach (char c in match.Value)
|
foreach (var c in match.Value)
|
||||||
{
|
{
|
||||||
if (c != '=')
|
if (c != '=')
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
headingMarkers++;
|
headingMarkers++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (headingMarkers >= 2)
|
if (headingMarkers >= 2)
|
||||||
{
|
{
|
||||||
string link = _tocName + "_" + TableOfContents.Count.ToString();
|
var link = _tocName + "_" + TableOfContents.Count.ToString();
|
||||||
string text = match.Value.Substring(headingMarkers, match.Value.Length - headingMarkers).Trim().Trim(['=']).Trim();
|
var text = match.Value.Substring(headingMarkers, match.Value.Length - headingMarkers).Trim()
|
||||||
|
.Trim(['=']).Trim();
|
||||||
|
|
||||||
var result = Engine.HeadingHandler.Handle(this, headingMarkers, link, text);
|
var result = Engine.HeadingHandler.Handle(this, headingMarkers, link, text);
|
||||||
|
|
||||||
if (!result.Instructions.Contains(Constants.HandlerResultInstruction.Skip))
|
if (!result.Instructions.Contains(HandlerResultInstruction.Skip))
|
||||||
{
|
{
|
||||||
TableOfContents.Add(new TableOfContentsTag(headingMarkers - 1, match.Index, link, text));
|
TableOfContents.Add(new TableOfContentsTag(headingMarkers - 1, match.Index, link, text));
|
||||||
}
|
}
|
||||||
|
|
||||||
StoreHandlerResult(result, Constants.WikiMatchType.Heading, pageContent, match.Value, result.Content);
|
StoreHandlerResult(result, WikiMatchType.Heading, pageContent, match.Value,
|
||||||
|
result.Content);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -465,7 +470,7 @@ namespace ZelWiki.Engine
|
|||||||
foreach (var match in orderedMatches)
|
foreach (var match in orderedMatches)
|
||||||
{
|
{
|
||||||
var result = Engine.CommentHandler.Handle(this, match.Value);
|
var result = Engine.CommentHandler.Handle(this, match.Value);
|
||||||
StoreHandlerResult(result, Constants.WikiMatchType.Comment, pageContent, match.Value, result.Content);
|
StoreHandlerResult(result, WikiMatchType.Comment, pageContent, match.Value, result.Content);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -476,23 +481,23 @@ namespace ZelWiki.Engine
|
|||||||
|
|
||||||
foreach (var match in orderedMatches)
|
foreach (var match in orderedMatches)
|
||||||
{
|
{
|
||||||
string key = match.Value.Trim().ToLower().Trim('%');
|
var key = match.Value.Trim().ToLower().Trim('%');
|
||||||
int scale = 100;
|
var scale = 100;
|
||||||
|
|
||||||
var parts = key.Split(',');
|
var parts = key.Split(',');
|
||||||
if (parts.Length > 1)
|
if (parts.Length > 1)
|
||||||
{
|
{
|
||||||
key = parts[0]; //Image key;
|
key = parts[0];
|
||||||
scale = int.Parse(parts[1]); //Image scale.
|
scale = int.Parse(parts[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = Engine.EmojiHandler.Handle(this, $"%%{key}%%", scale);
|
var result = Engine.EmojiHandler.Handle(this, $"%%{key}%%", scale);
|
||||||
StoreHandlerResult(result, Constants.WikiMatchType.Emoji, pageContent, match.Value, result.Content);
|
StoreHandlerResult(result, WikiMatchType.Emoji, pageContent, match.Value, result.Content);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Transform variables.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pageContent"></param>
|
/// <param name="pageContent"></param>
|
||||||
private void TransformVariables(WikiString pageContent)
|
private void TransformVariables(WikiString pageContent)
|
||||||
@@ -502,7 +507,7 @@ namespace ZelWiki.Engine
|
|||||||
|
|
||||||
foreach (var match in orderedMatches)
|
foreach (var match in orderedMatches)
|
||||||
{
|
{
|
||||||
string key = match.Value.Trim(['{', '}', ' ', '\t', '$']);
|
var key = match.Value.Trim(['{', '}', ' ', '\t', '$']);
|
||||||
if (key.Contains("="))
|
if (key.Contains("="))
|
||||||
{
|
{
|
||||||
var sections = key.Split('=');
|
var sections = key.Split('=');
|
||||||
@@ -514,27 +519,27 @@ namespace ZelWiki.Engine
|
|||||||
Variables[key] = value;
|
Variables[key] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
var identifier = StoreMatch(Constants.WikiMatchType.Variable, pageContent, match.Value, "");
|
var identifier = StoreMatch(WikiMatchType.Variable, pageContent, match.Value, "");
|
||||||
pageContent.Replace($"{identifier}\n", $"{identifier}"); //Kill trailing newline.
|
pageContent.Replace($"{identifier}\n", $"{identifier}"); //Kill trailing newline.
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (Variables.TryGetValue(key, out string? value))
|
if (Variables.TryGetValue(key, out string? value))
|
||||||
{
|
{
|
||||||
var identifier = StoreMatch(Constants.WikiMatchType.Variable, pageContent, match.Value, value);
|
var identifier = StoreMatch(WikiMatchType.Variable, pageContent, match.Value, value);
|
||||||
pageContent.Replace($"{identifier}\n", $"{identifier}"); //Kill trailing newline.
|
pageContent.Replace($"{identifier}\n", $"{identifier}"); //Kill trailing newline.
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new Exception($"The wiki variable {key} is not defined. It should be set with ##Set() before calling Get().");
|
throw new Exception(
|
||||||
|
$"未定义的变量 {key} . 在再用Get()应该先使用##Set().");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Transform links, these can be internal Wiki links or external links.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pageContent"></param>
|
/// <param name="pageContent"></param>
|
||||||
private void TransformLinks(WikiString pageContent)
|
private void TransformLinks(WikiString pageContent)
|
||||||
@@ -572,7 +577,6 @@ namespace ZelWiki.Engine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Parse external explicit links. eg. [[https://test.net]].
|
|
||||||
orderedMatches = WikiUtility.OrderMatchesByLengthDescending(
|
orderedMatches = WikiUtility.OrderMatchesByLengthDescending(
|
||||||
PrecompiledRegex.TransformExplicitHTTPsLinks().Matches(pageContent.ToString()));
|
PrecompiledRegex.TransformExplicitHTTPsLinks().Matches(pageContent.ToString()));
|
||||||
|
|
||||||
@@ -605,7 +609,6 @@ namespace ZelWiki.Engine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Parse internal links. eg [[About Us]], [[About Us, Learn about us]], etc..
|
|
||||||
orderedMatches = WikiUtility.OrderMatchesByLengthDescending(
|
orderedMatches = WikiUtility.OrderMatchesByLengthDescending(
|
||||||
PrecompiledRegex.TransformInternalDynamicLinks().Matches(pageContent.ToString()));
|
PrecompiledRegex.TransformInternalDynamicLinks().Matches(pageContent.ToString()));
|
||||||
|
|
||||||
@@ -622,29 +625,26 @@ namespace ZelWiki.Engine
|
|||||||
|
|
||||||
if (args.Count == 1)
|
if (args.Count == 1)
|
||||||
{
|
{
|
||||||
//Page navigation only.
|
text = WikiUtility.GetPageNamePart(args[0]);
|
||||||
text = WikiUtility.GetPageNamePart(args[0]); //Text will be page name since we have an image.
|
|
||||||
pageName = args[0];
|
pageName = args[0];
|
||||||
}
|
}
|
||||||
else if (args.Count >= 2)
|
else if (args.Count >= 2)
|
||||||
{
|
{
|
||||||
//Page navigation and explicit text (possibly image).
|
|
||||||
pageName = args[0];
|
pageName = args[0];
|
||||||
|
|
||||||
string imageTag = "image:";
|
string imageTag = "image:";
|
||||||
if (args[1].StartsWith(imageTag, StringComparison.CurrentCultureIgnoreCase))
|
if (args[1].StartsWith(imageTag, StringComparison.CurrentCultureIgnoreCase))
|
||||||
{
|
{
|
||||||
image = args[1].Substring(imageTag.Length).Trim();
|
image = args[1].Substring(imageTag.Length).Trim();
|
||||||
text = WikiUtility.GetPageNamePart(args[0]); //Text will be page name since we have an image.
|
text = WikiUtility.GetPageNamePart(args[0]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
text = args[1]; //Explicit text.
|
text = args[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.Count >= 3)
|
if (args.Count >= 3)
|
||||||
{
|
{
|
||||||
//Get the specified image scale.
|
|
||||||
if (int.TryParse(args[2], out imageScale) == false)
|
if (int.TryParse(args[2], out imageScale) == false)
|
||||||
{
|
{
|
||||||
imageScale = 100;
|
imageScale = 100;
|
||||||
@@ -659,32 +659,24 @@ namespace ZelWiki.Engine
|
|||||||
|
|
||||||
var pageNavigation = new NamespaceNavigation(pageName);
|
var pageNavigation = new NamespaceNavigation(pageName);
|
||||||
|
|
||||||
if (pageName.Trim().StartsWith("::"))
|
|
||||||
{
|
|
||||||
//The user explicitly specified the root (unnamed) namespace.
|
|
||||||
}
|
|
||||||
else if (string.IsNullOrEmpty(pageNavigation.Namespace))
|
|
||||||
{
|
|
||||||
//No namespace was specified, use the current page namespace.
|
|
||||||
pageNavigation.Namespace = Page.Namespace;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//Use the namespace that the user explicitly specified.
|
|
||||||
}
|
|
||||||
|
|
||||||
var result = Engine.InternalLinkHandler.Handle(this, pageNavigation, pageName.Trim(':'), text, image, imageScale);
|
if (string.IsNullOrEmpty(pageNavigation.Namespace) || pageName.Trim().StartsWith("::"))
|
||||||
if (!result.Instructions.Contains(Constants.HandlerResultInstruction.Skip))
|
pageNavigation.Namespace = Page.Namespace;
|
||||||
|
|
||||||
|
|
||||||
|
var result = Engine.InternalLinkHandler.Handle(this, pageNavigation, pageName.Trim(':'), text, image,
|
||||||
|
imageScale);
|
||||||
|
if (!result.Instructions.Contains(HandlerResultInstruction.Skip))
|
||||||
{
|
{
|
||||||
OutgoingLinks.Add(new PageReference(pageName, pageNavigation.Canonical));
|
OutgoingLinks.Add(new PageReference(pageName, pageNavigation.Canonical));
|
||||||
}
|
}
|
||||||
|
|
||||||
StoreHandlerResult(result, Constants.WikiMatchType.Link, pageContent, match.Value, string.Empty);
|
StoreHandlerResult(result, WikiMatchType.Link, pageContent, match.Value, string.Empty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Transform processing instructions are used to flag pages for specific needs such as deletion, review, draft, etc.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pageContent"></param>
|
/// <param name="pageContent"></param>
|
||||||
private void TransformProcessingInstructionFunctions(WikiString pageContent)
|
private void TransformProcessingInstructionFunctions(WikiString pageContent)
|
||||||
@@ -701,7 +693,8 @@ namespace ZelWiki.Engine
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
function = FunctionParser.ParseAndGetFunctionCall(functionHandler.Prototypes, match.Value, out int matchEndIndex);
|
function = FunctionParser.ParseAndGetFunctionCall(functionHandler.Prototypes, match.Value,
|
||||||
|
out int matchEndIndex);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -712,7 +705,8 @@ namespace ZelWiki.Engine
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = functionHandler.Handle(this, function, string.Empty);
|
var result = functionHandler.Handle(this, function, string.Empty);
|
||||||
StoreHandlerResult(result, Constants.WikiMatchType.Instruction, pageContent, match.Value, string.Empty);
|
StoreHandlerResult(result, Constants.WikiMatchType.Instruction, pageContent, match.Value,
|
||||||
|
string.Empty);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -722,9 +716,10 @@ namespace ZelWiki.Engine
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Transform functions is used to call wiki functions such as including template pages, setting tags and displaying images.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pageContent"></param>
|
/// <param name="pageContent"></param>
|
||||||
|
/// <param name="isFirstChance"></param>
|
||||||
private void TransformStandardFunctions(WikiString pageContent, bool isFirstChance)
|
private void TransformStandardFunctions(WikiString pageContent, bool isFirstChance)
|
||||||
{
|
{
|
||||||
//Remove the last "(\#\#[\w-]+)" if you start to have matching problems:
|
//Remove the last "(\#\#[\w-]+)" if you start to have matching problems:
|
||||||
@@ -739,7 +734,8 @@ namespace ZelWiki.Engine
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
function = FunctionParser.ParseAndGetFunctionCall(functionHandler.Prototypes, match.Value, out int matchEndIndex);
|
function = FunctionParser.ParseAndGetFunctionCall(functionHandler.Prototypes, match.Value,
|
||||||
|
out int matchEndIndex);
|
||||||
}
|
}
|
||||||
catch (WikiFunctionPrototypeNotDefinedException ex)
|
catch (WikiFunctionPrototypeNotDefinedException ex)
|
||||||
{
|
{
|
||||||
@@ -753,6 +749,7 @@ namespace ZelWiki.Engine
|
|||||||
continue; //This IS a function, but it is meant to be parsed at the end of processing.
|
continue; //This IS a function, but it is meant to be parsed at the end of processing.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StoreError(pageContent, match.Value, ex.Message);
|
StoreError(pageContent, match.Value, ex.Message);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -771,7 +768,8 @@ namespace ZelWiki.Engine
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = functionHandler.Handle(this, function, string.Empty);
|
var result = functionHandler.Handle(this, function, string.Empty);
|
||||||
StoreHandlerResult(result, Constants.WikiMatchType.StandardFunction, pageContent, match.Value, string.Empty);
|
StoreHandlerResult(result, Constants.WikiMatchType.StandardFunction, pageContent, match.Value,
|
||||||
|
string.Empty);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -781,8 +779,9 @@ namespace ZelWiki.Engine
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Transform post-process are functions that must be called after all other transformations. For example, we can't build a table-of-contents until we have parsed the entire page.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="pageContent"></param>
|
||||||
private void TransformPostProcessingFunctions(WikiString pageContent)
|
private void TransformPostProcessingFunctions(WikiString pageContent)
|
||||||
{
|
{
|
||||||
//Remove the last "(\#\#[\w-]+)" if you start to have matching problems:
|
//Remove the last "(\#\#[\w-]+)" if you start to have matching problems:
|
||||||
@@ -797,7 +796,8 @@ namespace ZelWiki.Engine
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
function = FunctionParser.ParseAndGetFunctionCall(functionHandler.Prototypes, match.Value, out int matchEndIndex);
|
function = FunctionParser.ParseAndGetFunctionCall(functionHandler.Prototypes, match.Value,
|
||||||
|
out int matchEndIndex);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -808,7 +808,8 @@ namespace ZelWiki.Engine
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = functionHandler.Handle(this, function, string.Empty);
|
var result = functionHandler.Handle(this, function, string.Empty);
|
||||||
StoreHandlerResult(result, Constants.WikiMatchType.StandardFunction, pageContent, match.Value, string.Empty);
|
StoreHandlerResult(result, Constants.WikiMatchType.StandardFunction, pageContent, match.Value,
|
||||||
|
string.Empty);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -821,33 +822,31 @@ namespace ZelWiki.Engine
|
|||||||
{
|
{
|
||||||
string identifier = $"<!--{Guid.NewGuid()}-->";
|
string identifier = $"<!--{Guid.NewGuid()}-->";
|
||||||
|
|
||||||
//Replace new-lines with single character new line:
|
|
||||||
pageContent.Replace("\r\n", "\n");
|
pageContent.Replace("\r\n", "\n");
|
||||||
|
|
||||||
//Replace new-lines with an identifier so we can identify the places we are going to introduce line-breaks:
|
|
||||||
pageContent.Replace("\n", identifier);
|
pageContent.Replace("\n", identifier);
|
||||||
|
|
||||||
//Replace any consecutive to-be-line-breaks that we are introducing with single line-break identifiers.
|
|
||||||
pageContent.Replace($"{identifier}{identifier}", identifier);
|
pageContent.Replace($"{identifier}{identifier}", identifier);
|
||||||
|
|
||||||
//Swap in the real line-breaks.
|
|
||||||
pageContent.Replace(identifier, "<br />");
|
pageContent.Replace(identifier, "<br />");
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Utility.
|
#region Utility.
|
||||||
|
|
||||||
private void StoreHandlerResult(HandlerResult result, Constants.WikiMatchType matchType, WikiString pageContent, string matchValue, string scopeBody)
|
private void StoreHandlerResult(HandlerResult result, WikiMatchType matchType, WikiString pageContent,
|
||||||
|
string matchValue, string scopeBody)
|
||||||
{
|
{
|
||||||
if (result.Instructions.Contains(Constants.HandlerResultInstruction.Skip))
|
if (result.Instructions.Contains(HandlerResultInstruction.Skip))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool allowNestedDecode = !result.Instructions.Contains(Constants.HandlerResultInstruction.DisallowNestedProcessing);
|
bool allowNestedDecode =
|
||||||
|
!result.Instructions.Contains(HandlerResultInstruction.DisallowNestedProcessing);
|
||||||
|
|
||||||
string identifier;
|
string identifier;
|
||||||
|
|
||||||
if (result.Instructions.Contains(Constants.HandlerResultInstruction.OnlyReplaceFirstMatch))
|
if (result.Instructions.Contains(HandlerResultInstruction.OnlyReplaceFirstMatch))
|
||||||
{
|
{
|
||||||
identifier = StoreFirstMatch(matchType, pageContent, matchValue, result.Content, allowNestedDecode);
|
identifier = StoreFirstMatch(matchType, pageContent, matchValue, result.Content, allowNestedDecode);
|
||||||
}
|
}
|
||||||
@@ -860,7 +859,7 @@ namespace ZelWiki.Engine
|
|||||||
{
|
{
|
||||||
switch (instruction)
|
switch (instruction)
|
||||||
{
|
{
|
||||||
case Constants.HandlerResultInstruction.TruncateTrailingLine:
|
case HandlerResultInstruction.TruncateTrailingLine:
|
||||||
pageContent.Replace($"{identifier}\n", $"{identifier}"); //Kill trailing newline.
|
pageContent.Replace($"{identifier}\n", $"{identifier}"); //Kill trailing newline.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -888,7 +887,7 @@ namespace ZelWiki.Engine
|
|||||||
{
|
{
|
||||||
Content = $"<i><font size=\"3\" color=\"#BB0000\">{{{value}}}</font></a>",
|
Content = $"<i><font size=\"3\" color=\"#BB0000\">{{{value}}}</font></a>",
|
||||||
AllowNestedDecode = false,
|
AllowNestedDecode = false,
|
||||||
MatchType = Constants.WikiMatchType.Error
|
MatchType = WikiMatchType.Error
|
||||||
};
|
};
|
||||||
|
|
||||||
Matches.Add(identifier, matchSet);
|
Matches.Add(identifier, matchSet);
|
||||||
@@ -897,7 +896,8 @@ namespace ZelWiki.Engine
|
|||||||
return identifier;
|
return identifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string StoreMatch(Constants.WikiMatchType matchType, WikiString pageContent, string match, string value, bool allowNestedDecode = true)
|
private string StoreMatch(WikiMatchType matchType, WikiString pageContent, string match, string value,
|
||||||
|
bool allowNestedDecode = true)
|
||||||
{
|
{
|
||||||
MatchCount++;
|
MatchCount++;
|
||||||
_matchesStoredPerIteration++;
|
_matchesStoredPerIteration++;
|
||||||
@@ -917,7 +917,8 @@ namespace ZelWiki.Engine
|
|||||||
return identifier;
|
return identifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string StoreFirstMatch(Constants.WikiMatchType matchType, WikiString pageContent, string match, string value, bool allowNestedDecode = true)
|
private string StoreFirstMatch(WikiMatchType matchType, WikiString pageContent, string match,
|
||||||
|
string value, bool allowNestedDecode = true)
|
||||||
{
|
{
|
||||||
MatchCount++;
|
MatchCount++;
|
||||||
_matchesStoredPerIteration++;
|
_matchesStoredPerIteration++;
|
||||||
@@ -940,15 +941,14 @@ namespace ZelWiki.Engine
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used to generate unique and regenerable tokens so different wikification process can identify
|
///
|
||||||
/// their own query strings. For instance, we can have more than one pager on a wiki page, this
|
|
||||||
/// allows each pager to track its own current page in the query string.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public string GetNextQueryToken()
|
public string GetNextQueryToken()
|
||||||
{
|
{
|
||||||
_queryTokenHash = ZelWiki.Security.Helpers.Sha256(ZelWiki.Security.Helpers.EncryptString(ZelWiki.Security.Helpers.MachineKey, _queryTokenHash));
|
_queryTokenHash = Security.Helpers.Sha256(
|
||||||
return $"H{ZelWiki.Security.Helpers.Crc32(_queryTokenHash)}";
|
Security.Helpers.EncryptString(Security.Helpers.MachineKey, _queryTokenHash));
|
||||||
|
return $"H{Security.Helpers.Crc32(_queryTokenHash)}";
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@@ -6,14 +6,14 @@ namespace ZelWiki.Library
|
|||||||
public static class ConfirmActionHelper
|
public static class ConfirmActionHelper
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generates a link that navigates via GET to a "confirm action" page where the yes link is RED, but the NO button is still GREEN.
|
/// 生成一个链接,通过GET导航到“确认操作”页面,其中“是”链接为红色,但“否”按钮仍为绿色。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="message">The message to be displayed.</param>
|
/// <param name="basePath"></param>
|
||||||
/// <param name="linkLabel">the label for the link that will redirect to this confirm action page.</param>
|
/// <param name="message"></param>
|
||||||
/// <param name="controllerURL">The URL which will handle the click of the "yes" or "no" for the confirm action page.</param>
|
/// <param name="linkLabel"></param>
|
||||||
/// <param name="parameter">An optional parameter to pass to the page and controller function.</param>
|
/// <param name="controllerURL"></param>
|
||||||
/// <param name="yesOrDefaultRedirectURL">The URL to redirect to AFTER the controller has been called if the user selected YES (or NO, if the NO link is not specified.</param>
|
/// <param name="yesOrDefaultRedirectURL"></param>
|
||||||
/// <param name="noRedirectURL">The URL to redirect to AFTER the controller has been called if the user selected NO, if not specified, the same link that is provided to yesOrDefaultRedirectURL is used.</param>
|
/// <param name="noRedirectURL"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static string GenerateDangerLink(string basePath, string message, string linkLabel, string controllerURL,
|
public static string GenerateDangerLink(string basePath, string message, string linkLabel, string controllerURL,
|
||||||
string? yesOrDefaultRedirectURL, string? noRedirectURL = null)
|
string? yesOrDefaultRedirectURL, string? noRedirectURL = null)
|
||||||
@@ -30,18 +30,19 @@ namespace ZelWiki.Library
|
|||||||
param.Append($"&Message={Uri.EscapeDataString(message)}");
|
param.Append($"&Message={Uri.EscapeDataString(message)}");
|
||||||
param.Append($"&Style=Danger");
|
param.Append($"&Style=Danger");
|
||||||
|
|
||||||
return $"<a class=\"btn btn-danger btn-thin\" href=\"{basePath}/Utility/ConfirmAction?{param}\">{linkLabel}</a>";
|
return
|
||||||
|
$"<a class=\"btn btn-danger btn-thin\" href=\"{basePath}/Utility/ConfirmAction?{param}\">{linkLabel}</a>";
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generates a link that navigates via GET to a "confirm action" page where the yes link is GREEN.
|
/// 生成一个链接,通过GET导航到“确认操作”页面,其中“是”链接为绿色。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="message">The message to be displayed.</param>
|
/// <param name="basePath"></param>
|
||||||
/// <param name="linkLabel">the label for the link that will redirect to this confirm action page.</param>
|
/// <param name="message"></param>
|
||||||
/// <param name="controllerURL">The URL which will handle the click of the "yes" or "no" for the confirm action page.</param>
|
/// <param name="linkLabel"></param>
|
||||||
/// <param name="parameter">An optional parameter to pass to the page and controller function.</param>
|
/// <param name="controllerURL"></param>
|
||||||
/// <param name="yesOrDefaultRedirectURL">The URL to redirect to AFTER the controller has been called if the user selected YES (or NO, if the NO link is not specified.</param>
|
/// <param name="yesOrDefaultRedirectURL"></param>
|
||||||
/// <param name="noRedirectURL">The URL to redirect to AFTER the controller has been called if the user selected NO, if not specified, the same link that is provided to yesOrDefaultRedirectURL is used.</param>
|
/// <param name="noRedirectURL"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static string GenerateSafeLink(string basePath, string message, string linkLabel, string controllerURL,
|
public static string GenerateSafeLink(string basePath, string message, string linkLabel, string controllerURL,
|
||||||
string? yesOrDefaultRedirectURL, string? noRedirectURL = null)
|
string? yesOrDefaultRedirectURL, string? noRedirectURL = null)
|
||||||
@@ -58,18 +59,19 @@ namespace ZelWiki.Library
|
|||||||
param.Append($"&Message={Uri.EscapeDataString(message)}");
|
param.Append($"&Message={Uri.EscapeDataString(message)}");
|
||||||
param.Append($"&Style=Safe");
|
param.Append($"&Style=Safe");
|
||||||
|
|
||||||
return $"<a class=\"btn btn-success btn-thin\" href=\"{basePath}/Utility/ConfirmAction?{param}\">{linkLabel}</a>";
|
return
|
||||||
|
$"<a class=\"btn btn-success btn-thin\" href=\"{basePath}/Utility/ConfirmAction?{param}\">{linkLabel}</a>";
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generates a link that navigates via GET to a "confirm action" page where the yes link is YELLOW, but the NO button is still GREEN.
|
/// 生成一个链接,通过GET导航到“确认操作”页面,其中“是”链接为黄色,但“否”按钮仍为绿色。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="message">The message to be displayed.</param>
|
/// <param name="basePath"></param>
|
||||||
/// <param name="linkLabel">the label for the link that will redirect to this confirm action page.</param>
|
/// <param name="message"></param>
|
||||||
/// <param name="controllerURL">The URL which will handle the click of the "yes" or "no" for the confirm action page.</param>
|
/// <param name="linkLabel"></param>
|
||||||
/// <param name="parameter">An optional parameter to pass to the page and controller function.</param>
|
/// <param name="controllerURL"></param>
|
||||||
/// <param name="yesOrDefaultRedirectURL">The URL to redirect to AFTER the controller has been called if the user selected YES (or NO, if the NO link is not specified.</param>
|
/// <param name="yesOrDefaultRedirectURL"></param>
|
||||||
/// <param name="noRedirectURL">The URL to redirect to AFTER the controller has been called if the user selected NO, if not specified, the same link that is provided to yesOrDefaultRedirectURL is used.</param>
|
/// <param name="noRedirectURL"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static string GenerateWarnLink(string basePath, string message, string linkLabel, string controllerURL,
|
public static string GenerateWarnLink(string basePath, string message, string linkLabel, string controllerURL,
|
||||||
string? yesOrDefaultRedirectURL, string? noRedirectURL = null)
|
string? yesOrDefaultRedirectURL, string? noRedirectURL = null)
|
||||||
@@ -86,19 +88,19 @@ namespace ZelWiki.Library
|
|||||||
param.Append($"&Message={Uri.EscapeDataString(message)}");
|
param.Append($"&Message={Uri.EscapeDataString(message)}");
|
||||||
param.Append($"&Style=Warn");
|
param.Append($"&Style=Warn");
|
||||||
|
|
||||||
return $"<a class=\"btn btn-warning btn-thin\" href=\"{basePath}/Utility/ConfirmAction?{param}\">{linkLabel}</a>";
|
return
|
||||||
|
$"<a class=\"btn btn-warning btn-thin\" href=\"{basePath}/Utility/ConfirmAction?{param}\">{linkLabel}</a>";
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generates a link that navigates via POST to a "confirm action" page where the yes button is RED, but the NO button is still GREEN.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="message">The message to be displayed.</param>
|
/// <param name="message"></param>
|
||||||
/// <param name="buttonLabel">the label for the button that will redirect to this confirm action page.</param>
|
/// <param name="buttonLabel"></param>
|
||||||
/// <param name="controllerURL">The URL which will handle the click of the "yes" or "no" for the confirm action page.</param>
|
/// <param name="controllerURL"></param>
|
||||||
/// <param name="parameter">An optional parameter to pass to the page and controller function.</param>
|
/// <param name="yesOrDefaultRedirectURL"></param>
|
||||||
/// <param name="yesOrDefaultRedirectURL">The URL to redirect to AFTER the controller has been called if the user selected YES (or NO, if the NO link is not specified.</param>
|
/// <param name="noRedirectURL"></param>
|
||||||
/// <param name="noRedirectURL">The URL to redirect to AFTER the controller has been called if the user selected NO, if not specified, the same link that is provided to yesOrDefaultRedirectURL is used.</param>
|
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static string GenerateDangerButton(string message, string buttonLabel, string controllerURL,
|
public static string GenerateDangerButton(string message, string buttonLabel, string controllerURL,
|
||||||
string? yesOrDefaultRedirectURL, string? noRedirectURL = null)
|
string? yesOrDefaultRedirectURL, string? noRedirectURL = null)
|
||||||
@@ -115,21 +117,22 @@ namespace ZelWiki.Library
|
|||||||
html.Append($"<input type='hidden' name='NoRedirectURL' value='{noRedirectURL}' />");
|
html.Append($"<input type='hidden' name='NoRedirectURL' value='{noRedirectURL}' />");
|
||||||
html.Append($"<input type='hidden' name='Message' value='{message}' />");
|
html.Append($"<input type='hidden' name='Message' value='{message}' />");
|
||||||
html.Append($"<input type='hidden' name='Style' value='Danger' />");
|
html.Append($"<input type='hidden' name='Style' value='Danger' />");
|
||||||
html.Append($"<button type='submit' class='btn btn-danger rounded-0' name='ActionToConfirm' value='PurgeDeletedPages'>{buttonLabel}</button>");
|
html.Append(
|
||||||
|
$"<button type='submit' class='btn btn-danger rounded-0' name='ActionToConfirm' value='PurgeDeletedPages'>{buttonLabel}</button>");
|
||||||
html.Append("</form>");
|
html.Append("</form>");
|
||||||
|
|
||||||
return html.ToString();
|
return html.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generates a link that navigates via POST to a "confirm action" page where the yes and no buttons are GREEN.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="message">The message to be displayed.</param>
|
/// <param name="message"></param>
|
||||||
/// <param name="buttonLabel">the label for the button that will redirect to this confirm action page.</param>
|
/// <param name="buttonLabel"></param>
|
||||||
/// <param name="controllerURL">The URL which will handle the click of the "yes" or "no" for the confirm action page.</param>
|
/// <param name="controllerURL"></param>
|
||||||
/// <param name="parameter">An optional parameter to pass to the page and controller function.</param>
|
/// <param name="yesOrDefaultRedirectURL"></param>
|
||||||
/// <param name="yesOrDefaultRedirectURL">The URL to redirect to AFTER the controller has been called if the user selected YES (or NO, if the NO link is not specified.</param>
|
/// <param name="noRedirectURL"></param>
|
||||||
/// <param name="noRedirectURL">The URL to redirect to AFTER the controller has been called if the user selected NO, if not specified, the same link that is provided to yesOrDefaultRedirectURL is used.</param>
|
/// <returns></returns>
|
||||||
public static string GenerateSafeButton(string message, string buttonLabel, string controllerURL,
|
public static string GenerateSafeButton(string message, string buttonLabel, string controllerURL,
|
||||||
string? yesOrDefaultRedirectURL, string? noRedirectURL = null)
|
string? yesOrDefaultRedirectURL, string? noRedirectURL = null)
|
||||||
{
|
{
|
||||||
@@ -146,21 +149,22 @@ namespace ZelWiki.Library
|
|||||||
html.Append($"<input type='hidden' name='NoRedirectURL' value='{noRedirectURL}' />");
|
html.Append($"<input type='hidden' name='NoRedirectURL' value='{noRedirectURL}' />");
|
||||||
html.Append($"<input type='hidden' name='Message' value='{message}' />");
|
html.Append($"<input type='hidden' name='Message' value='{message}' />");
|
||||||
html.Append($"<input type='hidden' name='Style' value='Safe' />");
|
html.Append($"<input type='hidden' name='Style' value='Safe' />");
|
||||||
html.Append($"<button type='submit' class='btn btn-success rounded-0' name='ActionToConfirm' value='PurgeDeletedPages'>{buttonLabel}</button>");
|
html.Append(
|
||||||
|
$"<button type='submit' class='btn btn-success rounded-0' name='ActionToConfirm' value='PurgeDeletedPages'>{buttonLabel}</button>");
|
||||||
html.Append("</form>");
|
html.Append("</form>");
|
||||||
|
|
||||||
return html.ToString();
|
return html.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generates a link that navigates via POST to a "confirm action" page where the yes button is YELLOW, but the NO button is still GREEN.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="message">The message to be displayed.</param>
|
/// <param name="message"></param>
|
||||||
/// <param name="buttonLabel">the label for the button that will redirect to this confirm action page.</param>
|
/// <param name="buttonLabel"></param>
|
||||||
/// <param name="controllerURL">The URL which will handle the click of the "yes" or "no" for the confirm action page.</param>
|
/// <param name="controllerURL"></param>
|
||||||
/// <param name="parameter">An optional parameter to pass to the page and controller function.</param>
|
/// <param name="yesOrDefaultRedirectURL"></param>
|
||||||
/// <param name="yesOrDefaultRedirectURL">The URL to redirect to AFTER the controller has been called if the user selected YES (or NO, if the NO link is not specified.</param>
|
/// <param name="noRedirectURL"></param>
|
||||||
/// <param name="noRedirectURL">The URL to redirect to AFTER the controller has been called if the user selected NO, if not specified, the same link that is provided to yesOrDefaultRedirectURL is used.</param>
|
/// <returns></returns>
|
||||||
public static string GenerateWarnButton(string message, string buttonLabel, string controllerURL,
|
public static string GenerateWarnButton(string message, string buttonLabel, string controllerURL,
|
||||||
string? yesOrDefaultRedirectURL, string? noRedirectURL = null)
|
string? yesOrDefaultRedirectURL, string? noRedirectURL = null)
|
||||||
{
|
{
|
||||||
@@ -177,11 +181,11 @@ namespace ZelWiki.Library
|
|||||||
html.Append($"<input type='hidden' name='NoRedirectURL' value='{noRedirectURL}' />");
|
html.Append($"<input type='hidden' name='NoRedirectURL' value='{noRedirectURL}' />");
|
||||||
html.Append($"<input type='hidden' name='Message' value='{message}' />");
|
html.Append($"<input type='hidden' name='Message' value='{message}' />");
|
||||||
html.Append($"<input type='hidden' name='Style' value='Warn' />");
|
html.Append($"<input type='hidden' name='Style' value='Warn' />");
|
||||||
html.Append($"<button type='submit' class='btn btn-warning rounded-0' name='ActionToConfirm' value='PurgeDeletedPages'>{buttonLabel}</button>");
|
html.Append(
|
||||||
|
$"<button type='submit' class='btn btn-warning rounded-0' name='ActionToConfirm' value='PurgeDeletedPages'>{buttonLabel}</button>");
|
||||||
html.Append("</form>");
|
html.Append("</form>");
|
||||||
|
|
||||||
return html.ToString();
|
return html.ToString();
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,9 +3,9 @@
|
|||||||
public static class Constants
|
public static class Constants
|
||||||
{
|
{
|
||||||
public const string CRYPTOCHECK = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
public const string CRYPTOCHECK = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
public const string DEFAULTUSERNAME = "admin@tightwiki.com";
|
public const string DEFAULTUSERNAME = "admin@ipangci.top";
|
||||||
public const string DEFAULTACCOUNT = "admin";
|
public const string DEFAULTACCOUNT = "admin";
|
||||||
public const string DEFAULTPASSWORD = "2Tight2Wiki@";
|
public const string DEFAULTPASSWORD = "Zhu0906.";
|
||||||
|
|
||||||
public enum WikiTheme
|
public enum WikiTheme
|
||||||
{
|
{
|
||||||
@@ -16,15 +16,15 @@
|
|||||||
public enum AdminPasswordChangeState
|
public enum AdminPasswordChangeState
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The password has not been changed, display a big warning.
|
/// 密码为默认
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IsDefault,
|
IsDefault,
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// All is well!
|
/// 已修改密码
|
||||||
/// </summary>
|
/// </summary>
|
||||||
HasBeenChanged,
|
HasBeenChanged,
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The default password status does not exist and the password needs to be set to default.
|
/// 默认密码状态不存在,需要将密码设置为默认值
|
||||||
/// </summary>
|
/// </summary>
|
||||||
NeedsToBeSet
|
NeedsToBeSet
|
||||||
}
|
}
|
||||||
@@ -45,19 +45,19 @@
|
|||||||
public static class Roles
|
public static class Roles
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Administrators can do anything. Add, edit, delete, pages, users, etc.
|
///管理员可以做任何事情。添加、编辑、删除、页面、用户等。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const string Administrator = "Administrator";
|
public const string Administrator = "Administrator";
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Read-only user with a profile.
|
/// 成员
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const string Member = "Member";
|
public const string Member = "Member";
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Contributor can add and edit pages.
|
/// 版主
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const string Contributor = "Contributor";
|
public const string Contributor = "Contributor";
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Moderators can add, edit and delete pages.
|
/// 主持
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const string Moderator = "Moderator";
|
public const string Moderator = "Moderator";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ namespace ZelWiki.Library
|
|||||||
foreach (var ci in CultureInfo.GetCultures(CultureTypes.SpecificCultures))
|
foreach (var ci in CultureInfo.GetCultures(CultureTypes.SpecificCultures))
|
||||||
{
|
{
|
||||||
var regionInfo = new RegionInfo(ci.Name);
|
var regionInfo = new RegionInfo(ci.Name);
|
||||||
if (list.Where(o => o.Value == regionInfo.Name).Any() == false)
|
if (list.Any(o => o.Value == regionInfo.Name) == false)
|
||||||
{
|
{
|
||||||
list.Add(new CountryItem
|
list.Add(new CountryItem
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ namespace ZelWiki.Library
|
|||||||
image.SaveAsBmp(ms);
|
image.SaveAsBmp(ms);
|
||||||
return preferredContentType;
|
return preferredContentType;
|
||||||
case "image/gif":
|
case "image/gif":
|
||||||
throw new NotImplementedException("Use [ResizeGifImage] for saving animated images.");
|
throw new NotImplementedException("使用 [ResizeGifImage] 保存动图");
|
||||||
//image.SaveAsGif(ms);
|
//image.SaveAsGif(ms);
|
||||||
//return preferredContentType;
|
//return preferredContentType;
|
||||||
case "image/tiff":
|
case "image/tiff":
|
||||||
|
|||||||
@@ -9,32 +9,32 @@ namespace ZelWiki.Library.Interfaces
|
|||||||
IQueryCollection? QueryString { get; set; }
|
IQueryCollection? QueryString { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Is the current user (or anonymous) allowed to view?
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool CanView => true;
|
public bool CanView => true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Is the current user allowed to edit?
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool CanEdit { get; }
|
public bool CanEdit { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Is the current user allowed to perform administrative functions?
|
/// 是否允许当前用户执行管理功能?
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool CanAdmin { get; }
|
public bool CanAdmin { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Is the current user allowed to moderate content (such as delete comments, and view moderation tools)?
|
/// 是否允许当前用户审核内容(如删除评论和查看审核工具)?
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool CanModerate { get; }
|
public bool CanModerate { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Is the current user allowed to create pages?
|
///是否允许当前用户创建页面?
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool CanCreate { get; }
|
public bool CanCreate { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Is the current user allowed to delete unprotected pages?
|
/// 是否允许当前用户删除未受保护的页面?
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool CanDelete { get; }
|
public bool CanDelete { get; }
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ namespace ZelWiki.Library
|
|||||||
name = name.Substring(0, name.IndexOf('(')).Trim();
|
name = name.Substring(0, name.IndexOf('(')).Trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (list.Where(o => o.Value == name).Any() == false)
|
if (list.Any(o => o.Value == name) == false)
|
||||||
{
|
{
|
||||||
list.Add(new LanguageItem
|
list.Add(new LanguageItem
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,14 +5,14 @@ namespace ZelWiki.Library
|
|||||||
internal static class MimeTypes
|
internal static class MimeTypes
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Given a file path, determine the MIME type
|
/// 给定文件路径,确定MIME类型
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="subpath">A file path</param>
|
/// <param name="filePath">A file path</param>
|
||||||
/// <param name="contentType">The resulting MIME type</param>
|
/// <param name="contentType">The resulting MIME type</param>
|
||||||
/// <returns>True if MIME type could be determined</returns>
|
/// <returns>True if MIME type could be determined</returns>
|
||||||
public static bool TryGetContentType(string filePath, [MaybeNullWhen(false)] out string contentType)
|
public static bool TryGetContentType(string filePath, [MaybeNullWhen(false)] out string contentType)
|
||||||
{
|
{
|
||||||
string extension = Path.GetExtension(filePath);
|
var extension = Path.GetExtension(filePath);
|
||||||
if (extension == null)
|
if (extension == null)
|
||||||
{
|
{
|
||||||
contentType = null;
|
contentType = null;
|
||||||
@@ -21,7 +21,6 @@ namespace ZelWiki.Library
|
|||||||
return Collection.TryGetValue(extension, out contentType);
|
return Collection.TryGetValue(extension, out contentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Borrowed from FileExtensionContentTypeProvider().TryGetContentType
|
|
||||||
public static Dictionary<string, string> Collection = new(StringComparer.OrdinalIgnoreCase)
|
public static Dictionary<string, string> Collection = new(StringComparer.OrdinalIgnoreCase)
|
||||||
{
|
{
|
||||||
{ ".323", "text/h323" },
|
{ ".323", "text/h323" },
|
||||||
@@ -78,7 +77,7 @@ namespace ZelWiki.Library
|
|||||||
{ ".crt", "application/x-x509-ca-cert" },
|
{ ".crt", "application/x-x509-ca-cert" },
|
||||||
{ ".csh", "application/x-csh" },
|
{ ".csh", "application/x-csh" },
|
||||||
{ ".css", "text/css" },
|
{ ".css", "text/css" },
|
||||||
{ ".csv", "text/csv" }, // https://tools.ietf.org/html/rfc7111#section-5.1
|
{ ".csv", "text/csv" },
|
||||||
{ ".cur", "application/octet-stream" },
|
{ ".cur", "application/octet-stream" },
|
||||||
{ ".dcr", "application/x-director" },
|
{ ".dcr", "application/x-director" },
|
||||||
{ ".deploy", "application/octet-stream" },
|
{ ".deploy", "application/octet-stream" },
|
||||||
@@ -106,7 +105,7 @@ namespace ZelWiki.Library
|
|||||||
{ ".eps", "application/postscript" },
|
{ ".eps", "application/postscript" },
|
||||||
{ ".etx", "text/x-setext" },
|
{ ".etx", "text/x-setext" },
|
||||||
{ ".evy", "application/envoy" },
|
{ ".evy", "application/envoy" },
|
||||||
{ ".exe", "application/vnd.microsoft.portable-executable" }, // https://www.iana.org/assignments/media-types/application/vnd.microsoft.portable-executable
|
{ ".exe", "application/vnd.microsoft.portable-executable" },
|
||||||
{ ".fdf", "application/vnd.fdf" },
|
{ ".fdf", "application/vnd.fdf" },
|
||||||
{ ".fif", "application/fractals" },
|
{ ".fif", "application/fractals" },
|
||||||
{ ".fla", "application/octet-stream" },
|
{ ".fla", "application/octet-stream" },
|
||||||
@@ -347,7 +346,7 @@ namespace ZelWiki.Library
|
|||||||
{ ".wcm", "application/vnd.ms-works" },
|
{ ".wcm", "application/vnd.ms-works" },
|
||||||
{ ".wdb", "application/vnd.ms-works" },
|
{ ".wdb", "application/vnd.ms-works" },
|
||||||
{ ".webm", "video/webm" },
|
{ ".webm", "video/webm" },
|
||||||
{ ".webmanifest", "application/manifest+json" }, // https://w3c.github.io/manifest/#media-type-registration
|
{ ".webmanifest", "application/manifest+json" },
|
||||||
{ ".webp", "image/webp" },
|
{ ".webp", "image/webp" },
|
||||||
{ ".wks", "application/vnd.ms-works" },
|
{ ".wks", "application/vnd.ms-works" },
|
||||||
{ ".wm", "video/x-ms-wm" },
|
{ ".wm", "video/x-ms-wm" },
|
||||||
@@ -362,8 +361,8 @@ namespace ZelWiki.Library
|
|||||||
{ ".wmv", "video/x-ms-wmv" },
|
{ ".wmv", "video/x-ms-wmv" },
|
||||||
{ ".wmx", "video/x-ms-wmx" },
|
{ ".wmx", "video/x-ms-wmx" },
|
||||||
{ ".wmz", "application/x-ms-wmz" },
|
{ ".wmz", "application/x-ms-wmz" },
|
||||||
{ ".woff", "application/font-woff" }, // https://www.w3.org/TR/WOFF/#appendix-b
|
{ ".woff", "application/font-woff" },
|
||||||
{ ".woff2", "font/woff2" }, // https://www.w3.org/TR/WOFF2/#IMT
|
{ ".woff2", "font/woff2" },
|
||||||
{ ".wps", "application/vnd.ms-works" },
|
{ ".wps", "application/vnd.ms-works" },
|
||||||
{ ".wri", "application/x-mswrite" },
|
{ ".wri", "application/x-mswrite" },
|
||||||
{ ".wrl", "x-world/x-vrml" },
|
{ ".wrl", "x-world/x-vrml" },
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ namespace ZelWiki.Library
|
|||||||
{
|
{
|
||||||
return Page;
|
return Page;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $"{Namespace}::{Page}";
|
return $"{Namespace}::{Page}";
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
@@ -49,9 +50,9 @@ namespace ZelWiki.Library
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of NamespaceNavigation.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="givenCanonical">Page navigation with optional namespace.</param>
|
/// <param name="givenCanonical"></param>
|
||||||
public NamespaceNavigation(string givenCanonical)
|
public NamespaceNavigation(string givenCanonical)
|
||||||
{
|
{
|
||||||
_lowerCase = true;
|
_lowerCase = true;
|
||||||
@@ -59,10 +60,10 @@ namespace ZelWiki.Library
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of NamespaceNavigation.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="givenCanonical">Page navigation with optional namespace.</param>
|
/// <param name="givenCanonical"></param>
|
||||||
/// <param name="lowerCase">If false, the namespace and page name will not be lowercased.</param>
|
/// <param name="lowerCase"></param>
|
||||||
public NamespaceNavigation(string givenCanonical, bool lowerCase)
|
public NamespaceNavigation(string givenCanonical, bool lowerCase)
|
||||||
{
|
{
|
||||||
_lowerCase = lowerCase;
|
_lowerCase = lowerCase;
|
||||||
@@ -75,10 +76,10 @@ namespace ZelWiki.Library
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Takes a page name with optional namespace and returns the cleaned version that can be used for matching Navigations.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="givenCanonical">Page navigation with optional namespace.</param>
|
/// <param name="str"></param>
|
||||||
/// <param name="lowerCase">If false, the namespace and page name will not be lowercased.</param>
|
/// <param name="lowerCase"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
/// <exception cref="Exception"></exception>
|
/// <exception cref="Exception"></exception>
|
||||||
public static string CleanAndValidate(string? str, bool lowerCase = true)
|
public static string CleanAndValidate(string? str, bool lowerCase = true)
|
||||||
@@ -88,7 +89,6 @@ namespace ZelWiki.Library
|
|||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Fix names like "::Page" or "Namespace::".
|
|
||||||
str = str.Trim().Trim([':']).Trim();
|
str = str.Trim().Trim([':']).Trim();
|
||||||
|
|
||||||
if (str.Contains("::"))
|
if (str.Contains("::"))
|
||||||
@@ -96,23 +96,22 @@ namespace ZelWiki.Library
|
|||||||
var parts = str.Split("::");
|
var parts = str.Split("::");
|
||||||
if (parts.Length != 2)
|
if (parts.Length != 2)
|
||||||
{
|
{
|
||||||
throw new Exception("Navigation can not contain more than one namespace.");
|
throw new Exception("导航不能包含多个命名空间");
|
||||||
}
|
}
|
||||||
|
|
||||||
return $"{CleanAndValidate(parts[0].Trim())}::{CleanAndValidate(parts[1].Trim(), lowerCase)}";
|
return $"{CleanAndValidate(parts[0].Trim())}::{CleanAndValidate(parts[1].Trim(), lowerCase)}";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode common HTML entities
|
|
||||||
str = str.Replace(""", "\"")
|
str = str.Replace(""", "\"")
|
||||||
.Replace("&", "&")
|
.Replace("&", "&")
|
||||||
.Replace("<", "<")
|
.Replace("<", "<")
|
||||||
.Replace(">", ">")
|
.Replace(">", ">")
|
||||||
.Replace(" ", " ");
|
.Replace(" ", " ");
|
||||||
|
|
||||||
// Normalize backslashes to forward slashes
|
|
||||||
str = str.Replace('\\', '/');
|
str = str.Replace('\\', '/');
|
||||||
|
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
foreach (char c in str)
|
foreach (var c in str)
|
||||||
{
|
{
|
||||||
if (char.IsWhiteSpace(c) || c == '.')
|
if (char.IsWhiteSpace(c) || c == '.')
|
||||||
{
|
{
|
||||||
@@ -124,21 +123,13 @@ namespace ZelWiki.Library
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string result = sb.ToString();
|
var result = sb.ToString();
|
||||||
|
|
||||||
// Remove multiple consecutive underscores or slashes
|
|
||||||
result = Regex.Replace(result, @"[_]{2,}", "_");
|
result = Regex.Replace(result, @"[_]{2,}", "_");
|
||||||
result = Regex.Replace(result, @"[/]{2,}", "/");
|
result = Regex.Replace(result, @"[/]{2,}", "/");
|
||||||
|
|
||||||
|
|
||||||
if (lowerCase)
|
return lowerCase ? result.TrimEnd(['/', '\\']).ToLowerInvariant() : result.TrimEnd(['/', '\\']);
|
||||||
{
|
|
||||||
return result.TrimEnd(['/', '\\']).ToLowerInvariant();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return result.TrimEnd(['/', '\\']);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,6 +3,9 @@ using System.Text.RegularExpressions;
|
|||||||
|
|
||||||
namespace ZelWiki.Library
|
namespace ZelWiki.Library
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 导航
|
||||||
|
/// </summary>
|
||||||
public class Navigation
|
public class Navigation
|
||||||
{
|
{
|
||||||
public static string Clean(string? str)
|
public static string Clean(string? str)
|
||||||
@@ -12,29 +15,25 @@ namespace ZelWiki.Library
|
|||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Fix names like "::Page" or "Namespace::".
|
|
||||||
str = str.Trim().Trim([':']).Trim();
|
str = str.Trim().Trim([':']).Trim();
|
||||||
|
|
||||||
if (str.Contains("::"))
|
if (str.Contains("::"))
|
||||||
{
|
{
|
||||||
throw new Exception("Navigation can not contain a namespace.");
|
throw new Exception("导航不能包含命名空间");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode common HTML entities
|
|
||||||
str = str.Replace(""", "\"")
|
str = str.Replace(""", "\"")
|
||||||
.Replace("&", "&")
|
.Replace("&", "&")
|
||||||
.Replace("<", "<")
|
.Replace("<", "<")
|
||||||
.Replace(">", ">")
|
.Replace(">", ">")
|
||||||
.Replace(" ", " ");
|
.Replace(" ", " ");
|
||||||
|
|
||||||
// Normalize backslashes to forward slashes
|
|
||||||
str = str.Replace('\\', '/');
|
str = str.Replace('\\', '/');
|
||||||
|
|
||||||
// Replace special sequences
|
|
||||||
str = str.Replace("::", "_").Trim();
|
str = str.Replace("::", "_").Trim();
|
||||||
|
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
foreach (char c in str)
|
foreach (var c in str)
|
||||||
{
|
{
|
||||||
if (char.IsWhiteSpace(c) || c == '.')
|
if (char.IsWhiteSpace(c) || c == '.')
|
||||||
{
|
{
|
||||||
@@ -46,9 +45,8 @@ namespace ZelWiki.Library
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string result = sb.ToString();
|
var result = sb.ToString();
|
||||||
|
|
||||||
// Remove multiple consecutive underscores or slashes
|
|
||||||
result = Regex.Replace(result, @"[_]{2,}", "_");
|
result = Regex.Replace(result, @"[_]{2,}", "_");
|
||||||
result = Regex.Replace(result, @"[/]{2,}", "/");
|
result = Regex.Replace(result, @"[/]{2,}", "/");
|
||||||
|
|
||||||
|
|||||||
@@ -42,25 +42,25 @@ namespace ZelWiki.Library
|
|||||||
sb.Append($"<center>");
|
sb.Append($"<center>");
|
||||||
if (currentPage > 1)
|
if (currentPage > 1)
|
||||||
{
|
{
|
||||||
sb.Append($"<a href=\"{url}?{QueryStringConverter.FromCollection(firstPage)}\"><< First</a>");
|
sb.Append($"<a href=\"{url}?{QueryStringConverter.FromCollection(firstPage)}\"><< 首页</a>");
|
||||||
sb.Append(" | ");
|
sb.Append(" | ");
|
||||||
sb.Append($"<a href=\"{url}?{QueryStringConverter.FromCollection(prevPage)}\">< Previous</a>");
|
sb.Append($"<a href=\"{url}?{QueryStringConverter.FromCollection(prevPage)}\">< 上一页</a>");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sb.Append($"<< First | < Previous");
|
sb.Append($"<< 首页 | < 上一页");
|
||||||
}
|
}
|
||||||
sb.Append(" | ");
|
sb.Append(" | ");
|
||||||
|
|
||||||
if (currentPage < totalPageCount)
|
if (currentPage < totalPageCount)
|
||||||
{
|
{
|
||||||
sb.Append($"<a href=\"{url}?{QueryStringConverter.FromCollection(nextPage)}\">Next ></a>");
|
sb.Append($"<a href=\"{url}?{QueryStringConverter.FromCollection(nextPage)}\">下一页 ></a>");
|
||||||
sb.Append(" | ");
|
sb.Append(" | ");
|
||||||
sb.Append($"<a href=\"{url}?{QueryStringConverter.FromCollection(lastPage)}\">Last >></a>");
|
sb.Append($"<a href=\"{url}?{QueryStringConverter.FromCollection(lastPage)}\">尾页 >></a>");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sb.Append("Next > | Last >>");
|
sb.Append("下一页 > | 尾页 >>");
|
||||||
}
|
}
|
||||||
sb.Append($"</center>");
|
sb.Append($"</center>");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,18 +8,19 @@ namespace ZelWiki.Library
|
|||||||
public static class QueryStringConverter
|
public static class QueryStringConverter
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Takes the current page query string and upserts the given order-by field,
|
/// 排序
|
||||||
/// if the string already sorts on the given field then the order is inverted (asc/desc).
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="context"></param>
|
||||||
|
/// <param name="value"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static string OrderHelper(ISessionState context, string value)
|
public static string OrderHelper(ISessionState context, string value)
|
||||||
{
|
{
|
||||||
string orderByKey = "OrderBy";
|
var orderByKey = "OrderBy";
|
||||||
string orderByDirectionKey = "OrderByDirection";
|
var orderByDirectionKey = "OrderByDirection";
|
||||||
string? currentDirection = "asc";
|
var currentDirection = "asc";
|
||||||
var collection = ToDictionary(context.QueryString);
|
var collection = ToDictionary(context.QueryString);
|
||||||
|
|
||||||
//Check to see if we are sorting on the value that we are already sorted on, this would mean we need to invert the sort.
|
|
||||||
if (collection.TryGetValue(orderByKey, out var currentValue))
|
if (collection.TryGetValue(orderByKey, out var currentValue))
|
||||||
{
|
{
|
||||||
bool invertDirection = string.Equals(currentValue, value, StringComparison.InvariantCultureIgnoreCase);
|
bool invertDirection = string.Equals(currentValue, value, StringComparison.InvariantCultureIgnoreCase);
|
||||||
@@ -28,14 +29,7 @@ namespace ZelWiki.Library
|
|||||||
{
|
{
|
||||||
if (collection.TryGetValue(orderByDirectionKey, out currentDirection))
|
if (collection.TryGetValue(orderByDirectionKey, out currentDirection))
|
||||||
{
|
{
|
||||||
if (currentDirection == "asc")
|
currentDirection = currentDirection == "asc" ? "desc" : "asc";
|
||||||
{
|
|
||||||
currentDirection = "desc";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
currentDirection = "asc";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -54,7 +48,7 @@ namespace ZelWiki.Library
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Takes the current page query string and upserts a query key/value, replacing any conflicting query string entry.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="queryString"></param>
|
/// <param name="queryString"></param>
|
||||||
/// <param name="name"></param>
|
/// <param name="name"></param>
|
||||||
@@ -79,8 +73,6 @@ namespace ZelWiki.Library
|
|||||||
|
|
||||||
foreach (var item in queryString)
|
foreach (var item in queryString)
|
||||||
{
|
{
|
||||||
//Technically, keys can be duplicated in a IQueryCollection but we do not
|
|
||||||
//support this. Use .Single() to throw exception if duplicates are found.
|
|
||||||
dictionary.Add(item.Key, item.Value.Single() ?? string.Empty);
|
dictionary.Add(item.Key, item.Value.Single() ?? string.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,13 +90,11 @@ namespace ZelWiki.Library
|
|||||||
return dictionary;
|
return dictionary;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the query string starts with '?', remove it
|
|
||||||
if (queryString.StartsWith('?'))
|
if (queryString.StartsWith('?'))
|
||||||
{
|
{
|
||||||
queryString = queryString.Substring(1);
|
queryString = queryString.Substring(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Split the query string into key-value pairs
|
|
||||||
var keyValuePairs = queryString.Split('&');
|
var keyValuePairs = queryString.Split('&');
|
||||||
|
|
||||||
foreach (var kvp in keyValuePairs)
|
foreach (var kvp in keyValuePairs)
|
||||||
@@ -158,6 +148,7 @@ namespace ZelWiki.Library
|
|||||||
{
|
{
|
||||||
queryString.Append('&');
|
queryString.Append('&');
|
||||||
}
|
}
|
||||||
|
|
||||||
queryString.Append($"{Uri.EscapeDataString(kvp.Key)}={Uri.EscapeDataString(kvp.Value)}");
|
queryString.Append($"{Uri.EscapeDataString(kvp.Key)}={Uri.EscapeDataString(kvp.Value)}");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,6 +167,7 @@ namespace ZelWiki.Library
|
|||||||
{
|
{
|
||||||
clone.Add(kvp.Key, kvp.Value);
|
clone.Add(kvp.Key, kvp.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,13 +2,28 @@
|
|||||||
{
|
{
|
||||||
public class Theme
|
public class Theme
|
||||||
{
|
{
|
||||||
public string Name { get; set; } = string.Empty;
|
/// <summary>
|
||||||
public string DelimitedFiles { get; set; } = string.Empty;
|
///
|
||||||
public string ClassNavBar { get; set; } = string.Empty;
|
/// </summary>
|
||||||
public string ClassNavLink { get; set; } = string.Empty;
|
public Theme()
|
||||||
public string ClassDropdown { get; set; } = string.Empty;
|
{
|
||||||
public string ClassBranding { get; set; } = string.Empty;
|
Name = string.Empty;
|
||||||
public string EditorTheme { get; set; } = string.Empty;
|
DelimitedFiles = string.Empty;
|
||||||
public List<string> Files { get; set; } = new();
|
ClassNavBar = string.Empty;
|
||||||
|
ClassNavLink = string.Empty;
|
||||||
|
ClassDropdown = string.Empty;
|
||||||
|
ClassBranding = string.Empty;
|
||||||
|
EditorTheme = string.Empty;
|
||||||
|
Files = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string DelimitedFiles { get; set; }
|
||||||
|
public string ClassNavBar { get; set; }
|
||||||
|
public string ClassNavLink { get; set; }
|
||||||
|
public string ClassDropdown { get; set; }
|
||||||
|
public string ClassBranding { get; set; }
|
||||||
|
public string EditorTheme { get; set; }
|
||||||
|
public List<string> Files { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,8 +2,17 @@
|
|||||||
{
|
{
|
||||||
public class TimeZoneItem
|
public class TimeZoneItem
|
||||||
{
|
{
|
||||||
public string Text { get; set; } = string.Empty;
|
/// <summary>
|
||||||
public string Value { get; set; } = string.Empty;
|
///
|
||||||
|
/// </summary>
|
||||||
|
public TimeZoneItem()
|
||||||
|
{
|
||||||
|
Text = string.Empty;
|
||||||
|
Value = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Text { get; set; }
|
||||||
|
public string Value { get; set; }
|
||||||
|
|
||||||
public static List<TimeZoneItem> GetAll()
|
public static List<TimeZoneItem> GetAll()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ namespace ZelWiki.Library
|
|||||||
|
|
||||||
public static string SanitizeAccountName(string fileName, char[]? extraInvalidCharacters = null)
|
public static string SanitizeAccountName(string fileName, char[]? extraInvalidCharacters = null)
|
||||||
{
|
{
|
||||||
// Get array of invalid characters for file names
|
|
||||||
var invalidChars = Path.GetInvalidFileNameChars().ToList();
|
var invalidChars = Path.GetInvalidFileNameChars().ToList();
|
||||||
|
|
||||||
if (extraInvalidCharacters != null)
|
if (extraInvalidCharacters != null)
|
||||||
@@ -27,7 +26,7 @@ namespace ZelWiki.Library
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Take a height and width and enforces a max on both dimensions while maintaining the ratio.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="originalWidth"></param>
|
/// <param name="originalWidth"></param>
|
||||||
/// <param name="originalHeight"></param>
|
/// <param name="originalHeight"></param>
|
||||||
@@ -35,20 +34,16 @@ namespace ZelWiki.Library
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static (int Width, int Height) ScaleToMaxOf(int originalWidth, int originalHeight, int maxSize)
|
public static (int Width, int Height) ScaleToMaxOf(int originalWidth, int originalHeight, int maxSize)
|
||||||
{
|
{
|
||||||
// Calculate aspect ratio
|
var aspectRatio = (float)originalWidth / originalHeight;
|
||||||
float aspectRatio = (float)originalWidth / originalHeight;
|
|
||||||
|
|
||||||
// Determine new dimensions based on the larger dimension
|
|
||||||
int newWidth, newHeight;
|
int newWidth, newHeight;
|
||||||
if (originalWidth > originalHeight)
|
if (originalWidth > originalHeight)
|
||||||
{
|
{
|
||||||
// Scale down the width to the maxSize and calculate the height
|
|
||||||
newWidth = maxSize;
|
newWidth = maxSize;
|
||||||
newHeight = (int)(maxSize / aspectRatio);
|
newHeight = (int)(maxSize / aspectRatio);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Scale down the height to the maxSize and calculate the width
|
|
||||||
newHeight = maxSize;
|
newHeight = maxSize;
|
||||||
newWidth = (int)(maxSize * aspectRatio);
|
newWidth = (int)(maxSize * aspectRatio);
|
||||||
}
|
}
|
||||||
@@ -72,7 +67,7 @@ namespace ZelWiki.Library
|
|||||||
public static byte[] ConvertHttpFileToBytes(IFormFile image)
|
public static byte[] ConvertHttpFileToBytes(IFormFile image)
|
||||||
{
|
{
|
||||||
using var stream = image.OpenReadStream();
|
using var stream = image.OpenReadStream();
|
||||||
using BinaryReader reader = new BinaryReader(stream);
|
using var reader = new BinaryReader(stream);
|
||||||
return reader.ReadBytes((int)image.Length);
|
return reader.ReadBytes((int)image.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,7 +75,7 @@ namespace ZelWiki.Library
|
|||||||
{
|
{
|
||||||
if (data == null)
|
if (data == null)
|
||||||
{
|
{
|
||||||
return Array.Empty<byte>();
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
using var compressedStream = new MemoryStream();
|
using var compressedStream = new MemoryStream();
|
||||||
@@ -88,15 +83,15 @@ namespace ZelWiki.Library
|
|||||||
{
|
{
|
||||||
compressor.Write(data, 0, data.Length);
|
compressor.Write(data, 0, data.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
return compressedStream.ToArray();
|
return compressedStream.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] Decompress(byte[] data)
|
public static byte[] Decompress(byte[] data)
|
||||||
{
|
{
|
||||||
if (data == null)
|
if (data == null)
|
||||||
{
|
return [];
|
||||||
return Array.Empty<byte>();
|
|
||||||
}
|
|
||||||
|
|
||||||
using var compressedStream = new MemoryStream(data);
|
using var compressedStream = new MemoryStream(data);
|
||||||
using var decompressor = new GZipStream(compressedStream, CompressionMode.Decompress);
|
using var decompressor = new GZipStream(compressedStream, CompressionMode.Decompress);
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
public T? Value<T>(string name)
|
public T? Value<T>(string name)
|
||||||
{
|
{
|
||||||
var value = Collection.Where(o => o.Name == name).FirstOrDefault();
|
var value = Collection.FirstOrDefault(o => o.Name == name);
|
||||||
if (value == null)
|
if (value == null)
|
||||||
{
|
{
|
||||||
return default;
|
return default;
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
public T Value<T>(string name, T defaultValue)
|
public T Value<T>(string name, T defaultValue)
|
||||||
{
|
{
|
||||||
var value = Collection.Where(o => o.Name == name).FirstOrDefault();
|
var value = Collection.FirstOrDefault(o => o.Name == name);
|
||||||
if (value == null)
|
if (value == null)
|
||||||
{
|
{
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
|
|||||||
@@ -19,12 +19,7 @@ namespace ZelWiki.Models.DataModels
|
|||||||
|
|
||||||
public T? As<T>(T defaultValue)
|
public T? As<T>(T defaultValue)
|
||||||
{
|
{
|
||||||
if (Value == null)
|
return Value == null ? defaultValue : Converters.ConvertTo<T>(Value);
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Converters.ConvertTo<T>(Value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string DataType { get; set; } = string.Empty;
|
public string DataType { get; set; } = string.Empty;
|
||||||
|
|||||||
@@ -7,23 +7,23 @@ namespace ZelWiki.Models.DataModels
|
|||||||
public int Id { get; set; } = 0;
|
public int Id { get; set; } = 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The revision of this page that is being viewed. May not be the latest revision.
|
/// 正在查看的此页面的修订版。可能不是最新版本
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Revision { get; set; }
|
public int Revision { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The most current revision of this page.
|
/// 此页面的最新修订版
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int MostCurrentRevision { get; set; }
|
public int MostCurrentRevision { get; set; }
|
||||||
|
|
||||||
public bool IsHistoricalVersion => Revision != MostCurrentRevision;
|
public bool IsHistoricalVersion => Revision != MostCurrentRevision;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Lets us know whether this page exists and is loaded.
|
/// 此页面是否存在并已加载
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Exists => Id > 0;
|
public bool Exists => Id > 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Count of revisions higher than Revision.
|
/// 修订次数高于修订次数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int HigherRevisionCount { get; set; }
|
public int HigherRevisionCount { get; set; }
|
||||||
public int DeletedRevisionCount { get; set; }
|
public int DeletedRevisionCount { get; set; }
|
||||||
@@ -36,8 +36,8 @@ namespace ZelWiki.Models.DataModels
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
int idealLength = 64;
|
var idealLength = 64;
|
||||||
int maxLength = 100;
|
var maxLength = 100;
|
||||||
|
|
||||||
if (Description.Length > idealLength)
|
if (Description.Length > idealLength)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
namespace ZelWiki.Models.DataModels
|
namespace ZelWiki.Models.DataModels
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used to cache pre-processed wiki results.
|
/// 用于缓存预处理的结果
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class PageCache
|
public class PageCache
|
||||||
{
|
{
|
||||||
|
public PageCache(string body)
|
||||||
|
{
|
||||||
|
Body = body;
|
||||||
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Custom page title set by a call to @@Title("...")
|
/// 通过调用@@Title("...")设置自定义页面title
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? PageTitle { get; set; }
|
public string? PageTitle { get; set; }
|
||||||
public string Body { get; set; }
|
public string Body { get; set; }
|
||||||
|
|
||||||
public PageCache(string body)
|
|
||||||
{
|
|
||||||
Body = body;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ namespace ZelWiki.Models.DataModels
|
|||||||
{
|
{
|
||||||
public int PageId { get; set; }
|
public int PageId { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// TightWiki.Library.Constants.WikiInstruction
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Instruction { get; set; } = string.Empty;
|
public string Instruction { get; set; } = string.Empty;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
public List<ProcessingInstruction> Collection { get; set; } = new();
|
public List<ProcessingInstruction> Collection { get; set; } = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns true if the collection contains the given processing instruction.
|
/// 如果集合包含给定的处理指令,则返回true
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="wikiInstruction">WikiInstruction.Protect</param>
|
/// <param name="wikiInstruction">WikiInstruction.Protect</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
|
|||||||
@@ -13,11 +13,12 @@ namespace ZelWiki.Repository
|
|||||||
{
|
{
|
||||||
public static class ConfigurationRepository
|
public static class ConfigurationRepository
|
||||||
{
|
{
|
||||||
#region Upgrade Database.
|
#region
|
||||||
|
|
||||||
public static string GetVersionStateVersion()
|
public static string GetVersionStateVersion()
|
||||||
{
|
{
|
||||||
var entries = ManagedDataStorage.Config.ExecuteScalar<string>(@"Scripts\Initialization\GetVersionStateVersion.sql");
|
var entries =
|
||||||
|
ManagedDataStorage.Config.ExecuteScalar<string>(@"Scripts\Initialization\GetVersionStateVersion.sql");
|
||||||
return entries ?? "0.0.0";
|
return entries ?? "0.0.0";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,11 +26,12 @@ namespace ZelWiki.Repository
|
|||||||
{
|
{
|
||||||
var version = string.Join('.',
|
var version = string.Join('.',
|
||||||
(Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "0.0.0.0").Split('.').Take(3));
|
(Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "0.0.0.0").Split('.').Take(3));
|
||||||
ManagedDataStorage.Config.Execute(@"Scripts\Initialization\SetVersionStateVersion.sql", new { Version = version });
|
ManagedDataStorage.Config.Execute(@"Scripts\Initialization\SetVersionStateVersion.sql",
|
||||||
|
new { Version = version });
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// See @Initialization.Versions.md
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static void UpgradeDatabase()
|
public static void UpgradeDatabase()
|
||||||
{
|
{
|
||||||
@@ -45,43 +47,44 @@ namespace ZelWiki.Repository
|
|||||||
|
|
||||||
if (currentPaddedVersion == storedPaddedVersion)
|
if (currentPaddedVersion == storedPaddedVersion)
|
||||||
{
|
{
|
||||||
return; //The database version is already at the latest version.
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var updateScriptNames = Assembly.GetExecutingAssembly().GetManifestResourceNames()
|
var updateScriptNames = Assembly.GetExecutingAssembly().GetManifestResourceNames()
|
||||||
.Where(o => o.Contains("Repository.Scripts.Initialization.Versions", StringComparison.InvariantCultureIgnoreCase)).OrderBy(o => o);
|
.Where(o => o.Contains("Repository.Scripts.Initialization.Versions",
|
||||||
|
StringComparison.InvariantCultureIgnoreCase)).OrderBy(o => o);
|
||||||
|
|
||||||
string startVersionTag = ".Initialization.Versions.";
|
var startVersionTag = ".Initialization.Versions.";
|
||||||
string endVersionTag = ".^";
|
var endVersionTag = ".^";
|
||||||
|
|
||||||
foreach (var updateScriptName in updateScriptNames)
|
foreach (var updateScriptName in updateScriptNames)
|
||||||
{
|
{
|
||||||
int startIndex = updateScriptName.IndexOf(startVersionTag, StringComparison.InvariantCultureIgnoreCase);
|
int startIndex =
|
||||||
|
updateScriptName.IndexOf(startVersionTag, StringComparison.InvariantCultureIgnoreCase);
|
||||||
if (startIndex >= 0)
|
if (startIndex >= 0)
|
||||||
{
|
{
|
||||||
startIndex += startVersionTag.Length;
|
startIndex += startVersionTag.Length;
|
||||||
|
|
||||||
int endIndex = updateScriptName.IndexOf(endVersionTag, startIndex, StringComparison.InvariantCultureIgnoreCase);
|
var endIndex = updateScriptName.IndexOf(endVersionTag, startIndex,
|
||||||
|
StringComparison.InvariantCultureIgnoreCase);
|
||||||
if (endIndex > startIndex)
|
if (endIndex > startIndex)
|
||||||
{
|
{
|
||||||
//The name of the script file without the namespaces, version numbers etc.
|
var fullScriptName = updateScriptName.Substring(endIndex + endVersionTag.Length).Trim()
|
||||||
var fullScriptName = updateScriptName.Substring(endIndex + endVersionTag.Length).Trim().Replace("_", "");
|
.Replace("_", "");
|
||||||
|
|
||||||
int filesFolderVersion = Utility.PadVersionString(updateScriptName.Substring(startIndex, endIndex - startIndex).Trim().Replace("_", ""));
|
int filesFolderVersion = Utility.PadVersionString(updateScriptName
|
||||||
|
.Substring(startIndex, endIndex - startIndex).Trim().Replace("_", ""));
|
||||||
if (filesFolderVersion > storedPaddedVersion)
|
if (filesFolderVersion > storedPaddedVersion)
|
||||||
{
|
{
|
||||||
//Get the script text.
|
|
||||||
using var stream = assembly.GetManifestResourceStream(updateScriptName);
|
using var stream = assembly.GetManifestResourceStream(updateScriptName);
|
||||||
using var reader = new StreamReader(stream.EnsureNotNull());
|
using var reader = new StreamReader(stream.EnsureNotNull());
|
||||||
var scriptText = reader.ReadToEnd();
|
var scriptText = reader.ReadToEnd();
|
||||||
|
|
||||||
//Get the script "metadata" from the file name.
|
|
||||||
var scriptNameParts = fullScriptName.Split('^');
|
var scriptNameParts = fullScriptName.Split('^');
|
||||||
//string executionOrder = scriptNameParts[0];
|
var databaseName = scriptNameParts[1];
|
||||||
string databaseName = scriptNameParts[1];
|
|
||||||
//string scriptName = scriptNameParts[2];
|
|
||||||
|
|
||||||
var databaseFactory = ManagedDataStorage.Collection.Single(o => o.Name == databaseName).Factory;
|
var databaseFactory = ManagedDataStorage.Collection.Single(o => o.Name == databaseName)
|
||||||
|
.Factory;
|
||||||
|
|
||||||
databaseFactory.Execute(scriptText);
|
databaseFactory.Execute(scriptText);
|
||||||
}
|
}
|
||||||
@@ -95,13 +98,14 @@ namespace ZelWiki.Repository
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
ExceptionRepository.InsertException(ex, "Database upgrade failed.");
|
ExceptionRepository.InsertException(ex, "数据库升级失败");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public static ConfigurationEntries GetConfigurationEntryValuesByGroupName(string groupName, bool allowCache = true)
|
public static ConfigurationEntries GetConfigurationEntryValuesByGroupName(string groupName,
|
||||||
|
bool allowCache = true)
|
||||||
{
|
{
|
||||||
if (allowCache)
|
if (allowCache)
|
||||||
{
|
{
|
||||||
@@ -163,25 +167,23 @@ namespace ZelWiki.Repository
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines if this is the first time the wiki has run. Returns true if it is the first time.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static bool IsFirstRun()
|
public static bool IsFirstRun()
|
||||||
{
|
{
|
||||||
bool isEncryptionValid = GetCryptoCheck();
|
var isEncryptionValid = GetCryptoCheck();
|
||||||
if (isEncryptionValid == false)
|
if (isEncryptionValid == false)
|
||||||
{
|
{
|
||||||
SetCryptoCheck();
|
SetCryptoCheck();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reads an encrypted value from the database so we can determine if encryption is setup.
|
///
|
||||||
/// If the value is missing then we are NOT setup.
|
|
||||||
/// If the value is present but we cant decrypt it, then we are NOT setup.
|
|
||||||
/// /// If the value is present and we can decrypt it, then we are setup and good to go!
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static bool GetCryptoCheck()
|
public static bool GetCryptoCheck()
|
||||||
@@ -204,7 +206,7 @@ namespace ZelWiki.Repository
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Writes an encrypted value to the database so we can test at a later time to ensure that encryption is setup.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static void SetCryptoCheck()
|
public static void SetCryptoCheck()
|
||||||
{
|
{
|
||||||
@@ -275,6 +277,7 @@ namespace ZelWiki.Repository
|
|||||||
ConfigurationGroupId = group.Key,
|
ConfigurationGroupId = group.Key,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
result.Add(nest);
|
result.Add(nest);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,14 +287,16 @@ namespace ZelWiki.Repository
|
|||||||
public static List<ConfigurationFlat> GetFlatConfiguration()
|
public static List<ConfigurationFlat> GetFlatConfiguration()
|
||||||
=> ManagedDataStorage.Config.Query<ConfigurationFlat>("GetFlatConfiguration.sql").ToList();
|
=> ManagedDataStorage.Config.Query<ConfigurationFlat>("GetFlatConfiguration.sql").ToList();
|
||||||
|
|
||||||
public static string? GetConfigurationEntryValuesByGroupNameAndEntryName(string groupName, string entryName, bool allowCache = true)
|
public static string? GetConfigurationEntryValuesByGroupNameAndEntryName(string groupName, string entryName,
|
||||||
|
bool allowCache = true)
|
||||||
{
|
{
|
||||||
if (allowCache)
|
if (allowCache)
|
||||||
{
|
{
|
||||||
var cacheKey = WikiCacheKeyFunction.Build(WikiCache.Category.Configuration, [groupName, entryName]);
|
var cacheKey = WikiCacheKeyFunction.Build(WikiCache.Category.Configuration, [groupName, entryName]);
|
||||||
if (!WikiCache.TryGet<string>(cacheKey, out var result))
|
if (!WikiCache.TryGet<string>(cacheKey, out var result))
|
||||||
{
|
{
|
||||||
if ((result = GetConfigurationEntryValuesByGroupNameAndEntryName(groupName, entryName, false)) != null)
|
if ((result = GetConfigurationEntryValuesByGroupNameAndEntryName(groupName, entryName, false)) !=
|
||||||
|
null)
|
||||||
{
|
{
|
||||||
WikiCache.Put(cacheKey, result);
|
WikiCache.Put(cacheKey, result);
|
||||||
}
|
}
|
||||||
@@ -306,7 +311,9 @@ namespace ZelWiki.Repository
|
|||||||
EntryName = entryName
|
EntryName = entryName
|
||||||
};
|
};
|
||||||
|
|
||||||
var configEntry = ManagedDataStorage.Config.QuerySingle<ConfigurationEntry>("GetConfigurationEntryValuesByGroupNameAndEntryName.sql", param);
|
var configEntry =
|
||||||
|
ManagedDataStorage.Config.QuerySingle<ConfigurationEntry>(
|
||||||
|
"GetConfigurationEntryValuesByGroupNameAndEntryName.sql", param);
|
||||||
if (configEntry?.IsEncrypted == true)
|
if (configEntry?.IsEncrypted == true)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -431,33 +438,31 @@ namespace ZelWiki.Repository
|
|||||||
|
|
||||||
if (emoji.ImageData != null)
|
if (emoji.ImageData != null)
|
||||||
{
|
{
|
||||||
var scaledImageCacheKey = WikiCacheKey.Build(WikiCache.Category.Emoji, [emoji.Shortcut, "100"]);
|
var scaledImageCacheKey =
|
||||||
|
WikiCacheKey.Build(WikiCache.Category.Emoji, [emoji.Shortcut, "100"]);
|
||||||
var decompressedImageBytes = Utility.Decompress(emoji.ImageData);
|
var decompressedImageBytes = Utility.Decompress(emoji.ImageData);
|
||||||
var img = Image.Load(new MemoryStream(decompressedImageBytes));
|
var img = Image.Load(new MemoryStream(decompressedImageBytes));
|
||||||
|
|
||||||
int customScalePercent = 100;
|
var customScalePercent = 100;
|
||||||
|
|
||||||
var (Width, Height) = Utility.ScaleToMaxOf(img.Width, img.Height, GlobalConfiguration.DefaultEmojiHeight);
|
var (Width, Height) = Utility.ScaleToMaxOf(img.Width, img.Height,
|
||||||
|
GlobalConfiguration.DefaultEmojiHeight);
|
||||||
|
|
||||||
//Adjust to any specified scaling.
|
|
||||||
Height = (int)(Height * (customScalePercent / 100.0));
|
Height = (int)(Height * (customScalePercent / 100.0));
|
||||||
Width = (int)(Width * (customScalePercent / 100.0));
|
Width = (int)(Width * (customScalePercent / 100.0));
|
||||||
|
|
||||||
//Adjusting by a ratio (and especially after applying additional scaling) may have caused one
|
|
||||||
// dimension to become very small (or even negative). So here we will check the height and width
|
|
||||||
// to ensure they are both at least n pixels and adjust both dimensions.
|
|
||||||
if (Height < 16)
|
if (Height < 16)
|
||||||
{
|
{
|
||||||
Height += 16 - Height;
|
Height += 16 - Height;
|
||||||
Width += 16 - Height;
|
Width += 16 - Height;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Width < 16)
|
if (Width < 16)
|
||||||
{
|
{
|
||||||
Height += 16 - Width;
|
Height += 16 - Width;
|
||||||
Width += 16 - Width;
|
Width += 16 - Width;
|
||||||
}
|
}
|
||||||
|
|
||||||
//These are hard to generate, so just keep it forever.
|
|
||||||
var resized = Images.ResizeGifImage(decompressedImageBytes, Width, Height);
|
var resized = Images.ResizeGifImage(decompressedImageBytes, Width, Height);
|
||||||
var itemCache = new ImageCacheItem(resized, "image/gif");
|
var itemCache = new ImageCacheItem(resized, "image/gif");
|
||||||
WikiCache.Put(scaledImageCacheKey, itemCache, new CacheItemPolicy());
|
WikiCache.Put(scaledImageCacheKey, itemCache, new CacheItemPolicy());
|
||||||
@@ -497,27 +502,34 @@ namespace ZelWiki.Repository
|
|||||||
|
|
||||||
GlobalConfiguration.FixedMenuPosition = customizationConfig.Value("Fixed Header Menu Position", false);
|
GlobalConfiguration.FixedMenuPosition = customizationConfig.Value("Fixed Header Menu Position", false);
|
||||||
GlobalConfiguration.AllowSignup = membershipConfig.Value("Allow Signup", false);
|
GlobalConfiguration.AllowSignup = membershipConfig.Value("Allow Signup", false);
|
||||||
GlobalConfiguration.DefaultProfileRecentlyModifiedCount = performanceConfig.Value<int>("Default Profile Recently Modified Count");
|
GlobalConfiguration.DefaultProfileRecentlyModifiedCount =
|
||||||
|
performanceConfig.Value<int>("Default Profile Recently Modified Count");
|
||||||
GlobalConfiguration.PreLoadAnimatedEmojis = performanceConfig.Value<bool>("Pre-Load Animated Emojis");
|
GlobalConfiguration.PreLoadAnimatedEmojis = performanceConfig.Value<bool>("Pre-Load Animated Emojis");
|
||||||
GlobalConfiguration.SystemTheme = GetAllThemes().Single(o => o.Name == themeName);
|
GlobalConfiguration.SystemTheme = GetAllThemes().Single(o => o.Name == themeName);
|
||||||
GlobalConfiguration.DefaultEmojiHeight = customizationConfig.Value<int>("Default Emoji Height");
|
GlobalConfiguration.DefaultEmojiHeight = customizationConfig.Value<int>("Default Emoji Height");
|
||||||
GlobalConfiguration.AllowGoogleAuthentication = membershipConfig.Value<bool>("Allow Google Authentication");
|
GlobalConfiguration.AllowGoogleAuthentication = membershipConfig.Value<bool>("Allow Google Authentication");
|
||||||
GlobalConfiguration.DefaultTimeZone = customizationConfig?.Value<string>("Default TimeZone") ?? string.Empty;
|
GlobalConfiguration.DefaultTimeZone =
|
||||||
GlobalConfiguration.IncludeWikiDescriptionInMeta = functionalityConfig.Value<bool>("Include wiki Description in Meta");
|
customizationConfig?.Value<string>("Default TimeZone") ?? string.Empty;
|
||||||
|
GlobalConfiguration.IncludeWikiDescriptionInMeta =
|
||||||
|
functionalityConfig.Value<bool>("Include wiki Description in Meta");
|
||||||
GlobalConfiguration.IncludeWikiTagsInMeta = functionalityConfig.Value<bool>("Include wiki Tags in Meta");
|
GlobalConfiguration.IncludeWikiTagsInMeta = functionalityConfig.Value<bool>("Include wiki Tags in Meta");
|
||||||
GlobalConfiguration.EnablePageComments = functionalityConfig.Value<bool>("Enable Page Comments");
|
GlobalConfiguration.EnablePageComments = functionalityConfig.Value<bool>("Enable Page Comments");
|
||||||
GlobalConfiguration.EnablePublicProfiles = functionalityConfig.Value<bool>("Enable Public Profiles");
|
GlobalConfiguration.EnablePublicProfiles = functionalityConfig.Value<bool>("Enable Public Profiles");
|
||||||
GlobalConfiguration.ShowCommentsOnPageFooter = functionalityConfig.Value<bool>("Show Comments on Page Footer");
|
GlobalConfiguration.ShowCommentsOnPageFooter =
|
||||||
GlobalConfiguration.ShowLastModifiedOnPageFooter = functionalityConfig.Value<bool>("Show Last Modified on Page Footer");
|
functionalityConfig.Value<bool>("Show Comments on Page Footer");
|
||||||
|
GlobalConfiguration.ShowLastModifiedOnPageFooter =
|
||||||
|
functionalityConfig.Value<bool>("Show Last Modified on Page Footer");
|
||||||
GlobalConfiguration.IncludeSearchOnNavbar = searchConfig.Value<bool>("Include Search on Navbar");
|
GlobalConfiguration.IncludeSearchOnNavbar = searchConfig.Value<bool>("Include Search on Navbar");
|
||||||
GlobalConfiguration.HTMLHeader = htmlConfig?.Value<string>("Header") ?? string.Empty;
|
GlobalConfiguration.HTMLHeader = htmlConfig?.Value<string>("Header") ?? string.Empty;
|
||||||
GlobalConfiguration.HTMLFooter = htmlConfig?.Value<string>("Footer") ?? string.Empty;
|
GlobalConfiguration.HTMLFooter = htmlConfig?.Value<string>("Footer") ?? string.Empty;
|
||||||
GlobalConfiguration.HTMLPreBody = htmlConfig?.Value<string>("Pre-Body") ?? string.Empty;
|
GlobalConfiguration.HTMLPreBody = htmlConfig?.Value<string>("Pre-Body") ?? string.Empty;
|
||||||
GlobalConfiguration.HTMLPostBody = htmlConfig?.Value<string>("Post-Body") ?? string.Empty;
|
GlobalConfiguration.HTMLPostBody = htmlConfig?.Value<string>("Post-Body") ?? string.Empty;
|
||||||
GlobalConfiguration.BrandImageSmall = customizationConfig?.Value<string>("Brand Image (Small)") ?? string.Empty;
|
GlobalConfiguration.BrandImageSmall =
|
||||||
|
customizationConfig?.Value<string>("Brand Image (Small)") ?? string.Empty;
|
||||||
GlobalConfiguration.FooterBlurb = customizationConfig?.Value<string>("FooterBlurb") ?? string.Empty;
|
GlobalConfiguration.FooterBlurb = customizationConfig?.Value<string>("FooterBlurb") ?? string.Empty;
|
||||||
GlobalConfiguration.MaxAvatarFileSize = filesAndAttachmentsConfig.Value<int>("Max Avatar File Size");
|
GlobalConfiguration.MaxAvatarFileSize = filesAndAttachmentsConfig.Value<int>("Max Avatar File Size");
|
||||||
GlobalConfiguration.MaxAttachmentFileSize = filesAndAttachmentsConfig.Value<int>("Max Attachment File Size");
|
GlobalConfiguration.MaxAttachmentFileSize =
|
||||||
|
filesAndAttachmentsConfig.Value<int>("Max Attachment File Size");
|
||||||
GlobalConfiguration.MaxEmojiFileSize = filesAndAttachmentsConfig.Value<int>("Max Emoji File Size");
|
GlobalConfiguration.MaxEmojiFileSize = filesAndAttachmentsConfig.Value<int>("Max Emoji File Size");
|
||||||
|
|
||||||
GlobalConfiguration.MenuItems = GetAllMenuItems();
|
GlobalConfiguration.MenuItems = GetAllMenuItems();
|
||||||
|
|||||||
@@ -2,9 +2,6 @@
|
|||||||
|
|
||||||
namespace ZelWiki.Repository
|
namespace ZelWiki.Repository
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Stores instances of ManagedDataStorageFactories that are used to store various parts of the data for the site.
|
|
||||||
/// </summary>
|
|
||||||
public static class ManagedDataStorage
|
public static class ManagedDataStorage
|
||||||
{
|
{
|
||||||
private static (string Name, ManagedDataStorageFactory Factory)[]? _collection = null;
|
private static (string Name, ManagedDataStorageFactory Factory)[]? _collection = null;
|
||||||
|
|||||||
@@ -179,8 +179,6 @@ namespace ZelWiki.Repository
|
|||||||
var pageFileInfo = GetPageFileInfoByFileNavigation(o, item.PageId, item.FileNavigation);
|
var pageFileInfo = GetPageFileInfoByFileNavigation(o, item.PageId, item.FileNavigation);
|
||||||
if (pageFileInfo == null)
|
if (pageFileInfo == null)
|
||||||
{
|
{
|
||||||
//If the page file does not exist, then insert it.
|
|
||||||
|
|
||||||
var InsertPageFileParam = new
|
var InsertPageFileParam = new
|
||||||
{
|
{
|
||||||
PageId = item.PageId,
|
PageId = item.PageId,
|
||||||
@@ -194,7 +192,6 @@ namespace ZelWiki.Repository
|
|||||||
|
|
||||||
o.Execute("InsertPageFile.sql", InsertPageFileParam);
|
o.Execute("InsertPageFile.sql", InsertPageFileParam);
|
||||||
|
|
||||||
//Get the id of the newly inserted page file.
|
|
||||||
pageFileInfo = GetPageFileInfoByFileNavigation(o, item.PageId, item.FileNavigation)
|
pageFileInfo = GetPageFileInfoByFileNavigation(o, item.PageId, item.FileNavigation)
|
||||||
?? throw new Exception("Failed find newly inserted page attachment.");
|
?? throw new Exception("Failed find newly inserted page attachment.");
|
||||||
|
|
||||||
@@ -208,18 +205,12 @@ namespace ZelWiki.Repository
|
|||||||
var currentlyAttachedFile = GetPageCurrentRevisionAttachmentByFileNavigation(o, item.PageId, item.FileNavigation);
|
var currentlyAttachedFile = GetPageCurrentRevisionAttachmentByFileNavigation(o, item.PageId, item.FileNavigation);
|
||||||
if (currentlyAttachedFile != null)
|
if (currentlyAttachedFile != null)
|
||||||
{
|
{
|
||||||
//The PageFile exists and a revision of it is attached to this page revision.
|
|
||||||
//Keep track of the file revision, and determine if the file has changed (via the file hash).
|
|
||||||
|
|
||||||
currentFileRevision = currentlyAttachedFile.Revision;
|
currentFileRevision = currentlyAttachedFile.Revision;
|
||||||
hasFileChanged = currentlyAttachedFile.DataHash != newDataHash;
|
hasFileChanged = currentlyAttachedFile.DataHash != newDataHash;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//The file either does not exist or is not attached to the current page revision.
|
|
||||||
hasFileChanged = true;
|
hasFileChanged = true;
|
||||||
|
|
||||||
//We determined earlier that the PageFile does exist, so keep track of the file revision.
|
|
||||||
currentFileRevision = pageFileInfo.Revision;
|
currentFileRevision = pageFileInfo.Revision;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,7 +218,6 @@ namespace ZelWiki.Repository
|
|||||||
{
|
{
|
||||||
currentFileRevision++;
|
currentFileRevision++;
|
||||||
|
|
||||||
//Get the current page revision so that we can associate the page file attachment with the current page revision.
|
|
||||||
int currentPageRevision = PageRepository.GetCurrentPageRevision(o, item.PageId);
|
int currentPageRevision = PageRepository.GetCurrentPageRevision(o, item.PageId);
|
||||||
|
|
||||||
var updatePageFileRevisionParam = new
|
var updatePageFileRevisionParam = new
|
||||||
@@ -235,7 +225,6 @@ namespace ZelWiki.Repository
|
|||||||
PageFileId = pageFileInfo.PageFileId,
|
PageFileId = pageFileInfo.PageFileId,
|
||||||
FileRevision = currentFileRevision
|
FileRevision = currentFileRevision
|
||||||
};
|
};
|
||||||
//The file has changed (or is newly inserted), bump the file revision.
|
|
||||||
o.Execute("UpdatePageFileRevision.sql", updatePageFileRevisionParam);
|
o.Execute("UpdatePageFileRevision.sql", updatePageFileRevisionParam);
|
||||||
|
|
||||||
var insertPageFileRevisionParam = new
|
var insertPageFileRevisionParam = new
|
||||||
@@ -250,7 +239,6 @@ namespace ZelWiki.Repository
|
|||||||
DataHash = newDataHash,
|
DataHash = newDataHash,
|
||||||
};
|
};
|
||||||
|
|
||||||
//Insert the actual file data.
|
|
||||||
o.Execute("InsertPageFileRevision.sql", insertPageFileRevisionParam);
|
o.Execute("InsertPageFileRevision.sql", insertPageFileRevisionParam);
|
||||||
|
|
||||||
var associatePageFileAttachmentWithPageRevisionParam = new
|
var associatePageFileAttachmentWithPageRevisionParam = new
|
||||||
@@ -259,10 +247,9 @@ namespace ZelWiki.Repository
|
|||||||
PageFileId = pageFileInfo.PageFileId,
|
PageFileId = pageFileInfo.PageFileId,
|
||||||
PageRevision = currentPageRevision,
|
PageRevision = currentPageRevision,
|
||||||
FileRevision = currentFileRevision,
|
FileRevision = currentFileRevision,
|
||||||
PreviousFileRevision = currentlyAttachedFile?.Revision //This is so we can disassociate the previous file revision.
|
PreviousFileRevision = currentlyAttachedFile?.Revision
|
||||||
};
|
};
|
||||||
|
|
||||||
//Associate the latest version of the file with the latest version of the page.
|
|
||||||
o.Execute("AssociatePageFileAttachmentWithPageRevision.sql", associatePageFileAttachmentWithPageRevisionParam);
|
o.Execute("AssociatePageFileAttachmentWithPageRevision.sql", associatePageFileAttachmentWithPageRevisionParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,8 @@ namespace ZelWiki.Repository
|
|||||||
return ManagedDataStorage.Pages.QuerySingleOrDefault<Page>("GetPageRevisionInfoById.sql", param);
|
return ManagedDataStorage.Pages.QuerySingleOrDefault<Page>("GetPageRevisionInfoById.sql", param);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ProcessingInstructionCollection GetPageProcessingInstructionsByPageId(int pageId, bool allowCache = true)
|
public static ProcessingInstructionCollection GetPageProcessingInstructionsByPageId(int pageId,
|
||||||
|
bool allowCache = true)
|
||||||
{
|
{
|
||||||
if (allowCache)
|
if (allowCache)
|
||||||
{
|
{
|
||||||
@@ -41,7 +42,8 @@ namespace ZelWiki.Repository
|
|||||||
|
|
||||||
return new ProcessingInstructionCollection()
|
return new ProcessingInstructionCollection()
|
||||||
{
|
{
|
||||||
Collection = ManagedDataStorage.Pages.Query<ProcessingInstruction>("GetPageProcessingInstructionsByPageId.sql", param).ToList()
|
Collection = ManagedDataStorage.Pages
|
||||||
|
.Query<ProcessingInstruction>("GetPageProcessingInstructionsByPageId.sql", param).ToList()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,7 +70,8 @@ namespace ZelWiki.Repository
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static List<PageRevision> GetPageRevisionsInfoByNavigationPaged(
|
public static List<PageRevision> GetPageRevisionsInfoByNavigationPaged(
|
||||||
string navigation, int pageNumber, string? orderBy = null, string? orderByDirection = null, int? pageSize = null)
|
string navigation, int pageNumber, string? orderBy = null, string? orderByDirection = null,
|
||||||
|
int? pageSize = null)
|
||||||
{
|
{
|
||||||
pageSize ??= ConfigurationRepository.Get<int>("Customization", "Pagination Size");
|
pageSize ??= ConfigurationRepository.Get<int>("Customization", "Pagination Size");
|
||||||
|
|
||||||
@@ -83,7 +86,8 @@ namespace ZelWiki.Repository
|
|||||||
{
|
{
|
||||||
using var users_db = o.Attach("users.db", "users_db");
|
using var users_db = o.Attach("users.db", "users_db");
|
||||||
|
|
||||||
var query = RepositoryHelper.TransposeOrderby("GetPageRevisionsInfoByNavigationPaged.sql", orderBy, orderByDirection);
|
var query = RepositoryHelper.TransposeOrderby("GetPageRevisionsInfoByNavigationPaged.sql", orderBy,
|
||||||
|
orderByDirection);
|
||||||
return o.Query<PageRevision>(query, param).ToList();
|
return o.Query<PageRevision>(query, param).ToList();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -96,7 +100,8 @@ namespace ZelWiki.Repository
|
|||||||
TopCount = topCount
|
TopCount = topCount
|
||||||
};
|
};
|
||||||
|
|
||||||
return ManagedDataStorage.Pages.Query<PageRevision>("GetTopRecentlyModifiedPagesInfoByUserId.sql", param).ToList();
|
return ManagedDataStorage.Pages.Query<PageRevision>("GetTopRecentlyModifiedPagesInfoByUserId.sql", param)
|
||||||
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string? GetPageNavigationByPageId(int pageId)
|
public static string? GetPageNavigationByPageId(int pageId)
|
||||||
@@ -149,12 +154,13 @@ namespace ZelWiki.Repository
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<PageSearchToken> GetMeteredPageSearchTokens(List<string> searchTerms, bool allowFuzzyMatching, bool allowCache = true)
|
private static List<PageSearchToken> GetMeteredPageSearchTokens(List<string> searchTerms,
|
||||||
|
bool allowFuzzyMatching, bool allowCache = true)
|
||||||
{
|
{
|
||||||
if (allowCache)
|
if (allowCache)
|
||||||
{
|
{
|
||||||
//This caching is really just used for paging - so we don't have to do a token search for every click of next/previous.
|
var cacheKey = WikiCacheKeyFunction.Build(WikiCache.Category.Search,
|
||||||
var cacheKey = WikiCacheKeyFunction.Build(WikiCache.Category.Search, [string.Join(',', searchTerms), allowFuzzyMatching]);
|
[string.Join(',', searchTerms), allowFuzzyMatching]);
|
||||||
if (!WikiCache.TryGet<List<PageSearchToken>>(cacheKey, out var result))
|
if (!WikiCache.TryGet<List<PageSearchToken>>(cacheKey, out var result))
|
||||||
{
|
{
|
||||||
result = GetMeteredPageSearchTokens(searchTerms, allowFuzzyMatching, false);
|
result = GetMeteredPageSearchTokens(searchTerms, allowFuzzyMatching, false);
|
||||||
@@ -182,7 +188,7 @@ namespace ZelWiki.Repository
|
|||||||
|
|
||||||
return allTokens
|
return allTokens
|
||||||
.GroupBy(token => token.PageId)
|
.GroupBy(token => token.PageId)
|
||||||
.Where(group => group.Sum(g => g.Score) >= minimumMatchScore) // Filtering groups
|
.Where(group => group.Sum(g => g.Score) >= minimumMatchScore)
|
||||||
.Select(group => new PageSearchToken
|
.Select(group => new PageSearchToken
|
||||||
{
|
{
|
||||||
PageId = group.Key,
|
PageId = group.Key,
|
||||||
@@ -204,7 +210,7 @@ namespace ZelWiki.Repository
|
|||||||
return new List<Page>();
|
return new List<Page>();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool allowFuzzyMatching = ConfigurationRepository.Get<bool>("Search", "Allow Fuzzy Matching");
|
var allowFuzzyMatching = ConfigurationRepository.Get<bool>("Search", "Allow Fuzzy Matching");
|
||||||
var meteredSearchTokens = GetMeteredPageSearchTokens(searchTerms, allowFuzzyMatching == true);
|
var meteredSearchTokens = GetMeteredPageSearchTokens(searchTerms, allowFuzzyMatching == true);
|
||||||
if (meteredSearchTokens.Count == 0)
|
if (meteredSearchTokens.Count == 0)
|
||||||
{
|
{
|
||||||
@@ -224,7 +230,8 @@ namespace ZelWiki.Repository
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<Page> PageSearchPaged(List<string> searchTerms, int pageNumber, int? pageSize = null, bool? allowFuzzyMatching = null)
|
public static List<Page> PageSearchPaged(List<string> searchTerms, int pageNumber, int? pageSize = null,
|
||||||
|
bool? allowFuzzyMatching = null)
|
||||||
{
|
{
|
||||||
if (searchTerms.Count == 0)
|
if (searchTerms.Count == 0)
|
||||||
{
|
{
|
||||||
@@ -256,7 +263,8 @@ namespace ZelWiki.Repository
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<RelatedPage> GetSimilarPagesPaged(int pageId, int similarity, int pageNumber, int? pageSize = null)
|
public static List<RelatedPage> GetSimilarPagesPaged(int pageId, int similarity, int pageNumber,
|
||||||
|
int? pageSize = null)
|
||||||
{
|
{
|
||||||
pageSize ??= ConfigurationRepository.Get<int>("Customization", "Pagination Size");
|
pageSize ??= ConfigurationRepository.Get<int>("Customization", "Pagination Size");
|
||||||
|
|
||||||
@@ -364,7 +372,8 @@ namespace ZelWiki.Repository
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<NonexistentPage> GetMissingPagesPaged(int pageNumber, string? orderBy = null, string? orderByDirection = null)
|
public static List<NonexistentPage> GetMissingPagesPaged(int pageNumber, string? orderBy = null,
|
||||||
|
string? orderByDirection = null)
|
||||||
{
|
{
|
||||||
int pageSize = ConfigurationRepository.Get<int>("Customization", "Pagination Size");
|
int pageSize = ConfigurationRepository.Get<int>("Customization", "Pagination Size");
|
||||||
|
|
||||||
@@ -478,17 +487,18 @@ namespace ZelWiki.Repository
|
|||||||
return ManagedDataStorage.Pages.Ephemeral(o =>
|
return ManagedDataStorage.Pages.Ephemeral(o =>
|
||||||
{
|
{
|
||||||
using var users_db = o.Attach("users.db", "users_db");
|
using var users_db = o.Attach("users.db", "users_db");
|
||||||
var query = RepositoryHelper.TransposeOrderby("GetAllNamespacePagesPaged.sql", orderBy, orderByDirection);
|
var query = RepositoryHelper.TransposeOrderby("GetAllNamespacePagesPaged.sql", orderBy,
|
||||||
|
orderByDirection);
|
||||||
return o.Query<Page>(query, param).ToList();
|
return o.Query<Page>(query, param).ToList();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unlike the search, this method returns all pages and allows them to be paired down using the search terms.
|
///
|
||||||
/// Whereas the search requires a search term to get results. The matching here is also exact, no score based matching.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pageNumber"></param>
|
/// <param name="pageNumber"></param>
|
||||||
/// <param name="pageSize"></param>
|
/// <param name="orderBy"></param>
|
||||||
|
/// <param name="orderByDirection"></param>
|
||||||
/// <param name="searchTerms"></param>
|
/// <param name="searchTerms"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static List<Page> GetAllPagesPaged(int pageNumber,
|
public static List<Page> GetAllPagesPaged(int pageNumber,
|
||||||
@@ -512,7 +522,8 @@ namespace ZelWiki.Repository
|
|||||||
using var deletedpagerevisions_db = o.Attach("deletedpagerevisions.db", "deletedpagerevisions_db");
|
using var deletedpagerevisions_db = o.Attach("deletedpagerevisions.db", "deletedpagerevisions_db");
|
||||||
using var tempTable = o.CreateTempTableFrom("TempPageIds", pageIds);
|
using var tempTable = o.CreateTempTableFrom("TempPageIds", pageIds);
|
||||||
|
|
||||||
var query = RepositoryHelper.TransposeOrderby("GetAllPagesByPageIdPaged.sql", orderBy, orderByDirection);
|
var query = RepositoryHelper.TransposeOrderby("GetAllPagesByPageIdPaged.sql", orderBy,
|
||||||
|
orderByDirection);
|
||||||
return o.Query<Page>(query, param).ToList();
|
return o.Query<Page>(query, param).ToList();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -528,11 +539,11 @@ namespace ZelWiki.Repository
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unlike the search, this method returns all pages and allows them to be paired down using the search terms.
|
///
|
||||||
/// Whereas the search requires a search term to get results. The matching here is also exact, no score based matching.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pageNumber"></param>
|
/// <param name="pageNumber"></param>
|
||||||
/// <param name="pageSize"></param>
|
/// <param name="orderBy"></param>
|
||||||
|
/// <param name="orderByDirection"></param>
|
||||||
/// <param name="searchTerms"></param>
|
/// <param name="searchTerms"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static List<Page> GetAllDeletedPagesPaged(int pageNumber, string? orderBy = null,
|
public static List<Page> GetAllDeletedPagesPaged(int pageNumber, string? orderBy = null,
|
||||||
@@ -554,7 +565,8 @@ namespace ZelWiki.Repository
|
|||||||
using var users_db = o.Attach("users.db", "users_db");
|
using var users_db = o.Attach("users.db", "users_db");
|
||||||
using var tempTable = o.CreateTempTableFrom("TempPageIds", pageIds);
|
using var tempTable = o.CreateTempTableFrom("TempPageIds", pageIds);
|
||||||
|
|
||||||
var query = RepositoryHelper.TransposeOrderby("GetAllDeletedPagesByPageIdPaged.sql", orderBy, orderByDirection);
|
var query = RepositoryHelper.TransposeOrderby("GetAllDeletedPagesByPageIdPaged.sql", orderBy,
|
||||||
|
orderByDirection);
|
||||||
return o.Query<Page>(query, param).ToList();
|
return o.Query<Page>(query, param).ToList();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -567,7 +579,8 @@ namespace ZelWiki.Repository
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<NamespaceStat> GetAllNamespacesPaged(int pageNumber, string? orderBy = null, string? orderByDirection = null)
|
public static List<NamespaceStat> GetAllNamespacesPaged(int pageNumber, string? orderBy = null,
|
||||||
|
string? orderByDirection = null)
|
||||||
{
|
{
|
||||||
int pageSize = ConfigurationRepository.Get<int>("Customization", "Pagination Size");
|
int pageSize = ConfigurationRepository.Get<int>("Customization", "Pagination Size");
|
||||||
|
|
||||||
@@ -683,6 +696,7 @@ namespace ZelWiki.Repository
|
|||||||
WikiCache.Put(cacheKey, result);
|
WikiCache.Put(cacheKey, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -719,27 +733,23 @@ namespace ZelWiki.Repository
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
int currentPageRevision = 0;
|
var currentPageRevision = 0;
|
||||||
bool hasPageChanged = false;
|
var hasPageChanged = false;
|
||||||
|
|
||||||
if (page.Id == 0)
|
if (page.Id == 0)
|
||||||
{
|
{
|
||||||
//This is a new page, just insert it.
|
|
||||||
page.Id = o.ExecuteScalar<int>("CreatePage.sql", pageUpsertParam);
|
page.Id = o.ExecuteScalar<int>("CreatePage.sql", pageUpsertParam);
|
||||||
hasPageChanged = true;
|
hasPageChanged = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//Get current page so we can determine if anything has changed.
|
|
||||||
var currentRevisionInfo = GetLimitedPageInfoByIdAndRevision(page.Id)
|
var currentRevisionInfo = GetLimitedPageInfoByIdAndRevision(page.Id)
|
||||||
?? throw new Exception("The page could not be found.");
|
?? throw new Exception("The page could not be found.");
|
||||||
|
|
||||||
currentPageRevision = currentRevisionInfo.Revision;
|
currentPageRevision = currentRevisionInfo.Revision;
|
||||||
|
|
||||||
//Update the existing page.
|
|
||||||
o.Execute("UpdatePage.sql", pageUpsertParam);
|
o.Execute("UpdatePage.sql", pageUpsertParam);
|
||||||
|
|
||||||
//Determine if anything has actually changed.
|
|
||||||
hasPageChanged = currentRevisionInfo.Name != page.Name
|
hasPageChanged = currentRevisionInfo.Name != page.Name
|
||||||
|| currentRevisionInfo.Namespace != page.Namespace
|
|| currentRevisionInfo.Namespace != page.Namespace
|
||||||
|| currentRevisionInfo.Description != page.Description
|
|| currentRevisionInfo.Description != page.Description
|
||||||
@@ -755,7 +765,6 @@ namespace ZelWiki.Repository
|
|||||||
PageId = page.Id,
|
PageId = page.Id,
|
||||||
PageRevision = currentPageRevision
|
PageRevision = currentPageRevision
|
||||||
};
|
};
|
||||||
//The page content has actually changed (according to the checksum), so we will bump the page revision.
|
|
||||||
o.Execute("UpdatePageRevisionNumber.sql", updatePageRevisionNumberParam);
|
o.Execute("UpdatePageRevisionNumber.sql", updatePageRevisionNumberParam);
|
||||||
|
|
||||||
var InsertPageRevisionParam = new
|
var InsertPageRevisionParam = new
|
||||||
@@ -770,7 +779,6 @@ namespace ZelWiki.Repository
|
|||||||
ModifiedByUserId = page.ModifiedByUserId,
|
ModifiedByUserId = page.ModifiedByUserId,
|
||||||
ModifiedDate = DateTime.UtcNow,
|
ModifiedDate = DateTime.UtcNow,
|
||||||
};
|
};
|
||||||
//Insert the new actual page revision entry (this is the data).
|
|
||||||
o.Execute("InsertPageRevision.sql", InsertPageRevisionParam);
|
o.Execute("InsertPageRevision.sql", InsertPageRevisionParam);
|
||||||
|
|
||||||
var reassociateAllPageAttachmentsParam = new
|
var reassociateAllPageAttachmentsParam = new
|
||||||
@@ -778,7 +786,6 @@ namespace ZelWiki.Repository
|
|||||||
PageId = page.Id,
|
PageId = page.Id,
|
||||||
PageRevision = currentPageRevision,
|
PageRevision = currentPageRevision,
|
||||||
};
|
};
|
||||||
//Associate all page attachments with the latest revision.
|
|
||||||
o.Execute("ReassociateAllPageAttachments.sql", reassociateAllPageAttachmentsParam);
|
o.Execute("ReassociateAllPageAttachments.sql", reassociateAllPageAttachmentsParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -795,7 +802,7 @@ namespace ZelWiki.Repository
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the page info without the content.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="navigation"></param>
|
/// <param name="navigation"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
@@ -1001,7 +1008,8 @@ namespace ZelWiki.Repository
|
|||||||
{
|
{
|
||||||
using var users_db = o.Attach("users.db", "users_db");
|
using var users_db = o.Attach("users.db", "users_db");
|
||||||
|
|
||||||
var query = RepositoryHelper.TransposeOrderby("GetDeletedPageRevisionsByIdPaged.sql", orderBy, orderByDirection);
|
var query = RepositoryHelper.TransposeOrderby("GetDeletedPageRevisionsByIdPaged.sql", orderBy,
|
||||||
|
orderByDirection);
|
||||||
return o.Query<DeletedPageRevision>(query, param).ToList();
|
return o.Query<DeletedPageRevision>(query, param).ToList();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1083,7 +1091,8 @@ namespace ZelWiki.Repository
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Page? GetPageRevisionByNavigation(string givenNavigation, int? revision = null, bool allowCache = true)
|
public static Page? GetPageRevisionByNavigation(string givenNavigation, int? revision = null,
|
||||||
|
bool allowCache = true)
|
||||||
{
|
{
|
||||||
var navigation = new NamespaceNavigation(givenNavigation);
|
var navigation = new NamespaceNavigation(givenNavigation);
|
||||||
|
|
||||||
|
|||||||
@@ -5,11 +5,13 @@ namespace ZelWiki.Repository
|
|||||||
internal static class RepositoryHelper
|
internal static class RepositoryHelper
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fills in a custom orderby on a given sql script.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="filename"></param>
|
/// <param name="filename"></param>
|
||||||
/// <param name="orderBy"></param>
|
/// <param name="orderBy"></param>
|
||||||
|
/// <param name="orderByDirection"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
|
/// <exception cref="Exception"></exception>
|
||||||
public static string TransposeOrderby(string filename, string? orderBy, string? orderByDirection)
|
public static string TransposeOrderby(string filename, string? orderBy, string? orderByDirection)
|
||||||
{
|
{
|
||||||
var script = ManagedDataStorageInstance.TranslateSqlScript(filename);
|
var script = ManagedDataStorageInstance.TranslateSqlScript(filename);
|
||||||
@@ -19,47 +21,53 @@ namespace ZelWiki.Repository
|
|||||||
return script;
|
return script;
|
||||||
}
|
}
|
||||||
|
|
||||||
string beginParentTag = "--CUSTOM_ORDER_BEGIN::";
|
var beginParentTag = "--CUSTOM_ORDER_BEGIN::";
|
||||||
string endParentTag = "--::CUSTOM_ORDER_BEGIN";
|
var endParentTag = "--::CUSTOM_ORDER_BEGIN";
|
||||||
|
|
||||||
string beginConfigTag = "--CONFIG::";
|
var beginConfigTag = "--CONFIG::";
|
||||||
string endConfigTag = "--::CONFIG";
|
var endConfigTag = "--::CONFIG";
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
int beginParentIndex = script.IndexOf(beginParentTag, StringComparison.OrdinalIgnoreCase);
|
var beginParentIndex = script.IndexOf(beginParentTag, StringComparison.OrdinalIgnoreCase);
|
||||||
int endParentIndex = script.IndexOf(endParentTag, StringComparison.OrdinalIgnoreCase);
|
var endParentIndex = script.IndexOf(endParentTag, StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
if (beginParentIndex > 0 && endParentIndex > beginParentIndex)
|
if (beginParentIndex > 0 && endParentIndex > beginParentIndex)
|
||||||
{
|
{
|
||||||
var sectionText = script.Substring(beginParentIndex + beginParentTag.Length, (endParentIndex - beginParentIndex) - endParentTag.Length).Trim();
|
var sectionText = script.Substring(beginParentIndex + beginParentTag.Length,
|
||||||
|
(endParentIndex - beginParentIndex) - endParentTag.Length).Trim();
|
||||||
|
|
||||||
int beginConfigIndex = sectionText.IndexOf(beginConfigTag, StringComparison.OrdinalIgnoreCase);
|
var beginConfigIndex = sectionText.IndexOf(beginConfigTag, StringComparison.OrdinalIgnoreCase);
|
||||||
int endConfigIndex = sectionText.IndexOf(endConfigTag, StringComparison.OrdinalIgnoreCase);
|
var endConfigIndex = sectionText.IndexOf(endConfigTag, StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
if (beginConfigIndex >= 0 && endConfigIndex > beginConfigIndex)
|
if (beginConfigIndex >= 0 && endConfigIndex > beginConfigIndex)
|
||||||
{
|
{
|
||||||
var configText = sectionText.Substring(beginConfigIndex + beginConfigTag.Length, (endConfigIndex - beginConfigIndex) - endConfigTag.Length).Trim();
|
var configText = sectionText.Substring(beginConfigIndex + beginConfigTag.Length,
|
||||||
|
(endConfigIndex - beginConfigIndex) - endConfigTag.Length).Trim();
|
||||||
|
|
||||||
var configs = configText.Split("\n").Select(o => o.Trim())
|
var configs = configText.Split("\n").Select(o => o.Trim())
|
||||||
.Where(o => o.Contains('='))
|
.Where(o => o.Contains('='))
|
||||||
.Select(o => (Name: o.Split("=")[0], Field: o.Split("=")[1]));
|
.Select(o => (Name: o.Split("=")[0], Field: o.Split("=")[1]));
|
||||||
|
|
||||||
var selectedConfig = configs.SingleOrDefault(o => string.Equals(o.Name, orderBy, StringComparison.OrdinalIgnoreCase));
|
var selectedConfig = configs.SingleOrDefault(o =>
|
||||||
|
string.Equals(o.Name, orderBy, StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
if (selectedConfig == default)
|
if (selectedConfig == default)
|
||||||
{
|
{
|
||||||
throw new Exception($"No order by mapping was found in '{filename}' for the field '{orderBy}'.");
|
throw new Exception(
|
||||||
|
$"在 '{filename}' 中找不到排序字段 '{orderBy}'的映射");
|
||||||
}
|
}
|
||||||
|
|
||||||
script = script.Substring(0, beginParentIndex)
|
script = script.Substring(0, beginParentIndex)
|
||||||
+ $"ORDER BY\r\n\t{selectedConfig.Field} "
|
+ $"ORDER BY\r\n\t{selectedConfig.Field} "
|
||||||
+ (string.Equals(orderByDirection, "asc", StringComparison.InvariantCultureIgnoreCase) ? "asc" : "desc")
|
+ (string.Equals(orderByDirection, "asc", StringComparison.InvariantCultureIgnoreCase)
|
||||||
|
? "asc"
|
||||||
|
: "desc")
|
||||||
+ script.Substring(endParentIndex + endParentTag.Length);
|
+ script.Substring(endParentIndex + endParentTag.Length);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new Exception($"No order configuration was found in '{filename}'.");
|
throw new Exception($"在 '{filename}'中找不到配置");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
--Remove the previous page file revision attachment, if any.
|
|
||||||
DELETE FROM PageRevisionAttachment
|
DELETE FROM PageRevisionAttachment
|
||||||
WHERE
|
WHERE
|
||||||
PageId = @PageId
|
PageId = @PageId
|
||||||
@@ -6,7 +5,7 @@ WHERE
|
|||||||
AND FileRevision = @PreviousFileRevision
|
AND FileRevision = @PreviousFileRevision
|
||||||
AND PageRevision = @PageRevision;
|
AND PageRevision = @PageRevision;
|
||||||
|
|
||||||
--Associate the file revision record with the page revision.
|
|
||||||
INSERT INTO PageRevisionAttachment
|
INSERT INTO PageRevisionAttachment
|
||||||
(
|
(
|
||||||
PageId,
|
PageId,
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
--This proc is exactly like GetAllUsersPaged except it has no filter on personal infomation so it can be used for public info.
|
|
||||||
|
|
||||||
SELECT
|
SELECT
|
||||||
U.UserId,
|
U.UserId,
|
||||||
U.AccountName,
|
U.AccountName,
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ FROM
|
|||||||
T.PageId,
|
T.PageId,
|
||||||
COUNT(DISTINCT T.Token) / (@TokenCount + 0.0) as [Match],
|
COUNT(DISTINCT T.Token) / (@TokenCount + 0.0) as [Match],
|
||||||
SUM(T.[Weight] * 1.5) as [Weight],
|
SUM(T.[Weight] * 1.5) as [Weight],
|
||||||
--Extra weight on score for exact matches:
|
|
||||||
SUM(T.[Weight] * 1.5) * (COUNT(DISTINCT T.Token) / (@TokenCount + 0.0)) as [Score]
|
SUM(T.[Weight] * 1.5) * (COUNT(DISTINCT T.Token) / (@TokenCount + 0.0)) as [Score]
|
||||||
FROM
|
FROM
|
||||||
PageToken as T
|
PageToken as T
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ FROM
|
|||||||
T.PageId,
|
T.PageId,
|
||||||
COUNT(DISTINCT T.DoubleMetaphone) / (@TokenCount + 0.0) as [Match],
|
COUNT(DISTINCT T.DoubleMetaphone) / (@TokenCount + 0.0) as [Match],
|
||||||
SUM(T.[Weight] * 1.0) as [Weight],
|
SUM(T.[Weight] * 1.0) as [Weight],
|
||||||
--No weight benefits on score for fuzzy matching weight for exact matches:
|
|
||||||
(COUNT(DISTINCT T.DoubleMetaphone) / (@TokenCount + 0.0)) as [Score]
|
(COUNT(DISTINCT T.DoubleMetaphone) / (@TokenCount + 0.0)) as [Score]
|
||||||
FROM
|
FROM
|
||||||
PageToken as T
|
PageToken as T
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ INNER JOIN PageRevisionAttachment as PRA
|
|||||||
ON PRA.PageId = P.Id
|
ON PRA.PageId = P.Id
|
||||||
AND PRA.PageFileId = PF.Id
|
AND PRA.PageFileId = PF.Id
|
||||||
AND PRA.PageRevision = PR.Revision
|
AND PRA.PageRevision = PR.Revision
|
||||||
AND PRA.FileRevision = PF.Revision --Latest file revision.
|
AND PRA.FileRevision = PF.Revision
|
||||||
INNER JOIN PageFileRevision as PFR
|
INNER JOIN PageFileRevision as PFR
|
||||||
ON PFR.PageFileId = PF.Id
|
ON PFR.PageFileId = PF.Id
|
||||||
AND PFR.Revision = PRA.FileRevision
|
AND PFR.Revision = PRA.FileRevision
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ SELECT
|
|||||||
ON PRA.PageId = P.Id
|
ON PRA.PageId = P.Id
|
||||||
AND PRA.PageFileId = PF.Id
|
AND PRA.PageFileId = PF.Id
|
||||||
AND PRA.PageRevision = PR.Revision
|
AND PRA.PageRevision = PR.Revision
|
||||||
AND PRA.FileRevision = PF.Revision --Latest file revision.
|
AND PRA.FileRevision = PF.Revision
|
||||||
INNER JOIN PageFileRevision as PFR
|
INNER JOIN PageFileRevision as PFR
|
||||||
ON PFR.PageFileId = PF.Id
|
ON PFR.PageFileId = PF.Id
|
||||||
AND PFR.Revision = PRA.FileRevision
|
AND PFR.Revision = PRA.FileRevision
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
# Database Upgrade Initialization
|
|
||||||
|
|
||||||
When TightWiki is run, any scripts in the folders contained in "TightWiki.Repository\Scripts\Initialization\Versions"
|
|
||||||
are executed. The "previous version" of TightWiki is stored in the Config database VersionState table.
|
|
||||||
|
|
||||||
The scripts are executed in the order denoted by the name of the folders in "Version\*", these folders are
|
|
||||||
expected to be named with a three-part version scheme. MM.mm.pp (major.minor.patch).
|
|
||||||
|
|
||||||
The scripts are only executed if the three-part folder version is
|
|
||||||
greater than the "previous version" from the VersionState table.
|
|
||||||
|
|
||||||
Theses scripts are executed in the order of their name as well, their name consists of three parts:
|
|
||||||
"\^EXECUTION_ORDER\^DATABASE_NAME\^SCRIPT_NAME" where the execution order should be a zero padded numeric string,
|
|
||||||
database name is the key from ManagedDataStorage.Collection, and script name is whatever you want to call it.
|
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
--Insert the actual file data.
|
|
||||||
INSERT INTO PageFileRevision
|
INSERT INTO PageFileRevision
|
||||||
(
|
(
|
||||||
PageFileId,
|
PageFileId,
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ INSERT INTO deletedpages_db.[PageFileRevision] SELECT * FROM PageFileRevision WH
|
|||||||
INSERT INTO deletedpages_db.[PageFile] SELECT * FROM [PageFile] WHERE PageId = @PageId;
|
INSERT INTO deletedpages_db.[PageFile] SELECT * FROM [PageFile] WHERE PageId = @PageId;
|
||||||
INSERT INTO deletedpages_db.[Page] SELECT * FROM [Page] WHERE Id = @PageId;
|
INSERT INTO deletedpages_db.[Page] SELECT * FROM [Page] WHERE Id = @PageId;
|
||||||
|
|
||||||
--We save these so we can search for deleted pages.
|
|
||||||
INSERT INTO deletedpages_db.[PageTag] SELECT * FROM [PageTag] WHERE PageId = @PageId;
|
INSERT INTO deletedpages_db.[PageTag] SELECT * FROM [PageTag] WHERE PageId = @PageId;
|
||||||
INSERT INTO deletedpages_db.[PageToken] SELECT * FROM [PageToken] WHERE PageId = @PageId;
|
INSERT INTO deletedpages_db.[PageToken] SELECT * FROM [PageToken] WHERE PageId = @PageId;
|
||||||
INSERT INTO deletedpages_db.[PageProcessingInstruction] SELECT * FROM [PageProcessingInstruction] WHERE PageId = @PageId;
|
INSERT INTO deletedpages_db.[PageProcessingInstruction] SELECT * FROM [PageProcessingInstruction] WHERE PageId = @PageId;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--Cleanup
|
|
||||||
DELETE FROM DeletionMeta WHERE PageId = @PageId;
|
DELETE FROM DeletionMeta WHERE PageId = @PageId;
|
||||||
|
|
||||||
DELETE FROM [PageTag] WHERE PageId = @PageId;
|
DELETE FROM [PageTag] WHERE PageId = @PageId;
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
BEGIN TRANSACTION;
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
--Delete orphaned PageFileRevision.
|
|
||||||
DELETE FROM PageFileRevision WHERE PageFileId = @PageFileId AND Revision = @Revision;
|
DELETE FROM PageFileRevision WHERE PageFileId = @PageFileId AND Revision = @Revision;
|
||||||
|
|
||||||
--Delete orphaned PageFile.
|
|
||||||
DELETE FROM PageFile
|
DELETE FROM PageFile
|
||||||
WHERE Id = @PageFileId
|
WHERE Id = @PageFileId
|
||||||
AND Id NOT IN (SELECT PFR.PageFileId FROM PageFileRevision as PFR WHERE PFR.PageFileId = @PageFileId);
|
AND Id NOT IN (SELECT PFR.PageFileId FROM PageFileRevision as PFR WHERE PFR.PageFileId = @PageFileId);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
BEGIN TRANSACTION;
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
--Delete orphaned PageFileRevision.
|
|
||||||
DELETE FROM PageFileRevision
|
DELETE FROM PageFileRevision
|
||||||
WHERE (PageFileId, Revision) IN (
|
WHERE (PageFileId, Revision) IN (
|
||||||
SELECT
|
SELECT
|
||||||
@@ -19,7 +19,7 @@ WHERE (PageFileId, Revision) IN (
|
|||||||
PRA.PageFileId IS NULL
|
PRA.PageFileId IS NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
--Delete orphaned PageFile.
|
|
||||||
DELETE FROM PageFile
|
DELETE FROM PageFile
|
||||||
WHERE Id NOT IN (SELECT PageFileId FROM PageFileRevision);
|
WHERE Id NOT IN (SELECT PageFileId FROM PageFileRevision);
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--Restore:
|
|
||||||
INSERT INTO [Page] SELECT * FROM deletedpages_db.[Page] WHERE Id = @PageId;
|
INSERT INTO [Page] SELECT * FROM deletedpages_db.[Page] WHERE Id = @PageId;
|
||||||
INSERT INTO [PageRevision] SELECT * FROM deletedpages_db.[PageRevision] WHERE PageId = @PageId;
|
INSERT INTO [PageRevision] SELECT * FROM deletedpages_db.[PageRevision] WHERE PageId = @PageId;
|
||||||
INSERT INTO [PageFile] SELECT * FROM deletedpages_db.[PageFile] WHERE PageId = @PageId;
|
INSERT INTO [PageFile] SELECT * FROM deletedpages_db.[PageFile] WHERE PageId = @PageId;
|
||||||
@@ -6,7 +6,7 @@ INSERT INTO [PageFileRevision] SELECT * FROM deletedpages_db.PageFileRevision WH
|
|||||||
INSERT INTO [PageRevisionAttachment] SELECT * FROM deletedpages_db.[PageRevisionAttachment] WHERE PageId = @PageId;
|
INSERT INTO [PageRevisionAttachment] SELECT * FROM deletedpages_db.[PageRevisionAttachment] WHERE PageId = @PageId;
|
||||||
INSERT INTO [PageComment] SELECT * FROM deletedpages_db.[PageComment] WHERE PageId = @PageId;
|
INSERT INTO [PageComment] SELECT * FROM deletedpages_db.[PageComment] WHERE PageId = @PageId;
|
||||||
|
|
||||||
--Cleanup
|
|
||||||
DELETE FROM deletedpages_db.DeletionMeta WHERE PageId = @PageId;
|
DELETE FROM deletedpages_db.DeletionMeta WHERE PageId = @PageId;
|
||||||
|
|
||||||
DELETE FROM deletedpages_db.[PageTag] WHERE PageId = @PageId;
|
DELETE FROM deletedpages_db.[PageTag] WHERE PageId = @PageId;
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
-- Deleting non-current page revisions
|
|
||||||
DELETE FROM PageRevision
|
DELETE FROM PageRevision
|
||||||
WHERE EXISTS (
|
WHERE EXISTS (
|
||||||
SELECT 1
|
SELECT 1
|
||||||
@@ -11,7 +10,6 @@ WHERE EXISTS (
|
|||||||
AND PageRevision.Revision < MostRecent.MaxRevision
|
AND PageRevision.Revision < MostRecent.MaxRevision
|
||||||
);
|
);
|
||||||
|
|
||||||
-- Deleting non-current attachments.
|
|
||||||
DELETE FROM PageRevisionAttachment
|
DELETE FROM PageRevisionAttachment
|
||||||
WHERE EXISTS (
|
WHERE EXISTS (
|
||||||
SELECT 1
|
SELECT 1
|
||||||
@@ -25,7 +23,6 @@ WHERE EXISTS (
|
|||||||
AND PageRevisionAttachment.FileRevision < MostRecent.MaxFileRevision
|
AND PageRevisionAttachment.FileRevision < MostRecent.MaxFileRevision
|
||||||
);
|
);
|
||||||
|
|
||||||
-- Deleting non-current page revision attachments
|
|
||||||
DELETE FROM PageRevisionAttachment
|
DELETE FROM PageRevisionAttachment
|
||||||
WHERE EXISTS (
|
WHERE EXISTS (
|
||||||
SELECT 1
|
SELECT 1
|
||||||
@@ -39,7 +36,6 @@ WHERE EXISTS (
|
|||||||
AND PageRevisionAttachment.PageRevision < MostRecent.MaxPageRevision
|
AND PageRevisionAttachment.PageRevision < MostRecent.MaxPageRevision
|
||||||
);
|
);
|
||||||
|
|
||||||
-- Deleting non-current page file revisions.
|
|
||||||
DELETE FROM PageFileRevision
|
DELETE FROM PageFileRevision
|
||||||
WHERE EXISTS (
|
WHERE EXISTS (
|
||||||
SELECT 1
|
SELECT 1
|
||||||
@@ -52,19 +48,16 @@ WHERE EXISTS (
|
|||||||
AND PageFileRevision.Revision < MostRecent.MaxPageRevision
|
AND PageFileRevision.Revision < MostRecent.MaxPageRevision
|
||||||
);
|
);
|
||||||
|
|
||||||
-- Delete orphaned PageFileRevision
|
|
||||||
DELETE FROM PageFileRevision
|
DELETE FROM PageFileRevision
|
||||||
WHERE PageFileId NOT IN (
|
WHERE PageFileId NOT IN (
|
||||||
SELECT PageFileId FROM PageRevisionAttachment
|
SELECT PageFileId FROM PageRevisionAttachment
|
||||||
);
|
);
|
||||||
|
|
||||||
-- Delete orphaned PageFile
|
|
||||||
DELETE FROM PageFile
|
DELETE FROM PageFile
|
||||||
WHERE Id NOT IN (
|
WHERE Id NOT IN (
|
||||||
SELECT PageFileId FROM PageRevisionAttachment
|
SELECT PageFileId FROM PageRevisionAttachment
|
||||||
);
|
);
|
||||||
|
|
||||||
-- Assuming everything else worked, lets set all of the revisions back to 1.
|
|
||||||
UPDATE [Page] SET Revision = 1;
|
UPDATE [Page] SET Revision = 1;
|
||||||
UPDATE PageRevision SET Revision = 1;
|
UPDATE PageRevision SET Revision = 1;
|
||||||
UPDATE PageRevisionAttachment SET PageRevision = 1, FileRevision = 1;
|
UPDATE PageRevisionAttachment SET PageRevision = 1, FileRevision = 1;
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
--The ReferencesPageId is NULL by default and needs to be filled in for pages that referece orphaned pages.
|
|
||||||
UPDATE
|
UPDATE
|
||||||
PageReference
|
PageReference
|
||||||
SET
|
SET
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ DELETE FROM EmojiCategory WHERE Id IN
|
|||||||
AND TC.Value IS NULL
|
AND TC.Value IS NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
--Insert previously non-existing categories.
|
|
||||||
INSERT INTO EmojiCategory
|
INSERT INTO EmojiCategory
|
||||||
(
|
(
|
||||||
EmojiId,
|
EmojiId,
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user