diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Orchard.Blogs.csproj b/src/Orchard.Web/Modules/Orchard.Blogs/Orchard.Blogs.csproj index 215532f54..a2d862d84 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Orchard.Blogs.csproj +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Orchard.Blogs.csproj @@ -109,8 +109,12 @@ - - + + Designer + + + Designer + diff --git a/src/Orchard.Web/Modules/Orchard.DesignerTools/Orchard.DesignerTools.csproj b/src/Orchard.Web/Modules/Orchard.DesignerTools/Orchard.DesignerTools.csproj index 047e2118b..0b5eb5482 100644 --- a/src/Orchard.Web/Modules/Orchard.DesignerTools/Orchard.DesignerTools.csproj +++ b/src/Orchard.Web/Modules/Orchard.DesignerTools/Orchard.DesignerTools.csproj @@ -39,6 +39,7 @@ AllRules.ruleset + @@ -53,14 +54,16 @@ - + - + + Designer + @@ -78,6 +81,7 @@ + diff --git a/src/Orchard.Web/Modules/Orchard.DesignerTools/Scripts/orchard-designertools-shapetracing.js b/src/Orchard.Web/Modules/Orchard.DesignerTools/Scripts/orchard-designertools-shapetracing.js index 955564989..46342546b 100644 --- a/src/Orchard.Web/Modules/Orchard.DesignerTools/Scripts/orchard-designertools-shapetracing.js +++ b/src/Orchard.Web/Modules/Orchard.DesignerTools/Scripts/orchard-designertools-shapetracing.js @@ -1,18 +1,19 @@ (function($) { $(function() { - $("
  • shape templates
»
") + $("
  • shape templates
  • Zones
»
") .appendTo("body"); - $("#debug-shape-templates").click(function() { + $("#debug-shape-templates").click(function () { var _this = $(this); $("html").toggleClass(_this.attr("id")); $(this).toggleClass("debug-active"); }); - $("#debug-control-toggle").click(function() { + $("#debug-shape-zones").click(function () { + var _this = $(this); + $("html").toggleClass(_this.attr("id")); + $(this).toggleClass("debug-active"); + }); + $("#debug-control-toggle").click(function () { var _this = $(this), open = "debug-open"; - if (_this.is(":animated")) { - alert("aghhhh!"); - return; - } if (_this.is("."+open)) { _this.prev().hide("fast", function() {_this.removeClass(open).html("»");}); } else { diff --git a/src/Orchard.Web/Modules/Orchard.DesignerTools/Services/ObjectDumper.cs b/src/Orchard.Web/Modules/Orchard.DesignerTools/Services/ObjectDumper.cs new file mode 100644 index 000000000..3250f8740 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.DesignerTools/Services/ObjectDumper.cs @@ -0,0 +1,229 @@ +using System; +using System.Collections.Generic; +using System.Collections; +using System.Linq; +using System.Reflection; +using System.Xml.Linq; +using ClaySharp; +using ClaySharp.Behaviors; +using Orchard.DisplayManagement; + +namespace Orchard.DesignerTools.Services { + + public class ObjectDumper { + private const int MaxStringLength = 60; + + private readonly Stack _parents = new Stack(); + private readonly int _levels; + + private readonly XDocument _xdoc; + private XElement _node; + + public ObjectDumper(int levels) { + _levels = levels; + _xdoc = new XDocument(); + _xdoc.Add(_node = new XElement("ul")); + } + + public XElement Dump(object o, string name) { + // prevent cyclic references + if (_parents.Contains(o)) { + return _node; + } + + if(_parents.Count >= _levels) { + return _node; + } + + _parents.Push(o); + // starts a new container + _node.Add(_node = new XElement("li")); + + if(o == null) { + DumpValue(null, name); + } + else if (o.GetType().IsValueType || o is string) { + DumpValue(o, name); + } + else { + DumpObject(o, name); + } + + _parents.Pop(); + + if(_node.DescendantNodes().Count() == 0) { + _node.Remove(); + } + _node = _node.Parent; + + return _node; + } + + private void DumpValue(object o, string name) { + string formatted = FormatValue(o); + _node.Add( + new XElement("div", new XAttribute("class", "name"), name), + new XElement("div", new XAttribute("class", "value"), formatted) + ); + } + + private void DumpObject(object o, string name) { + if (_parents.Count >= _levels) { + _node.Add( + new XElement("div", new XAttribute("class", "name"), name), + new XElement("div", new XAttribute("class", "object last"), o) + ); + + return; + } + + _node.Add( + new XElement("div", new XAttribute("class", "name"), name), + new XElement("div", new XAttribute("class", "type"), FormatType(o.GetType())) + ); + + if (o is IDictionary) { + DumpDictionary((IDictionary)o); + } + else if (o is IShape) { + DumpShape((IShape)o); + + // a shape can also be IEnumerable + if (o is IEnumerable) { + DumpEnumerable((IEnumerable) o); + } + } + else if (o is IEnumerable) { + DumpEnumerable((IEnumerable)o); + } + else { + DumpMembers(o); + } + } + + private void DumpMembers(object o) { + var members = o.GetType() + .GetFields(BindingFlags.Instance | BindingFlags.Public).Cast() + .Union(o.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)) + .Where(m => !m.Name.StartsWith("_")) // remove members with a name starting with '_' (usually proxied objects) + .ToList(); + + if(members.Count() == 0) { + return; + } + + _node.Add(_node = new XElement("ul")); + foreach (var member in members) { + try { + DumpMember(o, member); + } + catch { + } + } + _node = _node.Parent; + } + + private void DumpEnumerable(IEnumerable enumerable) { + if(!enumerable.GetEnumerator().MoveNext()) { + return; + } + + _node.Add(_node = new XElement("ul")); + int i = 0; + foreach (var child in enumerable) { + Dump(child, string.Format("[{0}]", i++)); + } + + _node = _node.Parent; + } + + private void DumpDictionary(IDictionary dictionary) { + if (dictionary.Keys.Count == 0) { + return; + } + _node.Add(_node = new XElement("ul")); + foreach (var key in dictionary.Keys) { + Dump(dictionary[key], string.Format("[\"{0}\"]", key)); + } + _node = _node.Parent; + } + + private void DumpShape(IShape shape) { + + var b = ((IClayBehaviorProvider)(dynamic)shape).Behavior as ClayBehaviorCollection; + + if (b == null) + return; + + // seek the PropBehavior if exists + var propBehavior = b.OfType().FirstOrDefault(); + + if (propBehavior == null) + return; + + // retrieve the internal dictionary for properties + var props = propBehavior.GetType().GetField("_props", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetField).GetValue(propBehavior) as Dictionary; + + if (props == null) + return; + + if (props.Keys.Count == 0) { + return; + } + + _node.Add(_node = new XElement("ul")); + foreach (var key in props.Keys) { + Dump(props[key], key.ToString()); + } + _node = _node.Parent; + } + + private void DumpMember(object o, MemberInfo member) { + if (member is MethodInfo || member is ConstructorInfo || member is EventInfo) + return; + + if (member is FieldInfo) { + var field = (FieldInfo)member; + Dump(field.GetValue(o), member.Name); + } + else if (member is PropertyInfo) { + var prop = (PropertyInfo)member; + + if (prop.GetIndexParameters().Length == 0 && prop.CanRead) { + Dump(prop.GetValue(o, null), member.Name); + } + } + } + + private static string FormatValue(object o) { + if (o == null) + return "null"; + + var formatted = o.ToString(); + + if (o is string) { + // remove central part if tool long + if(formatted.Length > MaxStringLength) { + formatted = formatted.Substring(0, MaxStringLength/2) + "..." + formatted.Substring(formatted.Length - MaxStringLength/2); + } + + formatted = "\"" + formatted + "\""; + } + + return formatted; + } + + private static string FormatType(Type t) { + if(t.IsGenericType) { + var genericArguments = String.Join(", ", t.GetGenericArguments().Select(FormatType).ToArray()); + return String.Format("{0}<{1}>", t.Name.Substring(0, t.Name.IndexOf('`')), genericArguments); + } + + if(typeof(IShape).IsAssignableFrom(t)) { + return "Shape"; + } + + return t.Name; + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.DesignerTools/Services/ShapeTracingFactory.cs b/src/Orchard.Web/Modules/Orchard.DesignerTools/Services/ShapeTracingFactory.cs index c737e4d50..63671340d 100644 --- a/src/Orchard.Web/Modules/Orchard.DesignerTools/Services/ShapeTracingFactory.cs +++ b/src/Orchard.Web/Modules/Orchard.DesignerTools/Services/ShapeTracingFactory.cs @@ -8,7 +8,9 @@ namespace Orchard.DesignerTools.Services { } public void Created(ShapeCreatedContext context) { - if (context.ShapeType != "Layout" && context.ShapeType != "DocumentZone") { + if (context.ShapeType != "Layout" + && context.ShapeType != "DocumentZone" + ) { context.Shape.Metadata.Wrappers.Add("ShapeTracing_Wrapper"); } } diff --git a/src/Orchard.Web/Modules/Orchard.DesignerTools/Styles/orchard-designertools-shapetracing.css b/src/Orchard.Web/Modules/Orchard.DesignerTools/Styles/orchard-designertools-shapetracing.css index 2c2bf0874..fc6a1fda1 100644 --- a/src/Orchard.Web/Modules/Orchard.DesignerTools/Styles/orchard-designertools-shapetracing.css +++ b/src/Orchard.Web/Modules/Orchard.DesignerTools/Styles/orchard-designertools-shapetracing.css @@ -16,7 +16,7 @@ color:yellow; } #debug-control .debug-active { - color:greenyellow; + color:Lime; } #debug-control ul { display:none; @@ -36,11 +36,45 @@ #debug-control li { border-right:1px solid #999; } -html.debug-shape-templates .shapeTracingWrapper { + +.debug-shape-templates .shape-tracing .wrapper { background:#FFF; border:1px dotted #CA7230; - padding:5px; + padding:2px; } -html.debug-shape-templates .shapeTracingWrapper:hover { + +.debug-shape-templates .shape-tracing .wrapper :hover { background:#E0E9EE; +} + +.shape-tracing .meta { + display:none; +} + +.debug-shape-templates .shape-tracing .meta { + clear:both; + display:block; + background:#cfc; + font-size:9pt; + font-family:Segoe; + color:black; + margin-top:5px; +} + +.debug-shape-zones .shape-tracing .wrapper .zone { + border:1px dotted red; + margin:5px; + padding:2px; +} + +.meta .shape { + color:black; +} + +.meta .alternates { + color:red; +} + +.meta .wrappers { + color:green; } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.DesignerTools/Views/ShapeTracing.Wrapper.cshtml b/src/Orchard.Web/Modules/Orchard.DesignerTools/Views/ShapeTracing.Wrapper.cshtml index 4d7b9c9e7..26c41b77c 100644 --- a/src/Orchard.Web/Modules/Orchard.DesignerTools/Views/ShapeTracing.Wrapper.cshtml +++ b/src/Orchard.Web/Modules/Orchard.DesignerTools/Views/ShapeTracing.Wrapper.cshtml @@ -1,24 +1,59 @@ @using Orchard; @using Orchard.DisplayManagement.Descriptors; +@using Orchard.DesignerTools.Services; +@using System.Xml; + @{ - Script.Require("jQuery"); - Script.Include("orchard-designertools-shapetracing.js"); - Style.Include("orchard-designertools-shapetracing.css"); + Script.Require("jQuery"); + Script.Include("tooltip.min.js"); + Script.Include("orchard-designertools-shapetracing.js"); + Style.Include("orchard-designertools-shapetracing.css"); var workContext = ViewContext.GetWorkContext(); var shapeTable = workContext.Resolve().GetShapeTable(workContext.CurrentTheme.Id); - var descriptor = shapeTable.Descriptors[Model.Metadata.Type]; + var descriptor = shapeTable.Descriptors[Model.Metadata.Type]; +} +@functions { + string FormatShape(string type, string themeId) { + return "~/Themes/" + themeId + "/Views/" + type.Replace("__", "-").Replace("_", ".") + ".cshtml"; + } + + string DumpObject(object o) { + var dumper = new ObjectDumper(6); + var el = dumper.Dump(o, "Model"); + using(var sw = new StringWriter()) { + el.WriteTo(new XmlTextWriter(sw) { Formatting = Formatting.Indented }); + return sw.ToString(); + } + } } -
-@Display(Model.Metadata.ChildContent) +
+ @Display(Model.Metadata.ChildContent) -@foreach(var alternate in Model.Metadata.Alternates) { -
@alternate
-} -@foreach(var wrapper in Model.Metadata.Wrappers) { - if(wrapper != "ShapeTracing_Wrapper") { -
@wrapper
- } -} -
\ No newline at end of file +
+
+ Shape: @Model.Metadata.Type
+ Definition: @descriptor.BindingSource
+ Display Type: @(Model.Metadata.DisplayType ?? "n/a")
+ Position: @(Model.Metadata.Position ?? "n/a")
+
+ +
+ @foreach(var alternate in Model.Metadata.Alternates) { + var formatted = @FormatShape(alternate, workContext.CurrentTheme.Id); +
@formatted
+ } +
+
+ @foreach(var wrapper in Model.Metadata.Wrappers) { + if(wrapper != "ShapeTracing_Wrapper") { +
@wrapper
+ } + } +
+
+
@DumpObject((object)Model)
+
+
+
diff --git a/src/Orchard.Web/Modules/Orchard.DesignerTools/Web.config b/src/Orchard.Web/Modules/Orchard.DesignerTools/Web.config index 5884c5879..95c16e1b4 100644 --- a/src/Orchard.Web/Modules/Orchard.DesignerTools/Web.config +++ b/src/Orchard.Web/Modules/Orchard.DesignerTools/Web.config @@ -32,6 +32,7 @@ + diff --git a/src/Orchard/ContentManagement/DefaultContentDisplay.cs b/src/Orchard/ContentManagement/DefaultContentDisplay.cs index 2f59d16c5..6fb975cc0 100644 --- a/src/Orchard/ContentManagement/DefaultContentDisplay.cs +++ b/src/Orchard/ContentManagement/DefaultContentDisplay.cs @@ -109,7 +109,7 @@ namespace Orchard.ContentManagement { ContentType = context.ContentItem.ContentType, DisplayType = displayType, Differentiator = differentiator, - Path = request.Path.Substring((request.ApplicationPath ?? "").Length) + Path = request.Path.Substring((request.ApplicationPath ?? "").Length) // get the current app-relative path, i.e. /my-blog }; var location = descriptor.Placement(placementContext); return location ?? defaultLocation;