Merge branch 'MentionsFeature'

main
Inga 🏳‍🌈 13 years ago
commit a24168632c
  1. 4
      FLocal.Common/BBCodes/AbstractLocalLink.cs
  2. 4
      FLocal.Common/BBCodes/B.cs
  3. 2
      FLocal.Common/BBCodes/Code.cs
  4. 4
      FLocal.Common/BBCodes/ECode.cs
  5. 4
      FLocal.Common/BBCodes/FUrl.cs
  6. 4
      FLocal.Common/BBCodes/Font.cs
  7. 4
      FLocal.Common/BBCodes/FontColor.cs
  8. 4
      FLocal.Common/BBCodes/FontSize.cs
  9. 4
      FLocal.Common/BBCodes/Google.cs
  10. 4
      FLocal.Common/BBCodes/I.cs
  11. 2
      FLocal.Common/BBCodes/Image.cs
  12. 4
      FLocal.Common/BBCodes/List.cs
  13. 2
      FLocal.Common/BBCodes/ListElem.cs
  14. 4
      FLocal.Common/BBCodes/Lurk.cs
  15. 2
      FLocal.Common/BBCodes/Math.cs
  16. 4
      FLocal.Common/BBCodes/Quote.cs
  17. 4
      FLocal.Common/BBCodes/QuoteSkipper.cs
  18. 4
      FLocal.Common/BBCodes/RuWiki.cs
  19. 4
      FLocal.Common/BBCodes/S.cs
  20. 4
      FLocal.Common/BBCodes/Spoiler.cs
  21. 2
      FLocal.Common/BBCodes/Tex.cs
  22. 4
      FLocal.Common/BBCodes/U.cs
  23. 2
      FLocal.Common/BBCodes/UploadImage.cs
  24. 4
      FLocal.Common/BBCodes/UploadLink.cs
  25. 4
      FLocal.Common/BBCodes/Url.cs
  26. 6
      FLocal.Common/BBCodes/User.cs
  27. 4
      FLocal.Common/BBCodes/Wiki.cs
  28. 7
      FLocal.Common/BBCodes/helpers/BBCode.cs
  29. 10
      FLocal.Common/BBCodes/helpers/IPostParsingContext.cs
  30. 21
      FLocal.Common/BBCodes/helpers/UserMentionProcessor.cs
  31. 6
      FLocal.Common/FLocal.Common.csproj
  32. 53
      FLocal.Common/UBBParser.cs
  33. 3
      FLocal.Common/URL/UrlManager.cs
  34. 6
      FLocal.Common/URL/users/user/Mentions.cs
  35. 1
      FLocal.Common/actions/ChangeSet.cs
  36. 69
      FLocal.Common/dataobjects/Mention.cs
  37. 46
      FLocal.Common/dataobjects/Post.cs
  38. 22
      FLocal.Common/dataobjects/Thread.cs
  39. 30
      FLocal.Common/dataobjects/User.cs
  40. 25
      FLocal.Common/helpers/DelegatePostParsingContext.cs
  41. 2
      FLocal.IISHandler/HandlersFactory.cs
  42. 4
      FLocal.IISHandler/handlers/response/UserRepliesHandler.cs
  43. 3
      FLocal.Patcher.Common/FLocal.Patcher.Common.csproj
  44. 91
      FLocal.Patcher.Common/Resources/Patch_00002_mentions.xml
  45. 10
      MySQLConnector/Connection.cs
  46. 4
      Resources/FLocal/static/css/modern/global.css
  47. 2
      Resources/FLocal/templates/Full/Boards.xslt
  48. 4
      Resources/FLocal/templates/Full/UserInfo.xslt
  49. 4
      Resources/FLocal/templates/Lite/UserInfo.xslt
  50. 2
      Resources/FLocal/templates/Modern/Boards.xslt
  51. 4
      Resources/FLocal/templates/Modern/elems/ForumHeader.xslt
  52. 4
      Resources/FLocal/templates/Modern/elems/UserHeader.xslt
  53. 12
      ThirdParty/PJonDevelopment.BBCode/Classes/BBCodeConfiguration.vb
  54. 22
      ThirdParty/PJonDevelopment.BBCode/Classes/BBCodeDocument.vb
  55. 26
      ThirdParty/PJonDevelopment.BBCode/Classes/BBCodeElement.vb
  56. 20
      ThirdParty/PJonDevelopment.BBCode/Classes/BBCodeElementFactory.vb
  57. 6
      ThirdParty/PJonDevelopment.BBCode/Classes/BBCodeElementTypeDictionary.vb
  58. 6
      ThirdParty/PJonDevelopment.BBCode/Classes/BBCodeHtmlFormatter.vb
  59. 20
      ThirdParty/PJonDevelopment.BBCode/Classes/BBCodeNode.vb
  60. 18
      ThirdParty/PJonDevelopment.BBCode/Classes/BBCodeNodeCollection.vb
  61. 44
      ThirdParty/PJonDevelopment.BBCode/Classes/BBCodeParser.vb
  62. 8
      ThirdParty/PJonDevelopment.BBCode/Classes/BBCodeText.vb
  63. 4
      ThirdParty/PJonDevelopment.BBCode/Interfaces/ITextFormatter.vb
  64. 4
      ThirdParty/PJonDevelopment.BBCode/Modules/Utils.vb
  65. 8
      ThirdParty/PJonDevelopment.BBCode/README.TXT
  66. 8
      Web.Core/DB/IDBConnection.cs

