diff --git a/src/Umbraco.Core/Dynamics/DynamicDocument.cs b/src/Umbraco.Core/Dynamics/DynamicDocument.cs index 89b714a961..abe26aa058 100644 --- a/src/Umbraco.Core/Dynamics/DynamicDocument.cs +++ b/src/Umbraco.Core/Dynamics/DynamicDocument.cs @@ -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 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; } } diff --git a/src/Umbraco.Core/Dynamics/DynamicDocumentWalker.cs b/src/Umbraco.Core/Dynamics/DynamicDocumentWalker.cs index 3a1ca1398d..9f52378dce 100644 --- a/src/Umbraco.Core/Dynamics/DynamicDocumentWalker.cs +++ b/src/Umbraco.Core/Dynamics/DynamicDocumentWalker.cs @@ -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); diff --git a/src/Umbraco.Core/Dynamics/DynamicNull.cs b/src/Umbraco.Core/Dynamics/DynamicNull.cs index 5139df17b6..0788e68923 100644 --- a/src/Umbraco.Core/Dynamics/DynamicNull.cs +++ b/src/Umbraco.Core/Dynamics/DynamicNull.cs @@ -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() { diff --git a/src/Umbraco.Web/DefaultPublishedMediaStore.cs b/src/Umbraco.Web/DefaultPublishedMediaStore.cs index 831c65f06b..0a5a3f853c 100644 --- a/src/Umbraco.Web/DefaultPublishedMediaStore.cs +++ b/src/Umbraco.Web/DefaultPublishedMediaStore.cs @@ -14,6 +14,9 @@ namespace Umbraco.Web /// /// An IPublishedMediaStore that first checks for the media in Examine, and then reverts to the database /// + /// + /// 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. + /// 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(); } diff --git a/src/Umbraco.Web/DynamicDocumentSearchExtensions.cs b/src/Umbraco.Web/DynamicDocumentSearchExtensions.cs index 8f9773bec9..ebac0d8160 100644 --- a/src/Umbraco.Web/DynamicDocumentSearchExtensions.cs +++ b/src/Umbraco.Web/DynamicDocumentSearchExtensions.cs @@ -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 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; - } + } } \ No newline at end of file diff --git a/src/Umbraco.Web/ExamineExtensions.cs b/src/Umbraco.Web/ExamineExtensions.cs new file mode 100644 index 0000000000..36976dfe7d --- /dev/null +++ b/src/Umbraco.Web/ExamineExtensions.cs @@ -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 +{ + /// + /// Extension methods for Examine + /// + internal static class ExamineExtensions + { + internal static DynamicDocumentList ConvertSearchResultToDynamicDocument( + this IEnumerable 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; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/PublishedContentStoreResolver.cs b/src/Umbraco.Web/PublishedContentStoreResolver.cs index e8450efe43..0e0f049443 100644 --- a/src/Umbraco.Web/PublishedContentStoreResolver.cs +++ b/src/Umbraco.Web/PublishedContentStoreResolver.cs @@ -3,7 +3,7 @@ using Umbraco.Core.ObjectResolution; namespace Umbraco.Web { /// - /// An object resolver to return the IContentStore + /// An object resolver to return the IPublishedContentStore /// internal class PublishedContentStoreResolver : SingleObjectResolverBase { diff --git a/src/Umbraco.Web/PublishedMediaStoreResolver.cs b/src/Umbraco.Web/PublishedMediaStoreResolver.cs new file mode 100644 index 0000000000..e3a7dc3bac --- /dev/null +++ b/src/Umbraco.Web/PublishedMediaStoreResolver.cs @@ -0,0 +1,32 @@ +using Umbraco.Core.ObjectResolution; + +namespace Umbraco.Web +{ + /// + /// An object resolver to return the IPublishedMediaStore + /// + internal class PublishedMediaStoreResolver : SingleObjectResolverBase + { + internal PublishedMediaStoreResolver(IPublishedMediaStore publishedMediaStore) + : base(publishedMediaStore) + { + } + + /// + /// Can be used by developers at runtime to set their IContentStore at app startup + /// + /// + public void SetContentStore(IPublishedMediaStore publishedMediaStore) + { + Value = publishedMediaStore; + } + + /// + /// Returns the IContentStore + /// + public IPublishedMediaStore PublishedMediaStore + { + get { return Value; } + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index d4c57a793f..7cd33581d8 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -245,6 +245,7 @@ + ASPXCodeBehind @@ -262,6 +263,7 @@ + diff --git a/src/Umbraco.Web/UmbracoHelper.cs b/src/Umbraco.Web/UmbracoHelper.cs index abbdd0324a..e4bc97ba8a 100644 --- a/src/Umbraco.Web/UmbracoHelper.cs +++ b/src/Umbraco.Web/UmbracoHelper.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 { + /// /// A helper class that provides many useful methods and functionality for using Umbraco in templates /// @@ -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(x)) + .Cast(); + return new DynamicDocumentList(nodes); + } + + private dynamic DocumentByIds(IPublishedStore store, params string[] ids) + { + var nodes = ids.Select(eachId => DocumentById(eachId, store)) + .Where(x => !TypeHelper.IsTypeAssignableFrom(x)) + .Cast(); + return new DynamicDocumentList(nodes); + } + + #endregion + + #region Search + + /// + /// Searches content + /// + /// + /// + /// + /// + 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); + } + + /// + /// Searhes content + /// + /// + /// + /// + 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("

" + html + "

"); + using (var ms = new MemoryStream()) + { + var targets = new List(); + + 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(args); + } + + internal string Coalesce(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(args); + } + + internal string Concatenate(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(seperator, args); + } + + internal string Join(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(); + 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(""); + } + 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 } } diff --git a/src/Umbraco.Web/WebBootManager.cs b/src/Umbraco.Web/WebBootManager.cs index 1887d0151c..25b8a8617e 100644 --- a/src/Umbraco.Web/WebBootManager.cs +++ b/src/Umbraco.Web/WebBootManager.cs @@ -134,6 +134,7 @@ namespace Umbraco.Web PropertyEditorValueConvertersResolver.Current.AddType(); 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 diff --git a/src/umbraco.MacroEngines/RazorDynamicNode/DynamicDocumentExtensions.cs b/src/umbraco.MacroEngines/RazorDynamicNode/DynamicDocumentExtensions.cs new file mode 100644 index 0000000000..bbafe791aa --- /dev/null +++ b/src/umbraco.MacroEngines/RazorDynamicNode/DynamicDocumentExtensions.cs @@ -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 +{ + /// + /// Extension methods for converting DynamicDocument to INode + /// + 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 PropertiesAsList + { + get { return _doc.Properties.Select(ConvertToNodeProperty).ToList(); } + } + public List ChildrenAsList + { + get { return _doc.Children.Select(x => x.ConvertToNode()).ToList(); } + } + public IProperty GetProperty(string Alias) + { + return PropertiesAsList.Cast().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(); + } + } + } +} \ No newline at end of file diff --git a/src/umbraco.MacroEngines/RazorDynamicNode/RazorLibraryCore.cs b/src/umbraco.MacroEngines/RazorDynamicNode/RazorLibraryCore.cs index 8aaeafec60..e2983c2685 100644 --- a/src/umbraco.MacroEngines/RazorDynamicNode/RazorLibraryCore.cs +++ b/src/umbraco.MacroEngines/RazorDynamicNode/RazorLibraryCore.cs @@ -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(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(args); } public string Join(string seperator, params object[] args) { - List results = new List(); - 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(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 tagStack = new Stack(); - 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(""); - } - 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)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)null); + return _umbracoHelper.StripHtml(html); } public HtmlString StripHtml(IHtmlString html, List tags) { - return StripHtml(html.ToHtmlString(), tags); + return _umbracoHelper.StripHtml(html, tags.ToArray()); } public HtmlString StripHtml(DynamicNull html, List tags) { @@ -524,12 +347,12 @@ namespace umbraco.MacroEngines.Library } public HtmlString StripHtml(string html, List 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 tags) - { - HtmlDocument doc = new HtmlDocument(); - doc.LoadHtml("

" + html + "

"); - using (MemoryStream ms = new MemoryStream()) - { - List targets = new List(); - - 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); - } - } - - } } diff --git a/src/umbraco.MacroEngines/umbraco.MacroEngines.csproj b/src/umbraco.MacroEngines/umbraco.MacroEngines.csproj index 4e1d9bc4d8..58786d2ce8 100644 --- a/src/umbraco.MacroEngines/umbraco.MacroEngines.csproj +++ b/src/umbraco.MacroEngines/umbraco.MacroEngines.csproj @@ -85,6 +85,7 @@ +