Migrated most of the functionality from RazorLibraryCore to UmbracoHelper and updated RazorLibraryCore to call
the methods in UmbracoHelper so we only have to maintain one set of code. Didn't port over the Wrap methods because I need feedback on these as to what they do/are supposed to do. Added the Media methods to UmbracoHelper using the media store stuff.
This commit is contained in:
@@ -843,7 +843,7 @@ namespace Umbraco.Core.Dynamics
|
||||
}
|
||||
public DynamicDocument AncestorOrSelf(string nodeTypeAlias)
|
||||
{
|
||||
return AncestorOrSelf(node => node.NodeTypeAlias == nodeTypeAlias);
|
||||
return AncestorOrSelf(node => node.DocumentTypeAlias == nodeTypeAlias);
|
||||
}
|
||||
public DynamicDocument AncestorOrSelf(Func<DynamicDocument, bool> func)
|
||||
{
|
||||
@@ -908,7 +908,7 @@ namespace Umbraco.Core.Dynamics
|
||||
}
|
||||
public DynamicDocumentList AncestorsOrSelf(string nodeTypeAlias)
|
||||
{
|
||||
return AncestorsOrSelf(n => n.NodeTypeAlias == nodeTypeAlias);
|
||||
return AncestorsOrSelf(n => n.DocumentTypeAlias == nodeTypeAlias);
|
||||
}
|
||||
public DynamicDocumentList AncestorsOrSelf(int level)
|
||||
{
|
||||
@@ -963,7 +963,7 @@ namespace Umbraco.Core.Dynamics
|
||||
}
|
||||
public DynamicDocumentList Ancestors(string nodeTypeAlias)
|
||||
{
|
||||
return Ancestors(n => n.NodeTypeAlias == nodeTypeAlias);
|
||||
return Ancestors(n => n.DocumentTypeAlias == nodeTypeAlias);
|
||||
}
|
||||
public DynamicDocumentList Ancestors()
|
||||
{
|
||||
@@ -1049,7 +1049,7 @@ namespace Umbraco.Core.Dynamics
|
||||
get { return _backingItem.UrlName; }
|
||||
}
|
||||
|
||||
public string NodeTypeAlias
|
||||
public string DocumentTypeAlias
|
||||
{
|
||||
get { return _backingItem.DocumentTypeAlias; }
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace Umbraco.Core.Dynamics
|
||||
}
|
||||
else
|
||||
{
|
||||
while ((context = context.Parent) != null && context.NodeTypeAlias != nodeTypeAlias) ;
|
||||
while ((context = context.Parent) != null && context.DocumentTypeAlias != nodeTypeAlias) ;
|
||||
return context;
|
||||
}
|
||||
}
|
||||
@@ -144,7 +144,7 @@ namespace Umbraco.Core.Dynamics
|
||||
while (workingIndex != currentIndex)
|
||||
{
|
||||
var working = container.ElementAtOrDefault(workingIndex);
|
||||
if (working != null && working.NodeTypeAlias == nodeTypeAlias)
|
||||
if (working != null && working.DocumentTypeAlias == nodeTypeAlias)
|
||||
{
|
||||
return working;
|
||||
}
|
||||
@@ -180,7 +180,7 @@ namespace Umbraco.Core.Dynamics
|
||||
var currentIndex = container.FindIndex(n => n.Id == context.Id);
|
||||
if (currentIndex != -1)
|
||||
{
|
||||
var newIndex = container.FindIndex(currentIndex, n => n.NodeTypeAlias == nodeTypeAlias);
|
||||
var newIndex = container.FindIndex(currentIndex, n => n.DocumentTypeAlias == nodeTypeAlias);
|
||||
if (newIndex != -1)
|
||||
{
|
||||
return container.ElementAt(newIndex);
|
||||
@@ -242,7 +242,7 @@ namespace Umbraco.Core.Dynamics
|
||||
if (currentIndex != -1)
|
||||
{
|
||||
var previousNodes = container.Take(currentIndex).ToList();
|
||||
int newIndex = previousNodes.FindIndex(n => n.NodeTypeAlias == nodeTypeAlias);
|
||||
int newIndex = previousNodes.FindIndex(n => n.DocumentTypeAlias == nodeTypeAlias);
|
||||
if (newIndex != -1)
|
||||
{
|
||||
return container.ElementAt(newIndex);
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Umbraco.Core.Dynamics
|
||||
//Because it's IEnumerable, if the user is actually trying @Model.TextPages or similar
|
||||
//it will still return an enumerable object (assuming the call actually failed because there were no children of that type)
|
||||
//but in .Where, if they use a property that doesn't exist, the lambda will bypass this and return false
|
||||
internal class DynamicNull : DynamicObject, IEnumerable, IHtmlString
|
||||
public class DynamicNull : DynamicObject, IEnumerable, IHtmlString
|
||||
{
|
||||
public IEnumerator GetEnumerator()
|
||||
{
|
||||
|
||||
@@ -14,6 +14,9 @@ namespace Umbraco.Web
|
||||
/// <summary>
|
||||
/// An IPublishedMediaStore that first checks for the media in Examine, and then reverts to the database
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// NOTE: In the future if we want to properly cache all media this class can be extended or replaced when these classes/interfaces are exposed publicly.
|
||||
/// </remarks>
|
||||
internal class DefaultPublishedMediaStore : IPublishedMediaStore
|
||||
{
|
||||
public virtual IDocument GetDocumentById(UmbracoContext umbracoContext, int nodeId)
|
||||
@@ -60,6 +63,8 @@ namespace Umbraco.Web
|
||||
internal IDocument ConvertFromSearchResult(SearchResult searchResult)
|
||||
{
|
||||
//TODO: Unit test this
|
||||
//NOTE: we could just use the ExamineExtensions.ConvertFromSearchResult method but it will be faster to just
|
||||
// use the data store in Examine cache.
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using Examine;
|
||||
using Examine.LuceneEngine.SearchCriteria;
|
||||
using Umbraco.Core.Dynamics;
|
||||
|
||||
@@ -57,26 +52,9 @@ namespace Umbraco.Web
|
||||
s = searchProvider;
|
||||
|
||||
var results = s.Search(criteria);
|
||||
return ConvertSearchResultToDynamicNode(results);
|
||||
return results.ConvertSearchResultToDynamicDocument(PublishedContentStoreResolver.Current.PublishedContentStore);
|
||||
}
|
||||
|
||||
private static DynamicDocumentList ConvertSearchResultToDynamicNode(IEnumerable<SearchResult> results)
|
||||
{
|
||||
var list = new DynamicDocumentList();
|
||||
var xd = new XmlDocument();
|
||||
|
||||
foreach (var result in results.OrderByDescending(x => x.Score))
|
||||
{
|
||||
var doc = PublishedContentStoreResolver.Current.PublishedContentStore.GetDocumentById(
|
||||
UmbracoContext.Current,
|
||||
result.Id);
|
||||
if (doc == null) continue; //skip if this doesn't exist in the cache
|
||||
doc.Properties.Add(
|
||||
new PropertyResult("examineScore", result.Score.ToString(), Guid.Empty, PropertyResultType.CustomProperty));
|
||||
var dynamicDoc = new DynamicDocument(doc);
|
||||
list.Add(dynamicDoc);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
36
src/Umbraco.Web/ExamineExtensions.cs
Normal file
36
src/Umbraco.Web/ExamineExtensions.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using Examine;
|
||||
using Umbraco.Core.Dynamics;
|
||||
|
||||
namespace Umbraco.Web
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods for Examine
|
||||
/// </summary>
|
||||
internal static class ExamineExtensions
|
||||
{
|
||||
internal static DynamicDocumentList ConvertSearchResultToDynamicDocument(
|
||||
this IEnumerable<SearchResult> results,
|
||||
IPublishedStore store)
|
||||
{
|
||||
var list = new DynamicDocumentList();
|
||||
var xd = new XmlDocument();
|
||||
|
||||
foreach (var result in results.OrderByDescending(x => x.Score))
|
||||
{
|
||||
var doc = store.GetDocumentById(
|
||||
UmbracoContext.Current,
|
||||
result.Id);
|
||||
if (doc == null) continue; //skip if this doesn't exist in the cache
|
||||
doc.Properties.Add(
|
||||
new PropertyResult("examineScore", result.Score.ToString(), Guid.Empty, PropertyResultType.CustomProperty));
|
||||
var dynamicDoc = new DynamicDocument(doc);
|
||||
list.Add(dynamicDoc);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ using Umbraco.Core.ObjectResolution;
|
||||
namespace Umbraco.Web
|
||||
{
|
||||
/// <summary>
|
||||
/// An object resolver to return the IContentStore
|
||||
/// An object resolver to return the IPublishedContentStore
|
||||
/// </summary>
|
||||
internal class PublishedContentStoreResolver : SingleObjectResolverBase<PublishedContentStoreResolver, IPublishedContentStore>
|
||||
{
|
||||
|
||||
32
src/Umbraco.Web/PublishedMediaStoreResolver.cs
Normal file
32
src/Umbraco.Web/PublishedMediaStoreResolver.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
|
||||
namespace Umbraco.Web
|
||||
{
|
||||
/// <summary>
|
||||
/// An object resolver to return the IPublishedMediaStore
|
||||
/// </summary>
|
||||
internal class PublishedMediaStoreResolver : SingleObjectResolverBase<PublishedMediaStoreResolver, IPublishedMediaStore>
|
||||
{
|
||||
internal PublishedMediaStoreResolver(IPublishedMediaStore publishedMediaStore)
|
||||
: base(publishedMediaStore)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Can be used by developers at runtime to set their IContentStore at app startup
|
||||
/// </summary>
|
||||
/// <param name="publishedMediaStore"></param>
|
||||
public void SetContentStore(IPublishedMediaStore publishedMediaStore)
|
||||
{
|
||||
Value = publishedMediaStore;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the IContentStore
|
||||
/// </summary>
|
||||
public IPublishedMediaStore PublishedMediaStore
|
||||
{
|
||||
get { return Value; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -245,6 +245,7 @@
|
||||
<Compile Include="Dictionary\UmbracoCultureDictionary.cs" />
|
||||
<Compile Include="Dictionary\UmbracoCultureDictionaryFactory.cs" />
|
||||
<Compile Include="DynamicDocumentSearchExtensions.cs" />
|
||||
<Compile Include="ExamineExtensions.cs" />
|
||||
<Compile Include="FormlessPage.cs">
|
||||
<SubType>ASPXCodeBehind</SubType>
|
||||
</Compile>
|
||||
@@ -262,6 +263,7 @@
|
||||
<Compile Include="Media\EmbedProviders\Twitgoo.cs" />
|
||||
<Compile Include="ModelStateExtensions.cs" />
|
||||
<Compile Include="PropertyEditors\RteMacroRenderingPropertyEditorValueConverter.cs" />
|
||||
<Compile Include="PublishedMediaStoreResolver.cs" />
|
||||
<Compile Include="RenderFieldCaseType.cs" />
|
||||
<Compile Include="RenderFieldEncodingType.cs" />
|
||||
<Compile Include="Routing\LookupByPageIdQuery.cs" />
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
using System.Web.Configuration;
|
||||
using System.Web.UI;
|
||||
using System.Xml.Linq;
|
||||
using System.Xml.XPath;
|
||||
using HtmlAgilityPack;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Dynamics;
|
||||
using Umbraco.Core.Models;
|
||||
using umbraco;
|
||||
using System.Collections.Generic;
|
||||
@@ -12,6 +18,7 @@ using umbraco.presentation.templateControls;
|
||||
|
||||
namespace Umbraco.Web
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// A helper class that provides many useful methods and functionality for using Umbraco in templates
|
||||
/// </summary>
|
||||
@@ -208,5 +215,432 @@ namespace Umbraco.Web
|
||||
|
||||
#endregion
|
||||
|
||||
#region Content
|
||||
|
||||
public dynamic ContentById(int id)
|
||||
{
|
||||
return DocumentById(id, PublishedContentStoreResolver.Current.PublishedContentStore);
|
||||
}
|
||||
|
||||
public dynamic ContentById(string id)
|
||||
{
|
||||
return DocumentById(id, PublishedContentStoreResolver.Current.PublishedContentStore);
|
||||
}
|
||||
|
||||
public dynamic ContentByIds(params int[] ids)
|
||||
{
|
||||
return DocumentByIds(PublishedContentStoreResolver.Current.PublishedContentStore, ids);
|
||||
}
|
||||
|
||||
public dynamic ContentByIds(params string[] ids)
|
||||
{
|
||||
return DocumentByIds(PublishedContentStoreResolver.Current.PublishedContentStore, ids);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Media
|
||||
|
||||
public dynamic MediaById(int id)
|
||||
{
|
||||
return DocumentById(id, PublishedMediaStoreResolver.Current.PublishedMediaStore);
|
||||
}
|
||||
|
||||
public dynamic MediaById(string id)
|
||||
{
|
||||
return DocumentById(id, PublishedMediaStoreResolver.Current.PublishedMediaStore);
|
||||
}
|
||||
|
||||
public dynamic MediaByIds(params int[] ids)
|
||||
{
|
||||
return DocumentByIds(PublishedMediaStoreResolver.Current.PublishedMediaStore, ids);
|
||||
}
|
||||
|
||||
public dynamic MediaByIds(params string[] ids)
|
||||
{
|
||||
return DocumentByIds(PublishedMediaStoreResolver.Current.PublishedMediaStore, ids);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Used by Content/Media
|
||||
|
||||
private dynamic DocumentById(int id, IPublishedStore store)
|
||||
{
|
||||
var doc = store.GetDocumentById(UmbracoContext.Current, id);
|
||||
return doc == null
|
||||
? new DynamicNull()
|
||||
: new DynamicDocument(doc).AsDynamic();
|
||||
}
|
||||
|
||||
private dynamic DocumentById(string id, IPublishedStore store)
|
||||
{
|
||||
int docId;
|
||||
return int.TryParse(id, out docId)
|
||||
? DocumentById(docId, store)
|
||||
: new DynamicNull();
|
||||
}
|
||||
|
||||
private dynamic DocumentByIds(IPublishedStore store, params int[] ids)
|
||||
{
|
||||
var nodes = ids.Select(eachId => DocumentById(eachId, store))
|
||||
.Where(x => !TypeHelper.IsTypeAssignableFrom<DynamicNull>(x))
|
||||
.Cast<DynamicDocument>();
|
||||
return new DynamicDocumentList(nodes);
|
||||
}
|
||||
|
||||
private dynamic DocumentByIds(IPublishedStore store, params string[] ids)
|
||||
{
|
||||
var nodes = ids.Select(eachId => DocumentById(eachId, store))
|
||||
.Where(x => !TypeHelper.IsTypeAssignableFrom<DynamicNull>(x))
|
||||
.Cast<DynamicDocument>();
|
||||
return new DynamicDocumentList(nodes);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Search
|
||||
|
||||
/// <summary>
|
||||
/// Searches content
|
||||
/// </summary>
|
||||
/// <param name="term"></param>
|
||||
/// <param name="useWildCards"></param>
|
||||
/// <param name="searchProvider"></param>
|
||||
/// <returns></returns>
|
||||
public dynamic Search(string term, bool useWildCards = true, string searchProvider = null)
|
||||
{
|
||||
var searcher = Examine.ExamineManager.Instance.DefaultSearchProvider;
|
||||
if (!string.IsNullOrEmpty(searchProvider))
|
||||
searcher = Examine.ExamineManager.Instance.SearchProviderCollection[searchProvider];
|
||||
|
||||
var results = searcher.Search(term, useWildCards);
|
||||
return results.ConvertSearchResultToDynamicDocument(PublishedContentStoreResolver.Current.PublishedContentStore);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searhes content
|
||||
/// </summary>
|
||||
/// <param name="criteria"></param>
|
||||
/// <param name="searchProvider"></param>
|
||||
/// <returns></returns>
|
||||
public dynamic Search(Examine.SearchCriteria.ISearchCriteria criteria, Examine.Providers.BaseSearchProvider searchProvider = null)
|
||||
{
|
||||
var s = Examine.ExamineManager.Instance.DefaultSearchProvider;
|
||||
if (searchProvider != null)
|
||||
s = searchProvider;
|
||||
|
||||
var results = s.Search(criteria);
|
||||
return results.ConvertSearchResultToDynamicDocument(PublishedContentStoreResolver.Current.PublishedContentStore);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Xml
|
||||
|
||||
public dynamic ToDynamicXml(string xml)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(xml)) return null;
|
||||
var xElement = XElement.Parse(xml);
|
||||
return new DynamicXml(xElement);
|
||||
}
|
||||
|
||||
public dynamic ToDynamicXml(XElement xElement)
|
||||
{
|
||||
return new DynamicXml(xElement);
|
||||
}
|
||||
|
||||
public dynamic ToDynamicXml(XPathNodeIterator xpni)
|
||||
{
|
||||
return new DynamicXml(xpni);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Strings
|
||||
|
||||
public HtmlString StripHtml(IHtmlString html, params string[] tags)
|
||||
{
|
||||
return StripHtml(html.ToHtmlString(), tags);
|
||||
}
|
||||
public HtmlString StripHtml(DynamicNull html, params string[] tags)
|
||||
{
|
||||
return new HtmlString(string.Empty);
|
||||
}
|
||||
public HtmlString StripHtml(string html, params string[] tags)
|
||||
{
|
||||
return StripHtmlTags(html, tags);
|
||||
}
|
||||
|
||||
private HtmlString StripHtmlTags(string html, params string[] tags)
|
||||
{
|
||||
var doc = new HtmlDocument();
|
||||
doc.LoadHtml("<p>" + html + "</p>");
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
var targets = new List<HtmlNode>();
|
||||
|
||||
var nodes = doc.DocumentNode.FirstChild.SelectNodes(".//*");
|
||||
if (nodes != null)
|
||||
{
|
||||
foreach (var node in nodes)
|
||||
{
|
||||
//is element
|
||||
if (node.NodeType != HtmlNodeType.Element) continue;
|
||||
var filterAllTags = (tags == null || !tags.Any());
|
||||
if (filterAllTags || tags.Any(tag => string.Equals(tag, node.Name, StringComparison.CurrentCultureIgnoreCase)))
|
||||
{
|
||||
targets.Add(node);
|
||||
}
|
||||
}
|
||||
foreach (var target in targets)
|
||||
{
|
||||
HtmlNode content = doc.CreateTextNode(target.InnerText);
|
||||
target.ParentNode.ReplaceChild(content, target);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return new HtmlString(html);
|
||||
}
|
||||
return new HtmlString(doc.DocumentNode.FirstChild.InnerHtml);
|
||||
}
|
||||
}
|
||||
|
||||
public string Coalesce(params object[] args)
|
||||
{
|
||||
return Coalesce<DynamicNull>(args);
|
||||
}
|
||||
|
||||
internal string Coalesce<TIgnore>(params object[] args)
|
||||
{
|
||||
foreach (var sArg in args.Where(arg => arg != null && arg.GetType() != typeof(TIgnore)).Select(arg => string.Format("{0}", arg)).Where(sArg => !string.IsNullOrWhiteSpace(sArg)))
|
||||
{
|
||||
return sArg;
|
||||
}
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public string Concatenate(params object[] args)
|
||||
{
|
||||
return Concatenate<DynamicNull>(args);
|
||||
}
|
||||
|
||||
internal string Concatenate<TIgnore>(params object[] args)
|
||||
{
|
||||
var result = new StringBuilder();
|
||||
foreach (var sArg in args.Where(arg => arg != null && arg.GetType() != typeof(TIgnore)).Select(arg => string.Format("{0}", arg)).Where(sArg => !string.IsNullOrWhiteSpace(sArg)))
|
||||
{
|
||||
result.Append(sArg);
|
||||
}
|
||||
return result.ToString();
|
||||
}
|
||||
|
||||
public string Join(string seperator, params object[] args)
|
||||
{
|
||||
return Join<DynamicNull>(seperator, args);
|
||||
}
|
||||
|
||||
internal string Join<TIgnore>(string seperator, params object[] args)
|
||||
{
|
||||
var results = args.Where(arg => arg != null && arg.GetType() != typeof (TIgnore)).Select(arg => string.Format("{0}", arg)).Where(sArg => !string.IsNullOrWhiteSpace(sArg)).ToList();
|
||||
return string.Join(seperator, results);
|
||||
}
|
||||
|
||||
public IHtmlString Truncate(IHtmlString html, int length)
|
||||
{
|
||||
return Truncate(html.ToHtmlString(), length, true, false);
|
||||
}
|
||||
public IHtmlString Truncate(IHtmlString html, int length, bool addElipsis)
|
||||
{
|
||||
return Truncate(html.ToHtmlString(), length, addElipsis, false);
|
||||
}
|
||||
public IHtmlString Truncate(IHtmlString html, int length, bool addElipsis, bool treatTagsAsContent)
|
||||
{
|
||||
return Truncate(html.ToHtmlString(), length, addElipsis, treatTagsAsContent);
|
||||
}
|
||||
public IHtmlString Truncate(DynamicNull html, int length)
|
||||
{
|
||||
return new HtmlString(string.Empty);
|
||||
}
|
||||
public IHtmlString Truncate(DynamicNull html, int length, bool addElipsis)
|
||||
{
|
||||
return new HtmlString(string.Empty);
|
||||
}
|
||||
public IHtmlString Truncate(DynamicNull html, int length, bool addElipsis, bool treatTagsAsContent)
|
||||
{
|
||||
return new HtmlString(string.Empty);
|
||||
}
|
||||
public IHtmlString Truncate(string html, int length)
|
||||
{
|
||||
return Truncate(html, length, true, false);
|
||||
}
|
||||
public IHtmlString Truncate(string html, int length, bool addElipsis)
|
||||
{
|
||||
return Truncate(html, length, addElipsis, false);
|
||||
}
|
||||
public IHtmlString Truncate(string html, int length, bool addElipsis, bool treatTagsAsContent)
|
||||
{
|
||||
using (var outputms = new MemoryStream())
|
||||
{
|
||||
using (var outputtw = new StreamWriter(outputms))
|
||||
{
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
using (var tw = new StreamWriter(ms))
|
||||
{
|
||||
tw.Write(html);
|
||||
tw.Flush();
|
||||
ms.Position = 0;
|
||||
var tagStack = new Stack<string>();
|
||||
using (TextReader tr = new StreamReader(ms))
|
||||
{
|
||||
bool IsInsideElement = false;
|
||||
bool lengthReached = false;
|
||||
int ic = 0;
|
||||
int currentLength = 0, currentTextLength = 0;
|
||||
string currentTag = string.Empty;
|
||||
string tagContents = string.Empty;
|
||||
bool insideTagSpaceEncountered = false;
|
||||
bool isTagClose = false;
|
||||
while ((ic = tr.Read()) != -1)
|
||||
{
|
||||
bool write = true;
|
||||
|
||||
if (ic == (int)'<')
|
||||
{
|
||||
if (!lengthReached)
|
||||
{
|
||||
IsInsideElement = true;
|
||||
}
|
||||
insideTagSpaceEncountered = false;
|
||||
currentTag = string.Empty;
|
||||
tagContents = string.Empty;
|
||||
isTagClose = false;
|
||||
if (tr.Peek() == (int)'/')
|
||||
{
|
||||
isTagClose = true;
|
||||
}
|
||||
}
|
||||
else if (ic == (int)'>')
|
||||
{
|
||||
//if (IsInsideElement)
|
||||
//{
|
||||
IsInsideElement = false;
|
||||
//if (write)
|
||||
//{
|
||||
// outputtw.Write('>');
|
||||
//}
|
||||
currentTextLength++;
|
||||
if (isTagClose && tagStack.Count > 0)
|
||||
{
|
||||
string thisTag = tagStack.Pop();
|
||||
outputtw.Write("</" + thisTag + ">");
|
||||
}
|
||||
if (!isTagClose && currentTag.Length > 0)
|
||||
{
|
||||
if (!lengthReached)
|
||||
{
|
||||
tagStack.Push(currentTag);
|
||||
outputtw.Write("<" + currentTag);
|
||||
if (tr.Peek() != (int)' ')
|
||||
{
|
||||
if (!string.IsNullOrEmpty(tagContents))
|
||||
{
|
||||
if (tagContents.EndsWith("/"))
|
||||
{
|
||||
//short close
|
||||
tagStack.Pop();
|
||||
}
|
||||
outputtw.Write(tagContents);
|
||||
}
|
||||
outputtw.Write(">");
|
||||
}
|
||||
}
|
||||
}
|
||||
//}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsInsideElement)
|
||||
{
|
||||
if (ic == (int)' ')
|
||||
{
|
||||
if (!insideTagSpaceEncountered)
|
||||
{
|
||||
insideTagSpaceEncountered = true;
|
||||
//if (!isTagClose)
|
||||
//{
|
||||
// tagStack.Push(currentTag);
|
||||
//}
|
||||
}
|
||||
}
|
||||
if (!insideTagSpaceEncountered)
|
||||
{
|
||||
currentTag += (char)ic;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (IsInsideElement || insideTagSpaceEncountered)
|
||||
{
|
||||
write = false;
|
||||
if (insideTagSpaceEncountered)
|
||||
{
|
||||
tagContents += (char)ic;
|
||||
}
|
||||
}
|
||||
if (!IsInsideElement || treatTagsAsContent)
|
||||
{
|
||||
currentTextLength++;
|
||||
}
|
||||
currentLength++;
|
||||
if (currentTextLength <= length || (lengthReached && IsInsideElement))
|
||||
{
|
||||
if (write)
|
||||
{
|
||||
outputtw.Write((char)ic);
|
||||
}
|
||||
}
|
||||
if (!lengthReached && currentTextLength >= length)
|
||||
{
|
||||
//reached truncate point
|
||||
if (addElipsis)
|
||||
{
|
||||
outputtw.Write("…");
|
||||
}
|
||||
lengthReached = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
outputtw.Flush();
|
||||
outputms.Position = 0;
|
||||
using (TextReader outputtr = new StreamReader(outputms))
|
||||
{
|
||||
return new HtmlString(outputtr.ReadToEnd().Replace(" ", " ").Trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region If
|
||||
|
||||
public HtmlString If(bool test, string valueIfTrue, string valueIfFalse)
|
||||
{
|
||||
return test ? new HtmlString(valueIfTrue) : new HtmlString(valueIfFalse);
|
||||
}
|
||||
public HtmlString If(bool test, string valueIfTrue)
|
||||
{
|
||||
return test ? new HtmlString(valueIfTrue) : new HtmlString(string.Empty);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,6 +134,7 @@ namespace Umbraco.Web
|
||||
PropertyEditorValueConvertersResolver.Current.AddType<RteMacroRenderingPropertyEditorValueConverter>();
|
||||
|
||||
PublishedContentStoreResolver.Current = new PublishedContentStoreResolver(new DefaultPublishedContentStore());
|
||||
PublishedMediaStoreResolver.Current = new PublishedMediaStoreResolver(new DefaultPublishedMediaStore());
|
||||
|
||||
FilteredControllerFactoriesResolver.Current = new FilteredControllerFactoriesResolver(
|
||||
//add all known factories, devs can then modify this list on application startup either by binding to events
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Dynamics;
|
||||
using Umbraco.Core.Models;
|
||||
using umbraco.NodeFactory;
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace umbraco.MacroEngines.Library
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods for converting DynamicDocument to INode
|
||||
/// </summary>
|
||||
internal static class DynamicDocumentExtensions
|
||||
{
|
||||
|
||||
internal static IProperty ConvertToNodeProperty(this IDocumentProperty prop)
|
||||
{
|
||||
return new PropertyResult(prop.Alias, prop.Value.ToString(), prop.Version);
|
||||
}
|
||||
|
||||
internal static INode ConvertToNode(this DynamicDocument doc)
|
||||
{
|
||||
var node = new SimpleNode(doc);
|
||||
return node;
|
||||
}
|
||||
|
||||
private class SimpleNode : INode
|
||||
{
|
||||
private readonly DynamicDocument _doc;
|
||||
|
||||
public SimpleNode(DynamicDocument doc)
|
||||
{
|
||||
_doc = doc;
|
||||
template = doc.TemplateId;
|
||||
Id = doc.Id;
|
||||
Path = doc.Path;
|
||||
CreatorName = doc.CreatorName;
|
||||
SortOrder = doc.SortOrder;
|
||||
UpdateDate = doc.UpdateDate;
|
||||
Name = doc.Name;
|
||||
NodeTypeAlias = doc.DocumentTypeAlias;
|
||||
CreateDate = doc.CreateDate;
|
||||
CreatorID = doc.CreatorId;
|
||||
Level = doc.Level;
|
||||
UrlName = doc.UrlName;
|
||||
Version = doc.Version;
|
||||
WriterID = doc.WriterId;
|
||||
WriterName = doc.WriterName;
|
||||
}
|
||||
|
||||
public INode Parent
|
||||
{
|
||||
get { return _doc.Parent.ConvertToNode(); }
|
||||
}
|
||||
public int Id { get; private set; }
|
||||
public int template { get; private set; }
|
||||
public int SortOrder { get; private set; }
|
||||
public string Name { get; private set; }
|
||||
public string UrlName { get; private set; }
|
||||
public string NodeTypeAlias { get; private set; }
|
||||
public string WriterName { get; private set; }
|
||||
public string CreatorName { get; private set; }
|
||||
public int WriterID { get; private set; }
|
||||
public int CreatorID { get; private set; }
|
||||
public string Path { get; private set; }
|
||||
public DateTime CreateDate { get; private set; }
|
||||
public DateTime UpdateDate { get; private set; }
|
||||
public Guid Version { get; private set; }
|
||||
|
||||
public string NiceUrl
|
||||
{
|
||||
get { return library.NiceUrl(Id); }
|
||||
}
|
||||
|
||||
public string Url
|
||||
{
|
||||
get { return library.NiceUrl(Id); }
|
||||
}
|
||||
|
||||
public int Level { get; private set; }
|
||||
public List<IProperty> PropertiesAsList
|
||||
{
|
||||
get { return _doc.Properties.Select(ConvertToNodeProperty).ToList(); }
|
||||
}
|
||||
public List<INode> ChildrenAsList
|
||||
{
|
||||
get { return _doc.Children.Select(x => x.ConvertToNode()).ToList(); }
|
||||
}
|
||||
public IProperty GetProperty(string Alias)
|
||||
{
|
||||
return PropertiesAsList.Cast<Property>().FirstOrDefault(p => p.Alias == Alias);
|
||||
}
|
||||
|
||||
public IProperty GetProperty(string Alias, out bool propertyExists)
|
||||
{
|
||||
foreach (var p in from Property p in PropertiesAsList where p.Alias == Alias select p)
|
||||
{
|
||||
propertyExists = true;
|
||||
return p;
|
||||
}
|
||||
propertyExists = false;
|
||||
return null;
|
||||
}
|
||||
|
||||
public DataTable ChildrenAsTable()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public DataTable ChildrenAsTable(string nodeTypeAliasFilter)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Umbraco.Core.Dynamics;
|
||||
using Umbraco.Web;
|
||||
using umbraco.interfaces;
|
||||
using System.Xml.Linq;
|
||||
using System.Xml.XPath;
|
||||
@@ -11,9 +13,10 @@ using HtmlAgilityPack;
|
||||
|
||||
namespace umbraco.MacroEngines.Library
|
||||
{
|
||||
public class RazorLibraryCore
|
||||
public class RazorLibraryCore
|
||||
{
|
||||
private INode _node;
|
||||
private readonly INode _node;
|
||||
private readonly UmbracoHelper _umbracoHelper;
|
||||
public INode Node
|
||||
{
|
||||
get { return _node; }
|
||||
@@ -21,6 +24,7 @@ namespace umbraco.MacroEngines.Library
|
||||
public RazorLibraryCore(INode node)
|
||||
{
|
||||
this._node = node;
|
||||
_umbracoHelper = new UmbracoHelper(UmbracoContext.Current);
|
||||
}
|
||||
|
||||
public dynamic NodeById(int Id)
|
||||
@@ -131,22 +135,18 @@ namespace umbraco.MacroEngines.Library
|
||||
|
||||
public dynamic Search(string term, bool useWildCards = true, string searchProvider = null)
|
||||
{
|
||||
var searcher = Examine.ExamineManager.Instance.DefaultSearchProvider;
|
||||
if (!string.IsNullOrEmpty(searchProvider))
|
||||
searcher = Examine.ExamineManager.Instance.SearchProviderCollection[searchProvider];
|
||||
|
||||
var results = searcher.Search(term, useWildCards);
|
||||
return ExamineSearchUtill.ConvertSearchResultToDynamicNode(results);
|
||||
//wraps the functionality in UmbracoHelper but still returns the legacy DynamicNodeList
|
||||
var nodes = ((DynamicDocumentList)_umbracoHelper.Search(term, useWildCards, searchProvider))
|
||||
.Select(x => x.ConvertToNode());
|
||||
return new DynamicNodeList(nodes);
|
||||
}
|
||||
|
||||
public dynamic Search(Examine.SearchCriteria.ISearchCriteria criteria, Examine.Providers.BaseSearchProvider searchProvider = null)
|
||||
{
|
||||
var s = Examine.ExamineManager.Instance.DefaultSearchProvider;
|
||||
if (searchProvider != null)
|
||||
s = searchProvider;
|
||||
|
||||
var results = s.Search(criteria);
|
||||
return ExamineSearchUtill.ConvertSearchResultToDynamicNode(results);
|
||||
//wraps the functionality in UmbracoHelper but still returns the legacy DynamicNodeList
|
||||
var nodes = ((DynamicDocumentList) _umbracoHelper.Search(criteria, searchProvider))
|
||||
.Select(x => x.ConvertToNode());
|
||||
return new DynamicNodeList(nodes);
|
||||
}
|
||||
|
||||
|
||||
@@ -157,74 +157,40 @@ namespace umbraco.MacroEngines.Library
|
||||
|
||||
public dynamic ToDynamicXml(string xml)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(xml)) return null;
|
||||
var xElement = XElement.Parse(xml);
|
||||
return new umbraco.MacroEngines.DynamicXml(xElement);
|
||||
return _umbracoHelper.ToDynamicXml(xml);
|
||||
}
|
||||
|
||||
public dynamic ToDynamicXml(XElement xElement)
|
||||
{
|
||||
return new DynamicXml(xElement);
|
||||
}
|
||||
{
|
||||
return _umbracoHelper.ToDynamicXml(xElement);
|
||||
}
|
||||
|
||||
public dynamic ToDynamicXml(XPathNodeIterator xpni)
|
||||
{
|
||||
return new DynamicXml(xpni);
|
||||
}
|
||||
{
|
||||
return _umbracoHelper.ToDynamicXml(xpni);
|
||||
}
|
||||
|
||||
public string Coalesce(params object[] args)
|
||||
{
|
||||
foreach (var arg in args)
|
||||
{
|
||||
if (arg != null && arg.GetType() != typeof(DynamicNull))
|
||||
{
|
||||
var sArg = string.Format("{0}", arg);
|
||||
if (!string.IsNullOrWhiteSpace(sArg))
|
||||
{
|
||||
return sArg;
|
||||
}
|
||||
}
|
||||
}
|
||||
return string.Empty;
|
||||
return _umbracoHelper.Coalesce<DynamicNull>(args);
|
||||
}
|
||||
|
||||
public string Concatenate(params object[] args)
|
||||
{
|
||||
StringBuilder result = new StringBuilder();
|
||||
foreach (var arg in args)
|
||||
{
|
||||
if (arg != null && arg.GetType() != typeof(DynamicNull))
|
||||
{
|
||||
var sArg = string.Format("{0}", arg);
|
||||
if (!string.IsNullOrWhiteSpace(sArg))
|
||||
{
|
||||
result.Append(sArg);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.ToString();
|
||||
return _umbracoHelper.Concatenate<DynamicNull>(args);
|
||||
}
|
||||
public string Join(string seperator, params object[] args)
|
||||
{
|
||||
List<string> results = new List<string>();
|
||||
foreach (var arg in args)
|
||||
{
|
||||
if (arg != null && arg.GetType() != typeof(DynamicNull))
|
||||
{
|
||||
var sArg = string.Format("{0}", arg);
|
||||
if (!string.IsNullOrWhiteSpace(sArg))
|
||||
{
|
||||
results.Add(sArg);
|
||||
}
|
||||
}
|
||||
}
|
||||
return string.Join(seperator, results);
|
||||
return _umbracoHelper.Join<DynamicNull>(seperator, args);
|
||||
}
|
||||
|
||||
public HtmlString If(bool test, string valueIfTrue, string valueIfFalse)
|
||||
{
|
||||
return test ? new HtmlString(valueIfTrue) : new HtmlString(valueIfFalse);
|
||||
return _umbracoHelper.If(test, valueIfTrue, valueIfFalse);
|
||||
}
|
||||
public HtmlString If(bool test, string valueIfTrue)
|
||||
{
|
||||
return test ? new HtmlString(valueIfTrue) : new HtmlString(string.Empty);
|
||||
return _umbracoHelper.If(test, valueIfTrue);
|
||||
}
|
||||
|
||||
public HtmlTagWrapper Wrap(string tag, string innerText, params HtmlTagWrapperBase[] Children)
|
||||
@@ -354,156 +320,13 @@ namespace umbraco.MacroEngines.Library
|
||||
}
|
||||
public IHtmlString Truncate(string html, int length, bool addElipsis, bool treatTagsAsContent)
|
||||
{
|
||||
using (MemoryStream outputms = new MemoryStream())
|
||||
{
|
||||
using (TextWriter outputtw = new StreamWriter(outputms))
|
||||
{
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
{
|
||||
using (TextWriter tw = new StreamWriter(ms))
|
||||
{
|
||||
tw.Write(html);
|
||||
tw.Flush();
|
||||
ms.Position = 0;
|
||||
Stack<string> tagStack = new Stack<string>();
|
||||
using (TextReader tr = new StreamReader(ms))
|
||||
{
|
||||
bool IsInsideElement = false;
|
||||
bool lengthReached = false;
|
||||
int ic = 0;
|
||||
int currentLength = 0, currentTextLength = 0;
|
||||
string currentTag = string.Empty;
|
||||
string tagContents = string.Empty;
|
||||
bool insideTagSpaceEncountered = false;
|
||||
bool isTagClose = false;
|
||||
while ((ic = tr.Read()) != -1)
|
||||
{
|
||||
bool write = true;
|
||||
|
||||
if (ic == (int)'<')
|
||||
{
|
||||
if (!lengthReached)
|
||||
{
|
||||
IsInsideElement = true;
|
||||
}
|
||||
insideTagSpaceEncountered = false;
|
||||
currentTag = string.Empty;
|
||||
tagContents = string.Empty;
|
||||
isTagClose = false;
|
||||
if (tr.Peek() == (int)'/')
|
||||
{
|
||||
isTagClose = true;
|
||||
}
|
||||
}
|
||||
else if (ic == (int)'>')
|
||||
{
|
||||
//if (IsInsideElement)
|
||||
//{
|
||||
IsInsideElement = false;
|
||||
//if (write)
|
||||
//{
|
||||
// outputtw.Write('>');
|
||||
//}
|
||||
currentTextLength++;
|
||||
if (isTagClose && tagStack.Count > 0)
|
||||
{
|
||||
string thisTag = tagStack.Pop();
|
||||
outputtw.Write("</" + thisTag + ">");
|
||||
}
|
||||
if (!isTagClose && currentTag.Length > 0)
|
||||
{
|
||||
if (!lengthReached)
|
||||
{
|
||||
tagStack.Push(currentTag);
|
||||
outputtw.Write("<" + currentTag);
|
||||
if (tr.Peek() != (int)' ')
|
||||
{
|
||||
if (!string.IsNullOrEmpty(tagContents))
|
||||
{
|
||||
if (tagContents.EndsWith("/"))
|
||||
{
|
||||
//short close
|
||||
tagStack.Pop();
|
||||
}
|
||||
outputtw.Write(tagContents);
|
||||
}
|
||||
outputtw.Write(">");
|
||||
}
|
||||
}
|
||||
}
|
||||
//}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsInsideElement)
|
||||
{
|
||||
if (ic == (int)' ')
|
||||
{
|
||||
if (!insideTagSpaceEncountered)
|
||||
{
|
||||
insideTagSpaceEncountered = true;
|
||||
//if (!isTagClose)
|
||||
//{
|
||||
// tagStack.Push(currentTag);
|
||||
//}
|
||||
}
|
||||
}
|
||||
if (!insideTagSpaceEncountered)
|
||||
{
|
||||
currentTag += (char)ic;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (IsInsideElement || insideTagSpaceEncountered)
|
||||
{
|
||||
write = false;
|
||||
if (insideTagSpaceEncountered)
|
||||
{
|
||||
tagContents += (char)ic;
|
||||
}
|
||||
}
|
||||
if (!IsInsideElement || treatTagsAsContent)
|
||||
{
|
||||
currentTextLength++;
|
||||
}
|
||||
currentLength++;
|
||||
if (currentTextLength <= length || (lengthReached && IsInsideElement))
|
||||
{
|
||||
if (write)
|
||||
{
|
||||
outputtw.Write((char)ic);
|
||||
}
|
||||
}
|
||||
if (!lengthReached && currentTextLength >= length)
|
||||
{
|
||||
//reached truncate point
|
||||
if (addElipsis)
|
||||
{
|
||||
outputtw.Write("…");
|
||||
}
|
||||
lengthReached = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
outputtw.Flush();
|
||||
outputms.Position = 0;
|
||||
using (TextReader outputtr = new StreamReader(outputms))
|
||||
{
|
||||
return new HtmlString(outputtr.ReadToEnd().Replace(" ", " ").Trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
return _umbracoHelper.Truncate(html, length, addElipsis, treatTagsAsContent);
|
||||
}
|
||||
|
||||
|
||||
public HtmlString StripHtml(IHtmlString html)
|
||||
{
|
||||
return StripHtml(html.ToHtmlString(), (List<string>)null);
|
||||
return _umbracoHelper.StripHtml(html);
|
||||
}
|
||||
public HtmlString StripHtml(DynamicNull html)
|
||||
{
|
||||
@@ -511,12 +334,12 @@ namespace umbraco.MacroEngines.Library
|
||||
}
|
||||
public HtmlString StripHtml(string html)
|
||||
{
|
||||
return StripHtmlTags(html, (List<string>)null);
|
||||
return _umbracoHelper.StripHtml(html);
|
||||
}
|
||||
|
||||
public HtmlString StripHtml(IHtmlString html, List<string> tags)
|
||||
{
|
||||
return StripHtml(html.ToHtmlString(), tags);
|
||||
return _umbracoHelper.StripHtml(html, tags.ToArray());
|
||||
}
|
||||
public HtmlString StripHtml(DynamicNull html, List<string> tags)
|
||||
{
|
||||
@@ -524,12 +347,12 @@ namespace umbraco.MacroEngines.Library
|
||||
}
|
||||
public HtmlString StripHtml(string html, List<string> tags)
|
||||
{
|
||||
return StripHtmlTags(html, tags);
|
||||
return _umbracoHelper.StripHtml(html, tags.ToArray());
|
||||
}
|
||||
|
||||
public HtmlString StripHtml(IHtmlString html, params string[] tags)
|
||||
{
|
||||
return StripHtml(html.ToHtmlString(), tags.ToList());
|
||||
return _umbracoHelper.StripHtml(html, tags);
|
||||
}
|
||||
public HtmlString StripHtml(DynamicNull html, params string[] tags)
|
||||
{
|
||||
@@ -537,47 +360,8 @@ namespace umbraco.MacroEngines.Library
|
||||
}
|
||||
public HtmlString StripHtml(string html, params string[] tags)
|
||||
{
|
||||
return StripHtmlTags(html, tags.ToList());
|
||||
return _umbracoHelper.StripHtml(html, tags);
|
||||
}
|
||||
|
||||
private HtmlString StripHtmlTags(string html, List<string> tags)
|
||||
{
|
||||
HtmlDocument doc = new HtmlDocument();
|
||||
doc.LoadHtml("<p>" + html + "</p>");
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
{
|
||||
List<HtmlNode> targets = new List<HtmlNode>();
|
||||
|
||||
var nodes = doc.DocumentNode.FirstChild.SelectNodes(".//*");
|
||||
if (nodes != null)
|
||||
{
|
||||
foreach (var node in nodes)
|
||||
{
|
||||
//is element
|
||||
if (node.NodeType == HtmlNodeType.Element)
|
||||
{
|
||||
bool filterAllTags = (tags == null || tags.Count == 0);
|
||||
if (filterAllTags || tags.Any(tag => string.Equals(tag, node.Name, StringComparison.CurrentCultureIgnoreCase)))
|
||||
{
|
||||
targets.Add(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (var target in targets)
|
||||
{
|
||||
HtmlNode content = doc.CreateTextNode(target.InnerText);
|
||||
target.ParentNode.ReplaceChild(content, target);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return new HtmlString(html);
|
||||
}
|
||||
return new HtmlString(doc.DocumentNode.FirstChild.InnerHtml);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,6 +85,7 @@
|
||||
<Compile Include="RazorDynamicNode\DynamicBackingItem.cs" />
|
||||
<Compile Include="RazorDynamicNode\DynamicBackingItemType.cs" />
|
||||
<Compile Include="RazorDynamicNode\DynamicClass.cs" />
|
||||
<Compile Include="RazorDynamicNode\DynamicDocumentExtensions.cs" />
|
||||
<Compile Include="RazorDynamicNode\DynamicExpression.cs" />
|
||||
<Compile Include="RazorDynamicNode\DynamicGrouping.cs" />
|
||||
<Compile Include="RazorDynamicNode\DynamicMedia.cs">
|
||||
|
||||
Reference in New Issue
Block a user