Providing designer notes html for zones

IZoneManagerEvents interface added to inject designer notes in empty zones
Static html file matching zone names displayed when nothing else is in that location
An Edit link simulates the look of an html widget
Clicking it creates a widget with the designer notes html
Code that calculates media path refactored and moved to viewmodel state

--HG--
branch : dev
This commit is contained in:
Louis DeJardin
2010-03-06 01:25:17 -08:00
parent dab326c267
commit 0320862826
20 changed files with 271 additions and 96 deletions

View File

@@ -1,6 +1,8 @@
using System.Text.RegularExpressions;
using System;
using System.Text.RegularExpressions;
using JetBrains.Annotations;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Aspects;
using Orchard.ContentManagement.Drivers;
using Orchard.Core.Common.Models;
using Orchard.Core.Common.ViewModels;
@@ -17,7 +19,7 @@ namespace Orchard.Core.Common.Drivers {
}
protected override string Prefix {
get {return "Body";}
get { return "Body"; }
}
// \/\/ Haackalicious on many accounts - don't copy what has been done here for the wrapper \/\/
@@ -30,18 +32,77 @@ namespace Orchard.Core.Common.Drivers {
ContentPartTemplate(model, TemplateName, Prefix).LongestMatch(displayType, "Summary", "SummaryAdmin").Location("primary", "5"),
Services.Authorizer.Authorize(Permissions.ChangeOwner) ? ContentPartTemplate(model, "Parts/Common.Body.ManageWrapperPost").Location("primary", "5") : null);
}
protected override DriverResult Editor(BodyAspect part) {
var model = new BodyEditorViewModel { BodyAspect = part, TextEditorTemplate = DefaultTextEditorTemplate };
var model = BuildEditorViewModel(part);
return ContentPartTemplate(model, TemplateName, Prefix).Location("primary", "5");
}
protected override DriverResult Editor(BodyAspect part, IUpdateModel updater) {
var model = new BodyEditorViewModel { BodyAspect = part, TextEditorTemplate = DefaultTextEditorTemplate };
var model = BuildEditorViewModel(part);
updater.TryUpdateModel(model, Prefix, null, null);
return ContentPartTemplate(model, TemplateName, Prefix).Location("primary", "5");
}
private static BodyEditorViewModel BuildEditorViewModel(BodyAspect part) {
return new BodyEditorViewModel {
BodyAspect = part,
TextEditorTemplate = DefaultTextEditorTemplate,
AddMediaPath= new PathBuilder(part).AddContentType().AddContainerSlug().AddSlug().ToString()
};
}
class PathBuilder {
private readonly IContent _content;
private string _path;
public PathBuilder(IContent content) {
_content = content;
_path = "";
}
public override string ToString() {
return _path;
}
public PathBuilder AddContentType() {
Add(_content.ContentItem.ContentType);
return this;
}
public PathBuilder AddContainerSlug() {
var common = _content.As<ICommonAspect>();
if (common == null)
return this;
var routable = common.Container.As<RoutableAspect>();
if (routable == null)
return this;
Add(routable.Slug);
return this;
}
public PathBuilder AddSlug() {
var routable = _content.As<RoutableAspect>();
if (routable == null)
return this;
Add(routable.Slug);
return this;
}
private void Add(string segment) {
if (string.IsNullOrEmpty(segment))
return;
if (string.IsNullOrEmpty(_path))
_path = segment;
else
_path = _path + "/" + segment;
}
}
// Can be moved somewhere else once we have IoC enabled body text filters.
private static string BbcodeReplace(string bodyText) {
Regex urlRegex = new Regex(@"\[url\]([^\]]+)\[\/url\]");

View File

@@ -15,5 +15,6 @@ namespace Orchard.Core.Common.ViewModels {
}
public string TextEditorTemplate { get; set; }
public string AddMediaPath { get; set; }
}
}

View File

@@ -131,6 +131,7 @@
<Compile Include="Scheduling\Models\Task.cs" />
<Compile Include="Settings\Drivers\SiteSettingsDriver.cs" />
<Compile Include="Settings\Permissions.cs" />
<Compile Include="Themes\DesignerNotes\ZoneManagerEvents.cs" />
<Compile Include="Themes\Preview\IPreviewTheme.cs" />
<Compile Include="Themes\Preview\PreviewThemeFilter.cs" />
<Compile Include="Themes\Preview\PreviewTheme.cs" />

