Merge branch 'master' of github.com:ONLYOFFICE/CommunityServer-AspNetCore
This commit is contained in:
commit
6b998cd1f1
@ -38,7 +38,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Data.Reassigns", "commo
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Notify", "common\services\ASC.Notify\ASC.Notify.csproj", "{8484A675-1C93-4D87-8FF2-7530A5711208}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ASC.Studio.Notify", "common\services\ASC.Studio.Notify\ASC.Studio.Notify.csproj", "{E3567AB9-0926-444D-A0D0-A369D5890EAA}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Studio.Notify", "common\services\ASC.Studio.Notify\ASC.Studio.Notify.csproj", "{E3567AB9-0926-444D-A0D0-A369D5890EAA}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ASC.Textile", "common\ASC.Textile\ASC.Textile.csproj", "{C8F410B4-B83B-47B9-9ECD-07590A8750A7}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
@ -114,6 +116,10 @@ Global
|
||||
{E3567AB9-0926-444D-A0D0-A369D5890EAA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E3567AB9-0926-444D-A0D0-A369D5890EAA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E3567AB9-0926-444D-A0D0-A369D5890EAA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C8F410B4-B83B-47B9-9ECD-07590A8750A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C8F410B4-B83B-47B9-9ECD-07590A8750A7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C8F410B4-B83B-47B9-9ECD-07590A8750A7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C8F410B4-B83B-47B9-9ECD-07590A8750A7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
25
common/ASC.Textile/ASC.Textile.csproj
Normal file
25
common/ASC.Textile/ASC.Textile.csproj
Normal file
@ -0,0 +1,25 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="Current">
|
||||
<PropertyGroup>
|
||||
<ProductVersion>9.0.30729</ProductVersion>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<FileUpgradeFlags>
|
||||
</FileUpgradeFlags>
|
||||
<UpgradeBackupLocation>
|
||||
</UpgradeBackupLocation>
|
||||
<AssemblyTitle>ASC.Textile</AssemblyTitle>
|
||||
<Company>Ascensio System SIA</Company>
|
||||
<Product>ASC.Textile</Product>
|
||||
<Copyright>(c) Ascensio System SIA. All rights reserved</Copyright>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugType>full</DebugType>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>none</DebugType>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Properties\" />
|
||||
</ItemGroup>
|
||||
</Project>
|
19
common/ASC.Textile/BlockModifier.cs
Normal file
19
common/ASC.Textile/BlockModifier.cs
Normal file
@ -0,0 +1,19 @@
|
||||
namespace Textile
|
||||
{
|
||||
public class BlockModifier
|
||||
{
|
||||
protected BlockModifier()
|
||||
{
|
||||
}
|
||||
|
||||
public virtual string ModifyLine(string line)
|
||||
{
|
||||
return line;
|
||||
}
|
||||
|
||||
public virtual string Conclude(string line)
|
||||
{
|
||||
return line;
|
||||
}
|
||||
}
|
||||
}
|
12
common/ASC.Textile/BlockModifierAttribute.cs
Normal file
12
common/ASC.Textile/BlockModifierAttribute.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System;
|
||||
|
||||
namespace Textile
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
|
||||
public sealed class BlockModifierAttribute : Attribute
|
||||
{
|
||||
public BlockModifierAttribute()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
157
common/ASC.Textile/Blocks/BlockAttributesParser.cs
Normal file
157
common/ASC.Textile/Blocks/BlockAttributesParser.cs
Normal file
@ -0,0 +1,157 @@
|
||||
#region License Statement
|
||||
// Copyright (c) L.A.B.Soft. All rights reserved.
|
||||
//
|
||||
// The use and distribution terms for this software are covered by the
|
||||
// Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
|
||||
// which can be found in the file CPL.TXT at the root of this distribution.
|
||||
// By using this software in any fashion, you are agreeing to be bound by
|
||||
// the terms of this license.
|
||||
//
|
||||
// You must not remove this notice, or any other, from this software.
|
||||
#endregion
|
||||
|
||||
#region Using Statements
|
||||
using System.Text.RegularExpressions;
|
||||
#endregion
|
||||
|
||||
|
||||
namespace Textile.Blocks
|
||||
{
|
||||
public class BlockAttributesParser
|
||||
{
|
||||
public static StyleReader Styler { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
static public string ParseBlockAttributes(string input)
|
||||
{
|
||||
return ParseBlockAttributes(input, "");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <param name="element"></param>
|
||||
/// <returns></returns>
|
||||
static public string ParseBlockAttributes(string input, string element)
|
||||
{
|
||||
var style = string.Empty;
|
||||
var cssClass = string.Empty;
|
||||
var lang = string.Empty;
|
||||
var colspan = string.Empty;
|
||||
var rowspan = string.Empty;
|
||||
var id = string.Empty;
|
||||
var atts = string.Empty;
|
||||
|
||||
if (Styler != null)
|
||||
{
|
||||
style = GetStyle(element, style);
|
||||
}
|
||||
|
||||
if (input.Length == 0)
|
||||
return (style.Length > 0 ? " style=\"" + style + "\"" : "");
|
||||
|
||||
|
||||
Match m;
|
||||
var matched = input;
|
||||
if (element == "td")
|
||||
{
|
||||
// column span
|
||||
m = Regex.Match(matched, @"\\(\d+)");
|
||||
if (m.Success)
|
||||
colspan = m.Groups[1].Value;
|
||||
// row span
|
||||
m = Regex.Match(matched, @"/(\d+)");
|
||||
if (m.Success)
|
||||
rowspan = m.Groups[1].Value;
|
||||
// vertical align
|
||||
m = Regex.Match(matched, @"(" + Globals.VerticalAlignPattern + @")");
|
||||
if (m.Success)
|
||||
style += "vertical-align:" + Globals.VerticalAlign[m.Captures[0].Value] + ";";
|
||||
}
|
||||
|
||||
// First, match custom styles
|
||||
m = Regex.Match(matched, @"\{([^}]*)\}");
|
||||
if (m.Success)
|
||||
{
|
||||
style += m.Groups[1].Value + ";";
|
||||
matched = matched.Replace(m.ToString(), "");
|
||||
}
|
||||
|
||||
// Then match the language
|
||||
m = Regex.Match(matched, @"\[([^()]+)\]");
|
||||
if (m.Success)
|
||||
{
|
||||
lang = m.Groups[1].Value;
|
||||
matched = matched.Replace(m.ToString(), "");
|
||||
}
|
||||
|
||||
// Match classes and IDs after that
|
||||
m = Regex.Match(matched, @"\(([^()]+)\)");
|
||||
if (m.Success)
|
||||
{
|
||||
cssClass = m.Groups[1].Value;
|
||||
matched = matched.Replace(m.ToString(), "");
|
||||
|
||||
// Separate the public class and the ID
|
||||
m = Regex.Match(cssClass, @"^(.*)#(.*)$");
|
||||
if (m.Success)
|
||||
{
|
||||
cssClass = m.Groups[1].Value;
|
||||
id = m.Groups[2].Value;
|
||||
}
|
||||
if (Styler != null && !string.IsNullOrEmpty(cssClass))
|
||||
{
|
||||
style = GetStyle("." + cssClass, style);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Get the padding on the left
|
||||
m = Regex.Match(matched, @"([(]+)");
|
||||
if (m.Success)
|
||||
{
|
||||
style += "padding-left:" + m.Groups[1].Length + "em;";
|
||||
matched = matched.Replace(m.ToString(), "");
|
||||
}
|
||||
|
||||
// Get the padding on the right
|
||||
m = Regex.Match(matched, @"([)]+)");
|
||||
if (m.Success)
|
||||
{
|
||||
style += "padding-right:" + m.Groups[1].Length + "em;";
|
||||
matched = matched.Replace(m.ToString(), "");
|
||||
}
|
||||
|
||||
// Get the text alignment
|
||||
m = Regex.Match(matched, "(" + Globals.HorizontalAlignPattern + ")");
|
||||
if (m.Success)
|
||||
style += "text-align:" + Globals.HorizontalAlign[m.Groups[1].Value] + ";";
|
||||
|
||||
|
||||
|
||||
return (
|
||||
(style.Length > 0 ? " style=\"" + style + "\"" : "") +
|
||||
(cssClass.Length > 0 ? " class=\"" + cssClass + "\"" : "") +
|
||||
(lang.Length > 0 ? " lang=\"" + lang + "\"" : "") +
|
||||
(id.Length > 0 ? " id=\"" + id + "\"" : "") +
|
||||
(colspan.Length > 0 ? " colspan=\"" + colspan + "\"" : "") +
|
||||
(rowspan.Length > 0 ? " rowspan=\"" + rowspan + "\"" : "")
|
||||
);
|
||||
}
|
||||
|
||||
private static string GetStyle(string element, string style)
|
||||
{
|
||||
var styled = Styler.GetStyle(element);
|
||||
if (!string.IsNullOrEmpty(styled))
|
||||
{
|
||||
style += styled;
|
||||
}
|
||||
return style;
|
||||
}
|
||||
}
|
||||
}
|
10
common/ASC.Textile/Blocks/BoldPhraseBlockModifier.cs
Normal file
10
common/ASC.Textile/Blocks/BoldPhraseBlockModifier.cs
Normal file
@ -0,0 +1,10 @@
|
||||
namespace Textile.Blocks
|
||||
{
|
||||
public class BoldPhraseBlockModifier : PhraseBlockModifier
|
||||
{
|
||||
public override string ModifyLine(string line)
|
||||
{
|
||||
return PhraseModifierFormat(line, @"\*\*", "b");
|
||||
}
|
||||
}
|
||||
}
|
19
common/ASC.Textile/Blocks/CapitalsBlockModifier.cs
Normal file
19
common/ASC.Textile/Blocks/CapitalsBlockModifier.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Textile.Blocks
|
||||
{
|
||||
public class CapitalsBlockModifier : BlockModifier
|
||||
{
|
||||
public override string ModifyLine(string line)
|
||||
{
|
||||
var me = new MatchEvaluator(CapitalsFormatMatchEvaluator);
|
||||
line = Regex.Replace(line, @"(?<=^|\s|" + Globals.PunctuationPattern + @")(?<caps>[A-Z][A-Z0-9]+)(?=$|\s|" + Globals.PunctuationPattern + @")", me);
|
||||
return line;
|
||||
}
|
||||
|
||||
static private string CapitalsFormatMatchEvaluator(Match m)
|
||||
{
|
||||
return @"<span class=""caps"">" + m.Groups["caps"].Value + @"</span>";
|
||||
}
|
||||
}
|
||||
}
|
10
common/ASC.Textile/Blocks/CitePhraseBlockModifier.cs
Normal file
10
common/ASC.Textile/Blocks/CitePhraseBlockModifier.cs
Normal file
@ -0,0 +1,10 @@
|
||||
namespace Textile.Blocks
|
||||
{
|
||||
public class CitePhraseBlockModifier : PhraseBlockModifier
|
||||
{
|
||||
public override string ModifyLine(string line)
|
||||
{
|
||||
return PhraseModifierFormat(line, @"\?\?", "cite");
|
||||
}
|
||||
}
|
||||
}
|
61
common/ASC.Textile/Blocks/CodeBlockModifier.cs
Normal file
61
common/ASC.Textile/Blocks/CodeBlockModifier.cs
Normal file
@ -0,0 +1,61 @@
|
||||
#region License Statement
|
||||
// Copyright (c) L.A.B.Soft. All rights reserved.
|
||||
//
|
||||
// The use and distribution terms for this software are covered by the
|
||||
// Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
|
||||
// which can be found in the file CPL.TXT at the root of this distribution.
|
||||
// By using this software in any fashion, you are agreeing to be bound by
|
||||
// the terms of this license.
|
||||
//
|
||||
// You must not remove this notice, or any other, from this software.
|
||||
#endregion
|
||||
|
||||
#region Using Statements
|
||||
using System.Text.RegularExpressions;
|
||||
#endregion
|
||||
|
||||
|
||||
namespace Textile.Blocks
|
||||
{
|
||||
public class CodeBlockModifier : BlockModifier
|
||||
{
|
||||
public override string ModifyLine(string line)
|
||||
{
|
||||
// Replace "@...@" zones with "<code>" tags.
|
||||
var me = new MatchEvaluator(CodeFormatMatchEvaluator);
|
||||
line = Regex.Replace(line,
|
||||
@"(?<before>^|([\s\([{]))" + // before
|
||||
"@" +
|
||||
@"(\|(?<lang>\w+)\|)?" + // lang
|
||||
"(?<code>[^@]+)" + // code
|
||||
"@" +
|
||||
@"(?<after>$|([\]}])|(?=" + Globals.PunctuationPattern + @"{1,2}|\s|$))", // after
|
||||
me);
|
||||
// Encode the contents of the "<code>" tags so that we don't
|
||||
// generate formatting out of it.
|
||||
line = NoTextileEncoder.EncodeNoTextileZones(line,
|
||||
@"(?<=(^|\s)<code(" + Globals.HtmlAttributesPattern + @")>)",
|
||||
@"(?=</code>)");
|
||||
return line;
|
||||
}
|
||||
|
||||
public override string Conclude(string line)
|
||||
{
|
||||
// Recode everything except "<" and ">";
|
||||
line = NoTextileEncoder.DecodeNoTextileZones(line,
|
||||
@"(?<=(^|\s)<code(" + Globals.HtmlAttributesPattern + @")>)",
|
||||
@"(?=</code>)",
|
||||
new string[] { "<", ">" });
|
||||
return line;
|
||||
}
|
||||
|
||||
static public string CodeFormatMatchEvaluator(Match m)
|
||||
{
|
||||
var res = m.Groups["before"].Value + "<code";
|
||||
if (m.Groups["lang"].Length > 0)
|
||||
res += " language=\"" + m.Groups["lang"].Value + "\"";
|
||||
res += ">" + m.Groups["code"].Value + "</code>" + m.Groups["after"].Value;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
10
common/ASC.Textile/Blocks/DeletedPhraseBlockModifier.cs
Normal file
10
common/ASC.Textile/Blocks/DeletedPhraseBlockModifier.cs
Normal file
@ -0,0 +1,10 @@
|
||||
namespace Textile.Blocks
|
||||
{
|
||||
public class DeletedPhraseBlockModifier : PhraseBlockModifier
|
||||
{
|
||||
public override string ModifyLine(string line)
|
||||
{
|
||||
return PhraseModifierFormat(line, @"\-", "del");
|
||||
}
|
||||
}
|
||||
}
|
10
common/ASC.Textile/Blocks/EmphasisPhraseBlockModifier.cs
Normal file
10
common/ASC.Textile/Blocks/EmphasisPhraseBlockModifier.cs
Normal file
@ -0,0 +1,10 @@
|
||||
namespace Textile.Blocks
|
||||
{
|
||||
public class EmphasisPhraseBlockModifier : PhraseBlockModifier
|
||||
{
|
||||
public override string ModifyLine(string line)
|
||||
{
|
||||
return PhraseModifierFormat(line, @"_", "em");
|
||||
}
|
||||
}
|
||||
}
|
27
common/ASC.Textile/Blocks/FootNoteReferenceBlockModifier.cs
Normal file
27
common/ASC.Textile/Blocks/FootNoteReferenceBlockModifier.cs
Normal file
@ -0,0 +1,27 @@
|
||||
#region License Statement
|
||||
// Copyright (c) L.A.B.Soft. All rights reserved.
|
||||
//
|
||||
// The use and distribution terms for this software are covered by the
|
||||
// Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
|
||||
// which can be found in the file CPL.TXT at the root of this distribution.
|
||||
// By using this software in any fashion, you are agreeing to be bound by
|
||||
// the terms of this license.
|
||||
//
|
||||
// You must not remove this notice, or any other, from this software.
|
||||
#endregion
|
||||
|
||||
#region Using Statements
|
||||
using System.Text.RegularExpressions;
|
||||
#endregion
|
||||
|
||||
|
||||
namespace Textile.Blocks
|
||||
{
|
||||
public class FootNoteReferenceBlockModifier : BlockModifier
|
||||
{
|
||||
public override string ModifyLine(string line)
|
||||
{
|
||||
return Regex.Replace(line, @"\b\[([0-9]+)\](\W)", "<sup><a href=\"#fn$1\">$1</a></sup>$2");
|
||||
}
|
||||
}
|
||||
}
|
92
common/ASC.Textile/Blocks/GlyphBlockModifier.cs
Normal file
92
common/ASC.Textile/Blocks/GlyphBlockModifier.cs
Normal file
@ -0,0 +1,92 @@
|
||||
#region License Statement
|
||||
// Copyright (c) L.A.B.Soft. All rights reserved.
|
||||
//
|
||||
// The use and distribution terms for this software are covered by the
|
||||
// Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
|
||||
// which can be found in the file CPL.TXT at the root of this distribution.
|
||||
// By using this software in any fashion, you are agreeing to be bound by
|
||||
// the terms of this license.
|
||||
//
|
||||
// You must not remove this notice, or any other, from this software.
|
||||
#endregion
|
||||
|
||||
#region Using Statements
|
||||
using System.Text.RegularExpressions;
|
||||
#endregion
|
||||
|
||||
|
||||
namespace Textile.Blocks
|
||||
{
|
||||
public class GlyphBlockModifier : BlockModifier
|
||||
{
|
||||
public override string ModifyLine(string line)
|
||||
{
|
||||
line = Regex.Replace(line, "\"\\z", "\" ");
|
||||
|
||||
// fix: hackish
|
||||
string[,] glyphs = {
|
||||
{ @"([^\s[{(>_*])?\'(?(1)|(\s|s\b|" + Globals.PunctuationPattern + @"))", "$1’$2" }, // single closing
|
||||
{ @"\'", "‘" }, // single opening
|
||||
{ @"([^\s[{(>_*])?""(?(1)|(\s|" + Globals.PunctuationPattern + @"))", "$1”$2" }, // double closing
|
||||
{ @"""", "“" }, // double opening
|
||||
{ @"\b( )?\.{3}", "$1…" }, // ellipsis
|
||||
{ @"\b([A-Z][A-Z0-9]{2,})\b(?:[(]([^)]*)[)])", "<acronym title=\"$2\">$1</acronym>" }, // 3+ uppercase acronym
|
||||
{ @"(\s)?--(\s)?", "$1—$2" }, // em dash
|
||||
{ @"\s-\s", " – " }, // en dash
|
||||
{ @"(\d+)( )?x( )?(\d+)", "$1$2×$3$4" }, // dimension sign
|
||||
{ @"\b ?[([](TM|tm)[])]", "™" }, // trademark
|
||||
{ @"\b ?[([](R|r)[])]", "®" }, // registered
|
||||
{ @"\b ?[([](C|c)[])]", "©" } // copyright
|
||||
};
|
||||
|
||||
var output = "";
|
||||
|
||||
if (!Regex.IsMatch(line, "<.*>"))
|
||||
{
|
||||
// If no HTML, do a simple search & replace.
|
||||
for (var i = 0; i < glyphs.GetLength(0); ++i)
|
||||
{
|
||||
line = Regex.Replace(line, glyphs[i, 0], glyphs[i, 1]);
|
||||
}
|
||||
output = line;
|
||||
}
|
||||
else
|
||||
{
|
||||
var splits = Regex.Split(line, "(<.*?>)");
|
||||
var offtags = "code|pre|notextile";
|
||||
var codepre = false;
|
||||
foreach (var split in splits)
|
||||
{
|
||||
var modifiedSplit = split;
|
||||
if (modifiedSplit.Length == 0)
|
||||
continue;
|
||||
|
||||
if (Regex.IsMatch(modifiedSplit, @"<(" + offtags + ")>"))
|
||||
codepre = true;
|
||||
if (Regex.IsMatch(modifiedSplit, @"<\/(" + offtags + ")>"))
|
||||
codepre = false;
|
||||
|
||||
if (!Regex.IsMatch(modifiedSplit, "<.*>") && !codepre)
|
||||
{
|
||||
for (var i = 0; i < glyphs.GetLength(0); ++i)
|
||||
{
|
||||
modifiedSplit = Regex.Replace(modifiedSplit, glyphs[i, 0], glyphs[i, 1]);
|
||||
}
|
||||
}
|
||||
|
||||
// do htmlspecial if between <code>
|
||||
if (codepre == true)
|
||||
{
|
||||
//TODO: htmlspecialchars(line)
|
||||
//line = Regex.Replace(line, @"<(\/?" + offtags + ")>", "<$1>");
|
||||
//line = line.Replace("&#", "&#");
|
||||
}
|
||||
|
||||
output += modifiedSplit;
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
62
common/ASC.Textile/Blocks/HyperLinkBlockModifier.cs
Normal file
62
common/ASC.Textile/Blocks/HyperLinkBlockModifier.cs
Normal file
@ -0,0 +1,62 @@
|
||||
#region License Statement
|
||||
// Copyright (c) L.A.B.Soft. All rights reserved.
|
||||
//
|
||||
// The use and distribution terms for this software are covered by the
|
||||
// Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
|
||||
// which can be found in the file CPL.TXT at the root of this distribution.
|
||||
// By using this software in any fashion, you are agreeing to be bound by
|
||||
// the terms of this license.
|
||||
//
|
||||
// You must not remove this notice, or any other, from this software.
|
||||
#endregion
|
||||
|
||||
#region Using Statements
|
||||
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
namespace Textile.Blocks
|
||||
{
|
||||
public class HyperLinkBlockModifier : BlockModifier
|
||||
{
|
||||
private readonly string m_rel = string.Empty;
|
||||
|
||||
public override string ModifyLine(string line)
|
||||
{
|
||||
line = Regex.Replace(line,
|
||||
@"(?<pre>[\s[{(]|" + Globals.PunctuationPattern + @")?" + // $pre
|
||||
"\"" + // start
|
||||
Globals.BlockModifiersPattern + // attributes
|
||||
"(?<text>[\\w\\W]+?)" + // text
|
||||
@"\s?" +
|
||||
@"(?:\((?<title>[^)]+)\)(?=""))?" + // title
|
||||
"\":" +
|
||||
string.Format(@"""(?<url>\S+[^""]+)""",Regex.Escape(@"a-zA-Z:/.-{}?&_%#+=@")) + // url
|
||||
@"(?<slash>\/)?" + // slash
|
||||
@"(?<post>[^\w\/;]*)" + // post
|
||||
@"(?=\s|$)",
|
||||
new MatchEvaluator(HyperLinksFormatMatchEvaluator));
|
||||
return line;
|
||||
}
|
||||
|
||||
private string HyperLinksFormatMatchEvaluator(Match m)
|
||||
{
|
||||
//TODO: check the URL
|
||||
var atts = BlockAttributesParser.ParseBlockAttributes(m.Groups["atts"].Value, "a");
|
||||
if (m.Groups["title"].Length > 0)
|
||||
atts += " title=\"" + m.Groups["title"].Value + "\"";
|
||||
var linkText = m.Groups["text"].Value.Trim(' ');
|
||||
|
||||
var str = m.Groups["pre"].Value + "<a ";
|
||||
if (!string.IsNullOrEmpty(m_rel))
|
||||
str += "ref=\"" + m_rel + "\" ";
|
||||
str += "href=\"" +
|
||||
m.Groups["url"].Value + m.Groups["slash"].Value + "\"" +
|
||||
atts +
|
||||
">" + linkText + "</a>" + m.Groups["post"].Value;
|
||||
return str;
|
||||
}
|
||||
}
|
||||
}
|
73
common/ASC.Textile/Blocks/ImageBlockModifier.cs
Normal file
73
common/ASC.Textile/Blocks/ImageBlockModifier.cs
Normal file
@ -0,0 +1,73 @@
|
||||
#region License Statement
|
||||
// Copyright (c) L.A.B.Soft. All rights reserved.
|
||||
//
|
||||
// The use and distribution terms for this software are covered by the
|
||||
// Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
|
||||
// which can be found in the file CPL.TXT at the root of this distribution.
|
||||
// By using this software in any fashion, you are agreeing to be bound by
|
||||
// the terms of this license.
|
||||
//
|
||||
// You must not remove this notice, or any other, from this software.
|
||||
#endregion
|
||||
|
||||
#region Using Statements
|
||||
using System.Text.RegularExpressions;
|
||||
#endregion
|
||||
|
||||
namespace Textile.Blocks
|
||||
{
|
||||
public class ImageBlockModifier : BlockModifier
|
||||
{
|
||||
public override string ModifyLine(string line)
|
||||
{
|
||||
line = Regex.Replace(line,
|
||||
@"\!" + // opening !
|
||||
@"(?<algn>\<|\=|\>)?" + // optional alignment atts
|
||||
Globals.BlockModifiersPattern + // optional style, public class atts
|
||||
@"(?:\. )?" + // optional dot-space
|
||||
@"(?<url>[^\s(!]+)" + // presume this is the src
|
||||
@"\s?" + // optional space
|
||||
@"(?:\((?<title>([^\)]+))\))?" +// optional title
|
||||
@"\!" + // closing
|
||||
@"(?::(?<href>(\S+)))?" + // optional href
|
||||
@"(?=\s|\.|,|;|\)|\||$)", // lookahead: space or simple punctuation or end of string
|
||||
new MatchEvaluator(ImageFormatMatchEvaluator)
|
||||
);
|
||||
return line;
|
||||
}
|
||||
|
||||
static string ImageFormatMatchEvaluator(Match m)
|
||||
{
|
||||
var atts = BlockAttributesParser.ParseBlockAttributes(m.Groups["atts"].Value, "img");
|
||||
if (m.Groups["algn"].Length > 0)
|
||||
atts += " align=\"" + Globals.ImageAlign[m.Groups["algn"].Value] + "\"";
|
||||
if (m.Groups["title"].Length > 0)
|
||||
{
|
||||
atts += " title=\"" + m.Groups["title"].Value + "\"";
|
||||
atts += " alt=\"" + m.Groups["title"].Value + "\"";
|
||||
}
|
||||
else
|
||||
{
|
||||
atts += " alt=\"\"";
|
||||
}
|
||||
// Get Image Size?
|
||||
|
||||
var res = "<img src=\"" + m.Groups["url"].Value + "\"" + atts + " />";
|
||||
|
||||
if (m.Groups["href"].Length > 0)
|
||||
{
|
||||
var href = m.Groups["href"].Value;
|
||||
var end = string.Empty;
|
||||
var endMatch = Regex.Match(href, @"(.*)(?<end>\.|,|;|\))$");
|
||||
if (m.Success && !string.IsNullOrEmpty(endMatch.Groups["end"].Value))
|
||||
{
|
||||
href = href[0..^1];
|
||||
end = endMatch.Groups["end"].Value;
|
||||
}
|
||||
res = "<a href=\"" + Globals.EncodeHTMLLink(href) + "\">" + res + "</a>" + end;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
10
common/ASC.Textile/Blocks/InsertedPhraseBlockModifier.cs
Normal file
10
common/ASC.Textile/Blocks/InsertedPhraseBlockModifier.cs
Normal file
@ -0,0 +1,10 @@
|
||||
namespace Textile.Blocks
|
||||
{
|
||||
public class InsertedPhraseBlockModifier : PhraseBlockModifier
|
||||
{
|
||||
public override string ModifyLine(string line)
|
||||
{
|
||||
return PhraseModifierFormat(line, @"\+", "ins");
|
||||
}
|
||||
}
|
||||
}
|
10
common/ASC.Textile/Blocks/ItalicPhraseBlockModifier.cs
Normal file
10
common/ASC.Textile/Blocks/ItalicPhraseBlockModifier.cs
Normal file
@ -0,0 +1,10 @@
|
||||
namespace Textile.Blocks
|
||||
{
|
||||
public class ItalicPhraseBlockModifier : PhraseBlockModifier
|
||||
{
|
||||
public override string ModifyLine(string line)
|
||||
{
|
||||
return PhraseModifierFormat(line, @"__", "i");
|
||||
}
|
||||
}
|
||||
}
|
35
common/ASC.Textile/Blocks/NoTextileBlockModifier.cs
Normal file
35
common/ASC.Textile/Blocks/NoTextileBlockModifier.cs
Normal file
@ -0,0 +1,35 @@
|
||||
#region License Statement
|
||||
// Copyright (c) L.A.B.Soft. All rights reserved.
|
||||
//
|
||||
// The use and distribution terms for this software are covered by the
|
||||
// Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
|
||||
// which can be found in the file CPL.TXT at the root of this distribution.
|
||||
// By using this software in any fashion, you are agreeing to be bound by
|
||||
// the terms of this license.
|
||||
//
|
||||
// You must not remove this notice, or any other, from this software.
|
||||
#endregion
|
||||
|
||||
#region Using Statements
|
||||
#endregion
|
||||
|
||||
|
||||
namespace Textile.Blocks
|
||||
{
|
||||
public class NoTextileBlockModifier : BlockModifier
|
||||
{
|
||||
public override string ModifyLine(string line)
|
||||
{
|
||||
line = NoTextileEncoder.EncodeNoTextileZones(line, @"(?<=^|\s)<notextile>", @"</notextile>(?=(\s|$)?)");
|
||||
line = NoTextileEncoder.EncodeNoTextileZones(line, @"==", @"==");
|
||||
return line;
|
||||
}
|
||||
|
||||
public override string Conclude(string line)
|
||||
{
|
||||
line = NoTextileEncoder.DecodeNoTextileZones(line, @"(?<=^|\s)<notextile>", @"</notextile>(?=(\s|$)?)");
|
||||
line = NoTextileEncoder.DecodeNoTextileZones(line, @"==", @"==");
|
||||
return line;
|
||||
}
|
||||
}
|
||||
}
|
82
common/ASC.Textile/Blocks/NoTextileEncoder.cs
Normal file
82
common/ASC.Textile/Blocks/NoTextileEncoder.cs
Normal file
@ -0,0 +1,82 @@
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Textile.Blocks
|
||||
{
|
||||
public static class NoTextileEncoder
|
||||
{
|
||||
private static readonly string[,] TextileModifiers = {
|
||||
{ "\"", """ },
|
||||
{ "%", "%" },
|
||||
{ "*", "*" },
|
||||
{ "+", "+" },
|
||||
{ "-", "-" },
|
||||
{ "<", "<" }, // or "<"
|
||||
{ "=", "=" },
|
||||
{ ">", ">" }, // or ">"
|
||||
{ "?", "?" },
|
||||
{ "^", "^" },
|
||||
{ "_", "_" },
|
||||
{ "~", "~" },
|
||||
{ "@", "@" },
|
||||
{ "'", "'" },
|
||||
{ "|", "|" },
|
||||
{ "!", "!" },
|
||||
{ "(", "(" },
|
||||
{ ")", ")" },
|
||||
{ ".", "." },
|
||||
{ "x", "x" }
|
||||
};
|
||||
|
||||
|
||||
public static string EncodeNoTextileZones(string tmp, string patternPrefix, string patternSuffix)
|
||||
{
|
||||
return EncodeNoTextileZones(tmp, patternPrefix, patternSuffix, null);
|
||||
}
|
||||
|
||||
public static string EncodeNoTextileZones(string tmp, string patternPrefix, string patternSuffix, string[] exceptions)
|
||||
{
|
||||
string evaluator(Match m)
|
||||
{
|
||||
var toEncode = m.Groups["notex"].Value;
|
||||
if (toEncode == string.Empty)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
for (var i = 0; i < TextileModifiers.GetLength(0); ++i)
|
||||
{
|
||||
if (exceptions == null || Array.IndexOf(exceptions, TextileModifiers[i, 0]) < 0)
|
||||
{
|
||||
toEncode = toEncode.Replace(TextileModifiers[i, 0], TextileModifiers[i, 1]);
|
||||
}
|
||||
}
|
||||
return patternPrefix + toEncode + patternSuffix;
|
||||
}
|
||||
tmp = Regex.Replace(tmp, string.Format("({0}(?<notex>.+?){1})*", patternPrefix, patternSuffix), new MatchEvaluator(evaluator));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
public static string DecodeNoTextileZones(string tmp, string patternPrefix, string patternSuffix)
|
||||
{
|
||||
return DecodeNoTextileZones(tmp, patternPrefix, patternSuffix, null);
|
||||
}
|
||||
|
||||
public static string DecodeNoTextileZones(string tmp, string patternPrefix, string patternSuffix, string[] exceptions)
|
||||
{
|
||||
string evaluator(Match m)
|
||||
{
|
||||
var toEncode = m.Groups["notex"].Value;
|
||||
for (var i = 0; i < TextileModifiers.GetLength(0); ++i)
|
||||
{
|
||||
if (exceptions == null || Array.IndexOf(exceptions, TextileModifiers[i, 0]) < 0)
|
||||
{
|
||||
toEncode = toEncode.Replace(TextileModifiers[i, 1], TextileModifiers[i, 0]);
|
||||
}
|
||||
}
|
||||
return toEncode;
|
||||
}
|
||||
tmp = Regex.Replace(tmp, string.Format("({0}(?<notex>.+?){1})*", patternPrefix, patternSuffix), new MatchEvaluator(evaluator));
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
}
|
96
common/ASC.Textile/Blocks/PhraseBlockModifier.cs
Normal file
96
common/ASC.Textile/Blocks/PhraseBlockModifier.cs
Normal file
@ -0,0 +1,96 @@
|
||||
#region License Statement
|
||||
// Copyright (c) L.A.B.Soft. All rights reserved.
|
||||
//
|
||||
// The use and distribution terms for this software are covered by the
|
||||
// Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
|
||||
// which can be found in the file CPL.TXT at the root of this distribution.
|
||||
// By using this software in any fashion, you are agreeing to be bound by
|
||||
// the terms of this license.
|
||||
//
|
||||
// You must not remove this notice, or any other, from this software.
|
||||
#endregion
|
||||
|
||||
#region Using Statements
|
||||
using System.Text.RegularExpressions;
|
||||
#endregion
|
||||
|
||||
|
||||
namespace Textile.Blocks
|
||||
{
|
||||
public abstract class PhraseBlockModifier : BlockModifier
|
||||
{
|
||||
protected PhraseBlockModifier()
|
||||
{
|
||||
}
|
||||
|
||||
protected string PhraseModifierFormat(string input, string modifier, string tag)
|
||||
{
|
||||
// All phrase modifiers are one character, or a double character. Sometimes,
|
||||
// there's an additional escape character for the regex ('\').
|
||||
var compressedModifier = modifier;
|
||||
if (modifier.Length == 4)
|
||||
{
|
||||
compressedModifier = modifier.Substring(0, 2);
|
||||
}
|
||||
else if (modifier.Length == 2)
|
||||
{
|
||||
if (modifier[0] != '\\')
|
||||
compressedModifier = modifier.Substring(0, 1);
|
||||
//else: compressedModifier = modifier;
|
||||
}
|
||||
//else: compressedModifier = modifier;
|
||||
|
||||
// We try to remove the Textile tag used for the formatting from
|
||||
// the punctuation pattern, so that we match the end of the formatted
|
||||
// zone correctly.
|
||||
var punctuationPattern = Globals.PunctuationPattern.Replace(compressedModifier, "");
|
||||
|
||||
// Now we can do the replacement.
|
||||
var pmme = new PhraseModifierMatchEvaluator(tag);
|
||||
var res = Regex.Replace(input,
|
||||
@"(?<=\s|" + punctuationPattern + @"|[{\(\[]|^)" +
|
||||
modifier +
|
||||
Globals.BlockModifiersPattern +
|
||||
@"(:(?<cite>(\S+)))?" +
|
||||
@"(?<content>[^" + compressedModifier + "]*)" +
|
||||
@"(?<end>" + punctuationPattern + @"*)" +
|
||||
modifier +
|
||||
@"(?=[\]\)}]|" + punctuationPattern + @"+|\s|$)",
|
||||
new MatchEvaluator(pmme.MatchEvaluator)
|
||||
);
|
||||
return res;
|
||||
}
|
||||
|
||||
private class PhraseModifierMatchEvaluator
|
||||
{
|
||||
readonly string m_tag;
|
||||
|
||||
public PhraseModifierMatchEvaluator(string tag)
|
||||
{
|
||||
m_tag = tag;
|
||||
}
|
||||
|
||||
public string MatchEvaluator(Match m)
|
||||
{
|
||||
if (m.Groups["content"].Length == 0)
|
||||
{
|
||||
// It's possible that the "atts" match groups eats the contents
|
||||
// when the user didn't want to give block attributes, but the content
|
||||
// happens to match the syntax. For example: "*(blah)*".
|
||||
if (m.Groups["atts"].Length == 0)
|
||||
return m.ToString();
|
||||
return "<" + m_tag + ">" + m.Groups["atts"].Value + m.Groups["end"].Value + "</" + m_tag + ">";
|
||||
}
|
||||
|
||||
var atts = BlockAttributesParser.ParseBlockAttributes(m.Groups["atts"].Value, m_tag);
|
||||
if (m.Groups["cite"].Length > 0)
|
||||
atts += " cite=\"" + m.Groups["cite"] + "\"";
|
||||
|
||||
var res = "<" + m_tag + atts + ">" +
|
||||
m.Groups["content"].Value + m.Groups["end"].Value +
|
||||
"</" + m_tag + ">";
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
41
common/ASC.Textile/Blocks/PreBlockModifier.cs
Normal file
41
common/ASC.Textile/Blocks/PreBlockModifier.cs
Normal file
@ -0,0 +1,41 @@
|
||||
#region License Statement
|
||||
// Copyright (c) L.A.B.Soft. All rights reserved.
|
||||
//
|
||||
// The use and distribution terms for this software are covered by the
|
||||
// Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
|
||||
// which can be found in the file CPL.TXT at the root of this distribution.
|
||||
// By using this software in any fashion, you are agreeing to be bound by
|
||||
// the terms of this license.
|
||||
//
|
||||
// You must not remove this notice, or any other, from this software.
|
||||
#endregion
|
||||
|
||||
#region Using Statements
|
||||
#endregion
|
||||
|
||||
|
||||
namespace Textile.Blocks
|
||||
{
|
||||
public class PreBlockModifier : BlockModifier
|
||||
{
|
||||
public override string ModifyLine(string line)
|
||||
{
|
||||
// Encode the contents of the "<pre>" tags so that we don't
|
||||
// generate formatting out of it.
|
||||
line = NoTextileEncoder.EncodeNoTextileZones(line,
|
||||
@"(?<=(^|\s)<pre(" + Globals.HtmlAttributesPattern + @")>)",
|
||||
@"(?=</pre>)");
|
||||
return line;
|
||||
}
|
||||
|
||||
public override string Conclude(string line)
|
||||
{
|
||||
// Recode everything.
|
||||
line = NoTextileEncoder.DecodeNoTextileZones(line,
|
||||
@"(?<=(^|\s)<pre(" + Globals.HtmlAttributesPattern + @")>)",
|
||||
@"(?=</pre>)",
|
||||
new string[] { "<", ">" });
|
||||
return line;
|
||||
}
|
||||
}
|
||||
}
|
10
common/ASC.Textile/Blocks/SpanPhraseBlockModifier.cs
Normal file
10
common/ASC.Textile/Blocks/SpanPhraseBlockModifier.cs
Normal file
@ -0,0 +1,10 @@
|
||||
namespace Textile.Blocks
|
||||
{
|
||||
public class SpanPhraseBlockModifier : PhraseBlockModifier
|
||||
{
|
||||
public override string ModifyLine(string line)
|
||||
{
|
||||
return PhraseModifierFormat(line, @"%", "span");
|
||||
}
|
||||
}
|
||||
}
|
10
common/ASC.Textile/Blocks/StrongPhraseBlockModifier.cs
Normal file
10
common/ASC.Textile/Blocks/StrongPhraseBlockModifier.cs
Normal file
@ -0,0 +1,10 @@
|
||||
namespace Textile.Blocks
|
||||
{
|
||||
public class StrongPhraseBlockModifier : PhraseBlockModifier
|
||||
{
|
||||
public override string ModifyLine(string line)
|
||||
{
|
||||
return PhraseModifierFormat(line, @"\*", "strong");
|
||||
}
|
||||
}
|
||||
}
|
10
common/ASC.Textile/Blocks/SubScriptPhraseBlockModifier.cs
Normal file
10
common/ASC.Textile/Blocks/SubScriptPhraseBlockModifier.cs
Normal file
@ -0,0 +1,10 @@
|
||||
namespace Textile.Blocks
|
||||
{
|
||||
public class SubScriptPhraseBlockModifier : PhraseBlockModifier
|
||||
{
|
||||
public override string ModifyLine(string line)
|
||||
{
|
||||
return PhraseModifierFormat(line, @"~", "sub");
|
||||
}
|
||||
}
|
||||
}
|
10
common/ASC.Textile/Blocks/SuperScriptPhraseBlockModifier.cs
Normal file
10
common/ASC.Textile/Blocks/SuperScriptPhraseBlockModifier.cs
Normal file
@ -0,0 +1,10 @@
|
||||
namespace Textile.Blocks
|
||||
{
|
||||
public class SuperScriptPhraseBlockModifier : PhraseBlockModifier
|
||||
{
|
||||
public override string ModifyLine(string line)
|
||||
{
|
||||
return PhraseModifierFormat(line, @"\^", "sup");
|
||||
}
|
||||
}
|
||||
}
|
141
common/ASC.Textile/FormatterState.cs
Normal file
141
common/ASC.Textile/FormatterState.cs
Normal file
@ -0,0 +1,141 @@
|
||||
#region License Statement
|
||||
// Copyright (c) L.A.B.Soft. All rights reserved.
|
||||
//
|
||||
// The use and distribution terms for this software are covered by the
|
||||
// Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
|
||||
// which can be found in the file CPL.TXT at the root of this distribution.
|
||||
// By using this software in any fashion, you are agreeing to be bound by
|
||||
// the terms of this license.
|
||||
//
|
||||
// You must not remove this notice, or any other, from this software.
|
||||
#endregion
|
||||
|
||||
#region Using Statements
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
#endregion
|
||||
|
||||
|
||||
namespace Textile
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for formatter states.
|
||||
/// </summary>
|
||||
/// A formatter state describes the current situation
|
||||
/// of the text being currently processed. A state can
|
||||
/// write HTML code when entered, exited, and can modify
|
||||
/// each line of text it receives.
|
||||
public abstract class FormatterState
|
||||
{
|
||||
/// <summary>
|
||||
/// The formatter this state belongs to.
|
||||
/// </summary>
|
||||
public TextileFormatter Formatter { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Public constructor.
|
||||
/// </summary>
|
||||
/// <param name="f">The parent formatter.</param>
|
||||
public FormatterState(TextileFormatter formatter)
|
||||
{
|
||||
Formatter = formatter;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <param name="m"></param>
|
||||
/// <returns></returns>
|
||||
public abstract string Consume(string input, Match m);
|
||||
|
||||
/// <summary>
|
||||
/// Method called when the state is entered.
|
||||
/// </summary>
|
||||
public abstract void Enter();
|
||||
/// <summary>
|
||||
/// Method called when the state is exited.
|
||||
/// </summary>
|
||||
public abstract void Exit();
|
||||
/// <summary>
|
||||
/// Method called when a line of text should be written
|
||||
/// to the web form.
|
||||
/// </summary>
|
||||
/// <param name="input">The line of text.</param>
|
||||
public abstract void FormatLine(string input);
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether this state can last for more than one line.
|
||||
/// </summary>
|
||||
/// <returns>A boolean value stating whether this state is only for one line.</returns>
|
||||
/// This method should return true only if this state is genuinely
|
||||
/// multi-line. For example, a header text is only one line long. You can
|
||||
/// have several consecutive lines of header texts, but they are not the same
|
||||
/// header - just several headers one after the other.
|
||||
/// Bulleted and numbered lists are good examples of multi-line states.
|
||||
//abstract public bool IsOneLineOnly();
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
public abstract bool ShouldExit(string input);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="actualTag"></param>
|
||||
/// <param name="alignNfo"></param>
|
||||
/// <param name="attNfo"></param>
|
||||
/// <returns></returns>
|
||||
public virtual bool ShouldNestState(FormatterState other)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether block formatting (quick phrase modifiers, etc.) should be
|
||||
/// applied to this line.
|
||||
/// </summary>
|
||||
/// <param name="input">The line of text</param>
|
||||
/// <returns>Whether the line should be formatted for blocks</returns>
|
||||
public virtual bool ShouldFormatBlocks(string input)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether the current state accepts being superceded by another one
|
||||
/// we would possibly find by parsing the input line of text.
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
public virtual bool ShouldParseForNewFormatterState(string input)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the formatting state we should fallback to if we don't find anything
|
||||
/// relevant in a line of text.
|
||||
/// </summary>
|
||||
public virtual Type FallbackFormattingState
|
||||
{
|
||||
get
|
||||
{
|
||||
return typeof(States.ParagraphFormatterState);
|
||||
}
|
||||
}
|
||||
|
||||
protected FormatterState CurrentFormatterState
|
||||
{
|
||||
get { return this.Formatter.CurrentState; }
|
||||
}
|
||||
|
||||
protected void ChangeFormatterState(FormatterState formatterState)
|
||||
{
|
||||
this.Formatter.ChangeState(formatterState);
|
||||
}
|
||||
}
|
||||
}
|
23
common/ASC.Textile/FormatterStateAttribute.cs
Normal file
23
common/ASC.Textile/FormatterStateAttribute.cs
Normal file
@ -0,0 +1,23 @@
|
||||
using System;
|
||||
|
||||
namespace Textile
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
|
||||
public sealed class FormatterStateAttribute : Attribute
|
||||
{
|
||||
public string Pattern { get; }
|
||||
|
||||
public FormatterStateAttribute(string pattern)
|
||||
{
|
||||
Pattern = pattern;
|
||||
}
|
||||
|
||||
public static FormatterStateAttribute Get(Type type)
|
||||
{
|
||||
var atts = type.GetCustomAttributes(typeof(FormatterStateAttribute), false);
|
||||
if (atts.Length == 0)
|
||||
return null;
|
||||
return (FormatterStateAttribute)atts[0];
|
||||
}
|
||||
}
|
||||
}
|
107
common/ASC.Textile/Globals.cs
Normal file
107
common/ASC.Textile/Globals.cs
Normal file
@ -0,0 +1,107 @@
|
||||
#region License Statement
|
||||
// Copyright (c) L.A.B.Soft. All rights reserved.
|
||||
//
|
||||
// The use and distribution terms for this software are covered by the
|
||||
// Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
|
||||
// which can be found in the file CPL.TXT at the root of this distribution.
|
||||
// By using this software in any fashion, you are agreeing to be bound by
|
||||
// the terms of this license.
|
||||
//
|
||||
// You must not remove this notice, or any other, from this software.
|
||||
#endregion
|
||||
|
||||
#region Using Statements
|
||||
using System.Collections.Generic;
|
||||
#endregion
|
||||
|
||||
|
||||
namespace Textile
|
||||
{
|
||||
/// <summary>
|
||||
/// A utility class for global things used by the TextileFormatter.
|
||||
/// </summary>
|
||||
class Globals
|
||||
{
|
||||
#region Global Regex Patterns
|
||||
|
||||
public const string HorizontalAlignPattern = @"(?:[()]*(\<(?!>)|(?<!<)\>|\<\>|=)[()]*)";
|
||||
public const string VerticalAlignPattern = @"[\-^~]";
|
||||
public const string CssClassPattern = @"(?:\([^)]+\))";
|
||||
public const string LanguagePattern = @"(?:\[[^]]+\])";
|
||||
public const string CssStylePattern = @"(?:\{[^}]+\})";
|
||||
public const string ColumnSpanPattern = @"(?:\\\d+)";
|
||||
public const string RowSpanPattern = @"(?:/\d+)";
|
||||
|
||||
public const string AlignPattern = "(?<align>" + HorizontalAlignPattern + "?" + VerticalAlignPattern + "?|" + VerticalAlignPattern + "?" + HorizontalAlignPattern + "?)";
|
||||
public const string SpanPattern = @"(?<span>" + ColumnSpanPattern + "?" + RowSpanPattern + "?|" + RowSpanPattern + "?" + ColumnSpanPattern + "?)";
|
||||
public const string BlockModifiersPattern = @"(?<atts>" + CssClassPattern + "?" + CssStylePattern + "?" + LanguagePattern + "?|" +
|
||||
CssStylePattern + "?" + LanguagePattern + "?" + CssClassPattern + "?|" +
|
||||
LanguagePattern + "?" + CssStylePattern + "?" + CssClassPattern + "?)";
|
||||
|
||||
public const string PunctuationPattern = @"[\!""#\$%&'()\*\+,\-\./:;<=>\?@\[\\\]\^_`{}~]";
|
||||
|
||||
public const string HtmlAttributesPattern = @"(\s+\w+=((""[^""]+"")|('[^']+')))*";
|
||||
|
||||
#endregion
|
||||
|
||||
private static Dictionary<string, string> m_imageAlign;
|
||||
/// <summary>
|
||||
/// Image alignment tags, mapped to their HTML meanings.
|
||||
/// </summary>
|
||||
public static Dictionary<string, string> ImageAlign
|
||||
{
|
||||
get { return Globals.m_imageAlign; }
|
||||
set { Globals.m_imageAlign = value; }
|
||||
}
|
||||
private static Dictionary<string, string> m_horizontalAlign;
|
||||
/// <summary>
|
||||
/// Horizontal text alignment tags, mapped to their HTML meanings.
|
||||
/// </summary>
|
||||
public static Dictionary<string, string> HorizontalAlign
|
||||
{
|
||||
get { return Globals.m_horizontalAlign; }
|
||||
set { Globals.m_horizontalAlign = value; }
|
||||
}
|
||||
private static Dictionary<string, string> m_verticalAlign;
|
||||
/// <summary>
|
||||
/// Vertical text alignment tags, mapped to their HTML meanings.
|
||||
/// </summary>
|
||||
public static Dictionary<string, string> VerticalAlign
|
||||
{
|
||||
get { return Globals.m_verticalAlign; }
|
||||
set { Globals.m_verticalAlign = value; }
|
||||
}
|
||||
|
||||
static Globals()
|
||||
{
|
||||
m_imageAlign = new Dictionary<string, string>
|
||||
{
|
||||
["<"] = "left",
|
||||
["="] = "center",
|
||||
[">"] = "right"
|
||||
};
|
||||
|
||||
m_horizontalAlign = new Dictionary<string, string>
|
||||
{
|
||||
["<"] = "left",
|
||||
["="] = "center",
|
||||
[">"] = "right",
|
||||
["<>"] = "justify"
|
||||
};
|
||||
|
||||
m_verticalAlign = new Dictionary<string, string>
|
||||
{
|
||||
["^"] = "top",
|
||||
["-"] = "middle",
|
||||
["~"] = "bottom"
|
||||
};
|
||||
}
|
||||
|
||||
public static string EncodeHTMLLink(string url)
|
||||
{
|
||||
url = url.Replace("&", "&");
|
||||
url = System.Text.RegularExpressions.Regex.Replace(url, "&(?=[^#])", "&");
|
||||
return url;
|
||||
}
|
||||
}
|
||||
}
|
53
common/ASC.Textile/IOutputter.cs
Normal file
53
common/ASC.Textile/IOutputter.cs
Normal file
@ -0,0 +1,53 @@
|
||||
#region License Statement
|
||||
// Copyright (c) L.A.B.Soft. All rights reserved.
|
||||
//
|
||||
// The use and distribution terms for this software are covered by the
|
||||
// Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
|
||||
// which can be found in the file CPL.TXT at the root of this distribution.
|
||||
// By using this software in any fashion, you are agreeing to be bound by
|
||||
// the terms of this license.
|
||||
//
|
||||
// You must not remove this notice, or any other, from this software.
|
||||
#endregion
|
||||
|
||||
#region Using Statements
|
||||
#endregion
|
||||
|
||||
|
||||
namespace Textile
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface through which the HTML formatted text
|
||||
/// will be sent.
|
||||
/// </summary>
|
||||
/// Clients of the TextileFormatter class will have to provide
|
||||
/// an outputter that implements this interface. Most of the
|
||||
/// time, it'll be the WebForm itself.
|
||||
public interface IOutputter
|
||||
{
|
||||
/// <summary>
|
||||
/// Method called just before the formatted text
|
||||
/// is sent to the outputter.
|
||||
/// </summary>
|
||||
void Begin();
|
||||
|
||||
/// <summary>
|
||||
/// Metohd called whenever the TextileFormatter wants to
|
||||
/// print some text.
|
||||
/// </summary>
|
||||
/// <param name="text">The formatted HTML text.</param>
|
||||
void Write(string text);
|
||||
/// <summary>
|
||||
/// Metohd called whenever the TextileFormatter wants to
|
||||
/// print some text. This should automatically print an
|
||||
/// additionnal end of line character.
|
||||
/// </summary>
|
||||
/// <param name="line">The formatted HTML text.</param>
|
||||
void WriteLine(string line);
|
||||
|
||||
/// <summary>
|
||||
/// Method called at the end of the formatting.
|
||||
/// </summary>
|
||||
void End();
|
||||
}
|
||||
}
|
57
common/ASC.Textile/States/BlockQuoteFormatterState.cs
Normal file
57
common/ASC.Textile/States/BlockQuoteFormatterState.cs
Normal file
@ -0,0 +1,57 @@
|
||||
#region License Statement
|
||||
// Copyright (c) L.A.B.Soft. All rights reserved.
|
||||
//
|
||||
// The use and distribution terms for this software are covered by the
|
||||
// Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
|
||||
// which can be found in the file CPL.TXT at the root of this distribution.
|
||||
// By using this software in any fashion, you are agreeing to be bound by
|
||||
// the terms of this license.
|
||||
//
|
||||
// You must not remove this notice, or any other, from this software.
|
||||
#endregion
|
||||
|
||||
#region Using Statements
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
#endregion
|
||||
|
||||
|
||||
namespace Textile.States
|
||||
{
|
||||
[FormatterState(SimpleBlockFormatterState.PatternBegin + @"bq" + SimpleBlockFormatterState.PatternEnd)]
|
||||
public class BlockQuoteFormatterState : SimpleBlockFormatterState
|
||||
{
|
||||
public BlockQuoteFormatterState(TextileFormatter f)
|
||||
: base(f)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Enter()
|
||||
{
|
||||
Formatter.Output.Write("<blockquote" + FormattedStylesAndAlignment("blockquote") + "><p>");
|
||||
}
|
||||
|
||||
public override void Exit()
|
||||
{
|
||||
Formatter.Output.WriteLine("</p></blockquote>");
|
||||
}
|
||||
|
||||
public override void FormatLine(string input)
|
||||
{
|
||||
Formatter.Output.Write(input);
|
||||
}
|
||||
|
||||
public override bool ShouldExit(string input)
|
||||
{
|
||||
if (Regex.IsMatch(input, @"^\s*$"))
|
||||
return true;
|
||||
Formatter.Output.WriteLine("<br />");
|
||||
return false;
|
||||
}
|
||||
|
||||
public override Type FallbackFormattingState
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
}
|
||||
}
|
80
common/ASC.Textile/States/CodeFormatterState.cs
Normal file
80
common/ASC.Textile/States/CodeFormatterState.cs
Normal file
@ -0,0 +1,80 @@
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Textile.States
|
||||
{
|
||||
[FormatterState(@"^\s*<code" + Globals.HtmlAttributesPattern + ">")]
|
||||
public class CodeFormatterState : FormatterState
|
||||
{
|
||||
bool m_shouldExitNextTime = false;
|
||||
bool m_shouldFixHtmlEntities = false;
|
||||
|
||||
public CodeFormatterState(TextileFormatter f)
|
||||
: base(f)
|
||||
{
|
||||
}
|
||||
|
||||
public override string Consume(string input, Match m)
|
||||
{
|
||||
if (!Regex.IsMatch(input, "</code>"))
|
||||
{
|
||||
this.Formatter.ChangeState(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Formatter.ChangeState(new PassthroughFormatterState(this.Formatter));
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
public override bool ShouldNestState(FormatterState other)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Enter()
|
||||
{
|
||||
m_shouldFixHtmlEntities = false;
|
||||
}
|
||||
|
||||
public override void Exit()
|
||||
{
|
||||
}
|
||||
|
||||
public override void FormatLine(string input)
|
||||
{
|
||||
if (m_shouldFixHtmlEntities)
|
||||
input = FixEntities(input);
|
||||
Formatter.Output.WriteLine(input);
|
||||
m_shouldFixHtmlEntities = true;
|
||||
}
|
||||
|
||||
public override bool ShouldExit(string input)
|
||||
{
|
||||
if (m_shouldExitNextTime)
|
||||
return true;
|
||||
m_shouldExitNextTime = Regex.IsMatch(input, @"</code>");
|
||||
m_shouldFixHtmlEntities = !m_shouldExitNextTime;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool ShouldFormatBlocks(string input)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool ShouldParseForNewFormatterState(string input)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private string FixEntities(string text)
|
||||
{
|
||||
// de-entify any remaining angle brackets or ampersands
|
||||
text = text.Replace("&", "&");
|
||||
text = text.Replace(">", ">");
|
||||
text = text.Replace("<", "<");
|
||||
//Regex.Replace(text, @"\b&([#a-z0-9]+;)", "x%x%");
|
||||
return text;
|
||||
}
|
||||
}
|
||||
}
|
65
common/ASC.Textile/States/FootNoteFormatterState.cs
Normal file
65
common/ASC.Textile/States/FootNoteFormatterState.cs
Normal file
@ -0,0 +1,65 @@
|
||||
#region License Statement
|
||||
// Copyright (c) L.A.B.Soft. All rights reserved.
|
||||
//
|
||||
// The use and distribution terms for this software are covered by the
|
||||
// Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
|
||||
// which can be found in the file CPL.TXT at the root of this distribution.
|
||||
// By using this software in any fashion, you are agreeing to be bound by
|
||||
// the terms of this license.
|
||||
//
|
||||
// You must not remove this notice, or any other, from this software.
|
||||
#endregion
|
||||
|
||||
#region Using Statements
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
#endregion
|
||||
|
||||
|
||||
namespace Textile.States
|
||||
{
|
||||
[FormatterState(SimpleBlockFormatterState.PatternBegin + @"fn[0-9]+" + SimpleBlockFormatterState.PatternEnd)]
|
||||
public class FootNoteFormatterState : SimpleBlockFormatterState
|
||||
{
|
||||
int m_noteID = 0;
|
||||
|
||||
public FootNoteFormatterState(TextileFormatter f)
|
||||
: base(f)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Enter()
|
||||
{
|
||||
Formatter.Output.Write(
|
||||
string.Format("<p id=\"fn{0}\"{1}><sup>{2}</sup> ",
|
||||
m_noteID,
|
||||
FormattedStylesAndAlignment("p"),
|
||||
m_noteID));
|
||||
}
|
||||
|
||||
public override void Exit()
|
||||
{
|
||||
Formatter.Output.WriteLine("</p>");
|
||||
}
|
||||
|
||||
public override void FormatLine(string input)
|
||||
{
|
||||
Formatter.Output.Write(input);
|
||||
}
|
||||
|
||||
public override bool ShouldExit(string input)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
protected override void OnContextAcquired()
|
||||
{
|
||||
var m = Regex.Match(Tag, @"^fn(?<id>[0-9]+)");
|
||||
m_noteID = int.Parse(m.Groups["id"].Value);
|
||||
}
|
||||
|
||||
public override bool ShouldNestState(FormatterState other)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
109
common/ASC.Textile/States/HeaderFormatterState.cs
Normal file
109
common/ASC.Textile/States/HeaderFormatterState.cs
Normal file
@ -0,0 +1,109 @@
|
||||
#region License Statement
|
||||
// Copyright (c) L.A.B.Soft. All rights reserved.
|
||||
//
|
||||
// The use and distribution terms for this software are covered by the
|
||||
// Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
|
||||
// which can be found in the file CPL.TXT at the root of this distribution.
|
||||
// By using this software in any fashion, you are agreeing to be bound by
|
||||
// the terms of this license.
|
||||
//
|
||||
// You must not remove this notice, or any other, from this software.
|
||||
#endregion
|
||||
|
||||
#region Using Statements
|
||||
using System.Text.RegularExpressions;
|
||||
#endregion
|
||||
|
||||
|
||||
namespace Textile.States
|
||||
{
|
||||
[FormatterState(SimpleBlockFormatterState.PatternBegin + @"pad[0-9]+" + SimpleBlockFormatterState.PatternEnd)]
|
||||
public class PaddingFormatterState : SimpleBlockFormatterState
|
||||
{
|
||||
public PaddingFormatterState(TextileFormatter formatter)
|
||||
: base(formatter)
|
||||
{
|
||||
}
|
||||
|
||||
public int HeaderLevel { get; private set; } = 0;
|
||||
|
||||
|
||||
public override void Enter()
|
||||
{
|
||||
for (var i = 0; i < HeaderLevel; i++)
|
||||
{
|
||||
Formatter.Output.Write(string.Format("<br {0}/>", FormattedStylesAndAlignment("br")));
|
||||
}
|
||||
}
|
||||
|
||||
public override void Exit()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnContextAcquired()
|
||||
{
|
||||
var m = Regex.Match(Tag, @"^pad(?<lvl>[0-9]+)");
|
||||
HeaderLevel = int.Parse(m.Groups["lvl"].Value);
|
||||
}
|
||||
|
||||
public override void FormatLine(string input)
|
||||
{
|
||||
Formatter.Output.Write(input);
|
||||
}
|
||||
|
||||
public override bool ShouldExit(string intput)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool ShouldNestState(FormatterState other)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formatting state for headers and titles.
|
||||
/// </summary>
|
||||
[FormatterState(SimpleBlockFormatterState.PatternBegin + @"h[0-9]+" + SimpleBlockFormatterState.PatternEnd)]
|
||||
public class HeaderFormatterState : SimpleBlockFormatterState
|
||||
{
|
||||
public int HeaderLevel { get; private set; } = 0;
|
||||
|
||||
public HeaderFormatterState(TextileFormatter f)
|
||||
: base(f)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Enter()
|
||||
{
|
||||
Formatter.Output.Write(string.Format("<h{0}{1}>", HeaderLevel, FormattedStylesAndAlignment(string.Format("h{0}", HeaderLevel))));
|
||||
}
|
||||
|
||||
public override void Exit()
|
||||
{
|
||||
Formatter.Output.WriteLine(string.Format("</h{0}>", HeaderLevel.ToString()));
|
||||
}
|
||||
|
||||
protected override void OnContextAcquired()
|
||||
{
|
||||
var m = Regex.Match(Tag, @"^h(?<lvl>[0-9]+)");
|
||||
HeaderLevel = int.Parse(m.Groups["lvl"].Value);
|
||||
}
|
||||
|
||||
public override void FormatLine(string input)
|
||||
{
|
||||
Formatter.Output.Write(input);
|
||||
}
|
||||
|
||||
public override bool ShouldExit(string intput)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool ShouldNestState(FormatterState other)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
141
common/ASC.Textile/States/ListFormatterState.cs
Normal file
141
common/ASC.Textile/States/ListFormatterState.cs
Normal file
@ -0,0 +1,141 @@
|
||||
#region License Statement
|
||||
// Copyright (c) L.A.B.Soft. All rights reserved.
|
||||
//
|
||||
// The use and distribution terms for this software are covered by the
|
||||
// Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
|
||||
// which can be found in the file CPL.TXT at the root of this distribution.
|
||||
// By using this software in any fashion, you are agreeing to be bound by
|
||||
// the terms of this license.
|
||||
//
|
||||
// You must not remove this notice, or any other, from this software.
|
||||
#endregion
|
||||
|
||||
#region Using Statements
|
||||
using System.Text.RegularExpressions;
|
||||
#endregion
|
||||
|
||||
|
||||
namespace Textile.States
|
||||
{
|
||||
/// <summary>
|
||||
/// Base formatting state for all lists.
|
||||
/// </summary>
|
||||
abstract public class ListFormatterState : FormatterState
|
||||
{
|
||||
internal const string PatternBegin = @"^\s*(?<tag>";
|
||||
internal const string PatternEnd = @")" + Globals.BlockModifiersPattern + @"(?:\s+)? (?<content>.*)$";
|
||||
|
||||
private bool m_firstItem = true;
|
||||
private bool m_firstItemLine = true;
|
||||
private string m_tag;
|
||||
private string m_attsInfo;
|
||||
private string m_alignInfo;
|
||||
|
||||
protected int NestingDepth
|
||||
{
|
||||
get { return m_tag.Length; }
|
||||
}
|
||||
|
||||
public ListFormatterState(TextileFormatter formatter)
|
||||
: base(formatter)
|
||||
{
|
||||
}
|
||||
|
||||
public override string Consume(string input, Match m)
|
||||
{
|
||||
m_tag = m.Groups["tag"].Value;
|
||||
m_alignInfo = m.Groups["align"].Value;
|
||||
m_attsInfo = m.Groups["atts"].Value;
|
||||
input = m.Groups["content"].Value;
|
||||
|
||||
this.Formatter.ChangeState(this);
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
public sealed override void Enter()
|
||||
{
|
||||
m_firstItem = true;
|
||||
m_firstItemLine = true;
|
||||
WriteIndent();
|
||||
}
|
||||
|
||||
public sealed override void Exit()
|
||||
{
|
||||
Formatter.Output.WriteLine("</li>");
|
||||
WriteOutdent();
|
||||
}
|
||||
|
||||
public sealed override void FormatLine(string input)
|
||||
{
|
||||
if (m_firstItemLine)
|
||||
{
|
||||
if (!m_firstItem)
|
||||
Formatter.Output.WriteLine("</li>");
|
||||
Formatter.Output.Write(string.Format("<li {0}>",FormattedStylesAndAlignment("li")));
|
||||
m_firstItemLine = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Formatter.Output.WriteLine("<br />");
|
||||
}
|
||||
Formatter.Output.Write(input);
|
||||
m_firstItem = false;
|
||||
}
|
||||
|
||||
public sealed override bool ShouldNestState(FormatterState other)
|
||||
{
|
||||
var listState = (ListFormatterState)other;
|
||||
return (listState.NestingDepth > NestingDepth);
|
||||
}
|
||||
|
||||
public sealed override bool ShouldExit(string input)
|
||||
{
|
||||
// If we have an empty line, we can exit.
|
||||
if (string.IsNullOrEmpty(input))
|
||||
return true;
|
||||
|
||||
// We exit this list if the next
|
||||
// list item is of the same type but less
|
||||
// deep as us, or of the other type of
|
||||
// list and as deep or less.
|
||||
if (NestingDepth > 1)
|
||||
{
|
||||
if (IsMatchForMe(input, 1, NestingDepth - 1))
|
||||
return true;
|
||||
}
|
||||
if (IsMatchForOthers(input, 1, NestingDepth))
|
||||
return true;
|
||||
|
||||
// As it seems we're going to continue taking
|
||||
// care of this line, we take the opportunity
|
||||
// to check whether it's the same list item as
|
||||
// previously (no "**" or "##" tags), or if it's
|
||||
// a new list item.
|
||||
if (IsMatchForMe(input, NestingDepth, NestingDepth))
|
||||
m_firstItemLine = true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public sealed override bool ShouldParseForNewFormatterState(string input)
|
||||
{
|
||||
// We don't let anyone but ourselves mess with our stuff.
|
||||
if (IsMatchForMe(input, 1, 100))
|
||||
return true;
|
||||
if (IsMatchForOthers(input, 1, 100))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
protected abstract void WriteIndent();
|
||||
protected abstract void WriteOutdent();
|
||||
protected abstract bool IsMatchForMe(string input, int minNestingDepth, int maxNestingDepth);
|
||||
protected abstract bool IsMatchForOthers(string input, int minNestingDepth, int maxNestingDepth);
|
||||
|
||||
protected string FormattedStylesAndAlignment(string element)
|
||||
{
|
||||
return Blocks.BlockAttributesParser.ParseBlockAttributes(m_alignInfo + m_attsInfo,element);
|
||||
}
|
||||
}
|
||||
}
|
67
common/ASC.Textile/States/NoTextileFormatterState.cs
Normal file
67
common/ASC.Textile/States/NoTextileFormatterState.cs
Normal file
@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Textile.States
|
||||
{
|
||||
[FormatterState(@"^\s*<notextile>\s*$")]
|
||||
public class NoTextileFormatterState : FormatterState
|
||||
{
|
||||
bool m_shouldExitNextTime = false;
|
||||
|
||||
public NoTextileFormatterState(TextileFormatter f)
|
||||
: base(f)
|
||||
{
|
||||
}
|
||||
|
||||
public override string Consume(string input, Match m)
|
||||
{
|
||||
this.Formatter.ChangeState(this);
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public override bool ShouldNestState(FormatterState other)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void Enter()
|
||||
{
|
||||
}
|
||||
|
||||
public override void Exit()
|
||||
{
|
||||
}
|
||||
|
||||
public override void FormatLine(string input)
|
||||
{
|
||||
if (!m_shouldExitNextTime)
|
||||
Formatter.Output.WriteLine(input);
|
||||
}
|
||||
|
||||
public override bool ShouldExit(string input)
|
||||
{
|
||||
if (m_shouldExitNextTime)
|
||||
return true;
|
||||
m_shouldExitNextTime = Regex.IsMatch(input, @"^\s*</notextile>\s*$");
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool ShouldFormatBlocks(string input)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool ShouldParseForNewFormatterState(string input)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public override Type FallbackFormattingState
|
||||
{
|
||||
get
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
51
common/ASC.Textile/States/OrderedListFormatterState.cs
Normal file
51
common/ASC.Textile/States/OrderedListFormatterState.cs
Normal file
@ -0,0 +1,51 @@
|
||||
#region License Statement
|
||||
// Copyright (c) L.A.B.Soft. All rights reserved.
|
||||
//
|
||||
// The use and distribution terms for this software are covered by the
|
||||
// Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
|
||||
// which can be found in the file CPL.TXT at the root of this distribution.
|
||||
// By using this software in any fashion, you are agreeing to be bound by
|
||||
// the terms of this license.
|
||||
//
|
||||
// You must not remove this notice, or any other, from this software.
|
||||
#endregion
|
||||
|
||||
#region Using Statements
|
||||
using System.Text.RegularExpressions;
|
||||
#endregion
|
||||
|
||||
|
||||
namespace Textile.States
|
||||
{
|
||||
/// <summary>
|
||||
/// Formatting state for a numbered list.
|
||||
/// </summary>
|
||||
[FormatterState(ListFormatterState.PatternBegin + @"#+" + ListFormatterState.PatternEnd)]
|
||||
public class OrderedListFormatterState : ListFormatterState
|
||||
{
|
||||
public OrderedListFormatterState(TextileFormatter formatter)
|
||||
: base(formatter)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void WriteIndent()
|
||||
{
|
||||
Formatter.Output.WriteLine("<ol" + FormattedStylesAndAlignment("ol") + ">");
|
||||
}
|
||||
|
||||
protected override void WriteOutdent()
|
||||
{
|
||||
Formatter.Output.WriteLine("</ol>");
|
||||
}
|
||||
|
||||
protected override bool IsMatchForMe(string input, int minNestingDepth, int maxNestingDepth)
|
||||
{
|
||||
return Regex.IsMatch(input, @"^\s*([\*#]{" + (minNestingDepth - 1) + @"," + (maxNestingDepth - 1) + @"})#" + Globals.BlockModifiersPattern + @"\s");
|
||||
}
|
||||
|
||||
protected override bool IsMatchForOthers(string input, int minNestingDepth, int maxNestingDepth)
|
||||
{
|
||||
return Regex.IsMatch(input, @"^\s*([\*#]{" + (minNestingDepth - 1) + @"," + (maxNestingDepth - 1) + @"})\*" + Globals.BlockModifiersPattern + @"\s");
|
||||
}
|
||||
}
|
||||
}
|
58
common/ASC.Textile/States/ParagraphFormatterState.cs
Normal file
58
common/ASC.Textile/States/ParagraphFormatterState.cs
Normal file
@ -0,0 +1,58 @@
|
||||
#region License Statement
|
||||
// Copyright (c) L.A.B.Soft. All rights reserved.
|
||||
//
|
||||
// The use and distribution terms for this software are covered by the
|
||||
// Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
|
||||
// which can be found in the file CPL.TXT at the root of this distribution.
|
||||
// By using this software in any fashion, you are agreeing to be bound by
|
||||
// the terms of this license.
|
||||
//
|
||||
// You must not remove this notice, or any other, from this software.
|
||||
#endregion
|
||||
|
||||
#region Using Statements
|
||||
using System.Text.RegularExpressions;
|
||||
#endregion
|
||||
|
||||
namespace Textile.States
|
||||
{
|
||||
/// <summary>
|
||||
/// Formatting state for a standard text (i.e. just paragraphs).
|
||||
/// </summary>
|
||||
[FormatterState(SimpleBlockFormatterState.PatternBegin + @"p" + SimpleBlockFormatterState.PatternEnd)]
|
||||
public class ParagraphFormatterState : SimpleBlockFormatterState
|
||||
{
|
||||
public ParagraphFormatterState(TextileFormatter f)
|
||||
: base(f)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Enter()
|
||||
{
|
||||
Formatter.Output.Write("<p" + FormattedStylesAndAlignment("p") + ">");
|
||||
}
|
||||
|
||||
public override void Exit()
|
||||
{
|
||||
Formatter.Output.WriteLine("</p>");
|
||||
}
|
||||
|
||||
public override void FormatLine(string input)
|
||||
{
|
||||
Formatter.Output.Write(input);
|
||||
}
|
||||
|
||||
public override bool ShouldExit(string input)
|
||||
{
|
||||
if (Regex.IsMatch(input, @"^\s*$"))
|
||||
return true;
|
||||
Formatter.Output.WriteLine("<br />");
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool ShouldNestState(FormatterState other)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
42
common/ASC.Textile/States/PassthroughFormatterState.cs
Normal file
42
common/ASC.Textile/States/PassthroughFormatterState.cs
Normal file
@ -0,0 +1,42 @@
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Textile.States
|
||||
{
|
||||
[FormatterState(@"^\s*<(h[0-9]|p|pre|blockquote)" + Globals.HtmlAttributesPattern + ">")]
|
||||
public class PassthroughFormatterState : FormatterState
|
||||
{
|
||||
public PassthroughFormatterState(TextileFormatter f)
|
||||
: base(f)
|
||||
{
|
||||
}
|
||||
|
||||
public override string Consume(string input, Match m)
|
||||
{
|
||||
this.Formatter.ChangeState(this);
|
||||
return input;
|
||||
}
|
||||
|
||||
public override bool ShouldNestState(FormatterState other)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void Enter()
|
||||
{
|
||||
}
|
||||
|
||||
public override void Exit()
|
||||
{
|
||||
}
|
||||
|
||||
public override void FormatLine(string input)
|
||||
{
|
||||
Formatter.Output.WriteLine(input);
|
||||
}
|
||||
|
||||
public override bool ShouldExit(string input)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
61
common/ASC.Textile/States/PreCodeFormatterState.cs
Normal file
61
common/ASC.Textile/States/PreCodeFormatterState.cs
Normal file
@ -0,0 +1,61 @@
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Textile.States
|
||||
{
|
||||
[FormatterState(SimpleBlockFormatterState.PatternBegin + @"bc" + SimpleBlockFormatterState.PatternEnd)]
|
||||
public class PreCodeFormatterState : SimpleBlockFormatterState
|
||||
{
|
||||
public PreCodeFormatterState(TextileFormatter formatter)
|
||||
: base(formatter)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Enter()
|
||||
{
|
||||
Formatter.Output.Write("<pre><code>");
|
||||
}
|
||||
|
||||
public override void Exit()
|
||||
{
|
||||
Formatter.Output.WriteLine("</code></pre>");
|
||||
}
|
||||
|
||||
public override void FormatLine(string input)
|
||||
{
|
||||
Formatter.Output.WriteLine(FixEntities(input));
|
||||
}
|
||||
|
||||
public override bool ShouldExit(string input)
|
||||
{
|
||||
if (Regex.IsMatch(input, @"^\s*$"))
|
||||
return true;
|
||||
Formatter.Output.WriteLine("<br />");
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool ShouldFormatBlocks(string input)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool ShouldNestState(FormatterState other)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool ShouldParseForNewFormatterState(string input)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private string FixEntities(string text)
|
||||
{
|
||||
// de-entify any remaining angle brackets or ampersands
|
||||
text = text.Replace("&", "&");
|
||||
text = text.Replace(">", ">");
|
||||
text = text.Replace("<", "<");
|
||||
//Regex.Replace(text, @"\b&([#a-z0-9]+;)", "x%x%");
|
||||
return text;
|
||||
}
|
||||
}
|
||||
}
|
78
common/ASC.Textile/States/PreFormatterState.cs
Normal file
78
common/ASC.Textile/States/PreFormatterState.cs
Normal file
@ -0,0 +1,78 @@
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Textile.States
|
||||
{
|
||||
[FormatterState(@"^\s*<pre" + Globals.HtmlAttributesPattern + ">")]
|
||||
public class PreFormatterState : FormatterState
|
||||
{
|
||||
bool m_shouldExitNextTime = false;
|
||||
int m_fakeNestingDepth = 0;
|
||||
|
||||
public PreFormatterState(TextileFormatter f)
|
||||
: base(f)
|
||||
{
|
||||
}
|
||||
|
||||
public override string Consume(string input, Match m)
|
||||
{
|
||||
if (!Regex.IsMatch(input, "</pre>"))
|
||||
{
|
||||
this.Formatter.ChangeState(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Formatter.ChangeState(new PassthroughFormatterState(this.Formatter));
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
public override bool ShouldNestState(FormatterState other)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void Enter()
|
||||
{
|
||||
}
|
||||
|
||||
public override void Exit()
|
||||
{
|
||||
}
|
||||
|
||||
public override void FormatLine(string input)
|
||||
{
|
||||
if (Regex.IsMatch(input, "<pre>"))
|
||||
m_fakeNestingDepth++;
|
||||
|
||||
Formatter.Output.WriteLine(input);
|
||||
}
|
||||
|
||||
public override bool ShouldExit(string input)
|
||||
{
|
||||
if (m_shouldExitNextTime)
|
||||
return true;
|
||||
if (Regex.IsMatch(input, @"</pre>"))
|
||||
m_fakeNestingDepth--;
|
||||
if (m_fakeNestingDepth <= 0)
|
||||
m_shouldExitNextTime = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool ShouldFormatBlocks(string input)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool ShouldParseForNewFormatterState(string input)
|
||||
{
|
||||
// Only allow a child formatting state for <code> tag.
|
||||
return Regex.IsMatch(input, @"^\s*<code");
|
||||
}
|
||||
|
||||
public override Type FallbackFormattingState
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
}
|
||||
}
|
66
common/ASC.Textile/States/SimpleBlockFormatterState.cs
Normal file
66
common/ASC.Textile/States/SimpleBlockFormatterState.cs
Normal file
@ -0,0 +1,66 @@
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Textile.States
|
||||
{
|
||||
public abstract class SimpleBlockFormatterState : FormatterState
|
||||
{
|
||||
internal const string PatternBegin = @"^\s*(?<tag>";
|
||||
internal const string PatternEnd = @")" + Globals.AlignPattern + Globals.BlockModifiersPattern + @"\.(?:\s+)?(?<content>.*)$";
|
||||
|
||||
public string Tag { get; private set; } = null;
|
||||
|
||||
public string AlignInfo { get; private set; } = null;
|
||||
|
||||
public string AttInfo { get; private set; } = null;
|
||||
|
||||
protected SimpleBlockFormatterState(TextileFormatter formatter)
|
||||
: base(formatter)
|
||||
{
|
||||
}
|
||||
|
||||
public override string Consume(string input, Match m)
|
||||
{
|
||||
Tag = m.Groups["tag"].Value;
|
||||
AlignInfo = m.Groups["align"].Value;
|
||||
AttInfo = m.Groups["atts"].Value;
|
||||
input = m.Groups["content"].Value;
|
||||
|
||||
OnContextAcquired();
|
||||
|
||||
this.Formatter.ChangeState(this);
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
public override bool ShouldNestState(FormatterState other)
|
||||
{
|
||||
var blockFormatterState = (SimpleBlockFormatterState)other;
|
||||
return (blockFormatterState.Tag != Tag ||
|
||||
blockFormatterState.AlignInfo != AlignInfo ||
|
||||
blockFormatterState.AttInfo != AttInfo);
|
||||
}
|
||||
|
||||
protected virtual void OnContextAcquired()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected string FormattedAlignment()
|
||||
{
|
||||
return Blocks.BlockAttributesParser.ParseBlockAttributes(AlignInfo);
|
||||
}
|
||||
|
||||
protected string FormattedStyles(string element)
|
||||
{
|
||||
return Blocks.BlockAttributesParser.ParseBlockAttributes(AttInfo, element);
|
||||
}
|
||||
|
||||
protected string FormattedStylesAndAlignment(string element)
|
||||
{
|
||||
return Blocks.BlockAttributesParser.ParseBlockAttributes(AlignInfo + AttInfo, element);
|
||||
}
|
||||
}
|
||||
}
|
49
common/ASC.Textile/States/TableCellParser.cs
Normal file
49
common/ASC.Textile/States/TableCellParser.cs
Normal file
@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
|
||||
namespace Textile.States
|
||||
{
|
||||
public class TableCellParser
|
||||
{
|
||||
readonly string m_lineFragment;
|
||||
|
||||
public TableCellParser(string input)
|
||||
{
|
||||
m_lineFragment = input;
|
||||
}
|
||||
|
||||
public string GetLineFragmentFormatting()
|
||||
{
|
||||
var htmlTag = "td";
|
||||
|
||||
var m = Regex.Match(m_lineFragment,
|
||||
@"^((?<head>_?)" +
|
||||
Globals.SpanPattern +
|
||||
Globals.AlignPattern +
|
||||
Globals.BlockModifiersPattern +
|
||||
@"(?<dot>\.)\s?)?" +
|
||||
@"(?<content>.*)"
|
||||
);
|
||||
if (!m.Success)
|
||||
throw new Exception("Couldn't parse table cell.");
|
||||
|
||||
if (m.Groups["head"].Value == "_")
|
||||
htmlTag = "th";
|
||||
//string opts = BlockAttributesParser.ParseBlockAttributes(m.Groups["span"].Value, "td") +
|
||||
// BlockAttributesParser.ParseBlockAttributes(m.Groups["align"].Value, "td") +
|
||||
// BlockAttributesParser.ParseBlockAttributes(m.Groups["atts"].Value, "td");
|
||||
var opts = Blocks.BlockAttributesParser.ParseBlockAttributes(m.Groups["span"].Value + m.Groups["align"].Value + m.Groups["atts"].Value, "td");
|
||||
|
||||
var res = "<" + htmlTag + opts + ">";
|
||||
// It may be possible the user actually intended to have a dot at the beginning of
|
||||
// this cell's text, without any formatting (header tag or options).
|
||||
if (string.IsNullOrEmpty(opts) && htmlTag == "td" && !string.IsNullOrEmpty(m.Groups["dot"].Value))
|
||||
res += ".";
|
||||
res += m.Groups["content"].Value;
|
||||
res += "</" + htmlTag + ">";
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
69
common/ASC.Textile/States/TableFormatterState.cs
Normal file
69
common/ASC.Textile/States/TableFormatterState.cs
Normal file
@ -0,0 +1,69 @@
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
|
||||
namespace Textile.States
|
||||
{
|
||||
[FormatterState(@"^\s*(?<tag>table)" +
|
||||
Globals.SpanPattern +
|
||||
Globals.AlignPattern +
|
||||
Globals.BlockModifiersPattern +
|
||||
@"\.\s*$")]
|
||||
public class TableFormatterState : FormatterState
|
||||
{
|
||||
private string m_attsInfo;
|
||||
private string m_alignInfo;
|
||||
|
||||
public TableFormatterState(TextileFormatter f)
|
||||
: base(f)
|
||||
{
|
||||
}
|
||||
|
||||
public override string Consume(string input, Match m)
|
||||
{
|
||||
m_alignInfo = m.Groups["align"].Value;
|
||||
m_attsInfo = m.Groups["atts"].Value;
|
||||
|
||||
//TODO: check the state (it could already be a table!)
|
||||
this.Formatter.ChangeState(this);
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public override bool ShouldNestState(FormatterState other)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void Enter()
|
||||
{
|
||||
Formatter.Output.WriteLine("<table" + FormattedStylesAndAlignment() + ">");
|
||||
}
|
||||
|
||||
public override void Exit()
|
||||
{
|
||||
Formatter.Output.WriteLine("</table>");
|
||||
}
|
||||
|
||||
public override void FormatLine(string input)
|
||||
{
|
||||
if (input.Length > 0)
|
||||
throw new Exception("The TableFormatter state is not supposed to format any lines!");
|
||||
}
|
||||
|
||||
public override bool ShouldExit(string input)
|
||||
{
|
||||
var m = Regex.Match(input,
|
||||
@"^\s*" + Globals.AlignPattern + Globals.BlockModifiersPattern +
|
||||
@"(\.\s?)?(?<tag>\|)" +
|
||||
@"(?<content>.*)(?=\|)"
|
||||
);
|
||||
return( m.Success == false );
|
||||
}
|
||||
|
||||
protected string FormattedStylesAndAlignment()
|
||||
{
|
||||
return Blocks.BlockAttributesParser.ParseBlockAttributes(m_alignInfo + m_attsInfo);
|
||||
}
|
||||
}
|
||||
}
|
76
common/ASC.Textile/States/TableRowFormatterState.cs
Normal file
76
common/ASC.Textile/States/TableRowFormatterState.cs
Normal file
@ -0,0 +1,76 @@
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Textile.States
|
||||
{
|
||||
[FormatterState(@"^\s*(" + Globals.AlignPattern + Globals.BlockModifiersPattern + @"\.\s?)?" +
|
||||
@"\|(?<content>.*)\|\s*$")]
|
||||
public class TableRowFormatterState : FormatterState
|
||||
{
|
||||
private string m_attsInfo;
|
||||
private string m_alignInfo;
|
||||
|
||||
public TableRowFormatterState(TextileFormatter f)
|
||||
: base(f)
|
||||
{
|
||||
}
|
||||
|
||||
public override string Consume(string input, Match m)
|
||||
{
|
||||
m_alignInfo = m.Groups["align"].Value;
|
||||
m_attsInfo = m.Groups["atts"].Value;
|
||||
input = string.Format("|{0}|", m.Groups["content"].Value);
|
||||
|
||||
if (!(this.Formatter.CurrentState is TableFormatterState))
|
||||
{
|
||||
var s = new TableFormatterState(this.Formatter);
|
||||
this.Formatter.ChangeState(s);
|
||||
}
|
||||
|
||||
this.Formatter.ChangeState(this);
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
public override bool ShouldNestState(FormatterState other)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void Enter()
|
||||
{
|
||||
Formatter.Output.WriteLine("<tr" + FormattedStylesAndAlignment() + ">");
|
||||
}
|
||||
|
||||
public override void Exit()
|
||||
{
|
||||
Formatter.Output.WriteLine("</tr>");
|
||||
}
|
||||
|
||||
public override void FormatLine(string input)
|
||||
{
|
||||
// can get: Align & Classes
|
||||
|
||||
var formattedLine = "";
|
||||
|
||||
var cellsInput = input.Split('|');
|
||||
for (var i = 1; i < cellsInput.Length - 1; i++)
|
||||
{
|
||||
var cellInput = cellsInput[i];
|
||||
var tcp = new TableCellParser(cellInput);
|
||||
formattedLine += tcp.GetLineFragmentFormatting();
|
||||
}
|
||||
|
||||
Formatter.Output.WriteLine(formattedLine);
|
||||
}
|
||||
|
||||
public override bool ShouldExit(string input)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
protected string FormattedStylesAndAlignment()
|
||||
{
|
||||
return Blocks.BlockAttributesParser.ParseBlockAttributes(m_alignInfo + m_attsInfo);
|
||||
}
|
||||
}
|
||||
}
|
51
common/ASC.Textile/States/UnorderedListFormatterState.cs
Normal file
51
common/ASC.Textile/States/UnorderedListFormatterState.cs
Normal file
@ -0,0 +1,51 @@
|
||||
#region License Statement
|
||||
// Copyright (c) L.A.B.Soft. All rights reserved.
|
||||
//
|
||||
// The use and distribution terms for this software are covered by the
|
||||
// Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
|
||||
// which can be found in the file CPL.TXT at the root of this distribution.
|
||||
// By using this software in any fashion, you are agreeing to be bound by
|
||||
// the terms of this license.
|
||||
//
|
||||
// You must not remove this notice, or any other, from this software.
|
||||
#endregion
|
||||
|
||||
#region Using Statements
|
||||
using System.Text.RegularExpressions;
|
||||
#endregion
|
||||
|
||||
|
||||
namespace Textile.States
|
||||
{
|
||||
/// <summary>
|
||||
/// Formatting state for a bulleted list.
|
||||
/// </summary>
|
||||
[FormatterState(ListFormatterState.PatternBegin + @"\*+" + ListFormatterState.PatternEnd)]
|
||||
public class UnorderedListFormatterState : ListFormatterState
|
||||
{
|
||||
public UnorderedListFormatterState(TextileFormatter formatter)
|
||||
: base(formatter)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void WriteIndent()
|
||||
{
|
||||
Formatter.Output.WriteLine("<ul" + FormattedStylesAndAlignment("ul") + ">");
|
||||
}
|
||||
|
||||
protected override void WriteOutdent()
|
||||
{
|
||||
Formatter.Output.WriteLine("</ul>");
|
||||
}
|
||||
|
||||
protected override bool IsMatchForMe(string input, int minNestingDepth, int maxNestingDepth)
|
||||
{
|
||||
return Regex.IsMatch(input, @"^\s*[\*]{" + minNestingDepth + @"," + maxNestingDepth + @"}" + Globals.BlockModifiersPattern + @"\s");
|
||||
}
|
||||
|
||||
protected override bool IsMatchForOthers(string input, int minNestingDepth, int maxNestingDepth)
|
||||
{
|
||||
return Regex.IsMatch(input, @"^\s*[#]{" + minNestingDepth + @"," + maxNestingDepth + @"}" + Globals.BlockModifiersPattern + @"\s");
|
||||
}
|
||||
}
|
||||
}
|
56
common/ASC.Textile/StringBuilderTextileFormatter.cs
Normal file
56
common/ASC.Textile/StringBuilderTextileFormatter.cs
Normal file
@ -0,0 +1,56 @@
|
||||
#region License Statement
|
||||
// Copyright (c) L.A.B.Soft. All rights reserved.
|
||||
//
|
||||
// The use and distribution terms for this software are covered by the
|
||||
// Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
|
||||
// which can be found in the file CPL.TXT at the root of this distribution.
|
||||
// By using this software in any fashion, you are agreeing to be bound by
|
||||
// the terms of this license.
|
||||
//
|
||||
// You must not remove this notice, or any other, from this software.
|
||||
#endregion
|
||||
|
||||
#region Using Statements
|
||||
using System.Text;
|
||||
#endregion
|
||||
|
||||
|
||||
namespace Textile
|
||||
{
|
||||
public class StringBuilderTextileFormatter : IOutputter
|
||||
{
|
||||
StringBuilder m_stringBuilder = null;
|
||||
|
||||
public StringBuilderTextileFormatter()
|
||||
{
|
||||
}
|
||||
|
||||
public string GetFormattedText()
|
||||
{
|
||||
return m_stringBuilder.ToString();
|
||||
}
|
||||
|
||||
#region IOutputter Members
|
||||
|
||||
public void Begin()
|
||||
{
|
||||
m_stringBuilder = new StringBuilder();
|
||||
}
|
||||
|
||||
public void End()
|
||||
{
|
||||
}
|
||||
|
||||
public void Write(string text)
|
||||
{
|
||||
m_stringBuilder.Append(text);
|
||||
}
|
||||
|
||||
public void WriteLine(string line)
|
||||
{
|
||||
m_stringBuilder.AppendLine(line);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
30
common/ASC.Textile/StyleReader.cs
Normal file
30
common/ASC.Textile/StyleReader.cs
Normal file
@ -0,0 +1,30 @@
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Textile
|
||||
{
|
||||
public class StyleReader
|
||||
{
|
||||
private readonly Regex _styleParser = new Regex(@"(?<selector>[^\{]+)(?<style>[^\}]+)");
|
||||
private readonly Regex _minimizer = new Regex(@";\s+");
|
||||
|
||||
private readonly System.Collections.Specialized.StringDictionary _tagStyler = new System.Collections.Specialized.StringDictionary();
|
||||
|
||||
public StyleReader(string styles)
|
||||
{
|
||||
//Read it
|
||||
var matches = _styleParser.Matches(styles.Replace(System.Environment.NewLine, ""));
|
||||
foreach (Match match in matches)
|
||||
{
|
||||
if (match.Success)
|
||||
{
|
||||
_tagStyler.Add(match.Groups["selector"].Value.Trim('{', '}', ' '), _minimizer.Replace(match.Groups["style"].Value.Trim('{', '}', ' '),";"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string GetStyle(string tag)
|
||||
{
|
||||
return _tagStyler[tag];
|
||||
}
|
||||
}
|
||||
}
|
175
common/ASC.Textile/TextileFormatter.cs
Normal file
175
common/ASC.Textile/TextileFormatter.cs
Normal file
@ -0,0 +1,175 @@
|
||||
#region License Statement
|
||||
// Copyright (c) L.A.B.Soft. All rights reserved.
|
||||
//
|
||||
// The use and distribution terms for this software are covered by the
|
||||
// Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
|
||||
// which can be found in the file CPL.TXT at the root of this distribution.
|
||||
// By using this software in any fashion, you are agreeing to be bound by
|
||||
// the terms of this license.
|
||||
//
|
||||
// You must not remove this notice, or any other, from this software.
|
||||
#endregion
|
||||
|
||||
#region Using Statements
|
||||
using Textile.Blocks;
|
||||
using Textile.States;
|
||||
#endregion
|
||||
|
||||
|
||||
namespace Textile
|
||||
{
|
||||
/// <summary>
|
||||
/// Class for formatting Textile input into HTML.
|
||||
/// </summary>
|
||||
/// This class takes raw Textile text and sends the
|
||||
/// formatted, ready to display HTML string to the
|
||||
/// outputter defined in the constructor of the
|
||||
/// class.
|
||||
public partial class TextileFormatter
|
||||
{
|
||||
static TextileFormatter()
|
||||
{
|
||||
RegisterFormatterState(typeof(HeaderFormatterState));
|
||||
RegisterFormatterState(typeof(PaddingFormatterState));
|
||||
RegisterFormatterState(typeof(BlockQuoteFormatterState));
|
||||
RegisterFormatterState(typeof(ParagraphFormatterState));
|
||||
RegisterFormatterState(typeof(FootNoteFormatterState));
|
||||
RegisterFormatterState(typeof(OrderedListFormatterState));
|
||||
RegisterFormatterState(typeof(UnorderedListFormatterState));
|
||||
RegisterFormatterState(typeof(TableFormatterState));
|
||||
RegisterFormatterState(typeof(TableRowFormatterState));
|
||||
RegisterFormatterState(typeof(CodeFormatterState));
|
||||
RegisterFormatterState(typeof(PreFormatterState));
|
||||
RegisterFormatterState(typeof(PreCodeFormatterState));
|
||||
RegisterFormatterState(typeof(NoTextileFormatterState));
|
||||
|
||||
RegisterBlockModifier(new NoTextileBlockModifier());
|
||||
RegisterBlockModifier(new CodeBlockModifier());
|
||||
RegisterBlockModifier(new PreBlockModifier());
|
||||
RegisterBlockModifier(new HyperLinkBlockModifier());
|
||||
RegisterBlockModifier(new ImageBlockModifier());
|
||||
RegisterBlockModifier(new GlyphBlockModifier());
|
||||
RegisterBlockModifier(new EmphasisPhraseBlockModifier());
|
||||
RegisterBlockModifier(new StrongPhraseBlockModifier());
|
||||
RegisterBlockModifier(new ItalicPhraseBlockModifier());
|
||||
RegisterBlockModifier(new BoldPhraseBlockModifier());
|
||||
RegisterBlockModifier(new CitePhraseBlockModifier());
|
||||
RegisterBlockModifier(new DeletedPhraseBlockModifier());
|
||||
RegisterBlockModifier(new InsertedPhraseBlockModifier());
|
||||
RegisterBlockModifier(new SuperScriptPhraseBlockModifier());
|
||||
RegisterBlockModifier(new SubScriptPhraseBlockModifier());
|
||||
RegisterBlockModifier(new SpanPhraseBlockModifier());
|
||||
RegisterBlockModifier(new FootNoteReferenceBlockModifier());
|
||||
|
||||
//TODO: capitals block modifier
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Public constructor, where the formatter is hooked up
|
||||
/// to an outputter.
|
||||
/// </summary>
|
||||
/// <param name="output">The outputter to be used.</param>
|
||||
public TextileFormatter(IOutputter output)
|
||||
{
|
||||
Output = output;
|
||||
}
|
||||
|
||||
#region Properties for Output
|
||||
|
||||
/// <summary>
|
||||
/// The ouputter to which the formatted text
|
||||
/// is sent to.
|
||||
/// </summary>
|
||||
public IOutputter Output { get; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// The offset for the header tags.
|
||||
/// </summary>
|
||||
/// When the formatted text is inserted into another page
|
||||
/// there might be a need to offset all headers (h1 becomes
|
||||
/// h4, for instance). The header offset allows this.
|
||||
public int HeaderOffset { get; set; } = 0;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties for Conversion
|
||||
|
||||
public bool FormatImages
|
||||
{
|
||||
get { return IsBlockModifierEnabled(typeof(ImageBlockModifier)); }
|
||||
set { SwitchBlockModifier(typeof(ImageBlockModifier), value); }
|
||||
}
|
||||
|
||||
public bool FormatLinks
|
||||
{
|
||||
get { return IsBlockModifierEnabled(typeof(HyperLinkBlockModifier)); }
|
||||
set { SwitchBlockModifier(typeof(HyperLinkBlockModifier), value); }
|
||||
}
|
||||
|
||||
public bool FormatLists
|
||||
{
|
||||
get { return IsBlockModifierEnabled(typeof(OrderedListFormatterState)); }
|
||||
set
|
||||
{
|
||||
SwitchBlockModifier(typeof(OrderedListFormatterState), value);
|
||||
SwitchBlockModifier(typeof(UnorderedListFormatterState), value);
|
||||
}
|
||||
}
|
||||
|
||||
public bool FormatFootNotes
|
||||
{
|
||||
get { return IsBlockModifierEnabled(typeof(FootNoteReferenceBlockModifier)); }
|
||||
set
|
||||
{
|
||||
SwitchBlockModifier(typeof(FootNoteReferenceBlockModifier), value);
|
||||
SwitchFormatterState(typeof(FootNoteFormatterState), value);
|
||||
}
|
||||
}
|
||||
|
||||
public bool FormatTables
|
||||
{
|
||||
get { return IsFormatterStateEnabled(typeof(TableFormatterState)); }
|
||||
set
|
||||
{
|
||||
SwitchFormatterState(typeof(TableFormatterState), value);
|
||||
SwitchFormatterState(typeof(TableRowFormatterState), value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attribute to add to all links.
|
||||
/// </summary>
|
||||
public string Rel { get; set; } = string.Empty;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Utility Methods
|
||||
|
||||
/// <summary>
|
||||
/// Utility method for quickly formatting a text without having
|
||||
/// to create a TextileFormatter with an IOutputter.
|
||||
/// </summary>
|
||||
/// <param name="input">The string to format</param>
|
||||
/// <returns>The formatted version of the string</returns>
|
||||
public static string FormatString(string input)
|
||||
{
|
||||
var s = new StringBuilderTextileFormatter();
|
||||
var f = new TextileFormatter(s);
|
||||
f.Format(input);
|
||||
return s.GetFormattedText();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Utility method for formatting a text with a given outputter.
|
||||
/// </summary>
|
||||
/// <param name="input">The string to format</param>
|
||||
/// <param name="outputter">The IOutputter to use</param>
|
||||
public static void FormatString(string input, IOutputter outputter)
|
||||
{
|
||||
var f = new TextileFormatter(outputter);
|
||||
f.Format(input);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
55
common/ASC.Textile/TextileFormatterBlocks.cs
Normal file
55
common/ASC.Textile/TextileFormatterBlocks.cs
Normal file
@ -0,0 +1,55 @@
|
||||
#region License Statement
|
||||
// Copyright (c) L.A.B.Soft. All rights reserved.
|
||||
//
|
||||
// The use and distribution terms for this software are covered by the
|
||||
// Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
|
||||
// which can be found in the file CPL.TXT at the root of this distribution.
|
||||
// By using this software in any fashion, you are agreeing to be bound by
|
||||
// the terms of this license.
|
||||
//
|
||||
// You must not remove this notice, or any other, from this software.
|
||||
#endregion
|
||||
|
||||
#region Using Statements
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
#endregion
|
||||
|
||||
|
||||
namespace Textile
|
||||
{
|
||||
public partial class TextileFormatter
|
||||
{
|
||||
#region Block Modifiers Registration
|
||||
|
||||
private static readonly List<BlockModifier> s_blockModifiers = new List<BlockModifier>();
|
||||
private static readonly List<Type> s_blockModifiersTypes = new List<Type>();
|
||||
|
||||
public static void RegisterBlockModifier(BlockModifier blockModifer)
|
||||
{
|
||||
s_blockModifiers.Add(blockModifer);
|
||||
s_blockModifiersTypes.Add(blockModifer.GetType());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Block Modifiers Management
|
||||
|
||||
private readonly List<Type> m_disabledBlockModifiers = new List<Type>();
|
||||
|
||||
public bool IsBlockModifierEnabled(Type type)
|
||||
{
|
||||
return !m_disabledBlockModifiers.Contains(type);
|
||||
}
|
||||
|
||||
public void SwitchBlockModifier(Type type, bool onOff)
|
||||
{
|
||||
if (onOff)
|
||||
m_disabledBlockModifiers.Remove(type);
|
||||
else if (!m_disabledBlockModifiers.Contains(type))
|
||||
m_disabledBlockModifiers.Add(type);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
122
common/ASC.Textile/TextileFormatterFormatting.cs
Normal file
122
common/ASC.Textile/TextileFormatterFormatting.cs
Normal file
@ -0,0 +1,122 @@
|
||||
#region License Statement
|
||||
// Copyright (c) L.A.B.Soft. All rights reserved.
|
||||
//
|
||||
// The use and distribution terms for this software are covered by the
|
||||
// Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
|
||||
// which can be found in the file CPL.TXT at the root of this distribution.
|
||||
// By using this software in any fashion, you are agreeing to be bound by
|
||||
// the terms of this license.
|
||||
//
|
||||
// You must not remove this notice, or any other, from this software.
|
||||
#endregion
|
||||
|
||||
#region Using Statements
|
||||
using System.Text.RegularExpressions;
|
||||
#endregion
|
||||
|
||||
|
||||
namespace Textile
|
||||
{
|
||||
public partial class TextileFormatter
|
||||
{
|
||||
private readonly Regex VelocityArguments =
|
||||
new Regex("nostyle(?<arg>.*?)/nostyle", RegexOptions.IgnoreCase | RegexOptions.Singleline);
|
||||
|
||||
private string argMatchReplace(Match match)
|
||||
{
|
||||
return match.Result("${arg}");
|
||||
}
|
||||
|
||||
#region Formatting Methods
|
||||
|
||||
/// <summary>
|
||||
/// Formats the given text.
|
||||
/// </summary>
|
||||
/// <param name="input">The text to format.</param>
|
||||
public void Format(string input)
|
||||
{
|
||||
Output.Begin();
|
||||
|
||||
// Clean the text...
|
||||
var str = PrepareInputForFormatting(input);
|
||||
// ...and format each line.
|
||||
foreach (var line in str.Split('\n'))
|
||||
{
|
||||
var tmp = line;
|
||||
|
||||
// Let's see if the current state(s) is(are) finished...
|
||||
while (CurrentState != null && CurrentState.ShouldExit(tmp))
|
||||
PopState();
|
||||
|
||||
if (!Regex.IsMatch(tmp, @"^\s*$"))
|
||||
{
|
||||
// Figure out the new state for this text line, if possible.
|
||||
if (CurrentState == null || CurrentState.ShouldParseForNewFormatterState(tmp))
|
||||
{
|
||||
tmp = HandleFormattingState(tmp);
|
||||
}
|
||||
// else, the current state doesn't want to be superceded by
|
||||
// a new one. We'll leave him be.
|
||||
|
||||
// Modify the line with our block modifiers.
|
||||
if (CurrentState == null || CurrentState.ShouldFormatBlocks(tmp))
|
||||
{
|
||||
foreach (var blockModifier in s_blockModifiers)
|
||||
{
|
||||
//TODO: if not disabled...
|
||||
tmp = blockModifier.ModifyLine(tmp);
|
||||
}
|
||||
|
||||
for (var i = s_blockModifiers.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var blockModifier = s_blockModifiers[i];
|
||||
tmp = blockModifier.Conclude(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
tmp = VelocityArguments.Replace(tmp, argMatchReplace);
|
||||
|
||||
// Format the current line.
|
||||
CurrentState.FormatLine(tmp);
|
||||
}
|
||||
}
|
||||
// We're done. There might be a few states still on
|
||||
// the stack (for example if the text ends with a nested
|
||||
// list), so we must pop them all so that they have
|
||||
// their "Exit" method called correctly.
|
||||
while (m_stackOfStates.Count > 0)
|
||||
PopState();
|
||||
|
||||
Output.End();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Preparation Methods
|
||||
|
||||
/// <summary>
|
||||
/// Cleans up a text before formatting.
|
||||
/// </summary>
|
||||
/// <param name="input">The text to clean up.</param>
|
||||
/// <returns>The clean text.</returns>
|
||||
/// This method cleans stuff like line endings, so that
|
||||
/// we don't have to bother with it while formatting.
|
||||
private string PrepareInputForFormatting(string input)
|
||||
{
|
||||
input = CleanWhiteSpace(input);
|
||||
return input;
|
||||
}
|
||||
|
||||
private string CleanWhiteSpace(string text)
|
||||
{
|
||||
text = text.Replace("\r\n", "\n");
|
||||
text = text.Replace("\t", "");
|
||||
text = Regex.Replace(text, @"\n{3,}", "\n\n");
|
||||
text = Regex.Replace(text, @"\n *\n", "\n\n");
|
||||
text = Regex.Replace(text, "\"$", "\" ");
|
||||
return text;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
160
common/ASC.Textile/TextileFormatterStates.cs
Normal file
160
common/ASC.Textile/TextileFormatterStates.cs
Normal file
@ -0,0 +1,160 @@
|
||||
#region License Statement
|
||||
// Copyright (c) L.A.B.Soft. All rights reserved.
|
||||
//
|
||||
// The use and distribution terms for this software are covered by the
|
||||
// Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
|
||||
// which can be found in the file CPL.TXT at the root of this distribution.
|
||||
// By using this software in any fashion, you are agreeing to be bound by
|
||||
// the terms of this license.
|
||||
//
|
||||
// You must not remove this notice, or any other, from this software.
|
||||
#endregion
|
||||
|
||||
#region Using Statements
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
#endregion
|
||||
|
||||
|
||||
namespace Textile
|
||||
{
|
||||
public partial class TextileFormatter
|
||||
{
|
||||
#region State Registration
|
||||
|
||||
private static readonly List<Type> s_registeredStates = new List<Type>();
|
||||
private static readonly List<FormatterStateAttribute> s_registeredStatesAttributes = new List<FormatterStateAttribute>();
|
||||
|
||||
public static void RegisterFormatterState(Type formatterStateType)
|
||||
{
|
||||
if (!formatterStateType.IsSubclassOf(typeof(FormatterState)))
|
||||
throw new ArgumentException("The formatter state must be a sub-public class of FormatterStateBase.");
|
||||
|
||||
if (formatterStateType.GetConstructor(new Type[] { typeof(TextileFormatter) }) == null)
|
||||
throw new ArgumentException("The formatter state must have a constructor that takes a TextileFormatter reference.");
|
||||
|
||||
var att = FormatterStateAttribute.Get(formatterStateType);
|
||||
if (att == null)
|
||||
throw new ArgumentException("The formatter state must have the FormatterStateAttribute.");
|
||||
|
||||
s_registeredStates.Add(formatterStateType);
|
||||
s_registeredStatesAttributes.Add(att);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region State Management
|
||||
|
||||
private readonly List<Type> m_disabledFormatterStates = new List<Type>();
|
||||
private readonly Stack<FormatterState> m_stackOfStates = new Stack<FormatterState>();
|
||||
|
||||
private bool IsFormatterStateEnabled(Type type)
|
||||
{
|
||||
return !m_disabledFormatterStates.Contains(type);
|
||||
}
|
||||
|
||||
private void SwitchFormatterState(Type type, bool onOff)
|
||||
{
|
||||
if (onOff)
|
||||
m_disabledFormatterStates.Remove(type);
|
||||
else if (!m_disabledFormatterStates.Contains(type))
|
||||
m_disabledFormatterStates.Add(type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pushes a new state on the stack.
|
||||
/// </summary>
|
||||
/// <param name="s">The state to push.</param>
|
||||
/// The state will be entered automatically.
|
||||
private void PushState(FormatterState s)
|
||||
{
|
||||
m_stackOfStates.Push(s);
|
||||
s.Enter();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the last state from the stack.
|
||||
/// </summary>
|
||||
/// The state will be exited automatically.
|
||||
private void PopState()
|
||||
{
|
||||
m_stackOfStates.Peek().Exit();
|
||||
m_stackOfStates.Pop();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The current state, if any.
|
||||
/// </summary>
|
||||
internal FormatterState CurrentState
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_stackOfStates.Count > 0)
|
||||
return m_stackOfStates.Peek();
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
internal void ChangeState(FormatterState formatterState)
|
||||
{
|
||||
if (CurrentState != null && CurrentState.GetType() == formatterState.GetType())
|
||||
{
|
||||
if (!CurrentState.ShouldNestState(formatterState))
|
||||
return;
|
||||
}
|
||||
PushState(formatterState);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region State Handling
|
||||
|
||||
/// <summary>
|
||||
/// Parses the string and updates the state accordingly.
|
||||
/// </summary>
|
||||
/// <param name="input">The text to process.</param>
|
||||
/// <returns>The text, ready for formatting.</returns>
|
||||
/// This method modifies the text because it removes some
|
||||
/// syntax stuff. Maybe the states themselves should handle
|
||||
/// their own syntax and remove it?
|
||||
private string HandleFormattingState(string input)
|
||||
{
|
||||
for (var i = 0; i < s_registeredStates.Count; i++)
|
||||
{
|
||||
var type = s_registeredStates[i];
|
||||
if (IsFormatterStateEnabled(type))
|
||||
{
|
||||
var att = s_registeredStatesAttributes[i];
|
||||
var m = Regex.Match(input, att.Pattern);
|
||||
if (m.Success)
|
||||
{
|
||||
var formatterState = (FormatterState)Activator.CreateInstance(type, this);
|
||||
return formatterState.Consume(input, m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Default, when no block is specified, we ask the current state, or
|
||||
// use the paragraph state.
|
||||
if (CurrentState != null)
|
||||
{
|
||||
if (CurrentState.FallbackFormattingState != null)
|
||||
{
|
||||
var formatterState = (FormatterState)Activator.CreateInstance(CurrentState.FallbackFormattingState, this);
|
||||
ChangeState(formatterState);
|
||||
}
|
||||
// else, the current state doesn't want to be superceded by
|
||||
// a new one. We'll leave him be.
|
||||
}
|
||||
else
|
||||
{
|
||||
ChangeState(new States.ParagraphFormatterState(this));
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -7,5 +7,16 @@
|
||||
"LastName": "Last Name",
|
||||
"Email": "Email",
|
||||
"Comments": "Comments",
|
||||
"ContactInformation": "Contact Information"
|
||||
"ContactInformation": "Contact Information",
|
||||
"UserType": "Type",
|
||||
"Sex": "Sex",
|
||||
"Birthdate": "Date of Birth",
|
||||
"Location": "Location",
|
||||
"Language": "Language",
|
||||
"Subscriptions": "Subscriptions",
|
||||
"SocialProfiles": "Social Profiles",
|
||||
"PendingTitle": "Pending",
|
||||
"EditUserDialogTitle": "Edit Profile",
|
||||
"LoadingProcessing": "Loading...",
|
||||
"LoadingDescription": "Please wait..."
|
||||
}
|
@ -9,8 +9,8 @@ import { useTranslation } from 'react-i18next';
|
||||
|
||||
const getSortData = () => {
|
||||
return [
|
||||
{ key: "firstname", label: "Name" },
|
||||
{ key: "lastname", label: "Surname" }
|
||||
{ key: "firstname", label: "By first name" },
|
||||
{ key: "lastname", label: "By last name" }
|
||||
];
|
||||
};
|
||||
|
||||
|
@ -3,6 +3,7 @@ import { connect } from "react-redux";
|
||||
import PropTypes from "prop-types";
|
||||
import { withRouter } from "react-router";
|
||||
import { PageLayout, RequestLoader } from "asc-web-components";
|
||||
import { withTranslation } from 'react-i18next';
|
||||
import {
|
||||
ArticleHeaderContent,
|
||||
ArticleBodyContent,
|
||||
@ -95,6 +96,7 @@ class Home extends React.Component {
|
||||
isHeaderChecked,
|
||||
selected
|
||||
} = this.state;
|
||||
const t = this.props.t;
|
||||
return (
|
||||
<>
|
||||
<RequestLoader
|
||||
@ -102,7 +104,7 @@ class Home extends React.Component {
|
||||
zIndex={256}
|
||||
loaderSize={16}
|
||||
loaderColor={"#999"}
|
||||
label={"Loading... Please wait..."}
|
||||
label={`${t('Resource:LoadingProcessing')} ${t('Resource:LoadingDescription')}`}
|
||||
fontSize={12}
|
||||
fontColor={"#999"}
|
||||
/>
|
||||
@ -156,4 +158,4 @@ function mapStateToProps(state) {
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
{ setSelected }
|
||||
)(withRouter(Home));
|
||||
)(withRouter(withTranslation()(Home)));
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React, { useCallback } from "react";
|
||||
import { withRouter } from "react-router";
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
Text,
|
||||
Avatar,
|
||||
@ -142,6 +143,7 @@ const createContacts = contacts => {
|
||||
};
|
||||
|
||||
const SectionBodyContent = props => {
|
||||
const { t, i18n } = useTranslation();
|
||||
const { profile, history, settings, isAdmin, viewer } = props;
|
||||
//console.log(props);
|
||||
const contacts = profile.contacts && getUserContacts(profile.contacts);
|
||||
@ -189,19 +191,19 @@ const SectionBodyContent = props => {
|
||||
<Button
|
||||
style={editButtonWrapper}
|
||||
size="big"
|
||||
label="Edit profile"
|
||||
label={t("Resource:EditUserDialogTitle")}
|
||||
onClick={onEditProfileClick}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div style={infoWrapper}>
|
||||
<div style={titlesWrapper}>
|
||||
<Text.Body style={restMargins} color="#A3A9AE" title="Type">
|
||||
Type:
|
||||
<Text.Body style={restMargins} color="#A3A9AE" title={t('Resource:UserType')}>
|
||||
{t('Resource:UserType')}:
|
||||
</Text.Body>
|
||||
{profile.email && (
|
||||
<Text.Body style={restMargins} color="#A3A9AE" title="E-mail">
|
||||
E-mail:
|
||||
<Text.Body style={restMargins} color="#A3A9AE" title={t('Resource:Email')}>
|
||||
{t('Resource:Email')}:
|
||||
</Text.Body>
|
||||
)}
|
||||
{profile.department && (
|
||||
@ -220,8 +222,8 @@ const SectionBodyContent = props => {
|
||||
</Text.Body>
|
||||
)}
|
||||
{profile.sex && (
|
||||
<Text.Body style={restMargins} color="#A3A9AE" title="Sex">
|
||||
Sex:
|
||||
<Text.Body style={restMargins} color="#A3A9AE" title={t('Resource:Sex')}>
|
||||
{t('Resource:Sex')}:
|
||||
</Text.Body>
|
||||
)}
|
||||
{profile.workFrom && (
|
||||
@ -237,19 +239,19 @@ const SectionBodyContent = props => {
|
||||
<Text.Body
|
||||
style={restMargins}
|
||||
color="#A3A9AE"
|
||||
title="Date of birth"
|
||||
title={t('Resource:Birthdate')}
|
||||
>
|
||||
Date of birth:
|
||||
{t('Resource:Birthdate')}:
|
||||
</Text.Body>
|
||||
)}
|
||||
{profile.location && (
|
||||
<Text.Body style={restMargins} color="#A3A9AE" title="Location">
|
||||
Location:
|
||||
<Text.Body style={restMargins} color="#A3A9AE" title={t('Resource:Location')}>
|
||||
{t('Resource:Location')}:
|
||||
</Text.Body>
|
||||
)}
|
||||
{isSelf && (
|
||||
<Text.Body style={restMargins} color="#A3A9AE" title="Language">
|
||||
Language:
|
||||
<Text.Body style={restMargins} color="#A3A9AE" title={t('Resource:Language')}>
|
||||
{t('Resource:Language')}:
|
||||
</Text.Body>
|
||||
)}
|
||||
{/*{isSelf && <Text.Body style={marginTop24} color='#A3A9AE' title='Affiliate status'>Affiliate status:</Text.Body>}*/}
|
||||
@ -267,7 +269,7 @@ const SectionBodyContent = props => {
|
||||
>
|
||||
{profile.email}
|
||||
</Link>
|
||||
{profile.activationStatus === 2 && " (Pending)"}
|
||||
{profile.activationStatus === 2 && ` (${t("Resource:PendingTitle")})`}
|
||||
</Text.Body>
|
||||
<Text.Body as="div" style={restMargins}>{formatedDepartments}</Text.Body>
|
||||
<Text.Body style={restMargins}>{profile.title}</Text.Body>
|
||||
@ -300,7 +302,7 @@ const SectionBodyContent = props => {
|
||||
{isSelf && (
|
||||
<div style={selfToggleWrapper}>
|
||||
<ToggleContent
|
||||
label="Subscriptions"
|
||||
label={t('Resource:Subscriptions')}
|
||||
style={notesWrapper}
|
||||
isOpen={true}
|
||||
>
|
||||
@ -317,7 +319,7 @@ const SectionBodyContent = props => {
|
||||
)}
|
||||
{profile.notes && (
|
||||
<div style={notesToggleWrapper}>
|
||||
<ToggleContent label="Comment" style={notesWrapper} isOpen={true}>
|
||||
<ToggleContent label={t('Resource:Comments')} style={notesWrapper} isOpen={true}>
|
||||
<Text.Body as="span">{profile.notes}</Text.Body>
|
||||
</ToggleContent>
|
||||
</div>
|
||||
@ -325,7 +327,7 @@ const SectionBodyContent = props => {
|
||||
{profile.contacts && (
|
||||
<div style={contactsToggleWrapper}>
|
||||
<ToggleContent
|
||||
label="Contact information"
|
||||
label={t('Resource:ContactInformation')}
|
||||
style={notesWrapper}
|
||||
isOpen={true}
|
||||
>
|
||||
@ -336,7 +338,7 @@ const SectionBodyContent = props => {
|
||||
{profile.contacts && (
|
||||
<div style={contactsToggleWrapper}>
|
||||
<ToggleContent
|
||||
label="Social profiles"
|
||||
label={t('Resource:SocialProfiles')}
|
||||
style={notesWrapper}
|
||||
isOpen={true}
|
||||
>
|
||||
|
9
web/ASC.Web.Client/public/locales/en/Resource.json
Normal file
9
web/ASC.Web.Client/public/locales/en/Resource.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"LoadingProcessing": "Loading...",
|
||||
"LoginButton": "Sign In",
|
||||
"Password": "Password",
|
||||
"RegistrationEmailWatermark": "Your registration email",
|
||||
"Profile": "Profile",
|
||||
"LogoutButton": "Sign Out",
|
||||
"AboutCompanyTitle": "About this program"
|
||||
}
|
@ -1,6 +1,3 @@
|
||||
{
|
||||
"Profile": "Profile",
|
||||
"LogoutButton": "Sign Out",
|
||||
"AboutCompanyTitle": "About this program",
|
||||
"ResourceNotFound": "Sorry, the resource cannot be found."
|
||||
}
|
5
web/ASC.Web.Client/public/locales/ru/Resource.json
Normal file
5
web/ASC.Web.Client/public/locales/ru/Resource.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"Profile": "Профиль",
|
||||
"LogoutButton": "Выйти",
|
||||
"AboutCompanyTitle": "О программе"
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"Profile": "Профиль",
|
||||
"LogoutButton": "Выйти",
|
||||
"AboutCompanyTitle": "О программе",
|
||||
"ResourceNotFound": "Извините, страница не найдена."
|
||||
}
|
@ -35,13 +35,13 @@ class StudioLayout extends React.Component {
|
||||
|
||||
const currentUserActions = [
|
||||
{
|
||||
key: 'ProfileBtn', label: t("Profile"), onClick: this.onProfileClick
|
||||
key: 'ProfileBtn', label: t("Resource:Profile"), onClick: this.onProfileClick
|
||||
},
|
||||
{
|
||||
key: 'AboutBtn', label: t("AboutCompanyTitle"), onClick: this.onAboutClick
|
||||
key: 'AboutBtn', label: t("Resource:AboutCompanyTitle"), onClick: this.onAboutClick
|
||||
},
|
||||
{
|
||||
key: 'LogoutBtn', label: t("LogoutButton"), onClick: this.onLogoutClick
|
||||
key: 'LogoutBtn', label: t("Resource:LogoutButton"), onClick: this.onLogoutClick
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -6,6 +6,7 @@ import { Button, TextInput, PageLayout } from 'asc-web-components';
|
||||
import { connect } from 'react-redux';
|
||||
import { login } from '../../../store/auth/actions';
|
||||
import styled from 'styled-components';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const FormContainer = styled(Container)`
|
||||
margin-top: 70px;
|
||||
@ -34,6 +35,7 @@ const FormContainer = styled(Container)`
|
||||
const mdOptions = { size: 6, offset: 3 };
|
||||
|
||||
const Form = props => {
|
||||
const { t, i18n } = useTranslation();
|
||||
const [identifier, setIdentifier] = useState('');
|
||||
const [identifierValid, setIdentifierValid] = useState(true);
|
||||
const [password, setPassword] = useState('');
|
||||
@ -115,7 +117,7 @@ const Form = props => {
|
||||
name="login"
|
||||
hasError={!identifierValid}
|
||||
value={identifier}
|
||||
placeholder="You registration email"
|
||||
placeholder={t('Resource:RegistrationEmailWatermark')}
|
||||
size='huge'
|
||||
scale={true}
|
||||
isAutoFocussed={true}
|
||||
@ -138,7 +140,7 @@ const Form = props => {
|
||||
type="password"
|
||||
hasError={!passwordValid}
|
||||
value={password}
|
||||
placeholder="Password"
|
||||
placeholder={t('Resource:Password')}
|
||||
size='huge'
|
||||
scale={true}
|
||||
tabIndex={2}
|
||||
@ -158,7 +160,7 @@ const Form = props => {
|
||||
<Button
|
||||
primary
|
||||
size='big'
|
||||
label={isLoading ? "Loading..." : "Sign In"}
|
||||
label={isLoading ? t('Resource:LoadingProcessing') : t('Resource:LoginButton')}
|
||||
tabIndex={3}
|
||||
isDisabled={isLoading}
|
||||
isLoading={isLoading}
|
||||
|
@ -15,9 +15,10 @@ i18n
|
||||
// init i18next
|
||||
// for all options read: https://www.i18next.com/overview/configuration-options
|
||||
.init({
|
||||
lng: "en",
|
||||
lng: "ru",
|
||||
fallbackLng: 'en',
|
||||
debug: true,
|
||||
ns: ['translation', 'Resource'],
|
||||
|
||||
interpolation: {
|
||||
escapeValue: false, // not needed for react as it escapes by default
|
||||
|
Loading…
Reference in New Issue
Block a user