From 044f079e28c77ef9cf1f261bc947be98ffe69286 Mon Sep 17 00:00:00 2001 From: Hermes Sbicego Date: Thu, 22 Jun 2017 21:25:39 +0200 Subject: [PATCH] [#7729] Text tokens enhancements (#7730) Fixes #7729 --- .../Orchard.Tokens/Providers/RequestTokens.cs | 2 +- .../Orchard.Tokens/Providers/TextTokens.cs | 100 +++++++++++++++++- 2 files changed, 99 insertions(+), 3 deletions(-) diff --git a/src/Orchard.Web/Modules/Orchard.Tokens/Providers/RequestTokens.cs b/src/Orchard.Web/Modules/Orchard.Tokens/Providers/RequestTokens.cs index 5f472b6d2..2c8971a69 100644 --- a/src/Orchard.Web/Modules/Orchard.Tokens/Providers/RequestTokens.cs +++ b/src/Orchard.Web/Modules/Orchard.Tokens/Providers/RequestTokens.cs @@ -152,7 +152,7 @@ namespace Orchard.Tokens.Providers { chainIndex = token.IndexOf(").") + 1; tokenLength = (tokenPrefix + ":").Length; if (chainIndex == 0) { // ")." has not be found - return new Tuple(token.Substring(tokenLength).Trim(new char[] { '(', ')' }), token.Length.ToString()); + return new Tuple(token.Substring(tokenLength).Trim(new char[] { '(', ')' }), ""); } if (!token.StartsWith((tokenPrefix + ":"), StringComparison.OrdinalIgnoreCase) || chainIndex <= tokenLength) { return null; diff --git a/src/Orchard.Web/Modules/Orchard.Tokens/Providers/TextTokens.cs b/src/Orchard.Web/Modules/Orchard.Tokens/Providers/TextTokens.cs index 825de9053..2d766c31d 100644 --- a/src/Orchard.Web/Modules/Orchard.Tokens/Providers/TextTokens.cs +++ b/src/Orchard.Web/Modules/Orchard.Tokens/Providers/TextTokens.cs @@ -1,11 +1,15 @@ using System; +using System.Linq; using System.Web; using Orchard.Localization; namespace Orchard.Tokens.Providers { public class TextTokens : ITokenProvider { + private static string[] _textChainableTokens; public TextTokens() { T = NullLocalizer.Instance; + _textChainableTokens = new string[] { "Limit", "Format", "TrimEnd", "TrimStart" }; + } public Localizer T { get; set; } @@ -15,6 +19,7 @@ namespace Orchard.Tokens.Providers { .Token("Limit:*", T("Limit:[,]"), T("Limit text to specified length and append an optional ellipsis text.")) .Token("Format:*", T("Format:"), T("Optional format specifier (e.g. foo{0}bar).")) .Token("TrimEnd:*", T("TrimEnd:"), T("Trims the specified characters or number of them from the end of the string.")) + .Token("TrimStart:*", T("TrimStart:"), T("Trims the specified characters or number of them from the beginning of the string.")) .Token("UrlEncode", T("Url Encode"), T("Encodes a URL string."), "Text") .Token("HtmlEncode", T("Html Encode"), T("Encodes an HTML string."), "Text") .Token("JavaScriptEncode", T("JavaScript Encode"), T("Encodes a JavaScript string."), "Text") @@ -32,12 +37,18 @@ namespace Orchard.Tokens.Providers { .Token( token => FilterTokenParam("Limit:", token), (token, t) => Limit(t, token)) + .Chain(FilterChainLimitParam, "Text", (token, t) => Limit(t, token)) // {Text.Format:} .Token( token => FilterTokenParam("Format:", token), (token, d) => String.Format(token, d)) + .Chain(FilterChainFormatParam, "Text", (token, d) => String.Format(token, d)) // {Text.TrimEnd:} .Token(token => FilterTokenParam("TrimEnd:", token), TrimEnd) + .Chain(FilterChainTrimEndParam, "Text", TrimEnd) + // {Text.TrimStart:} + .Token(token => FilterTokenParam("TrimStart:", token), TrimStart) + .Chain(FilterChainTrimStartParam, "Text", TrimStart) .Token("UrlEncode", HttpUtility.UrlEncode) .Chain("UrlEncode", "Text", HttpUtility.UrlEncode) .Token("HtmlEncode", HttpUtility.HtmlEncode) @@ -57,10 +68,95 @@ namespace Orchard.Tokens.Providers { .Replace("\n", "
"); } - private static string FilterTokenParam(string tokenName, string token) { - return token.StartsWith(tokenName, StringComparison.OrdinalIgnoreCase) ? token.Substring(tokenName.Length) : null; + private Tuple FilterChainLimitParam(string token) { + return FilterChainParam("Limit:", token); } + private Tuple FilterChainFormatParam(string token) { + return FilterChainParam("Format:", token); + } + + private Tuple FilterChainTrimEndParam(string token) { + return FilterChainParam("TrimEnd:", token); + } + + private Tuple FilterChainTrimStartParam(string token) { + return FilterChainParam("TrimStart:", token); + } + + private static string FilterTokenParam(string tokenName, string token) { + if (!token.StartsWith(tokenName, StringComparison.OrdinalIgnoreCase)) return null; + string tokenPrefix; + int chainIndex, tokenLength; + if (token.IndexOf(":") == -1) { + tokenPrefix = token; + } + else { + tokenPrefix = token.Substring(0, token.IndexOf(":")); + } + if (!_textChainableTokens.Contains(tokenPrefix, StringComparer.OrdinalIgnoreCase)) { + return token.StartsWith(tokenName, StringComparison.OrdinalIgnoreCase) ? token.Substring(tokenName.Length) : null; + } + + // use ")." as chars combination to discover the end of the parameter + chainIndex = token.IndexOf(").") + 1; + tokenLength = (tokenPrefix + ":").Length; + if (chainIndex == 0) {// ")." has not be found + return token.Substring(tokenLength).Trim(new char[] { '(', ')' }); + } + if (!token.StartsWith((tokenPrefix + ":"), StringComparison.OrdinalIgnoreCase) || chainIndex <= tokenLength) { + return null; + } + return token.Substring(tokenLength, chainIndex - tokenLength).Trim(new char[] { '(', ')' }); + } + + /// + /// + /// + /// The name of the Token (e.g. "Limit:") + /// The entire Token (e.g. "Limit:(3).TrimStart:4") + /// Tuple representing the token parameter and next tokens (e.g. for token "Limit:(3).TrimStart:4", first string have to be "3", second one have to be "TrimStart:4") + private static Tuple FilterChainParam(string tokenName, string token) { + if (!token.StartsWith(tokenName, StringComparison.OrdinalIgnoreCase)) return null; + string tokenPrefix; + int chainIndex, tokenLength; + + if (token.IndexOf(":") == -1) { + tokenPrefix = token; + } + else { + tokenPrefix = token.Substring(0, token.IndexOf(":")); + } + if (!_textChainableTokens.Contains(tokenPrefix, StringComparer.OrdinalIgnoreCase)) { + return new Tuple(token, token); + } + + // use ")." as chars combination to discover the end of the parameter + chainIndex = token.IndexOf(").") + 1; + tokenLength = (tokenPrefix + ":").Length; + if (chainIndex == 0) { // ")." has not be found + return new Tuple(token.Substring(tokenLength).Trim(new char[] { '(', ')' }), ""); + } + if (!token.StartsWith((tokenPrefix + ":"), StringComparison.OrdinalIgnoreCase) || chainIndex <= tokenLength) { + return null; + } + return new Tuple(token.Substring(tokenLength, chainIndex - tokenLength).Trim(new char[] { '(', ')' }), token.Substring(chainIndex + 1)); + + } + + private static string TrimStart(string param, string token) { + if (string.IsNullOrEmpty(param)) { + return token; + } + + int n; + if (!int.TryParse(param, out n)) { + return token.TrimStart(param.ToCharArray()); + } + + n = Math.Max(0, n); // prevent negative numbers + return token.Substring(n); + } private static string TrimEnd(string param, string token) { if (String.IsNullOrEmpty(param)) { return token;