View File

@@ -0,0 +1,61 @@
using System.IO;
using System.Linq;
using System.Web.Mvc.Html;
using Orchard.Security;
using Orchard.Themes;
using Orchard.UI.Zones;
namespace Orchard.Core.Themes.DesignerNotes {
public class ZoneManagerEvents : IZoneManagerEvents {
private readonly IThemeService _themeService;
private readonly IAuthorizationService _authorizationService;
public ZoneManagerEvents(IThemeService themeService, IAuthorizationService authorizationService) {
_themeService = themeService;
_authorizationService = authorizationService;
}
public virtual IUser CurrentUser { get; set; }
public void ZoneRendering(ZoneRenderContext context) {
if (context.RenderingItems.Any())
return;
var requestContext = context.Html.ViewContext.RequestContext;
var theme = _themeService.GetRequestTheme(requestContext);
var virtualPath = "~/Themes/" + theme.ThemeName + "/DesignerNotes/" + context.ZoneName + ".html";
var physicalPath = requestContext.HttpContext.Server.MapPath(virtualPath);
if (!File.Exists(physicalPath))
return;
var accessAdminPanel = _authorizationService.TryCheckAccess(
StandardPermissions.AccessAdminPanel, CurrentUser, null);
var writer = context.Html.ViewContext.Writer;
if (accessAdminPanel) {
writer.Write("<div class=\"managewrapper\"><div class=\"manage\">");
writer.Write(context.Html.ActionLink("Edit", "AddWidget", new {
Area = "Futures.Widgets",
Controller = "Admin",
context.ZoneName,
theme.ThemeName,
ReturnUrl = requestContext.HttpContext.Request.Url,
}));
writer.Write("</div>");
}
writer.Write(File.ReadAllText(physicalPath));
if (accessAdminPanel) {
writer.Write("</div>");
}
}
public void ZoneItemRendering(ZoneRenderContext context, ZoneItem item) {
}
public void ZoneItemRendered(ZoneRenderContext context, ZoneItem item) {
}
public void ZoneRendered(ZoneRenderContext context) {
}
}
}

View File