@ -16,11 +16,11 @@ namespace FLocal.Common.BBCodes {
get;
}
public override string Format(ITextFormatter formatter) {
public override string Format(IPostParsingContext context, ITextFormatter<IPostParsingContext> formatter) {
var url = this.url;
var name = this.Safe(url.title);
if(this.Default != null) {
name = this.GetInnerHTML(formatter);
name = this.GetInnerHTML(context, formatter);
}
return string.Format("<a href=\"{0}\">{1}</a>", url.canonical, url.title);
}

@ -11,8 +11,8 @@ namespace FLocal.Common.BBCodes {
: base("b") {
}
public override string Format(ITextFormatter formatter) {
return "<b>" + this.GetInnerHTML(formatter) + "</b>";
public override string Format(IPostParsingContext context, ITextFormatter<IPostParsingContext> formatter) {
return "<b>" + this.GetInnerHTML(context, formatter) + "</b>";
}
}

@ -11,7 +11,7 @@ namespace FLocal.Common.BBCodes {
: base("code") {
}
public override string Format(ITextFormatter formatter) {
public override string Format(IPostParsingContext context, ITextFormatter<IPostParsingContext> formatter) {
return "<pre>" + System.Web.HttpUtility.HtmlEncode(this.InnerBBCode) + "</pre><br/>";
}

@ -11,8 +11,8 @@ namespace FLocal.Common.BBCodes {
: base("ecode") {
}
public override string Format(ITextFormatter formatter) {
return this.GetInnerHTML(new BBCodeHtmlFormatter());
public override string Format(IPostParsingContext context, ITextFormatter<IPostParsingContext> formatter) {
return this.GetInnerHTML(context, new BBCodeHtmlFormatter<BBCodes.IPostParsingContext>());
}
}

@ -11,11 +11,11 @@ namespace FLocal.Common.BBCodes {
: base("furl") {
}
public override string Format(ITextFormatter formatter) {
public override string Format(IPostParsingContext context, ITextFormatter<IPostParsingContext> formatter) {
string rawUrl = this.DefaultOrValue;
string title = null;
if(rawUrl.ToLower() != this.InnerText.ToLower()) {
title = this.GetInnerHTML(formatter);
title = this.GetInnerHTML(context, formatter);
}
return UrlProcessor.ProcessLink(rawUrl, title, false);
}

@ -11,8 +11,8 @@ namespace FLocal.Common.BBCodes {
: base("font") {
}
public override string Format(ITextFormatter formatter) {
return "<font face=\"" + this.Default + "\">" + this.GetInnerHTML(formatter) + "</font>";
public override string Format(IPostParsingContext context, ITextFormatter<IPostParsingContext> formatter) {
return "<font face=\"" + this.Default + "\">" + this.GetInnerHTML(context, formatter) + "</font>";
}
}

@ -11,8 +11,8 @@ namespace FLocal.Common.BBCodes {
: base("color") {
}
public override string Format(ITextFormatter formatter) {
return "<font color=\"" + this.Default + "\">" + this.GetInnerHTML(formatter) + "</font>";
public override string Format(IPostParsingContext context, ITextFormatter<IPostParsingContext> formatter) {
return "<font color=\"" + this.Default + "\">" + this.GetInnerHTML(context, formatter) + "</font>";
}
}

@ -11,8 +11,8 @@ namespace FLocal.Common.BBCodes {
: base("size") {
}
public override string Format(ITextFormatter formatter) {
return "<font size=\"" + this.Default + "\">" + this.GetInnerHTML(formatter) + "</font>";
public override string Format(IPostParsingContext context, ITextFormatter<IPostParsingContext> formatter) {
return "<font size=\"" + this.Default + "\">" + this.GetInnerHTML(context, formatter) + "</font>";
}
}

@ -12,8 +12,8 @@ namespace FLocal.Common.BBCodes {
: base("google") {
}
public override string Format(ITextFormatter formatter) {
return "<a href=\"http://lmgtfy.com/?q=" + HttpUtility.UrlPathEncode(this.DefaultOrValue) + "\">g:" + this.GetInnerHTML(formatter) + "</a>";
public override string Format(IPostParsingContext context, ITextFormatter<IPostParsingContext> formatter) {
return "<a href=\"http://lmgtfy.com/?q=" + HttpUtility.UrlPathEncode(this.DefaultOrValue) + "\">g:" + this.GetInnerHTML(context, formatter) + "</a>";
}
}

@ -11,8 +11,8 @@ namespace FLocal.Common.BBCodes {
: base("i") {
}
public override string Format(ITextFormatter formatter) {
return "<i>" + this.GetInnerHTML(formatter) + "</i>";
public override string Format(IPostParsingContext context, ITextFormatter<IPostParsingContext> formatter) {
return "<i>" + this.GetInnerHTML(context, formatter) + "</i>";
}
}

@ -10,7 +10,7 @@ namespace FLocal.Common.BBCodes {
public Image() : base("image") {
}
public override string Format(ITextFormatter formatter) {
public override string Format(IPostParsingContext context, ITextFormatter<IPostParsingContext> formatter) {
var urlInfo = UrlProcessor.Process(this.InnerText);
if (urlInfo.isLocal && urlInfo.relativeUrl.StartsWith("/user/upload/")) {
return "<f:img><f:src>" + urlInfo.relativeUrl + "</f:src><f:alt>" + urlInfo.relativeUrl + "</f:alt></f:img>";

@ -11,8 +11,8 @@ namespace FLocal.Common.BBCodes {
: base("list") {
}
public override string Format(ITextFormatter formatter) {
return "<ul>" + this.GetInnerHTML(formatter) + "</ul>";
public override string Format(IPostParsingContext context, ITextFormatter<IPostParsingContext> formatter) {
return "<ul>" + this.GetInnerHTML(context, formatter) + "</ul>";
}
}

@ -11,7 +11,7 @@ namespace FLocal.Common.BBCodes {
: base("*") {
}
public override string Format(ITextFormatter formatter) {
public override string Format(IPostParsingContext context, ITextFormatter<IPostParsingContext> formatter) {
// return "<li>" + this.GetInnerHTML(formatter) + "</li>";
return "<li>";
}

@ -12,8 +12,8 @@ namespace FLocal.Common.BBCodes {
: base("lurk") {
}
public override string Format(ITextFormatter formatter) {
return "<a href=\"http://lurkmore.ru/" + HttpUtility.UrlPathEncode(this.DefaultOrValue) + "\">l:" + this.GetInnerHTML(formatter) + "</a>";
public override string Format(IPostParsingContext context, ITextFormatter<IPostParsingContext> formatter) {
return "<a href=\"http://lurkmore.ru/" + HttpUtility.UrlPathEncode(this.DefaultOrValue) + "\">l:" + this.GetInnerHTML(context, formatter) + "</a>";
}
}

@ -11,7 +11,7 @@ namespace FLocal.Common.BBCodes {
: base("math") {
}
public override string Format(ITextFormatter formatter) {
public override string Format(IPostParsingContext context, ITextFormatter<IPostParsingContext> formatter) {
string tex = "$$" + this.InnerBBCode + "$$";
var upload = helpers.TexProcessor.getCompiled(tex);
return "<f:img><f:src>/Upload/Item/" + upload.id.ToString() + "/</f:src><f:alt>" + this.Safe(tex) + "</f:alt></f:img>";

@ -12,8 +12,8 @@ namespace FLocal.Common.BBCodes {
: base("quote") {
}
public override string Format(ITextFormatter formatter) {
string inner = this.GetInnerHTML(formatter).TrimHtml();
public override string Format(IPostParsingContext context, ITextFormatter<IPostParsingContext> formatter) {
string inner = this.GetInnerHTML(context, formatter).TrimHtml();
if(inner == "") return "";
string marker = this.Default;
if(marker == null) marker = "Quote:";

@ -10,7 +10,7 @@ namespace FLocal.Common.BBCodes {
public QuoteSkipper() : base("quoteskipper") {
}
public override string Format(ITextFormatter formatter) {
public override string Format(IPostParsingContext context, ITextFormatter<IPostParsingContext> formatter) {
if(this.Name.ToLower() == "q" || this.Name.ToLower() == "quote") {
return "";
} else if(this.Name.ToLower() == "code") {
@ -36,7 +36,7 @@ namespace FLocal.Common.BBCodes {
}
sb.Append("]");
if(this.RequireClosingTag) {
sb.Append(this.GetInnerHTML(formatter));
sb.Append(this.GetInnerHTML(context, formatter));
sb.Append("[/");
sb.Append(name);
sb.Append("]");

@ -12,8 +12,8 @@ namespace FLocal.Common.BBCodes {
: base("ruwiki") {
}
public override string Format(ITextFormatter formatter) {
return "<a href=\"http://ru.wikipedia.org/wiki/" + HttpUtility.UrlPathEncode(this.DefaultOrValue) + "\">в:" + this.GetInnerHTML(formatter) + "</a>";
public override string Format(IPostParsingContext context, ITextFormatter<IPostParsingContext> formatter) {
return "<a href=\"http://ru.wikipedia.org/wiki/" + HttpUtility.UrlPathEncode(this.DefaultOrValue) + "\">в:" + this.GetInnerHTML(context, formatter) + "</a>";
}
}

@ -11,8 +11,8 @@ namespace FLocal.Common.BBCodes {
: base("s") {
}
public override string Format(ITextFormatter formatter) {
return "<s>" + this.GetInnerHTML(formatter) + "</s>";
public override string Format(IPostParsingContext context, ITextFormatter<IPostParsingContext> formatter) {
return "<s>" + this.GetInnerHTML(context, formatter) + "</s>";
}
}

@ -11,10 +11,10 @@ namespace FLocal.Common.BBCodes {
: base("spoiler") {
}
public override string Format(ITextFormatter formatter) {
public override string Format(IPostParsingContext context, ITextFormatter<IPostParsingContext> formatter) {
string marker = this.Default;
if(marker == null) marker = "Spoiler";
return "<blockquote spoiler><font opener class=\"small\" onClick=\"showSpoiler(this)\">" + marker + "</font><hr/><div inner name=\"inner\" style=\"display:none\">" + this.GetInnerHTML(formatter).Trim() + "</div><hr/></blockquote><br/>";
return "<blockquote spoiler><font opener class=\"small\" onClick=\"showSpoiler(this)\">" + marker + "</font><hr/><div inner name=\"inner\" style=\"display:none\">" + this.GetInnerHTML(context, formatter).Trim() + "</div><hr/></blockquote><br/>";
}
}

@ -11,7 +11,7 @@ namespace FLocal.Common.BBCodes {
: base("tex") {
}
public override string Format(ITextFormatter formatter) {
public override string Format(IPostParsingContext context, ITextFormatter<IPostParsingContext> formatter) {
string tex = this.InnerBBCode;
var upload = helpers.TexProcessor.getCompiled(tex);
return "<f:img><f:src>/Upload/Item/" + upload.id.ToString() + "/</f:src><f:alt>" + this.Safe(tex) + "</f:alt></f:img>";

@ -11,8 +11,8 @@ namespace FLocal.Common.BBCodes {
: base("u") {
}
public override string Format(ITextFormatter formatter) {
return "<u>" + this.GetInnerHTML(formatter) + "</u>";
public override string Format(IPostParsingContext context, ITextFormatter<IPostParsingContext> formatter) {
return "<u>" + this.GetInnerHTML(context, formatter) + "</u>";
}
}

@ -11,7 +11,7 @@ namespace FLocal.Common.BBCodes {
: base("uploadimage") {
}
public override string Format(ITextFormatter formatter) {
public override string Format(IPostParsingContext context, ITextFormatter<IPostParsingContext> formatter) {
var upload = dataobjects.Upload.LoadById(int.Parse(this.InnerText));
var name = upload.filename;
return "<f:img><f:src>/Upload/Item/" + upload.id.ToString() + "/</f:src><f:alt>" + this.Safe(upload.filename) + "</f:alt></f:img>";

@ -11,11 +11,11 @@ namespace FLocal.Common.BBCodes {
: base("uploadlink") {
}
public override string Format(ITextFormatter formatter) {
public override string Format(IPostParsingContext context, ITextFormatter<IPostParsingContext> formatter) {
var upload = dataobjects.Upload.LoadById(int.Parse(this.DefaultOrValue));
var name = this.Safe(upload.filename);
if(this.Default != null) {
name = this.GetInnerHTML(formatter);
name = this.GetInnerHTML(context, formatter);
}
return "<a href=\"/Upload/Info/" + upload.id.ToString() + "/\">" + name + "</a>";
}

@ -11,11 +11,11 @@ namespace FLocal.Common.BBCodes {
: base("url") {
}
public override string Format(ITextFormatter formatter) {
public override string Format(IPostParsingContext context, ITextFormatter<IPostParsingContext> formatter) {
string rawUrl = this.DefaultOrValue;
string title = null;
if(rawUrl.ToLower() != this.InnerText.ToLower()) {
title = this.GetInnerHTML(formatter);
title = this.GetInnerHTML(context, formatter);
}
return UrlProcessor.ProcessLink(rawUrl, title, true);
}

@ -11,10 +11,8 @@ namespace FLocal.Common.BBCodes {
: base("user") {
}
public override string Format(ITextFormatter formatter) {
var user = dataobjects.User.LoadByName(this.DefaultOrValue);
var url = new URL.users.user.Info(user.id.ToString(), null);
return String.Format("<a class=\"separate UG_{0}\" href=\"{1}\">{2}</a>", this.Safe(user.userGroup.name), url.canonical, this.Safe(user.name));
public override string Format(IPostParsingContext context, ITextFormatter<IPostParsingContext> formatter) {
return UserMentionProcessor.ProcessUserMention(context, this.DefaultOrValue);
}
}

@ -12,8 +12,8 @@ namespace FLocal.Common.BBCodes {
: base("wiki") {
}
public override string Format(ITextFormatter formatter) {
return "<a href=\"http://en.wikipedia.org/wiki/" + HttpUtility.UrlPathEncode(this.DefaultOrValue) + "\">w:" + this.GetInnerHTML(formatter) + "</a>";
public override string Format(IPostParsingContext context, ITextFormatter<IPostParsingContext> formatter) {
return "<a href=\"http://en.wikipedia.org/wiki/" + HttpUtility.UrlPathEncode(this.DefaultOrValue) + "\">w:" + this.GetInnerHTML(context, formatter) + "</a>";
}
}

@ -2,18 +2,19 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FLocal.Common.helpers;
namespace FLocal.Common.BBCodes {
abstract class BBCode : PJonDevelopment.BBCode.BBCodeElement {
abstract class BBCode : PJonDevelopment.BBCode.BBCodeElement<IPostParsingContext> {
public BBCode(string name)
: base(name) {
}
protected string GetInnerHTML(PJonDevelopment.BBCode.ITextFormatter formatter) {
protected string GetInnerHTML(IPostParsingContext context, PJonDevelopment.BBCode.ITextFormatter<IPostParsingContext> formatter) {
StringBuilder builder = new StringBuilder();
foreach (var node in this.Nodes) {
builder.Append(node.Format(formatter));
builder.Append(node.Format(context, formatter));
}
return builder.ToString();
}

@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace FLocal.Common.BBCodes {
public interface IPostParsingContext {
void OnUserMention(dataobjects.User user);
}
}

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace FLocal.Common.BBCodes {
class UserMentionProcessor {
private static string Safe(string str) {
return System.Web.HttpUtility.HtmlEncode(str);
}
public static string ProcessUserMention(IPostParsingContext context, string username) {
var user = dataobjects.User.LoadByName(username);
context.OnUserMention(user);
var url = new URL.users.user.Info(user.id.ToString(), null);
return String.Format("<a class=\"separate userreference UG_{0}\" href=\"{1}\">{2}</a>", Safe(user.userGroup.name), url.canonical, Safe(user.name));
}
}
}

@ -68,6 +68,7 @@
<Compile Include="BBCodes\Code.cs" />
<Compile Include="BBCodes\FUrl.cs" />
<Compile Include="BBCodes\helpers\TexProcessor.cs" />
<Compile Include="BBCodes\helpers\UserMentionProcessor.cs" />
<Compile Include="BBCodes\Image.cs" />
<Compile Include="BBCodes\List.cs" />
<Compile Include="BBCodes\ListElem.cs" />
@ -100,6 +101,7 @@
<Compile Include="dataobjects\AnonymousUserSettings.cs" />
<Compile Include="dataobjects\LocalNetwork.cs" />
<Compile Include="dataobjects\Machichara.cs" />
<Compile Include="dataobjects\Mention.cs" />
<Compile Include="dataobjects\Moderator.cs" />
<Compile Include="dataobjects\ModernSkin.cs" />
<Compile Include="dataobjects\PMConversation.cs" />
@ -122,6 +124,8 @@
<Compile Include="dataobjects\User.cs" />
<Compile Include="dataobjects\AccountSettings.cs" />
<Compile Include="dataobjects\UserGroup.cs" />
<Compile Include="helpers\DelegatePostParsingContext.cs" />
<Compile Include="BBCodes\helpers\IPostParsingContext.cs" />
<Compile Include="IComplexSqlObjectTableSpec.cs" />
<Compile Include="IOutputParams.cs" />
<Compile Include="ISqlObjectTableSpec.cs" />
@ -179,7 +183,7 @@
<Compile Include="URL\users\user\Info.cs" />
<Compile Include="URL\users\user\PollsParticipated.cs" />
<Compile Include="URL\users\user\Posts.cs" />
<Compile Include="URL\users\user\Replies.cs" />
<Compile Include="URL\users\user\Mentions.cs" />
<Compile Include="URL\users\user\Threads.cs" />
<Compile Include="UserContext.cs" />
<Compile Include="UserSettingsGateway.cs" />

@ -7,26 +7,27 @@ using System.Text.RegularExpressions;
using PJonDevelopment.BBCode;
using System.IO;
using Web.Core;
using FLocal.Common.helpers;
namespace FLocal.Common {
public static class UBBParser {
private class BBParserGateway {
private class SimpleFormatter : ITextFormatter {
private class SimpleFormatter : ITextFormatter<BBCodes.IPostParsingContext> {
public static readonly SimpleFormatter instance = new SimpleFormatter();
private SimpleFormatter() {
}
public string Format(string source) {
public string Format(BBCodes.IPostParsingContext context, string source) {
return source;
}
}
private class TextFormatter : ITextFormatter {
private class TextFormatter : ITextFormatter<BBCodes.IPostParsingContext> {
public static readonly TextFormatter instance = new TextFormatter();
@ -68,6 +69,14 @@ namespace FLocal.Common {
return BBCodes.UrlProcessor.ProcessLink(url, null, true) + remainder;
}
private static readonly Regex USERS_MATCHER = new Regex("(?<start>^|\\W)@(?<username>\\w+)(?<end>\\W|$)", RegexOptions.Singleline | RegexOptions.Compiled);
private static string USERS_REPLACE(BBCodes.IPostParsingContext context, Match match) {
string start = match.Groups["start"].Value;
string username = match.Groups["username"].Value;
string end = match.Groups["end"].Value;
return start + BBCodes.UserMentionProcessor.ProcessUserMention(context, username) + end;
}
private static readonly Dictionary<Regex, MatchEvaluator> TYPOGRAPHICS = new Dictionary<Regex, MatchEvaluator> {
{ new Regex("(?<=\\s)--?(?=\\s)", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline), match => "–" },
{ new Regex("(?<=\\s)---(?=\\s)", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline), match => "—" },
@ -85,15 +94,16 @@ namespace FLocal.Common {
{ new Regex("&lt;-", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline), match => "←" },
};
private ITextFormatter inner;
private ITextFormatter<BBCodes.IPostParsingContext> inner;
private TextFormatter() {
this.inner = new BBCodeHtmlFormatter();
this.inner = new BBCodeHtmlFormatter<BBCodes.IPostParsingContext>();
}
public string Format(string source) {
string result = this.inner.Format(source).Replace("&nbsp;", " ");
public string Format(BBCodes.IPostParsingContext context, string source) {
string result = this.inner.Format(context, source).Replace("&nbsp;", " ");
result = LINKS_MATCHER.Replace(result, LINKS_REPLACE);
result = USERS_MATCHER.Replace(result, match => USERS_REPLACE(context, match));
foreach(var smile in SMILEYS_DATA) {
result = smile.Key.Replace(result, smile.Value);
}
@ -108,14 +118,14 @@ namespace FLocal.Common {
public static readonly BBParserGateway instance = new BBParserGateway();
private BBCodeParser parser;
private ITextFormatter formatter;
private BBCodeParser<BBCodes.IPostParsingContext> parser;
private ITextFormatter<BBCodes.IPostParsingContext> formatter;
private BBCodeParser quotesParser;
private ITextFormatter simpleFormatter;
private BBCodeParser<BBCodes.IPostParsingContext> quotesParser;
private ITextFormatter<BBCodes.IPostParsingContext> simpleFormatter;
private BBParserGateway() {
this.parser = new BBCodeParser();
this.parser = new BBCodeParser<BBCodes.IPostParsingContext>();
this.parser.ElementTypes.Add("b", typeof(BBCodes.B), true);
this.parser.ElementTypes.Add("code", typeof(BBCodes.Code), true);
this.parser.ElementTypes.Add("ecode", typeof(BBCodes.ECode), true);
@ -146,29 +156,36 @@ namespace FLocal.Common {
this.parser.ElementTypes.Add("ruwiki", typeof(BBCodes.RuWiki), true);
this.formatter = TextFormatter.instance;
this.quotesParser = new BBCodeParser();
this.quotesParser = new BBCodeParser<BBCodes.IPostParsingContext>();
foreach(var elementType in this.parser.ElementTypes) {
this.quotesParser.ElementTypes.Add(elementType.Key, typeof(BBCodes.QuoteSkipper), elementType.Value.RequireClosingTag);
}
this.simpleFormatter = SimpleFormatter.instance;
}
public string Parse(string input) {
string result = this.parser.Parse(input).Format(this.formatter);
public string Parse(BBCodes.IPostParsingContext context, string input) {
string result = this.parser.Parse(input).Format(context, this.formatter);
if(result.EndsWith("<br/>")) result = result.Substring(0, result.Length - 5);
return result;
}
public string ParseQuote(string input) {
string result = this.quotesParser.Parse(input).Format(this.simpleFormatter);
string result = this.quotesParser.Parse(input).Format(CreateStubContext(), this.simpleFormatter);
return result;
}
}
private static BBCodes.IPostParsingContext CreateStubContext() {
return new DelegatePostParsingContext(user => {});
}
public static string UBBToIntermediate(BBCodes.IPostParsingContext context, string UBB) {
return BBParserGateway.instance.Parse(context, UBB);
}
public static string UBBToIntermediate(string UBB) {
//return HttpUtility.HtmlEncode(UBB).Replace(Util.EOL, "<br/>" + Util.EOL);
return BBParserGateway.instance.Parse(UBB);
return UBBToIntermediate(CreateStubContext(), UBB);
}
public static string ShallerToUBB(string shaller) {

@ -305,7 +305,8 @@ namespace FLocal.Common.URL {
case "posts":
return new users.user.Posts(requestParts[2], GetRemainder(requestParts, 4));
case "replies":
return new users.user.Replies(requestParts[2], GetRemainder(requestParts, 4));
case "mentions":
return new users.user.Mentions(requestParts[2], GetRemainder(requestParts, 4));
case "threads":
return new users.user.Threads(requestParts[2], GetRemainder(requestParts, 4));
default:

@ -4,14 +4,14 @@ using System.Linq;
using System.Text;
namespace FLocal.Common.URL.users.user {
public class Replies : Abstract {
public class Mentions : Abstract {
public Replies(string userId, string remainder) : base(userId, remainder) {
public Mentions(string userId, string remainder) : base(userId, remainder) {
}
protected override string _canonical {
get {
return "/Users/User/" + this.user.id + "/Replies/";
return "/Users/User/" + this.user.id + "/Mentions/";
}
}
}

@ -41,6 +41,7 @@ namespace FLocal.Common.actions {
dataobjects.PunishmentLayerChange.TableSpec.TABLE,
dataobjects.Restriction.TableSpec.TABLE,
dataobjects.TexImage.TableSpec.TABLE,
dataobjects.Mention.TableSpec.TABLE,
dataobjects.Session.TableSpec.TABLE,
}
);

@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Web.Core;
using Web.Core.DB;
using Web.Core.DB.conditions;
using FLocal.Common.actions;
namespace FLocal.Common.dataobjects {
public class Mention : SqlObject<Mention> {
public class TableSpec : ISqlObjectTableSpec {
public const string TABLE = "Mentions";
public const string FIELD_ID = "Id";
public const string FIELD_MENTIONEDUSERID = "MentionedUserId";
public const string FIELD_POSTID = "PostId";
public const string FIELD_DATE = "Date";
public static readonly TableSpec instance = new TableSpec();
public string name { get { return TABLE; } }
public string idName { get { return FIELD_ID; } }
public void refreshSqlObject(int id) { Refresh(id); }
}
protected override ISqlObjectTableSpec table { get { return TableSpec.instance; } }
private int _mentionedUserId;
public int mentionedUserId {
get {
this.LoadIfNotLoaded();
return this._mentionedUserId;
}
}
public User mentionedUser {
get {
return User.LoadById(this.mentionedUserId);
}
}
private int _postId;
public int postId {
get {
this.LoadIfNotLoaded();
return this._postId;
}
}
public Post post {
get {
return Post.LoadById(this.postId);
}
}
private DateTime _date;
public DateTime date {
get {
this.LoadIfNotLoaded();
return this._date;
}
}
protected override void doFromHash(Dictionary<string, string> data) {
this._mentionedUserId = int.Parse(data[TableSpec.FIELD_MENTIONEDUSERID]);
this._postId = int.Parse(data[TableSpec.FIELD_POSTID]);
this._date = Util.ParseDateTimeFromTimestamp(data[TableSpec.FIELD_DATE]).Value;
}
}
}

@ -8,6 +8,7 @@ using Web.Core.DB;
using Web.Core.DB.conditions;
using FLocal.Common;
using FLocal.Common.actions;
using FLocal.Common.helpers;
namespace FLocal.Common.dataobjects {
public class Post : SqlObject<Post> {
@ -330,12 +331,24 @@ namespace FLocal.Common.dataobjects {
actualLayer = this.layer;
}
lock(this.Edit_locker) {
DateTime date = DateTime.Now;
HashSet<int> newMentionedUsersIds = new HashSet<int>();
if(parentPost != null && parentPost.poster.id != poster.id) {
newMentionedUsersIds.Add(parentPost.poster.id);
}
string newBodyIntermediate = UBBParser.UBBToIntermediate(
new DelegatePostParsingContext(mentionedUser => newMentionedUsersIds.Add(mentionedUser.id)),
newBody
);
List<AbstractChange> changes = new List<AbstractChange> {
new InsertChange(
Revision.TableSpec.instance,
new Dictionary<string, AbstractFieldValue> {
{ Revision.TableSpec.FIELD_POSTID, new ScalarFieldValue(this.id.ToString()) },
{ Revision.TableSpec.FIELD_CHANGEDATE, new ScalarFieldValue(DateTime.Now.ToUTCString()) },
{ Revision.TableSpec.FIELD_CHANGEDATE, new ScalarFieldValue(date.ToUTCString()) },
{ Revision.TableSpec.FIELD_TITLE, new ScalarFieldValue(newTitle) },
{ Revision.TableSpec.FIELD_BODY, new ScalarFieldValue(newBody) },
{ Revision.TableSpec.FIELD_NUMBER, new ScalarFieldValue((this.revision + 1).ToString()) },
@ -345,8 +358,8 @@ namespace FLocal.Common.dataobjects {
TableSpec.instance,
new Dictionary<string, AbstractFieldValue> {
{ TableSpec.FIELD_TITLE, new ScalarFieldValue(newTitle) },
{ TableSpec.FIELD_BODY, new ScalarFieldValue(UBBParser.UBBToIntermediate(newBody)) },
{ TableSpec.FIELD_LASTCHANGEDATE, new ScalarFieldValue(DateTime.Now.ToUTCString()) },
{ TableSpec.FIELD_BODY, new ScalarFieldValue(newBodyIntermediate) },
{ TableSpec.FIELD_LASTCHANGEDATE, new ScalarFieldValue(date.ToUTCString()) },
{ TableSpec.FIELD_REVISION, new IncrementFieldValue() },
{ TableSpec.FIELD_LAYERID, new ScalarFieldValue(actualLayer.id.ToString()) },
},
@ -364,10 +377,37 @@ namespace FLocal.Common.dataobjects {
)
);
}
foreach(var mentionedUserId in newMentionedUsersIds.Except(this.mentionedUsersIds)) {
changes.Add(
new InsertChange(
Mention.TableSpec.instance,
new Dictionary<string, AbstractFieldValue> {
{ Mention.TableSpec.FIELD_MENTIONEDUSERID, new ScalarFieldValue(mentionedUserId.ToString()) },
{ Mention.TableSpec.FIELD_POSTID, new ScalarFieldValue(this.id.ToString()) },
{ Mention.TableSpec.FIELD_DATE, new ScalarFieldValue(date.ToUTCString()) },
}
)
);
}
ChangeSetUtil.ApplyChanges(changes.ToArray());
}
}
private IEnumerable<int> mentionedUsersIds {
get {
return from stringId in Config.instance.mainConnection.LoadIdsByConditions(
Mention.TableSpec.instance,
new ComparisonCondition(
Mention.TableSpec.instance.getColumnSpec(Mention.TableSpec.FIELD_POSTID),
ComparisonType.EQUAL,
this.id.ToString()
),
Diapasone.unlimited,
Mention.TableSpec.instance.getColumnSpec(Mention.TableSpec.FIELD_MENTIONEDUSERID)
) select int.Parse(stringId);
}
}
private IEnumerable<Post> subPosts {
get {
return Post.LoadByIds(

@ -7,6 +7,7 @@ using Web.Core;
using Web.Core.DB;
using Web.Core.DB.conditions;
using FLocal.Common.actions;
using FLocal.Common.helpers;
namespace FLocal.Common.dataobjects {
public class Thread : SqlObject<Thread> {
@ -411,12 +412,19 @@ namespace FLocal.Common.dataobjects {
string parentPostId = null;
if(parentPost != null) parentPostId = parentPost.id.ToString();
bool isNewThread = (parentPost == null);
HashSet<int> mentionedUsersIds = new HashSet<int>();
if(parentPost != null && parentPost.poster.id != poster.id) {
mentionedUsersIds.Add(parentPost.poster.id);
}
string bodyIntermediate;
if(forcedPostId.HasValue) {
//dirty hack
bodyIntermediate = body;
} else {
bodyIntermediate = UBBParser.UBBToIntermediate(body);
bodyIntermediate = UBBParser.UBBToIntermediate(
new DelegatePostParsingContext(mentionedUser => mentionedUsersIds.Add(mentionedUser.id)),
body
);
}
var postInsertData = new Dictionary<string,AbstractFieldValue> {
{ Post.TableSpec.FIELD_THREADID, new ScalarFieldValue(threadId.ToString()) },
@ -484,6 +492,18 @@ namespace FLocal.Common.dataobjects {
changes.Add(threadUpdate);
changes.Add(userUpdate);
foreach(var mentionedUserId in mentionedUsersIds) {
changes.Add(
new InsertChange(
Mention.TableSpec.instance,
new Dictionary<string, AbstractFieldValue> {
{ Mention.TableSpec.FIELD_MENTIONEDUSERID, new ScalarFieldValue(mentionedUserId.ToString()) },
{ Mention.TableSpec.FIELD_POSTID, new ReferenceFieldValue(postInsert) },
{ Mention.TableSpec.FIELD_DATE, new ScalarFieldValue(date.ToUTCString()) },
}
)
);
}
Dictionary<string, AbstractFieldValue> boardData = new Dictionary<string,AbstractFieldValue> {
{ Board.TableSpec.FIELD_TOTALPOSTS, new IncrementFieldValue() },

@ -253,38 +253,18 @@ namespace FLocal.Common.dataobjects {
);
}
public IEnumerable<Post> getReplies(Diapasone diapasone, bool isAscending) {
JoinSpec parent = new JoinSpec(
Post.TableSpec.instance.getColumnSpec(Post.TableSpec.FIELD_PARENTPOSTID),
Post.TableSpec.instance,
"parent"
);
public IEnumerable<Post> getMentions(Diapasone diapasone, bool isAscending) {
return Post.LoadByIds(
from stringId in Config.instance.mainConnection.LoadIdsByConditions(
Post.TableSpec.instance,
new ComplexCondition(
ConditionsJoinType.AND,
Mention.TableSpec.instance,
new ComparisonCondition(
parent.additionalTable.getColumnSpec(Post.TableSpec.FIELD_POSTERID),
Mention.TableSpec.instance.getColumnSpec(Mention.TableSpec.FIELD_MENTIONEDUSERID),
ComparisonType.EQUAL,
this.id.ToString()
),
new ComparisonCondition(
Post.TableSpec.instance.getColumnSpec(Post.TableSpec.FIELD_POSTERID),
ComparisonType.NOTEQUAL,
this.id.ToString()
)
),
diapasone,
new JoinSpec[] {
parent
},
new SortSpec[] {
new SortSpec(
Post.TableSpec.instance.getIdSpec(),
isAscending
),
}
Mention.TableSpec.instance.getColumnSpec(Mention.TableSpec.FIELD_POSTID),
new SortSpec(Mention.TableSpec.instance.getIdSpec(), isAscending)
) select int.Parse(stringId)
);
}

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FLocal.Common.dataobjects;
namespace FLocal.Common.helpers {
class DelegatePostParsingContext : BBCodes.IPostParsingContext {
private readonly Action<User> onUserMention;
public DelegatePostParsingContext(Action<User> onUserMention) {
this.onUserMention = onUserMention;
}
#region IPostParsingContext Members
public void OnUserMention(User user) {
this.onUserMention(user);
}
#endregion
}
}

@ -51,7 +51,7 @@ namespace FLocal.IISHandler {
{ typeof(URL.users.user.Info), CreateHandler<URL.users.user.Info, handlers.response.UserInfoHandler> },
{ typeof(URL.users.user.PollsParticipated), CreateHandler<URL.users.user.PollsParticipated, handlers.response.UserPollsParticipatedHandler> },
{ typeof(URL.users.user.Posts), CreateHandler<URL.users.user.Posts, handlers.response.UserPostsHandler> },
{ typeof(URL.users.user.Replies), CreateHandler<URL.users.user.Replies, handlers.response.UserRepliesHandler> },
{ typeof(URL.users.user.Mentions), CreateHandler<URL.users.user.Mentions, handlers.response.UserRepliesHandler> },
{ typeof(URL.users.user.Threads), CreateHandler<URL.users.user.Threads, handlers.response.UserThreadsHandler> },
};

@ -12,7 +12,7 @@ using Web.Core.DB.conditions;
namespace FLocal.IISHandler.handlers.response {
class UserRepliesHandler : AbstractUserGetHandler<FLocal.Common.URL.users.user.Replies> {
class UserRepliesHandler : AbstractUserGetHandler<FLocal.Common.URL.users.user.Mentions> {
override protected string templateName {
get {
@ -22,7 +22,7 @@ namespace FLocal.IISHandler.handlers.response {
override protected IEnumerable<XElement> getUserSpecificData(WebContext context, User user) {
PageOuter pageOuter = PageOuter.createFromUrl(this.url, context.userSettings.postsPerPage);
IEnumerable<Post> posts = user.getReplies(pageOuter, pageOuter.descendingDirection);
IEnumerable<Post> posts = user.getMentions(pageOuter, pageOuter.descendingDirection);
return new XElement[] {
user.exportToXmlForViewing(context),

@ -69,6 +69,9 @@
<EmbeddedResource Include="Resources\Patch_00000_cleaninstall.xml" />
<EmbeddedResource Include="Resources\Patch_00001_threadsindexes.xml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources\Patch_00002_mentions.xml" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="utf-8" ?>
<patch xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="..\..\Patcher\Resources\IPatch.xsd">
<version>
<number>2</number>
<author>mentions</author>
</version>
<looseCommandSet>
<persistentCommand>
<createTable>
<table>Mentions</table>
<primaryKey>
<column>Id</column>
<type>serial</type>
<isNotNull/>
</primaryKey>
<column>
<column>MentionedUserId</column>
<type>int</type>
<isNotNull/>
</column>
<column>
<column>PostId</column>
<type>integer</type>
<isNotNull/>
</column>
<column>
<column>Date</column>
<type>timestamp with time zone</type>
</column>
</createTable>
</persistentCommand>
<persistentCommand>
<createConstraint>
<table>Mentions</table>
<constraintName>Mentions_MentionedUserId_PostId_key</constraintName>
<unique>
<column>MentionedUserId</column>
<column>PostId</column>
</unique>
</createConstraint>
</persistentCommand>
<persistentCommand>
<createConstraint>
<table>Mentions</table>
<constraintName>Mentions_MentionedUserId_fkey</constraintName>
<foreignKey>
<column>MentionedUserId</column>
<referencedTable>Users</referencedTable>
<onUpdate>restrict</onUpdate>
<onDelete>restrict</onDelete>
</foreignKey>
</createConstraint>
</persistentCommand>
<persistentCommand>
<createConstraint>
<table>Mentions</table>
<constraintName>Mentions_PostId_fkey</constraintName>
<foreignKey>
<column>PostId</column>
<referencedTable>Posts</referencedTable>
<onUpdate>restrict</onUpdate>
<onDelete>restrict</onDelete>
</foreignKey>
</createConstraint>
</persistentCommand>
<command>
<sql>
<installSql>
<query>
INSERT INTO
"Mentions"("MentionedUserId", "PostId", "Date")
(
SELECT
parent."PosterId" "MentionedUserId",
post."Id" "PostId",
post."LastChangeDate" "Date"
FROM "Posts" post
JOIN "Posts" parent
ON post."ParentPostId" = parent."Id"
WHERE
post."PosterId" != parent."PosterId"
ORDER BY
post."Id" asc
)
</query>
</installSql>
<uninstallSql/>
</sql>
</command>
</looseCommandSet>
</patch>

@ -95,7 +95,7 @@ namespace MySQLConnector {
}
}
private List<string> _LoadIdsByConditions(DbCommand command, ITableSpec table, Web.Core.DB.conditions.AbstractCondition conditions, Diapasone diapasone, JoinSpec[] joins, SortSpec[] sorts, bool allowHugeLists) {
private List<string> _LoadIdsByConditions(DbCommand command, ITableSpec table, Web.Core.DB.conditions.AbstractCondition conditions, Diapasone diapasone, JoinSpec[] joins, SortSpec[] sorts, ColumnSpec idSpec, bool allowHugeLists) {
using(var logger = this.CreateCommandExecutionLogger()) {
command.CommandType = System.Data.CommandType.Text;
@ -164,7 +164,7 @@ namespace MySQLConnector {
if(diapasone.count >= 0) {
queryLimits = "LIMIT " + diapasone.count + " OFFSET " + diapasone.start;
}
command.CommandText = logger.commandText = "SELECT " + table.getIdSpec().compile(this.traits) + " " + queryMain + " " + querySorts + " " + queryLimits;
command.CommandText = logger.commandText = "SELECT " + idSpec.compile(this.traits) + " " + queryMain + " " + querySorts + " " + queryLimits;
List<string> result = new List<string>();
using(DbDataReader reader = command.ExecuteReader()) {
@ -177,10 +177,10 @@ namespace MySQLConnector {
}
}
public List<string> LoadIdsByConditions(ITableSpec table, Web.Core.DB.conditions.AbstractCondition conditions, Diapasone diapasone, JoinSpec[] joins, SortSpec[] sorts, bool allowHugeLists) {
public List<string> LoadIdsByConditions(ITableSpec table, Web.Core.DB.conditions.AbstractCondition conditions, Diapasone diapasone, JoinSpec[] joins, SortSpec[] sorts, ColumnSpec idSpec, bool allowHugeLists) {
using(DbConnection connection = this.createConnection()) {
using(DbCommand command = connection.CreateCommand()) {
return this._LoadIdsByConditions(command, table, conditions, diapasone, joins, sorts, allowHugeLists);
return this._LoadIdsByConditions(command, table, conditions, diapasone, joins, sorts, idSpec, allowHugeLists);
}
}
}
@ -274,7 +274,7 @@ namespace MySQLConnector {
lock(transaction) {
using(DbCommand command = transaction.sqlconnection.CreateCommand()) {
command.Transaction = transaction.sqltransaction;
return this._LoadIdsByConditions(command, table, conditions, diapasone, joins, sorts, allowHugeLists);
return this._LoadIdsByConditions(command, table, conditions, diapasone, joins, sorts, table.getIdSpec(), allowHugeLists);
}
}
}

@ -284,3 +284,7 @@ a.external {
margin-left:0.5em;
margin-right:0.5em;
}
.userreference:before {
content: "@";
}

@ -58,7 +58,7 @@
<br />
<a>
<xsl:if test="session/user">
<xsl:attribute name="href">/Users/User/<xsl:value-of select="session/user/id"/>/Replies/</xsl:attribute>
<xsl:attribute name="href">/Users/User/<xsl:value-of select="session/user/id"/>/Mentions/</xsl:attribute>
</xsl:if>
<xsl:text>Последние ответы на мои сообщения</xsl:text>
</a>

@ -192,8 +192,8 @@
</a>
<xsl:text> | </xsl:text>
<a>
<xsl:attribute name="href">/Users/User/<xsl:value-of select="user/id"/>/Replies/</xsl:attribute>
<xsl:text>Îòâåòû</xsl:text>
<xsl:attribute name="href">/Users/User/<xsl:value-of select="user/id"/>/Mentions/</xsl:attribute>
<xsl:text>Îòêëèêè</xsl:text>
</a>
<xsl:text> | </xsl:text>
<a>

@ -209,8 +209,8 @@
</a>
<xsl:text> | </xsl:text>
<a>
<xsl:attribute name="href">/Users/User/<xsl:value-of select="user/id"/>/Replies/</xsl:attribute>
<xsl:text>Îòâåòû</xsl:text>
<xsl:attribute name="href">/Users/User/<xsl:value-of select="user/id"/>/Mentions/</xsl:attribute>
<xsl:text>Îòêëèêè</xsl:text>
</a>
<xsl:text> | </xsl:text>
<a>

@ -53,7 +53,7 @@
<xsl:text>. </xsl:text>
<a>
<xsl:if test="session/user">
<xsl:attribute name="href">/Users/User/<xsl:value-of select="session/user/id"/>/Replies/</xsl:attribute>
<xsl:attribute name="href">/Users/User/<xsl:value-of select="session/user/id"/>/Mentions/</xsl:attribute>
</xsl:if>
<xsl:call-template name="Messages_LastReplies"/>
</a>

@ -17,8 +17,8 @@
<xsl:with-param name="text">Ñîîáùåíèÿ</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="headerLink">
<xsl:with-param name="url">/Users/User/<xsl:value-of select="session/user/id"/>/Replies/</xsl:with-param>
<xsl:with-param name="text">Îòâåòû</xsl:with-param>
<xsl:with-param name="url">/Users/User/<xsl:value-of select="session/user/id"/>/Mentions/</xsl:with-param>
<xsl:with-param name="text">Îòêëèêè</xsl:with-param>
<xsl:with-param name="isDisabled">
<xsl:if test="not(session/sessionKey)">true</xsl:if>
</xsl:with-param>

@ -17,8 +17,8 @@
<xsl:with-param name="text">Ñîîáùåíèÿ</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="headerLink">
<xsl:with-param name="url"><xsl:value-of select="$baseLink"/>Replies/</xsl:with-param>
<xsl:with-param name="text">Îòâåòû</xsl:with-param>
<xsl:with-param name="url"><xsl:value-of select="$baseLink"/>Mentions/</xsl:with-param>
<xsl:with-param name="text">Îòêëèêè</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="headerLink">
<xsl:with-param name="url"><xsl:value-of select="$baseLink"/>PollsParticipated/</xsl:with-param>

@ -22,14 +22,14 @@ Imports System.Xml.Serialization
''' </summary>
<Serializable()> _
<XmlRoot(ElementName:=STR_BBCodeConfigurationXmlElement, [Namespace]:=STR_BBCodeSchemaNamespace)> _
Public NotInheritable Class BBCodeConfiguration
Public NotInheritable Class BBCodeConfiguration(Of TContext As Class)
Implements IXmlSerializable
Private Shared ReadOnly __CurrentVersion As New System.Version(1, 0)
Private __Version As System.Version
Private __Dictionary As BBCodeElementDictionary
Private __ElementTypes As BBCodeElementTypeDictionary
Private __ElementTypes As BBCodeElementTypeDictionary(Of TContext)
''' <summary>Initializes an instance of the <see cref="BBCodeConfiguration" /> class.
''' This is the default constructor for this class.</summary>
@ -69,10 +69,10 @@ Public NotInheritable Class BBCodeConfiguration
''' Gets the factory configuration.
''' </summary>
<XmlArrayItem()> _
Public ReadOnly Property ElementTypes() As BBCodeElementTypeDictionary
Public ReadOnly Property ElementTypes() As BBCodeElementTypeDictionary(Of TContext)
Get
If (__ElementTypes Is Nothing) Then
__ElementTypes = New BBCodeElementTypeDictionary()
__ElementTypes = New BBCodeElementTypeDictionary(Of TContext)()
End If
Return __ElementTypes
End Get
@ -109,7 +109,7 @@ Public NotInheritable Class BBCodeConfiguration
reader.Read()
Dim dictionarySerializer = New XmlSerializer(GetType(BBCodeElementDictionary))
Dim typesSerializer = New XmlSerializer(GetType(BBCodeElementTypeDictionary))
Dim typesSerializer = New XmlSerializer(GetType(BBCodeElementTypeDictionary(Of TContext)))
__ElementTypes = Nothing
__Dictionary = Nothing
@ -133,7 +133,7 @@ Public NotInheritable Class BBCodeConfiguration
Public Sub WriteXml(ByVal writer As System.Xml.XmlWriter) Implements System.Xml.Serialization.IXmlSerializable.WriteXml
Dim dictionarySerializer = New XmlSerializer(GetType(BBCodeElementDictionary))
Dim typesSerializer = New XmlSerializer(GetType(BBCodeElementTypeDictionary))
Dim typesSerializer = New XmlSerializer(GetType(BBCodeElementTypeDictionary(Of TContext)))
If (ElementTypes.Count > 0) Then
typesSerializer.Serialize(writer, ElementTypes)

@ -18,22 +18,22 @@
''' <summary>
''' Represents a document writen in BBCode.
''' </summary>
Public NotInheritable Class BBCodeDocument
Public NotInheritable Class BBCodeDocument(Of TContext As Class)
Private __Text As String
Private __Parser As BBCodeParser
Private __Nodes As BBCodeNodeCollection
Private __Parser As BBCodeParser(Of TContext)
Private __Nodes As BBCodeNodeCollection(Of TContext)
''' <summary>Initializes an instance of the <see cref="BBCodeDocument" /> class.</summary>
''' <param name="parser">The <see cref="BBCodeParser"/> that created this instance.</param>
Friend Sub New(ByVal parser As BBCodeParser)
Friend Sub New(ByVal parser As BBCodeParser(Of TContext))
__Parser = parser
End Sub
''' <summary>
''' Gets the <see cref="BBCodeParser"/> that is responsible for this <see cref="BBCodeDocument"/>.
''' </summary>
Friend ReadOnly Property Parser() As BBCodeParser
Friend ReadOnly Property Parser() As BBCodeParser(Of TContext)
Get
Return __Parser
End Get
@ -57,10 +57,10 @@ Public NotInheritable Class BBCodeDocument
''' Gets the <see cref="BBCodeNodeCollection"/> generated ba the BBCode text.
''' </summary>
''' <value>A <see cref="BBCodeNodeCollection"/> that represents the parsed text of the document.</value>
Public ReadOnly Property Nodes() As BBCodeNodeCollection
Public ReadOnly Property Nodes() As BBCodeNodeCollection(Of TContext)
Get
If (__Nodes Is Nothing) Then
__Nodes = New BBCodeNodeCollection()
__Nodes = New BBCodeNodeCollection(Of TContext)()
End If
Return __Nodes
End Get
@ -70,8 +70,8 @@ Public NotInheritable Class BBCodeDocument
''' Returns the formatted text.
''' </summary>
''' <returns>The formatted text.</returns>
Public Function Format() As String
Return Format(New BBCodeHtmlFormatter())
Public Function Format(ByVal context As TContext) As String
Return Format(context, New BBCodeHtmlFormatter(Of TContext)())
End Function
''' <summary>
@ -79,10 +79,10 @@ Public NotInheritable Class BBCodeDocument
''' </summary>
''' <param name="formatter">An object that implements the <see cref="ITextFormatter"/> interface.</param>
''' <returns>The formatted text.</returns>
Public Function Format(ByVal formatter As ITextFormatter) As String
Public Function Format(ByVal context As TContext, ByVal formatter As ITextFormatter(Of TContext)) As String
Dim sb As New Text.StringBuilder()
For Each n In Nodes
sb.Append(n.Format(formatter))
sb.Append(n.Format(context, formatter))
Next
Return sb.ToString()
End Function

@ -21,11 +21,11 @@ Imports System.Text.RegularExpressions
''' <summary>
''' Represents an BBCode element.
''' </summary>
Public Class BBCodeElement
Inherits BBCodeNode
Public Class BBCodeElement(Of TContext As Class)
Inherits BBCodeNode(Of TContext)
Private __Name As String
Private __Nodes As BBCodeNodeCollection
Private __Nodes As BBCodeNodeCollection(Of TContext)
Private __Attributes As BBCodeAttributeDictionary
Private __ReplacementFormat As String = String.Empty
Private __RequireClosingTag As TriState = TriState.UseDefault
@ -46,7 +46,7 @@ Public Class BBCodeElement
''' <summary>Initializes an instance of the <see cref="BBCodeElement" /> class.</summary>
''' <param name="parser">The parser used to create this element.</param>
Friend Sub New(ByVal parser As BBCodeParser)
Friend Sub New(ByVal parser As BBCodeParser(Of TContext))
MyBase.New(parser)
End Sub
@ -123,10 +123,10 @@ Public Class BBCodeElement
''' <summary>
''' Gets the list of sub nodes.
''' </summary>
Public ReadOnly Property Nodes() As BBCodeNodeCollection
Public ReadOnly Property Nodes() As BBCodeNodeCollection(Of TContext)
Get
If (__Nodes Is Nothing) Then
__Nodes = New BBCodeNodeCollection(Me)
__Nodes = New BBCodeNodeCollection(Of TContext)(Me)
End If
Return __Nodes
End Get
@ -135,15 +135,15 @@ Public Class BBCodeElement
''' <summary>Transforms this instance of <see cref="BBCodeElement" /> into its desired text representation.</summary>
''' <param name="formatter">An object that implements the <see cref="ITextFormatter" /> interface.</param>
''' <returns>The text formatted by the <see cref="ITextFormatter" />.</returns>
Public Overrides Function Format(ByVal formatter As ITextFormatter) As String
Public Overrides Function Format(ByVal context As TContext, ByVal formatter As ITextFormatter(Of TContext)) As String
IsValueFormatted = False
Dim sb As New Text.StringBuilder(Me.ReplacementFormat)
Dim attribs = __RxAttribute.Matches(Me.ReplacementFormat)
For Each attrib As Match In attribs
sb.Replace(attrib.Value, GetAttribute(attrib.Groups("name").Value, formatter))
sb.Replace(attrib.Value, GetAttribute(attrib.Groups("name").Value, context, formatter))
Next
If Not IsValueFormatted Then
sb.Append(GetAttribute("value", formatter))
sb.Append(GetAttribute("value", context, formatter))
End If
Return sb.ToString()
End Function
@ -153,7 +153,7 @@ Public Class BBCodeElement
Public NotOverridable Overrides Property InnerBBCode() As String
Get
Dim sb As New System.Text.StringBuilder()
For Each n As BBCodeNode In Nodes
For Each n As BBCodeNode(Of TContext) In Nodes
sb.Append(n.OuterBBCode)
Next
Return sb.ToString()
@ -215,7 +215,7 @@ Public Class BBCodeElement
'*
'* Only append a BBCodeText element if the value is not empty
'*
Me.Nodes.Add(New BBCodeText(value))
Me.Nodes.Add(New BBCodeText(Of TContext)(value))
End If
End Set
End Property
@ -241,14 +241,14 @@ Public Class BBCodeElement
End Set
End Property
Private Function GetAttribute(ByVal name As String, ByVal formatter As ITextFormatter) As String
Private Function GetAttribute(ByVal name As String, ByVal context As TContext, ByVal formatter As ITextFormatter(Of TContext)) As String
Dim attribs = name.ToUpperInvariant().Split("|".ToCharArray(), StringSplitOptions.RemoveEmptyEntries)
For Each attrib In attribs
If (String.CompareOrdinal(attrib, "VALUE") = 0) Then
IsValueFormatted = True
Dim sb As New Text.StringBuilder()
For Each node In Me.Nodes
sb.Append(node.Format(formatter))
sb.Append(node.Format(context, formatter))
Next
Return sb.ToString()
ElseIf (Me.Attributes.ContainsKey(attrib)) Then

@ -18,20 +18,20 @@
''' <summary>
''' Creates instances of <see cref="BBCodeElement"/>.
''' </summary>
Friend NotInheritable Class BBCodeElementFactory
Friend NotInheritable Class BBCodeElementFactory(Of TContext As Class)
Private __Parser As BBCodeParser
Private __Parser As BBCodeParser(Of TContext)
''' <summary>Initializes an instance of the <see cref="BBCodeElementFactory" /> class.</summary>
''' <param name="parser">The <see cref="BBCodeParser"/> that will utilize the new instance of the <see cref="BBCodeElementFactory"/>.</param>
Friend Sub New(ByVal parser As BBCodeParser)
Friend Sub New(ByVal parser As BBCodeParser(Of TContext))
__Parser = parser
End Sub
''' <summary>
''' Gets the <see cref="BBCodeParser"/> that utilizes this instance of the <see cref="BBCodeElementFactory"/>.
''' </summary>
Public ReadOnly Property Parser() As BBCodeParser
Public ReadOnly Property Parser() As BBCodeParser(Of TContext)
Get
Return __Parser
End Get
@ -43,9 +43,9 @@ Friend NotInheritable Class BBCodeElementFactory
''' <param name="name">The name of the element.</param>
''' <param name="attributes">The attributes of the element.</param>
''' <returns>A new <see cref="BBCodeElement"/>.</returns>
Public Function CreateElement(ByVal name As String, ByVal attributes As BBCodeAttributeDictionary) As BBCodeElement
Public Function CreateElement(ByVal name As String, ByVal attributes As BBCodeAttributeDictionary) As BBCodeElement(Of TContext)
Dim el As BBCodeElement
Dim el As BBCodeElement(Of TContext)
'*
'* Check if we have a different type to create
@ -59,8 +59,8 @@ Friend NotInheritable Class BBCodeElementFactory
'*
'* Check if the type IS BBCodeElement
'*
If (type.Equals(GetType(BBCodeElement))) Then
el = New BBCodeElement()
If (type.Equals(GetType(BBCodeElement(Of TContext)))) Then
el = New BBCodeElement(Of TContext)()
Else
'*
'* Gets the default constructor
@ -73,13 +73,13 @@ Friend NotInheritable Class BBCodeElementFactory
'*
'* Creates the new element.
'*
el = TryCast(ctor.Invoke(New Object() {}), BBCodeElement)
el = TryCast(ctor.Invoke(New Object() {}), BBCodeElement(Of TContext))
If (el Is Nothing) Then
Throw New InvalidOperationException("The type " & type.FullName & " could not be assingned to BBCodeElement.")
End If
End If
Else
el = New BBCodeElement()
el = New BBCodeElement(Of TContext)()
End If
'*

@ -24,7 +24,7 @@ Imports System.Diagnostics.CodeAnalysis
''' </summary>
<Serializable()> _
<XmlRoot(ElementName:=STR_BBCodeElementTypesXmlElement, [Namespace]:=STR_BBCodeSchemaNamespace)> _
Public NotInheritable Class BBCodeElementTypeDictionary
Public NotInheritable Class BBCodeElementTypeDictionary(Of TContext As Class)
Inherits Dictionary(Of String, BBCodeElementTypeDefinition)
Implements IXmlSerializable
@ -49,7 +49,7 @@ Public NotInheritable Class BBCodeElementTypeDictionary
''' <param name="value">The value of the element to add.</param>
Private Shadows Sub Add(ByVal tagName As String, ByVal value As BBCodeElementTypeDefinition)
ValidateTagName(tagName)
ValidateBBCodeElementType(value.Type)
ValidateBBCodeElementType(Of TContext)(value.Type)
MyBase.Add(tagName.ToUpperInvariant(), value)
End Sub
@ -89,7 +89,7 @@ Public NotInheritable Class BBCodeElementTypeDictionary
Boolean.TryParse(reader.GetAttribute("requireClosingTag"), .RequireClosingTag)
.Type = System.Type.GetType(reader.GetAttribute("type"))
End With
If (definition.Type.IsSubclassOf(GetType(BBCodeElement))) Then
If (definition.Type.IsSubclassOf(GetType(BBCodeElement(Of TContext)))) Then
Me.Add(definition.TagName, definition)
End If
Loop

@ -18,15 +18,15 @@
''' <summary>
''' Represnts an HTML generator for the <see cref="BBCodeParser"/>.
''' </summary>
Public NotInheritable Class BBCodeHtmlFormatter
Implements ITextFormatter
Public NotInheritable Class BBCodeHtmlFormatter(Of TContext As Class)
Implements ITextFormatter(Of TContext)
''' <summary>
''' Generates the desired text from the specified source.
''' </summary>
''' <param name="source">The source to generate the text.</param>
''' <returns>The text generated by the source.</returns>
Public Function GenerateText(ByVal source As String) As String Implements ITextFormatter.Format
Public Function GenerateText(ByVal context As TContext, ByVal source As String) As String Implements ITextFormatter(Of TContext).Format
Dim sb As New Text.StringBuilder(HtmlEncode(source))
sb.Replace(vbCrLf, vbLf)
sb.Replace(vbCr, String.Empty)

@ -18,10 +18,10 @@
''' <summary>
''' Represents the basic node of an BBCode document.
''' </summary>
Public MustInherit Class BBCodeNode
Public MustInherit Class BBCodeNode(Of TContext As Class)
Private __Parent As BBCodeNode
Private __Parser As BBCodeParser
Private __Parent As BBCodeNode(Of TContext)
Private __Parser As BBCodeParser(Of TContext)
''' <summary>Initializes an instance of the <see cref="BBCodeNode" /> class.
''' This is the default constructor for this class.</summary>
@ -30,14 +30,14 @@ Public MustInherit Class BBCodeNode
''' <summary>Initializes an instance of the <see cref="BBCodeNode" /> class.</summary>
''' <param name="parser">The parser used to create this element.</param>
Protected Sub New(ByVal parser As BBCodeParser)
Protected Sub New(ByVal parser As BBCodeParser(Of TContext))
__Parser = parser
End Sub
''' <summary>
''' Gets the parent node.
''' </summary>
Public ReadOnly Property Parent() As BBCodeNode
Public ReadOnly Property Parent() As BBCodeNode(Of TContext)
Get
Return __Parent
End Get
@ -46,7 +46,7 @@ Public MustInherit Class BBCodeNode
''' <summary>
''' Gets the <see cref="BBCodeParser"/> that create this instance of the <see cref="BBCodeNode"/>.
''' </summary>
Protected Friend ReadOnly Property Parser() As BBCodeParser
Protected Friend ReadOnly Property Parser() As BBCodeParser(Of TContext)
Get
Return __Parser
End Get
@ -57,7 +57,7 @@ Public MustInherit Class BBCodeNode
''' </summary>
''' <param name="formatter">An object that implements the <see cref="ITextFormatter"/> interface.</param>
''' <returns>The text formatted by the <see cref="ITextFormatter"/>.</returns>
Public MustOverride Function Format(ByVal formatter As ITextFormatter) As String
Public MustOverride Function Format(ByVal context As TContext, ByVal formatter As ITextFormatter(Of TContext)) As String
''' <summary>
''' When implemented in a derived class, gets or sets the inner BBCode.
@ -81,7 +81,7 @@ Public MustInherit Class BBCodeNode
''' Sets the <see cref="BBCodeParser"/> of this instance.
''' </summary>
''' <param name="parser">The new parser of this instance.</param>
Friend Sub SetParser(ByVal parser As BBCodeParser)
Friend Sub SetParser(ByVal parser As BBCodeParser(Of TContext))
__Parser = parser
End Sub
@ -89,8 +89,8 @@ Public MustInherit Class BBCodeNode
''' The the parent node of this instance of the <see cref="BBCodeNode"/>.
''' </summary>
''' <param name="parentNode">The parent node.</param>
Protected Friend Sub SetParent(ByVal parentNode As BBCodeNode)
Dim element = TryCast(parentNode, BBCodeElement)
Protected Friend Sub SetParent(ByVal parentNode As BBCodeNode(Of TContext))
Dim element = TryCast(parentNode, BBCodeElement(Of TContext))
If (element Is Nothing) OrElse (String.IsNullOrEmpty(element.Name)) Then
__Parent = Nothing
Else

@ -18,10 +18,10 @@
''' <summary>
''' Represents a collection of <see cref="BBCodeNode"/>.
''' </summary>
Public Class BBCodeNodeCollection
Inherits ObjectModel.Collection(Of BBCodeNode)
Public Class BBCodeNodeCollection(Of TContext As Class)
Inherits ObjectModel.Collection(Of BBCodeNode(Of TContext))
Private __Owner As BBCodeNode
Private __Owner As BBCodeNode(Of TContext)
''' <summary>Initializes an instance of the <see cref="BBCodeNodeCollection" /> class.
''' This is the default constructor for this class.</summary>
@ -31,7 +31,7 @@ Public Class BBCodeNodeCollection
''' <summary>Initializes an instance of the <see cref="BBCodeNodeCollection" /> class.</summary>
''' <param name="owner">The collection owner.</param>
''' <exception cref="ArgumentNullException">The argument <paramref name="owner" /> is <langword name="null" />.</exception>
Friend Sub New(ByVal owner As BBCodeNode)
Friend Sub New(ByVal owner As BBCodeNode(Of TContext))
If (owner Is Nothing) Then
Throw New ArgumentNullException("owner")
End If
@ -41,7 +41,7 @@ Public Class BBCodeNodeCollection
''' <summary>
''' Gets or sets the owner of the collection.
''' </summary>
Friend ReadOnly Property Owner() As BBCodeNode
Friend ReadOnly Property Owner() As BBCodeNode(Of TContext)
Get
Return __Owner
End Get
@ -50,7 +50,7 @@ Public Class BBCodeNodeCollection
''' <summary>Adds an object to the end of the <see cref="BBCodeNodeCollection" />.</summary>
''' <param name="node">The object to be added to the end of the <see cref="BBCodeNodeCollection" />.</param>
''' <exception cref="ArgumentNullException">The argument <paramref name="node" /> is <langword name="null" />.</exception>
Public Shadows Sub Add(ByVal node As BBCodeNode)
Public Shadows Sub Add(ByVal node As BBCodeNode(Of TContext))
If (node Is Nothing) Then
Throw New ArgumentNullException("node")
End If
@ -61,7 +61,7 @@ Public Class BBCodeNodeCollection
''' <summary>Adds the elements of the specified collection to the end of the <see cref="BBCodeNodeCollection" />.</summary>
''' <param name="collection">The collection whose elements should be added to the end of the <see cref="BBCodeNodeCollection" />.</param>
''' <exception cref="ArgumentNullException">The argument <paramref name="collection" /> is <langword name="null" />.</exception>
Public Shadows Sub AddRange(ByVal collection As IEnumerable(Of BBCodeNode))
Public Shadows Sub AddRange(ByVal collection As IEnumerable(Of BBCodeNode(Of TContext)))
If (collection Is Nothing) Then
Throw New ArgumentNullException("collection")
End If
@ -75,7 +75,7 @@ Public Class BBCodeNodeCollection
''' </summary>
''' <param name="index">The zero-based index at which item should be inserted.</param>
''' <param name="node">The object to insert.</param>
Public Shadows Sub Insert(ByVal index As Integer, ByVal node As BBCodeNode)
Public Shadows Sub Insert(ByVal index As Integer, ByVal node As BBCodeNode(Of TContext))
node.SetParent(Me.Owner)
MyBase.Insert(index, node)
End Sub
@ -85,7 +85,7 @@ Public Class BBCodeNodeCollection
''' </summary>
''' <param name="index">The zero-based index at which item should be inserted.</param>
''' <param name="collection">The collection whose elements should be inserted into the <see cref="BBCodeNodeCollection" />.</param>
Public Shadows Sub InsertRange(ByVal index As Integer, ByVal collection As IEnumerable(Of BBCodeNode))
Public Shadows Sub InsertRange(ByVal index As Integer, ByVal collection As IEnumerable(Of BBCodeNode(Of TContext)))
For Each node In collection
node.SetParent(Me.Owner)
Next

@ -21,12 +21,12 @@ Imports System.Diagnostics.CodeAnalysis
''' <summary>
''' The parser of
''' </summary>
Public NotInheritable Class BBCodeParser
Public NotInheritable Class BBCodeParser(Of TContext As Class)
Private __Factory As BBCodeElementFactory
Private __Configuration As BBCodeConfiguration
Private __Factory As BBCodeElementFactory(Of TContext)
Private __Configuration As BBCodeConfiguration(Of TContext)
Private Shared ReadOnly __ConfigSerializer As New System.Xml.Serialization.XmlSerializer(GetType(BBCodeConfiguration))
Private Shared ReadOnly __ConfigSerializer As New System.Xml.Serialization.XmlSerializer(GetType(BBCodeConfiguration(Of TContext)))
Private Shared ReadOnly __Tokenizer As Tokenization.Tokenizer = PrepareTokenizer()
''' <summary>Initializes an instance of the <see cref="BBCodeParser" /> class.
@ -40,7 +40,7 @@ Public NotInheritable Class BBCodeParser
Public ReadOnly Property Dictionary() As BBCodeElementDictionary
Get
If (__Configuration Is Nothing) Then
__Configuration = New BBCodeConfiguration()
__Configuration = New BBCodeConfiguration(Of TContext)()
End If
Return __Configuration.Dictionary
End Get
@ -49,10 +49,10 @@ Public NotInheritable Class BBCodeParser
''' <summary>
''' Gets the dictionary of types created by the parser.
''' </summary>
Public ReadOnly Property ElementTypes() As BBCodeElementTypeDictionary
Public ReadOnly Property ElementTypes() As BBCodeElementTypeDictionary(Of TContext)
Get
If (__Configuration Is Nothing) Then
__Configuration = New BBCodeConfiguration()
__Configuration = New BBCodeConfiguration(Of TContext)()
End If
Return __Configuration.ElementTypes
End Get
@ -134,7 +134,7 @@ Public NotInheritable Class BBCodeParser
''' </summary>
''' <param name="text">The text to be parsed.</param>
''' <returns>A <see cref="BBCodeNodeCollection"/> containing the parsed text.</returns>
Public Function Parse(ByVal text As String) As BBCodeDocument
Public Function Parse(ByVal text As String) As BBCodeDocument(Of TContext)
Using reader As New IO.StringReader(text)
Return Parse(reader)
End Using
@ -145,7 +145,7 @@ Public NotInheritable Class BBCodeParser
''' </summary>
''' <param name="stream">The <see cref="IO.Stream"/> to be parsed.</param>
''' <returns>A <see cref="BBCodeNodeCollection"/> containing the parsed <see cref="IO.Stream"/>.</returns>
Public Function Parse(ByVal stream As IO.Stream) As BBCodeDocument
Public Function Parse(ByVal stream As IO.Stream) As BBCodeDocument(Of TContext)
Return Parse(stream, Text.Encoding.UTF8)
End Function
@ -155,7 +155,7 @@ Public NotInheritable Class BBCodeParser
''' <param name="stream">The <see cref="IO.Stream"/> to be parsed.</param>
''' <param name="encoding">The encoding of the stream.</param>
''' <returns>A <see cref="BBCodeNodeCollection"/> containing the parsed <see cref="IO.Stream"/>.</returns>
Public Function Parse(ByVal stream As IO.Stream, ByVal encoding As Text.Encoding) As BBCodeDocument
Public Function Parse(ByVal stream As IO.Stream, ByVal encoding As Text.Encoding) As BBCodeDocument(Of TContext)
Return Parse(New IO.StreamReader(stream, encoding))
End Function
@ -164,11 +164,11 @@ Public NotInheritable Class BBCodeParser
''' </summary>
''' <param name="reader">The <see cref="IO.TextReader"/> to be parsed.</param>
''' <returns>A <see cref="BBCodeNodeCollection"/> containing the parsed <see cref="IO.TextReader"/>.</returns>
Public Function Parse(ByVal reader As IO.TextReader) As BBCodeDocument
Public Function Parse(ByVal reader As IO.TextReader) As BBCodeDocument(Of TContext)
Dim doc = New BBCodeDocument(Me)
Dim rootElement As New BBCodeElement(Me)
Dim currentElement As BBCodeElement = rootElement
Dim doc = New BBCodeDocument(Of TContext)(Me)
Dim rootElement As New BBCodeElement(Of TContext)(Me)
Dim currentElement As BBCodeElement(Of TContext) = rootElement
Dim tk As Tokenization.Token
Dim sb As New Text.StringBuilder()
@ -195,7 +195,7 @@ Public NotInheritable Class BBCodeParser
'* Add the text node
'*
If (sb.Length > 0) Then
currentElement.Nodes.Add(New BBCodeText(sb.ToString()))
currentElement.Nodes.Add(New BBCodeText(Of TContext)(sb.ToString()))
End If
'*
@ -226,16 +226,16 @@ Public NotInheritable Class BBCodeParser
''' <summary>
''' Gets the <see cref="BBCodeElementFactory"/>.
''' </summary>
Private ReadOnly Property Factory() As BBCodeElementFactory
Private ReadOnly Property Factory() As BBCodeElementFactory(Of TContext)
Get
If (__Factory Is Nothing) Then
__Factory = New BBCodeElementFactory(Me)
__Factory = New BBCodeElementFactory(Of TContext)(Me)
End If
Return __Factory
End Get
End Property
Private Sub ParseElement(ByVal rootElement As BBCodeElement, ByRef currentElement As BBCodeElement, ByVal token As Tokenization.Token, ByVal sb As Text.StringBuilder, ByVal tag As BBCodeTag)
Private Sub ParseElement(ByVal rootElement As BBCodeElement(Of TContext), ByRef currentElement As BBCodeElement(Of TContext), ByVal token As Tokenization.Token, ByVal sb As Text.StringBuilder, ByVal tag As BBCodeTag)
'*
'* Check the token Type
@ -261,13 +261,13 @@ Public NotInheritable Class BBCodeParser
End Sub
Private Sub ParseTag(ByRef currentElement As BBCodeElement, ByVal sb As Text.StringBuilder, ByVal tag As BBCodeTag)
Private Sub ParseTag(ByRef currentElement As BBCodeElement(Of TContext), ByVal sb As Text.StringBuilder, ByVal tag As BBCodeTag)
'*
'* Add the text previous to the current element
'*
If (sb.Length > 0) Then
currentElement.Nodes.Add(New BBCodeText(sb.ToString()))
currentElement.Nodes.Add(New BBCodeText(Of TContext)(sb.ToString()))
sb.Remove(0, sb.Length)
End If
@ -286,7 +286,7 @@ Public NotInheritable Class BBCodeParser
End Sub
Private Shared Sub ParseClosingTag(ByVal rootElement As BBCodeElement, ByRef currentElement As BBCodeElement, ByVal token As Tokenization.Token, ByVal sb As Text.StringBuilder, ByVal tag As BBCodeTag)
Private Shared Sub ParseClosingTag(ByVal rootElement As BBCodeElement(Of TContext), ByRef currentElement As BBCodeElement(Of TContext), ByVal token As Tokenization.Token, ByVal sb As Text.StringBuilder, ByVal tag As BBCodeTag)
'*
'* Check if the closing tag is closing a previously open tag
@ -296,7 +296,7 @@ Public NotInheritable Class BBCodeParser
'* Add the inner text
'*
If (sb.Length > 0) Then
currentElement.Nodes.Add(New BBCodeText(sb.ToString()))
currentElement.Nodes.Add(New BBCodeText(Of TContext)(sb.ToString()))
sb.Remove(0, sb.Length)
End If

@ -18,8 +18,8 @@
''' <summary>
''' Represents a simple text in the BBCode.
''' </summary>
Public NotInheritable Class BBCodeText
Inherits BBCodeNode
Public NotInheritable Class BBCodeText(Of TContext As Class)
Inherits BBCodeNode(Of TContext)
Private __InnerText As String
@ -37,8 +37,8 @@ Public NotInheritable Class BBCodeText
''' <summary>Transforms this instance of <see cref="BBCodeText" /> into its desired text representation.</summary>
''' <param name="formatter">An object that implements the <see cref="ITextFormatter" /> interface.</param>
''' <returns>The text formatted by the <see cref="ITextFormatter" />.</returns>
Public Overrides Function Format(ByVal formatter As ITextFormatter) As String
Return formatter.Format(__InnerText)
Public Overrides Function Format(ByVal context As TContext, ByVal formatter As ITextFormatter(Of TContext)) As String
Return formatter.Format(context, __InnerText)
End Function
''' <summary>Gets or sets the inner BBCode.</summary>

@ -18,13 +18,13 @@
''' <summary>
''' Defines a generic text formatter.
''' </summary>
Public Interface ITextFormatter
Public Interface ITextFormatter(Of TContext As Class)
''' <summary>
''' Formats the specified text.
''' </summary>
''' <param name="source">The text to be formatted.</param>
''' <returns>The formatted text.</returns>
Function Format(ByVal source As String) As String
Function Format(ByVal context As TContext, ByVal source As String) As String
End Interface

@ -68,7 +68,7 @@ Friend Module Utils
''' Validates the specified type to ensure that it is a subclass of <see cref="BBCodeElement"/>.
''' </summary>
''' <param name="value">The <see cref="Type"/> to be validated.</param>
Public Sub ValidateBBCodeElementType(ByVal value As Type)
Public Sub ValidateBBCodeElementType(Of TContext As Class)(ByVal value As Type)
'*
'* Validate is nothing
@ -80,7 +80,7 @@ Friend Module Utils
'*
'* Validates the BBCodeElement itself
'*
Dim bbcodeType = GetType(BBCodeElement)
Dim bbcodeType = GetType(BBCodeElement(Of TContext))
If (value.Equals(bbcodeType)) Then
Exit Sub
End If

@ -3,3 +3,11 @@ Code taken from <http://pjondevelopment.50webs.com/articles/bbcodeParser.html> a
svn r133, git 71e2a7fd3675ddb5f57f9d4c9aecec204b984e6b
<https://github.com/inga-lovinde/FLocal/commit/71e2a7fd3675ddb5f57f9d4c9aecec204b984e6b>
Implemented RequireClosingTag flag for custom-defined elements
git eeae827bf12d943cbc55852c76b773b5554ebb4d
<https://github.com/inga-lovinde/FLocal/commit/eeae827bf12d943cbc55852c76b773b5554ebb4d>
PJonDevelopment refactored to use generic context
git f93fee93ee468b3a950704595988d6d2277d43ad
<https://github.com/inga-lovinde/FLocal/commit/f93fee93ee468b3a950704595988d6d2277d43ad>
PJonDevelopment.BBCode.ITextFormatter refactored to use generic context

@ -9,7 +9,7 @@ namespace Web.Core.DB {
List<Dictionary<string, string>> LoadByIds(ITableSpec table, List<string> ids);
List<string> LoadIdsByConditions(ITableSpec table, AbstractCondition conditions, Diapasone diapasone, JoinSpec[] joins, SortSpec[] sorts, bool allowHugeLists);
List<string> LoadIdsByConditions(ITableSpec table, AbstractCondition conditions, Diapasone diapasone, JoinSpec[] joins, SortSpec[] sorts, ColumnSpec idSpec, bool allowHugeLists);
long GetCountByConditions(ITableSpec table, AbstractCondition conditions, params JoinSpec[] joins);
@ -34,13 +34,17 @@ namespace Web.Core.DB {
public static class IDBConnectionExtensions {
public static List<string> LoadIdsByConditions(this IDBConnection connection, ITableSpec table, AbstractCondition conditions, Diapasone diapasone, JoinSpec[] joins, SortSpec[] sorts) {
return connection.LoadIdsByConditions(table, conditions, diapasone, joins, sorts, false);
return connection.LoadIdsByConditions(table, conditions, diapasone, joins, sorts, table.getIdSpec(), false);
}
public static List<string> LoadIdsByConditions(this IDBConnection connection, ITableSpec table, AbstractCondition conditions, Diapasone diapasone, params JoinSpec[] joins) {
return connection.LoadIdsByConditions(table, conditions, diapasone, joins, new SortSpec[] { new SortSpec(table.getIdSpec(), true) });
}
public static List<string> LoadIdsByConditions(this IDBConnection connection, ITableSpec table, AbstractCondition conditions, Diapasone diapasone, ColumnSpec idSpec, params SortSpec[] sorts) {
return connection.LoadIdsByConditions(table, conditions, diapasone, new JoinSpec[0], sorts, idSpec, false);
}
public static Transaction beginTransaction(this IDBConnection connection) {
return connection.beginTransaction(System.Data.IsolationLevel.ReadCommitted);
}

Loading…
Cancel
Save