mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-27 04:19:04 +08:00
Tabs and Cards to better organize parts and fields (#8310)
This commit is contained in:
committed by
GitHub
parent
e4ac0c02bc
commit
937702479c
@@ -31,11 +31,11 @@ namespace Orchard.Core.Shapes {
|
||||
private readonly IResourceFileHashProvider _resourceFileHashProvider;
|
||||
|
||||
public CoreShapes(
|
||||
Work<WorkContext> workContext,
|
||||
Work<WorkContext> workContext,
|
||||
Work<IResourceManager> resourceManager,
|
||||
Work<IHttpContextAccessor> httpContextAccessor,
|
||||
Work<IShapeFactory> shapeFactory,
|
||||
IResourceFileHashProvider resourceHashProvider
|
||||
IResourceFileHashProvider resourceHashProvider
|
||||
) {
|
||||
_workContext = workContext;
|
||||
_resourceManager = resourceManager;
|
||||
@@ -47,7 +47,7 @@ namespace Orchard.Core.Shapes {
|
||||
}
|
||||
|
||||
public Localizer T { get; set; }
|
||||
public dynamic New { get { return _shapeFactory.Value; } }
|
||||
public dynamic New { get { return _shapeFactory.Value; } }
|
||||
|
||||
public void Discover(ShapeTableBuilder builder) {
|
||||
// the root page shape named 'Layout' is wrapped with 'Document'
|
||||
@@ -57,7 +57,7 @@ namespace Orchard.Core.Shapes {
|
||||
.OnCreating(creating => creating.Create = () => new ZoneHolding(() => creating.New.Zone()))
|
||||
.OnCreated(created => {
|
||||
var layout = created.Shape;
|
||||
|
||||
|
||||
layout.Head = created.New.DocumentZone(ZoneName: "Head");
|
||||
layout.Body = created.New.DocumentZone(ZoneName: "Body");
|
||||
layout.Tail = created.New.DocumentZone(ZoneName: "Tail");
|
||||
@@ -112,7 +112,7 @@ namespace Orchard.Core.Shapes {
|
||||
string contentType = null;
|
||||
int level = menuItem.Level;
|
||||
if (menuItem.Content != null) {
|
||||
contentType = ((IContent) menuItem.Content).ContentItem.ContentType;
|
||||
contentType = ((IContent)menuItem.Content).ContentItem.ContentType;
|
||||
}
|
||||
|
||||
menuItem.Metadata.Alternates.Add("MenuItemLink__level__" + level);
|
||||
@@ -145,7 +145,7 @@ namespace Orchard.Core.Shapes {
|
||||
menu.Classes.Add("localmenu");
|
||||
menu.Metadata.Alternates.Add("LocalMenu__" + EncodeAlternateElement(menuName));
|
||||
});
|
||||
|
||||
|
||||
builder.Describe("LocalMenuItem")
|
||||
.OnDisplaying(displaying => {
|
||||
var menuItem = displaying.Shape;
|
||||
@@ -258,6 +258,7 @@ namespace Orchard.Core.Shapes {
|
||||
resource.Metadata.Alternates.Add("Resource__" + fileName);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -286,24 +287,26 @@ namespace Orchard.Core.Shapes {
|
||||
[Shape]
|
||||
public void ContentZone(dynamic Display, dynamic Shape, TextWriter Output) {
|
||||
var unordered = ((IEnumerable<dynamic>)Shape).ToArray();
|
||||
var tabbed = unordered.GroupBy(x => (string)x.Metadata.Tab ?? "");
|
||||
var ordered = Order(unordered);
|
||||
var tabbed = ordered.GroupBy(x => (string)x.Metadata.Tab ?? "");
|
||||
|
||||
if (tabbed.Count() > 1) {
|
||||
foreach (var tab in tabbed) {
|
||||
var tabName = String.IsNullOrWhiteSpace(tab.Key) ? "Content" : tab.Key;
|
||||
var tabBuilder = new TagBuilder("div");
|
||||
tabBuilder.Attributes["id"] = "tab-" + tabName.HtmlClassify();
|
||||
tabBuilder.Attributes["data-tab"] = tabName;
|
||||
Output.Write(tabBuilder.ToString(TagRenderMode.StartTag));
|
||||
foreach (var item in Order(tab))
|
||||
Output.Write(Display(item));
|
||||
|
||||
Output.Write(tabBuilder.ToString(TagRenderMode.EndTag));
|
||||
foreach (var tab in Order(tabbed)) {
|
||||
Output.Write(Display(New.Tab(Tab:tab)));
|
||||
}
|
||||
}
|
||||
else {
|
||||
foreach (var item in Order(unordered))
|
||||
Output.Write(Display(item));
|
||||
var cards = ordered.GroupBy(x => (string)x.Metadata.Card ?? "");
|
||||
|
||||
if (cards.Count() > 1) {
|
||||
foreach (var card in cards) {
|
||||
Output.Write(Display(New.Card(Card: card, ContainerName: "Content")));
|
||||
}
|
||||
}
|
||||
else {
|
||||
foreach (var item in ordered)
|
||||
Output.Write(Display(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -361,7 +364,7 @@ namespace Orchard.Core.Shapes {
|
||||
if (String.IsNullOrEmpty(tab))
|
||||
continue;
|
||||
|
||||
if(!tabs.Contains(tab))
|
||||
if (!tabs.Contains(tab))
|
||||
tabs.Add(tab);
|
||||
}
|
||||
|
||||
@@ -389,14 +392,14 @@ namespace Orchard.Core.Shapes {
|
||||
|
||||
[Shape]
|
||||
public void Metas(TextWriter Output) {
|
||||
foreach (var meta in _resourceManager.Value.GetRegisteredMetas() ) {
|
||||
foreach (var meta in _resourceManager.Value.GetRegisteredMetas()) {
|
||||
Output.WriteLine(meta.GetTag());
|
||||
}
|
||||
}
|
||||
|
||||
[Shape]
|
||||
public void HeadLinks(TextWriter Output) {
|
||||
foreach (var link in _resourceManager.Value.GetRegisteredLinks() ) {
|
||||
foreach (var link in _resourceManager.Value.GetRegisteredLinks()) {
|
||||
Output.WriteLine(link.GetTag());
|
||||
}
|
||||
}
|
||||
@@ -470,7 +473,7 @@ namespace Orchard.Core.Shapes {
|
||||
if (resourceType == "stylesheet") {
|
||||
result = Display.Style(Url: url, Condition: condition, Resource: context.Resource, TagAttributes: attributes);
|
||||
}
|
||||
else if (resourceType == "script") {
|
||||
else if (resourceType == "script") {
|
||||
result = Display.Script(Url: url, Condition: condition, Resource: context.Resource, TagAttributes: attributes);
|
||||
}
|
||||
else {
|
||||
@@ -502,11 +505,11 @@ namespace Orchard.Core.Shapes {
|
||||
currentPage = 1;
|
||||
|
||||
var pageSize = PageSize;
|
||||
|
||||
|
||||
var numberOfPagesToShow = Quantity ?? 0;
|
||||
if (Quantity == null || Quantity < 0)
|
||||
numberOfPagesToShow = 7;
|
||||
|
||||
|
||||
var totalPageCount = pageSize > 0 ? (int)Math.Ceiling(TotalItemCount / pageSize) : 1;
|
||||
|
||||
var firstText = FirstText ?? T("<<");
|
||||
@@ -531,7 +534,7 @@ namespace Orchard.Core.Shapes {
|
||||
if (shapeRouteData == null) {
|
||||
var route = shapeRoute as RouteData;
|
||||
if (route != null) {
|
||||
shapeRouteData = (route).Values;
|
||||
shapeRouteData = (route).Values;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -599,7 +602,7 @@ namespace Orchard.Core.Shapes {
|
||||
if (lastPage < totalPageCount && numberOfPagesToShow > 0) {
|
||||
Shape.Add(New.Pager_Gap(Value: gapText, Pager: Shape));
|
||||
}
|
||||
|
||||
|
||||
// next and last pages
|
||||
if (Page < totalPageCount) {
|
||||
// next
|
||||
@@ -615,47 +618,47 @@ namespace Orchard.Core.Shapes {
|
||||
|
||||
[Shape]
|
||||
public IHtmlString Pager(dynamic Shape, dynamic Display) {
|
||||
Shape.Metadata.Alternates.Clear();
|
||||
Shape.Metadata.Alternates.Clear();
|
||||
Shape.Metadata.Type = "Pager_Links";
|
||||
return Display(Shape);
|
||||
}
|
||||
|
||||
[Shape]
|
||||
public IHtmlString Pager_First(dynamic Shape, dynamic Display) {
|
||||
Shape.Metadata.Alternates.Clear();
|
||||
Shape.Metadata.Alternates.Clear();
|
||||
Shape.Metadata.Type = "Pager_Link";
|
||||
return Display(Shape);
|
||||
}
|
||||
|
||||
|
||||
[Shape]
|
||||
public IHtmlString Pager_Previous(dynamic Shape, dynamic Display) {
|
||||
Shape.Metadata.Alternates.Clear();
|
||||
Shape.Metadata.Alternates.Clear();
|
||||
Shape.Metadata.Type = "Pager_Link";
|
||||
return Display(Shape);
|
||||
}
|
||||
|
||||
|
||||
[Shape]
|
||||
public IHtmlString Pager_CurrentPage(HtmlHelper Html, dynamic Display, object Value) {
|
||||
var tagBuilder = new TagBuilder("span");
|
||||
tagBuilder.InnerHtml = EncodeOrDisplay(Value, Display, Html).ToString();
|
||||
|
||||
|
||||
return MvcHtmlString.Create(tagBuilder.ToString());
|
||||
}
|
||||
|
||||
|
||||
[Shape]
|
||||
public IHtmlString Pager_Next(dynamic Shape, dynamic Display) {
|
||||
Shape.Metadata.Alternates.Clear();
|
||||
Shape.Metadata.Alternates.Clear();
|
||||
Shape.Metadata.Type = "Pager_Link";
|
||||
return Display(Shape);
|
||||
}
|
||||
|
||||
|
||||
[Shape]
|
||||
public IHtmlString Pager_Last(dynamic Shape, dynamic Display) {
|
||||
Shape.Metadata.Alternates.Clear();
|
||||
Shape.Metadata.Alternates.Clear();
|
||||
Shape.Metadata.Type = "Pager_Link";
|
||||
return Display(Shape);
|
||||
}
|
||||
|
||||
|
||||
[Shape]
|
||||
public IHtmlString Pager_Link(HtmlHelper Html, dynamic Shape, dynamic Display, object Value) {
|
||||
Shape.Metadata.Alternates.Clear();
|
||||
@@ -709,7 +712,7 @@ namespace Orchard.Core.Shapes {
|
||||
|
||||
if (Items == null)
|
||||
return;
|
||||
|
||||
|
||||
// prevent multiple enumerations
|
||||
var items = Items.ToList();
|
||||
|
||||
@@ -719,7 +722,7 @@ namespace Orchard.Core.Shapes {
|
||||
return;
|
||||
|
||||
string listTagName = null;
|
||||
|
||||
|
||||
if (Tag != "-") {
|
||||
listTagName = string.IsNullOrEmpty(Tag) ? "ul" : Tag;
|
||||
}
|
||||
@@ -728,7 +731,7 @@ namespace Orchard.Core.Shapes {
|
||||
|
||||
string itemTagName = null;
|
||||
if (ItemTag != "-") {
|
||||
itemTagName = string.IsNullOrEmpty(ItemTag) ? "li" : ItemTag;
|
||||
itemTagName = string.IsNullOrEmpty(ItemTag) ? "li" : ItemTag;
|
||||
}
|
||||
|
||||
if (listTag != null) {
|
||||
@@ -741,7 +744,7 @@ namespace Orchard.Core.Shapes {
|
||||
// give the item shape the possibility to alter its container tag
|
||||
var index = 0;
|
||||
foreach (var item in items) {
|
||||
|
||||
|
||||
var itemTag = String.IsNullOrEmpty(itemTagName) ? null : GetTagBuilder(itemTagName, null, ItemClasses, ItemAttributes);
|
||||
|
||||
if (item is IShape) {
|
||||
@@ -762,7 +765,7 @@ namespace Orchard.Core.Shapes {
|
||||
}
|
||||
|
||||
index = 0;
|
||||
foreach(var itemOutput in itemOutputs) {
|
||||
foreach (var itemOutput in itemOutputs) {
|
||||
var itemTag = itemTags[index];
|
||||
|
||||
if (itemTag != null) {
|
||||
@@ -811,6 +814,54 @@ namespace Orchard.Core.Shapes {
|
||||
public void DefinitionTemplate(HtmlHelper Html, TextWriter Output, string TemplateName, object Model, string Prefix) {
|
||||
RenderInternal(Html, Output, "DefinitionTemplates/" + TemplateName, Model, Prefix);
|
||||
}
|
||||
[Shape]
|
||||
public void Tab(dynamic Display, IGrouping<string, dynamic> Tab, TextWriter Output) {
|
||||
var tabName = String.IsNullOrWhiteSpace(Tab.Key) ? "Content" : Tab.Key;
|
||||
var tabBuilder = new TagBuilder("div");
|
||||
tabBuilder.Attributes["id"] = "tab-" + tabName.HtmlClassify();
|
||||
tabBuilder.Attributes["data-tab"] = tabName;
|
||||
Output.Write(tabBuilder.ToString(TagRenderMode.StartTag));
|
||||
|
||||
//starts processing cards
|
||||
var cards = CoreShapes.Order(Tab).GroupBy(x => (string)x.Metadata.Card ?? "");
|
||||
foreach (var card in cards) {
|
||||
Output.Write(Display(New.Card(Card: card, ContainerName:tabName)));
|
||||
}
|
||||
|
||||
Output.Write(tabBuilder.ToString(TagRenderMode.EndTag));
|
||||
|
||||
}
|
||||
|
||||
[Shape]
|
||||
public void Card(dynamic Display, IGrouping<string, dynamic> Card, string ContainerName, TextWriter Output) {
|
||||
if (String.IsNullOrWhiteSpace(Card.Key)) {
|
||||
foreach (var item in CoreShapes.Order(Card)) {
|
||||
Output.Write(Display(item));
|
||||
}
|
||||
}
|
||||
else {
|
||||
var cardName = String.IsNullOrWhiteSpace(Card.Key) ? "" : Card.Key;
|
||||
var cardTag = new TagBuilder("div");
|
||||
var cardHeaderTag = new TagBuilder("div");
|
||||
var cardBodyTag = new TagBuilder("div");
|
||||
cardTag.Attributes["id"] = "group-" + ContainerName.HtmlClassify() + "-" + cardName.HtmlClassify();
|
||||
cardTag.Attributes["class"] = "row card";
|
||||
cardBodyTag.Attributes["class"] = "card-body";
|
||||
Output.Write(cardTag.ToString(TagRenderMode.StartTag));
|
||||
if (!String.IsNullOrWhiteSpace(Card.Key)) {
|
||||
cardHeaderTag.Attributes["class"] = "card-header";
|
||||
cardHeaderTag.SetInnerText(Card.Key);
|
||||
Output.Write(cardHeaderTag.ToString());
|
||||
}
|
||||
Output.Write(cardBodyTag.ToString(TagRenderMode.StartTag));
|
||||
foreach (var item in CoreShapes.Order(Card)) {
|
||||
Output.Write(Display(item));
|
||||
}
|
||||
Output.Write(cardBodyTag.ToString(TagRenderMode.EndTag));
|
||||
Output.Write(cardTag.ToString(TagRenderMode.EndTag));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void RenderInternal(HtmlHelper Html, TextWriter Output, string TemplateName, object Model, string Prefix) {
|
||||
var adjustedViewData = new ViewDataDictionary(Html.ViewDataContainer.ViewData) {
|
||||
@@ -861,7 +912,7 @@ namespace Orchard.Core.Shapes {
|
||||
if (Value is IShape) {
|
||||
return Display(Value).ToString();
|
||||
}
|
||||
|
||||
|
||||
return Html.Raw(Html.Encode(Value.ToString()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,17 +142,67 @@ namespace Orchard.ContentTypes.Controllers {
|
||||
|
||||
if (contentTypeDefinition == null) return HttpNotFound();
|
||||
|
||||
var grouped = _placementService.GetEditorPlacement(id)
|
||||
//Grouping Tabs > Cards > Shapes
|
||||
var grouped = _placementService
|
||||
// Get a collection of objects that describe the placement for all shapes
|
||||
// in the editor view for a ContentItem of the given ContentType
|
||||
.GetEditorPlacement(id)
|
||||
// Order all those shapes based on their position
|
||||
.OrderBy(x => x.PlacementInfo.GetPosition(), new FlatPositionComparer())
|
||||
// Then alphabetically by their shape type
|
||||
.ThenBy(x => x.PlacementSettings.ShapeType)
|
||||
// only pick those shapes that live int the "Content" zone
|
||||
.Where(e => e.PlacementSettings.Zone == "Content")
|
||||
.GroupBy(x => x.PlacementInfo.GetTab())
|
||||
.ToDictionary(x => x.Key, y => y.ToList());
|
||||
|
||||
var content = grouped.ContainsKey("") ? grouped[""] : new List<DriverResultPlacement>();
|
||||
var listPlacements = grouped.Values.SelectMany(e => e).ToList();
|
||||
|
||||
grouped.Remove("");
|
||||
// Form groups whose key is a string like {tabName}%{cardName}. Items
|
||||
// in a group represent the shapes that will be in the card called {cardName}
|
||||
// in the tab called {tabName}.
|
||||
.GroupBy(g => g.PlacementInfo.GetTab() + "%" + g.PlacementInfo.GetCard())
|
||||
// Transform each of those groups in an object representing the single cards.
|
||||
// Each of these objects contains the name of the tab that contains it, as
|
||||
// well as the list of shape placements in that card
|
||||
.Select(x =>
|
||||
new Card {
|
||||
Name = x.Key.Split('%')[1],
|
||||
TabName = x.Key.Split('%')[0],
|
||||
Placements = x.ToList()
|
||||
})
|
||||
// Group cards by tab
|
||||
.GroupBy(x => x.TabName)
|
||||
// Since each of those groups "represents" a card, we actually make it into one.
|
||||
.Select(x =>
|
||||
new Tab {
|
||||
Name = x.Key,
|
||||
Cards = x.ToList()
|
||||
})
|
||||
// Make the collection into a List<Tab> because it's easy to interact with it
|
||||
// (see later in the code)
|
||||
.ToList();
|
||||
var listPlacements = grouped
|
||||
// By selecting all placements from the Tab objects we built earlier, we have
|
||||
// them ordered nicely
|
||||
.SelectMany(x => x.Cards.SelectMany(m => m.Placements))
|
||||
.ToList();
|
||||
// We want to have an un-named "default" Tab for shapes, in case none was defined
|
||||
Tab content;
|
||||
if (grouped.Any(x => string.IsNullOrWhiteSpace(x.Name))) {
|
||||
// Because of the way the elements of the list have been ordered above,
|
||||
// if there is a Tab with empty name, it is the first in the list.
|
||||
content = grouped[0];
|
||||
grouped.Remove(content);
|
||||
} else {
|
||||
content = new Tab {
|
||||
Name = "",
|
||||
Cards = new List<Card> { new Card { Name = "", TabName = "", Placements = new List<DriverResultPlacement>() } }
|
||||
};
|
||||
}
|
||||
// In each Tab, we want to have a "default" un-named Card. This will simplfy
|
||||
// UI interactions, because it ensures that each Tab has some place we can drop
|
||||
// shapes in.
|
||||
for (int i = 0; i < grouped.Count(); i++) {
|
||||
if (!grouped[i].Cards.Any(x => string.IsNullOrEmpty(x.Name))) {
|
||||
grouped[i].Cards.Insert(0, new Card { Name = "", TabName = grouped[i].Name, Placements = new List<DriverResultPlacement>() });
|
||||
}
|
||||
}
|
||||
var placementModel = new EditPlacementViewModel {
|
||||
Content = content,
|
||||
AllPlacements = listPlacements,
|
||||
@@ -177,7 +227,7 @@ namespace Orchard.ContentTypes.Controllers {
|
||||
|
||||
foreach (var placement in viewModel.AllPlacements) {
|
||||
var placementSetting = placement.PlacementSettings;
|
||||
|
||||
|
||||
contentTypeDefinition.Placement(
|
||||
PlacementType.Editor,
|
||||
placementSetting.ShapeType,
|
||||
@@ -311,7 +361,7 @@ namespace Orchard.ContentTypes.Controllers {
|
||||
var partsToAdd = viewModel.PartSelections.Where(ps => ps.IsSelected).Select(ps => ps.PartName);
|
||||
foreach (var partToAdd in partsToAdd) {
|
||||
_contentDefinitionService.AddPartToType(partToAdd, typeViewModel.Name);
|
||||
|
||||
|
||||
Services.Notifier.Success(T("The \"{0}\" part has been added.", partToAdd));
|
||||
}
|
||||
|
||||
|
||||
@@ -4,9 +4,11 @@
|
||||
|
||||
$('.type').each(function () {
|
||||
var input = $(this);
|
||||
var tab = input.closest(".zone-container").data("tab");
|
||||
var tab = input.closest(".tab-container").data("tab");
|
||||
var card = input.closest(".card-container").data("card");
|
||||
//input = input.next();
|
||||
var postab = tab !== "" ? position + "#" + tab : position + "";
|
||||
postab += (card) && card !== "" ? "%" + card : "";
|
||||
reAssignIdName(input, position); // type
|
||||
|
||||
input = input.next();
|
||||
@@ -33,26 +35,32 @@
|
||||
|
||||
var startPos;
|
||||
|
||||
// Makes sortable Cards and Shapes
|
||||
function initTab() {
|
||||
$(".tabdrag").sortable({
|
||||
placeholder: "placement-placeholder",
|
||||
connectWith: ".tabdrag",
|
||||
stop: function (event, ui) {
|
||||
assignPositions();
|
||||
$('#save-message').show();
|
||||
}
|
||||
});
|
||||
$(".carddrag").sortable({
|
||||
placeholder: "placement-placeholder",
|
||||
connectWith: ".carddrag",
|
||||
stop: function (event, ui) {
|
||||
assignPositions();
|
||||
$('#save-message').show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Makes sortable tabs
|
||||
$('#sortableTabs').sortable({
|
||||
placeholder: "tab-placeholder",
|
||||
start: function (event, ui) {
|
||||
var self = $(ui.item);
|
||||
startPos = self.prevAll().size();
|
||||
},
|
||||
stop: function (event, ui) {
|
||||
assignPositions();
|
||||
$('#save-message').show();
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
@@ -75,9 +83,12 @@
|
||||
$("#tabName").val("");
|
||||
return;
|
||||
}
|
||||
|
||||
//Insert the tab with an empty card
|
||||
$("#sortableTabs").append('<div data-tab="' + tab + '" class="zone-container tab-container"><h2><a class="delete">Delete</a>'
|
||||
+ tab + '</h2><ul class="tabdrag"></ul></div>'
|
||||
+ tab + '</h2><ul class="tabdrag">'
|
||||
+ '<li data-tab="' + tab + '" data-card="" class="zone-container card-container">'
|
||||
+ '<ul class="carddrag"></ul></li>'
|
||||
+ '</ul></div> '
|
||||
);
|
||||
// make it sortable
|
||||
initTab();
|
||||
@@ -86,20 +97,46 @@
|
||||
$("#tabName").val("");
|
||||
});
|
||||
|
||||
$("#newCard").click(function (e) {
|
||||
e.preventDefault();
|
||||
// get the new tab name, cancel if blank
|
||||
var card = $("#tabName").val().replace(/\s/g, "");
|
||||
if (!card.length) {
|
||||
return;
|
||||
}
|
||||
// insert card in the Content Tab
|
||||
$("#content-tab > ul").append('<li data-tab="" data-card="' + card + '" class="zone-container card-container"><a class="delete">Delete</a><div class="card-type"><h2>'
|
||||
+ card + '</h2></div><ul class="carddrag"></ul></li>');
|
||||
// make it sortable
|
||||
initTab();
|
||||
$("#sortableTabs").sortable("refresh");
|
||||
// clear the textbox
|
||||
$("#tabName").val("");
|
||||
});
|
||||
// remove tabs
|
||||
// append items to content, create content if not there
|
||||
$("#placement").on("click", ".delete", function (e) {
|
||||
var me = $(this);
|
||||
var parent = me.parent(".zone-container");
|
||||
var list = parent.children(".tabdrag").html();
|
||||
if (!parent.length) {
|
||||
parent = me.parents(".zone-container");
|
||||
}
|
||||
var list, newList;
|
||||
if (parent.hasClass("tab-container")) {
|
||||
list = parent.children(".tabdrag").html();
|
||||
newList = $("#placement .tabdrag").first();
|
||||
} else if (parent.hasClass("card-container")) {
|
||||
list = parent.children(".carddrag").html();
|
||||
newList = $("#placement .tabdrag").first();
|
||||
}
|
||||
// get first tab
|
||||
var newList = $("#placement .tabdrag").first();
|
||||
if (newList.length) {
|
||||
parent.remove();
|
||||
newList.append(list);
|
||||
}
|
||||
|
||||
assignPositions();
|
||||
// make it sortable
|
||||
initTab();
|
||||
});
|
||||
|
||||
// toggle editor shapes
|
||||
|
||||
@@ -176,7 +176,7 @@ fieldset.action {
|
||||
|
||||
|
||||
/* PLACEMENT EDITOR */
|
||||
.tabdrag {
|
||||
.tabdrag, .carddrag {
|
||||
min-height: 20px;
|
||||
}
|
||||
|
||||
@@ -211,6 +211,15 @@ fieldset.action {
|
||||
padding: 5px 0px 0px 30px;
|
||||
}
|
||||
|
||||
.zone-container li .card-type {
|
||||
cursor: move;
|
||||
background-color: #ccc;
|
||||
background: #ccc url(images/move.gif) no-repeat 10px 10px;
|
||||
height: 30px;
|
||||
padding: 5px 10px 5px 30px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
#placement #content-tab {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,19 @@ namespace Orchard.ContentTypes.ViewModels {
|
||||
public class EditPlacementViewModel {
|
||||
public ContentTypeDefinition ContentTypeDefinition { get; set; }
|
||||
public List<DriverResultPlacement> AllPlacements { get; set; }
|
||||
public Dictionary<string, List<DriverResultPlacement>> Tabs { get; set; }
|
||||
public List<DriverResultPlacement> Content { get; set; }
|
||||
public List<Tab> Tabs { get; set; }
|
||||
public Tab Content { get; set; }
|
||||
}
|
||||
|
||||
public class Tab {
|
||||
public string Name { get; set; }
|
||||
public List<Card> Cards { get; set; }
|
||||
}
|
||||
|
||||
public class Card {
|
||||
public string Name { get; set; }
|
||||
public string TabName { get; set; }
|
||||
public List<DriverResultPlacement> Placements { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
@using Orchard.ContentTypes.Services
|
||||
@using Orchard.ContentTypes.ViewModels
|
||||
|
||||
@model Orchard.ContentTypes.ViewModels.EditPlacementViewModel
|
||||
|
||||
@@ -7,23 +8,22 @@
|
||||
Script.Require("PlacementEditor").AtFoot();
|
||||
Layout.Title = T("Edit Placement - {0}", Html.Raw(Model.ContentTypeDefinition.DisplayName)).Text;
|
||||
|
||||
int i = 0;
|
||||
}
|
||||
|
||||
@helper RenderPlacement(DriverResultPlacement p, int i)
|
||||
@functions
|
||||
{
|
||||
private int i = 0;
|
||||
}
|
||||
@helper RenderPlacement(DriverResultPlacement p) {
|
||||
var placement = p.PlacementSettings;
|
||||
|
||||
<li class="place" data-shape-type="@placement.ShapeType" data-shape-differentiator="@placement.Differentiator" data-shape-zone="Content" data-shape-position="@placement.Position">
|
||||
<span class="toggle" data-text-show="@T("Show Editor Shape")" data-text-hide="@T("Hide Editor Shape")">@T("Show Editor Shape")</span>
|
||||
<div class="shape-type"><h3>@placement.ShapeType @placement.Differentiator</h3></div>
|
||||
<div class="shape-editor">
|
||||
@try
|
||||
{
|
||||
@try {
|
||||
@Display(p.Shape)
|
||||
}
|
||||
catch
|
||||
{
|
||||
catch {
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -32,36 +32,52 @@
|
||||
@Html.HiddenFor(m => m.AllPlacements[i].PlacementSettings.Zone, new { @class = "zone" })
|
||||
@Html.HiddenFor(m => m.AllPlacements[i].PlacementSettings.Position, new { @class = "position" })
|
||||
</li>
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
@helper RenderCard(Card card) {
|
||||
<li data-tab="@(card.TabName)" data-card="@(card.Name)" class="zone-container card-container">
|
||||
@if (!string.IsNullOrWhiteSpace(card.Name)) {
|
||||
<a class="delete">@T("Delete")</a>
|
||||
<div class="card-type"><h2>@card.Name</h2></div>
|
||||
}
|
||||
<ul class="carddrag">
|
||||
@foreach (var p in card.Placements) {
|
||||
@RenderPlacement(p);
|
||||
}
|
||||
</ul>
|
||||
</li>
|
||||
}
|
||||
|
||||
<div id="save-message" class="message message-Warning">@T("You need to hit \"Save\" in order to save your changes.")</div>
|
||||
|
||||
@using (Html.BeginFormAntiForgeryPost())
|
||||
{
|
||||
@* Alert messages *@
|
||||
<div style="display:none">
|
||||
<div id="nested-cards" title="@T("Drag&Drop")">
|
||||
<p>@T("Nested cards are not allowed.")</p>
|
||||
</div>
|
||||
</div>
|
||||
@using (Html.BeginFormAntiForgeryPost()) {
|
||||
@Html.ValidationSummary()
|
||||
<div id="placement">
|
||||
<div data-tab="" class="zone-container" id="content-tab">
|
||||
<div data-tab="" class="zone-container tab-container" id="content-tab">
|
||||
<h2>@T("Content")</h2>
|
||||
<ul class="tabdrag">
|
||||
@foreach (var p in Model.Content)
|
||||
{
|
||||
@RenderPlacement(p, i);
|
||||
i++;
|
||||
@foreach (var c in Model.Content.Cards) {
|
||||
@RenderCard(c);
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div id="sortableTabs">
|
||||
@foreach (var tab in Model.Tabs)
|
||||
{
|
||||
<div data-tab="@tab.Key" class="zone-container tab-container">
|
||||
@foreach (var tab in Model.Tabs) {
|
||||
<div data-tab="@tab.Name" class="zone-container tab-container">
|
||||
<a class="delete">@T("Delete")</a>
|
||||
<h2>@tab.Key</h2>
|
||||
<h2>@tab.Name</h2>
|
||||
<ul class="tabdrag">
|
||||
@foreach (var p in tab.Value)
|
||||
{
|
||||
@RenderPlacement(p, i);
|
||||
i++;
|
||||
@foreach (var c in tab.Cards) {
|
||||
@RenderCard(c);
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
@@ -72,6 +88,7 @@
|
||||
<div>
|
||||
<input type="text" id="tabName" />
|
||||
<button class="primaryAction" id="newTab">@T("New Tab")</button>
|
||||
<button class="primaryAction" id="newCard">@T("New Card")</button>
|
||||
</div>
|
||||
|
||||
<fieldset class="action">
|
||||
|
||||
@@ -67,6 +67,7 @@ namespace Orchard.ContentManagement.Drivers {
|
||||
newShapeMetadata.DisplayType = displayType;
|
||||
newShapeMetadata.PlacementSource = placement.Source;
|
||||
newShapeMetadata.Tab = placement.GetTab();
|
||||
newShapeMetadata.Card = placement.GetCard();
|
||||
|
||||
// If a specific shape is provided, remove all previous alternates and wrappers.
|
||||
if (!String.IsNullOrEmpty(placement.ShapeType)) {
|
||||
|
||||
@@ -4,7 +4,7 @@ using System.Linq;
|
||||
|
||||
namespace Orchard.DisplayManagement.Descriptors {
|
||||
public class PlacementInfo {
|
||||
private static readonly char[] Delimiters = {':', '#', '@'};
|
||||
private static readonly char[] Delimiters = {':', '#', '@', '%'};
|
||||
|
||||
public PlacementInfo() {
|
||||
Alternates = Enumerable.Empty<string>();
|
||||
@@ -71,5 +71,19 @@ namespace Orchard.DisplayManagement.Descriptors {
|
||||
|
||||
return Location.Substring(groupDelimiter + 1, nextDelimiter - groupDelimiter - 1);
|
||||
}
|
||||
|
||||
public string GetCard() {
|
||||
var groupDelimiter = Location.IndexOf('%');
|
||||
if (groupDelimiter == -1) {
|
||||
return "";
|
||||
}
|
||||
|
||||
var nextDelimiter = Location.IndexOfAny(Delimiters, groupDelimiter + 1);
|
||||
if (nextDelimiter == -1) {
|
||||
return Location.Substring(groupDelimiter + 1);
|
||||
}
|
||||
|
||||
return Location.Substring(groupDelimiter + 1, nextDelimiter - groupDelimiter - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ namespace Orchard.DisplayManagement.Shapes {
|
||||
public string DisplayType { get; set; }
|
||||
public string Position { get; set; }
|
||||
public string Tab { get; set; }
|
||||
public string Card { get; set; }
|
||||
public string PlacementSource { get; set; }
|
||||
public string Prefix { get; set; }
|
||||
public IList<string> Wrappers { get; set; }
|
||||
|
||||
Reference in New Issue
Block a user