@@ -1,5 +1,4 @@
using System;
using System.Web.Mvc;
using System.Web.Mvc;
using Futures.Widgets.Models;
using Futures.Widgets.ViewModels;
using Orchard;
@@ -7,28 +6,39 @@ using Orchard.ContentManagement;
using Orchard.Core.Common.Models;
using Orchard.Localization;
using Orchard.Settings;
using Orchard.UI.Notify;
namespace Futures.Widgets.Controllers {
[ValidateInput(false)]
public class AdminController : Controller, IUpdateModel {
public AdminController(IOrchardServices services) {
Services = services;
T = NullLocalizer.Instance;
}
private IOrchardServices Services { get; set; }
protected virtual ISite CurrentSite { get; set; }
public Localizer T{ get; set;}
public ActionResult AddWidget() {
public ActionResult AddWidget(string zoneName, string themeName, string returnUrl) {
var hasWidgetsRecord = CurrentSite.As<HasWidgets>().Record;
var virtualPath = "~/Themes/" + themeName + "/DesignerNotes/" + zoneName + ".html";
var physicalPath = Server.MapPath(virtualPath);
if (!System.IO.File.Exists(physicalPath)) {
Services.Notifier.Error(T("Designer notes not found."));
return Redirect(returnUrl);
}
var widget = Services.ContentManager.Create<Widget>("HtmlWidget", init => {
init.Record.Scope = hasWidgetsRecord;
init.Record.Zone = "content";
init.Record.Position = "after";
init.As<BodyAspect>().Text = "Hello world!";
init.Record.Zone = zoneName;
init.Record.Position = "1";
init.As<BodyAspect>().Text = System.IO.File.ReadAllText(physicalPath);
});
return RedirectToAction("Edit", new {widget.ContentItem.Id });
return RedirectToAction("Edit", new { widget.ContentItem.Id, returnUrl });
}
public ActionResult Edit(int id, string returnUrl) {

View File

@@ -1,22 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using Orchard.Core.Common.Models;
using Orchard.Core.Common.ViewModels;
using Orchard.Extensions;
using Orchard.Mvc.Html;
namespace TinyMce.Extensions {
public static class HtmlHelperExtensions {
public static string GetCurrentMediaPath(this HtmlHelper<BodyEditorViewModel> htmlHelper) {
var body = htmlHelper.ViewData.Model.BodyAspect;
var currentDriver = htmlHelper.Resolve<IEnumerable<IContentItemDriver>>().Where(cid => cid.GetContentTypes().Any(ct => string.Compare(ct.Name, body.ContentItem.ContentType, true) == 0)).FirstOrDefault();
var currentModule = htmlHelper.Resolve<IExtensionManager>().ActiveExtensions().FirstOrDefault(ee => ee.Descriptor.ExtensionType == "Module" && ee.Assembly == currentDriver.GetType().Assembly);
var routable = body.ContentItem.Has<RoutableAspect>() ? body.ContentItem.As<RoutableAspect>() : null;
return string.Format("{0}{1}", currentModule.Descriptor.Name, routable != null && !string.IsNullOrEmpty(routable.ContainerPath) ? "/" + routable.ContainerPath : "");
}
}
}

View File

@@ -122,7 +122,6 @@
<Content Include="Scripts\utils\validate.js" />
</ItemGroup>
<ItemGroup>
<Compile Include="Extensions\HtmlHelperExtensions.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>

View File

@@ -19,7 +19,7 @@ using (this.Capture("end-of-page-scripts")) {%>
theme_advanced_buttons3: "",
convert_urls: false,
addmedia_action: "<%=Url.Action("AddFromClient", "Admin", new {area = "Orchard.Media"}) %>",
addmedia_path: "<%=Html.GetCurrentMediaPath() %>",
addmedia_path: "<%= Model.AddMediaPath %>",
request_verification_token: "<%=Html.AntiForgeryTokenValueOrchard() %>"
});
</script><%

View File

@@ -170,6 +170,7 @@
<Content Include="Themes\Classic\Content\Images\mainBackgroundgrey.png" />
<Content Include="Themes\Classic\Content\Images\navDivider.gif" />
<Content Include="Themes\Classic\Content\Images\sidebarBackground.gif" />
<Content Include="Themes\Classic\DesignerNotes\Sidebar.html" />
<Content Include="Themes\Classic\Styles\blog.css" />
<Content Include="Themes\Classic\Styles\site.css" />
<Content Include="Themes\Classic\Theme.png" />
@@ -192,6 +193,10 @@
<Content Include="Themes\Green\Content\Images\tabLeftOn.gif" />
<Content Include="Themes\Green\Content\Images\tabRightOff.gif" />
<Content Include="Themes\Green\Content\Images\tabRightOn.gif" />
<Content Include="Themes\Green\DesignerNotes\Sidebar.html" />
<Content Include="Themes\Green\DesignerNotes\User2.html" />
<Content Include="Themes\Green\DesignerNotes\User3.html" />
<Content Include="Themes\Green\DesignerNotes\User1.html" />
<Content Include="Themes\Green\Styles\blog.css" />
<Content Include="Themes\Green\Styles\site.css" />
<Content Include="Themes\Green\Styles\yui.css" />

View File

@@ -0,0 +1,8 @@
<ul>
<li>
<h3>Heading</h3>
</li>
<li>
<p class="small">Paragraph - Small</p>
</li>
</ul>

View File

@@ -33,16 +33,7 @@
<%Html.ZoneBody("content");%>
</div>
<div id="sidebar">
<ul>
<li>
<h3>
Heading</h3>
</li>
<li>
<p class="small">
Paragraph - Small</p>
</li>
</ul>
<%Html.Zone("sidebar");%>
</div>
<%-- End Content --%>
<% Html.Include("Footer"); %>

View File

@@ -0,0 +1,25 @@
<h3>Sidebar</h3>
<ul>
<li>
<h4>Item 1</h4>
</li>
<li>
<p class="small">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas adipiscing dolor
vel nunc molestie laoreet. Curabitur vitae elit et massa consequat interdum. Curabitur
blandit leo nec magna dictum vitae mollis tellus gravida. Morbi non condimentum
neque. Suspendisse commodo condimentum feugiat. Class aptent taciti sociosqu ad
litora torquent per conubia nostra, per inceptos himenaeos.</p>
</li>
<li>
<h4>Item 2</h4>
</li>
<li>
<p class="small">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas adipiscing dolor
vel nunc molestie laoreet. Curabitur vitae elit et massa consequat interdum. Curabitur
blandit leo nec magna dictum vitae mollis tellus gravida. Morbi non condimentum
neque. Suspendisse commodo condimentum feugiat. Class aptent taciti sociosqu ad
litora torquent per conubia nostra, per inceptos himenaeos.</p>
</li>
</ul>

View File

@@ -0,0 +1,3 @@
<h5>About Your Site</h5>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam nec nisi vel eros ornare auctor. Aenean vitae nulla. Sed in velit sit amet metus sollicitudin porttitor. Fusce non tortor. Nunc ornare imperdiet mauris. Nulla facilisi. In hac habitasse platea dictumst. Praesent pellentesque iaculis orci. Ut imperdiet dolor non turpis. In hac habitasse platea dictumst. <a href="#">More...</a>
</p>

View File

@@ -0,0 +1,8 @@
<h5>Lorem ipsum</h5>
<ul class="square">
<li><a href="#">Lorem ipsum</a></li>
<li><a href="#">Lorem ipsum</a></li>
<li><a href="#">Lorem ipsum</a></li>
<li><a href="#">Lorem ipsum</a></li>
<li>Lorem ipsum</li>
</ul>

View File

@@ -0,0 +1,8 @@
<h5>Lorem ipsum</h5>
<ul class="square">
<li><a href="#">Lorem ipsum</a></li>
<li><a href="#">Lorem ipsum</a></li>
<li><a href="#">Lorem ipsum</a></li>
<li><a href="#">Lorem ipsum</a></li>
<li>Lorem ipsum</li>
</ul>

View File

@@ -1,38 +1,17 @@
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<%--
--%>
<div id="ft" role="contentinfo">
<div id="innerft" class="yui-g">
<div class="yui-u first">
<h5>About <%=Html.Encode(Html.SiteName()) %></h5>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam nec nisi vel eros ornare auctor. Aenean vitae nulla. Sed in velit sit amet metus sollicitudin porttitor. Fusce non tortor. Nunc ornare imperdiet mauris. Nulla facilisi. In hac habitasse platea dictumst. Praesent pellentesque iaculis orci. Ut imperdiet dolor non turpis. In hac habitasse platea dictumst. <a href="#">More...</a>
</p>
</div>
<div class="yui-g">
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<BaseViewModel>" %>
<%@ Import Namespace="Orchard.Mvc.ViewModels" %>
<div id="ft" role="contentinfo">
<div id="innerft" class="yui-g">
<div class="yui-u first">
<h5>Lorem ipsum</h5>
<ul class="square">
<li><a href="#">Lorem ipsum</a></li>
<li><a href="#">Lorem ipsum</a></li>
<li><a href="#">Lorem ipsum</a></li>
<li><a href="#">Lorem ipsum</a></li>
<li>Lorem ipsum</li>
</ul>
</div>
<div class="yui-u">
<h5>Lorem ipsum</h5>
<ul class="square">
<li><a href="#">Lorem ipsum</a></li>
<li><a href="#">Lorem ipsum</a></li>
<li><a href="#">Lorem ipsum</a></li>
<li><a href="#">Lorem ipsum</a></li>
<li><a href="#">Lorem ipsum</a></li>
</ul>
<%Html.Zone("User1"); %>
</div>
<div class="yui-g">
<div class="yui-u first">
<%Html.Zone("User2"); %>
</div>
<div class="yui-u">
<%Html.Zone("User3"); %>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@@ -40,15 +40,7 @@
</div>
</div>
<div id="subcolumn" class="yui-b">
<h3>Sidebar</h3>
<ul>
<li><h4>Item 1</h4></li>
<li><p class="small">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas adipiscing dolor vel nunc molestie laoreet. Curabitur vitae elit et massa consequat interdum. Curabitur blandit leo nec magna dictum vitae mollis tellus gravida. Morbi non condimentum neque. Suspendisse commodo condimentum feugiat. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.</p></li>
<li><h4>Item 2</h4></li>
<li><p class="small">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas adipiscing dolor vel nunc molestie laoreet. Curabitur vitae elit et massa consequat interdum. Curabitur blandit leo nec magna dictum vitae mollis tellus gravida. Morbi non condimentum neque. Suspendisse commodo condimentum feugiat. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.</p></li>
</ul>
<%Html.Zone("sidebar"); %>
</div>
</div>
<%-- End Content --%>

View File

@@ -311,6 +311,7 @@
<Compile Include="UI\Zones\IZoneManager.cs" />
<Compile Include="UI\Zones\ContentPartDisplayZoneItem.cs" />
<Compile Include="UI\Zones\ContentPartEditorZoneItem.cs" />
<Compile Include="UI\Zones\IZoneManagerEvents.cs" />
<Compile Include="UI\Zones\RenderActionZoneItem.cs" />
<Compile Include="UI\Zones\RenderPartialZoneItem.cs" />
<Compile Include="UI\Zones\RenderStaticZoneItem.cs" />

View File

@@ -0,0 +1,18 @@
using System.Collections.Generic;
using System.Web.Mvc;
namespace Orchard.UI.Zones {
public interface IZoneManagerEvents : IEvents {
void ZoneRendering(ZoneRenderContext context);
void ZoneItemRendering(ZoneRenderContext context, ZoneItem item);
void ZoneItemRendered(ZoneRenderContext context, ZoneItem item);
void ZoneRendered(ZoneRenderContext context);
}
public class ZoneRenderContext {
public HtmlHelper Html { get; set; }
public ZoneCollection Zones { get; set; }
public string ZoneName { get; set; }
public IEnumerable<ZoneItem> RenderingItems { get; set; }
}
}

View File

@@ -2,10 +2,19 @@
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Orchard.Logging;
using Orchard.UI.Navigation;
namespace Orchard.UI.Zones {
public class ZoneManager : IZoneManager {
private readonly IEnumerable<IZoneManagerEvents> _events;
public ZoneManager(IEnumerable<IZoneManagerEvents> events) {
_events = events;
Logger = NullLogger.Instance;
}
public void Render<TModel>(HtmlHelper<TModel> html, ZoneCollection zones, string zoneName, string partitions, string[] exclude) {
IEnumerable<Group> groups;
if (string.IsNullOrEmpty(zoneName)) {
@@ -14,18 +23,35 @@ namespace Orchard.UI.Zones {
}
else {
ZoneEntry entry;
if (!zones.TryGetValue(zoneName, out entry))
return;
groups = BuildGroups(partitions, new[] { entry });
if (zones.TryGetValue(zoneName, out entry)) {
groups = BuildGroups(partitions, new[] { entry });
}
else {
groups = Enumerable.Empty<Group>();
}
}
foreach (var item in groups.SelectMany(x => x.Items)) {
item.WasExecuted = true;
item.Execute(html);
var context = new ZoneRenderContext {
Html = html,
Zones = zones,
ZoneName = zoneName,
RenderingItems = groups.SelectMany(x => x.Items).ToList()
};
_events.Invoke(x => x.ZoneRendering(context), Logger);
foreach (var item in context.RenderingItems) {
var zoneItem = item;
_events.Invoke(x => x.ZoneItemRendering(context, zoneItem), Logger);
zoneItem.WasExecuted = true;
zoneItem.Execute(html);
_events.Invoke(x => x.ZoneItemRendered(context, zoneItem), Logger);
}
_events.Invoke(x => x.ZoneRendered(context), Logger);
}
protected ILogger Logger { get; set; }
private IEnumerable<Group> BuildGroups(string partitions, IEnumerable<ZoneEntry> zones) {
var partitionCodes = (":before " + partitions + " :* :after").Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);