mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-04-05 21:01:35 +08:00
Dumping the model in Shape Tracing
--HG-- branch : dev
This commit is contained in:
parent
2d890f54a0
commit
b7d8e56398
@ -109,8 +109,12 @@
|
||||
<Content Include="Scripts\orchard-blogs-archives.js" />
|
||||
<Content Include="Styles\orchard-blogs-admin.css" />
|
||||
<Content Include="Styles\orchard-blogs-archives.css" />
|
||||
<Content Include="Views\BlogAdmin\Create.cshtml" />
|
||||
<Content Include="Views\BlogAdmin\Edit.cshtml" />
|
||||
<Content Include="Views\BlogAdmin\Create.cshtml">
|
||||
<SubType>Designer</SubType>
|
||||
</Content>
|
||||
<Content Include="Views\BlogAdmin\Edit.cshtml">
|
||||
<SubType>Designer</SubType>
|
||||
</Content>
|
||||
<Content Include="Views\BlogAdmin\Item.cshtml" />
|
||||
<Content Include="Views\BlogAdmin\List.cshtml" />
|
||||
<Content Include="Views\BlogPostAdmin\Create.cshtml" />
|
||||
|
@ -39,6 +39,7 @@
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="ClaySharp, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
@ -53,14 +54,16 @@
|
||||
<Reference Include="System.Web" />
|
||||
<Reference Include="System.Web.Abstractions" />
|
||||
<Reference Include="System.Web.Routing" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Scripts\orchard-designertools-shapetracing.js" />
|
||||
<Content Include="Styles\orchard-designertools-shapetracing.css" />
|
||||
<Content Include="Web.config" />
|
||||
<Content Include="Web.config">
|
||||
<SubType>Designer</SubType>
|
||||
</Content>
|
||||
<Content Include="Views\Web.config" />
|
||||
<Content Include="Scripts\Web.config" />
|
||||
<Content Include="Styles\Web.config" />
|
||||
@ -78,6 +81,7 @@
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Services\ObjectDumper.cs" />
|
||||
<Compile Include="Services\ShapeTracingFactory.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -1,18 +1,19 @@
|
||||
(function($) {
|
||||
$(function() {
|
||||
$("<div id='debug-control'><ul><li id='debug-shape-templates'>shape templates</li></ul><div id='debug-control-toggle'>»</div></div>")
|
||||
$("<div id='debug-control'><ul><li id='debug-shape-templates'>shape templates</li><li id='debug-shape-zones'>Zones</li></ul><div id='debug-control-toggle'>»</div></div>")
|
||||
.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 {
|
||||
|
@ -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<object> _parents = new Stack<object>();
|
||||
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<MemberInfo>()
|
||||
.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<PropBehavior>().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<object, object>;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
@ -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<IShapeTableManager>().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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
<div class="shapeTracingWrapper" title="@Model.Metadata.Type @descriptor.BindingSource">
|
||||
@Display(Model.Metadata.ChildContent)
|
||||
<div class="shape-tracing wrapper @Model.Metadata.Type">
|
||||
@Display(Model.Metadata.ChildContent)
|
||||
|
||||
@foreach(var alternate in Model.Metadata.Alternates) {
|
||||
<div style="color:red">@alternate</div>
|
||||
}
|
||||
@foreach(var wrapper in Model.Metadata.Wrappers) {
|
||||
if(wrapper != "ShapeTracing_Wrapper") {
|
||||
<div style="color:green">@wrapper</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
<div class="shape-tracing meta">
|
||||
<div class="shape">
|
||||
Shape: @Model.Metadata.Type <br />
|
||||
Definition: @descriptor.BindingSource <br />
|
||||
Display Type: @(Model.Metadata.DisplayType ?? "n/a")<br />
|
||||
Position: @(Model.Metadata.Position ?? "n/a") <br />
|
||||
</div>
|
||||
|
||||
<div class="alternates">
|
||||
@foreach(var alternate in Model.Metadata.Alternates) {
|
||||
var formatted = @FormatShape(alternate, workContext.CurrentTheme.Id);
|
||||
<div>@formatted</div>
|
||||
}
|
||||
</div>
|
||||
<div class="wrappers">
|
||||
@foreach(var wrapper in Model.Metadata.Wrappers) {
|
||||
if(wrapper != "ShapeTracing_Wrapper") {
|
||||
<div>@wrapper</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
<div class="dump">
|
||||
<pre>@DumpObject((object)Model)</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -32,6 +32,7 @@
|
||||
<add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
|
||||
<add assembly="System.Data.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
|
||||
<add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
|
||||
<add assembly="System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
</assemblies>
|
||||
</compilation>
|
||||
</system.web>
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user