mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-08-01 20:18:37 +08:00
Implementing hierarchical editor
--HG-- branch : 1.x extra : rebase_source : 03ee4afe2e9bb66dff80d8a750609ec537956151
This commit is contained in:
parent
0e2a17d417
commit
35424a4b56
25
src/Orchard.Web/Core/Navigation/Scripts/Web.config
Normal file
25
src/Orchard.Web/Core/Navigation/Scripts/Web.config
Normal file
@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<appSettings>
|
||||
<add key="webpages:Enabled" value="false" />
|
||||
</appSettings>
|
||||
<system.web>
|
||||
<httpHandlers>
|
||||
<!-- iis6 - for any request in this location, return via managed static file handler -->
|
||||
<add path="*" verb="*" type="System.Web.StaticFileHandler" />
|
||||
</httpHandlers>
|
||||
</system.web>
|
||||
<system.webServer>
|
||||
<staticContent>
|
||||
<clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="7.00:00:00" />
|
||||
</staticContent>
|
||||
|
||||
<handlers accessPolicy="Script,Read">
|
||||
<!--
|
||||
iis7 - for any request to a file exists on disk, return it via native http module.
|
||||
accessPolicy 'Script' is to allow for a managed 404 page.
|
||||
-->
|
||||
<add name="StaticFile" path="*" verb="*" modules="StaticFileModule" preCondition="integratedMode" resourceType="File" requireAccess="Read" />
|
||||
</handlers>
|
||||
</system.webServer>
|
||||
</configuration>
|
@ -0,0 +1,400 @@
|
||||
/*
|
||||
* jQuery UI Nested Sortable
|
||||
* v 1.4 / 30 dec 2011
|
||||
* http://mjsarfatti.com/code/nestedSortable
|
||||
*
|
||||
* Depends on:
|
||||
* jquery.ui.sortable.js 1.8+
|
||||
*
|
||||
* Copyright (c) 2010-2012 Manuele J Sarfatti
|
||||
* Licensed under the MIT License
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
(function ($) {
|
||||
|
||||
$.widget("mjs.nestedSortable", $.extend({}, $.ui.sortable.prototype, {
|
||||
|
||||
options: {
|
||||
tabSize: 20,
|
||||
disableNesting: 'mjs-nestedSortable-no-nesting',
|
||||
errorClass: 'mjs-nestedSortable-error',
|
||||
listType: 'ol',
|
||||
maxLevels: 0,
|
||||
protectRoot: false,
|
||||
rootID: null,
|
||||
rtl: false,
|
||||
isAllowed: function (item, parent) { return true; }
|
||||
},
|
||||
|
||||
_create: function () {
|
||||
this.element.data('sortable', this.element.data('nestedSortable'));
|
||||
|
||||
if (!this.element.is(this.options.listType))
|
||||
throw new Error('nestedSortable: Please check the listType option is set to your actual list type');
|
||||
|
||||
return $.ui.sortable.prototype._create.apply(this, arguments);
|
||||
},
|
||||
|
||||
destroy: function () {
|
||||
this.element
|
||||
.removeData("nestedSortable")
|
||||
.unbind(".nestedSortable");
|
||||
return $.ui.sortable.prototype.destroy.apply(this, arguments);
|
||||
},
|
||||
|
||||
_mouseDrag: function (event) {
|
||||
|
||||
//Compute the helpers position
|
||||
this.position = this._generatePosition(event);
|
||||
this.positionAbs = this._convertPositionTo("absolute");
|
||||
|
||||
if (!this.lastPositionAbs) {
|
||||
this.lastPositionAbs = this.positionAbs;
|
||||
}
|
||||
|
||||
//Do scrolling
|
||||
if (this.options.scroll) {
|
||||
var o = this.options, scrolled = false;
|
||||
if (this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') {
|
||||
|
||||
if ((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
|
||||
this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
|
||||
else if (event.pageY - this.overflowOffset.top < o.scrollSensitivity)
|
||||
this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
|
||||
|
||||
if ((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)
|
||||
this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
|
||||
else if (event.pageX - this.overflowOffset.left < o.scrollSensitivity)
|
||||
this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
|
||||
|
||||
} else {
|
||||
|
||||
if (event.pageY - $(document).scrollTop() < o.scrollSensitivity)
|
||||
scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
|
||||
else if ($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)
|
||||
scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
|
||||
|
||||
if (event.pageX - $(document).scrollLeft() < o.scrollSensitivity)
|
||||
scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
|
||||
else if ($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
|
||||
scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
|
||||
|
||||
}
|
||||
|
||||
if (scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
|
||||
$.ui.ddmanager.prepareOffsets(this, event);
|
||||
}
|
||||
|
||||
//Regenerate the absolute position used for position checks
|
||||
this.positionAbs = this._convertPositionTo("absolute");
|
||||
|
||||
//Set the helper position
|
||||
if (!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left + 'px';
|
||||
if (!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top + 'px';
|
||||
|
||||
//Rearrange
|
||||
for (var i = this.items.length - 1; i >= 0; i--) {
|
||||
|
||||
//Cache variables and intersection, continue if no intersection
|
||||
var item = this.items[i], itemElement = item.item[0], intersection = this._intersectsWithPointer(item);
|
||||
if (!intersection) continue;
|
||||
|
||||
if (itemElement != this.currentItem[0] //cannot intersect with itself
|
||||
&& this.placeholder[intersection == 1 ? "next" : "prev"]()[0] != itemElement //no useless actions that have been done before
|
||||
&& !$.contains(this.placeholder[0], itemElement) //no action if the item moved is the parent of the item checked
|
||||
&& (this.options.type == 'semi-dynamic' ? !$.contains(this.element[0], itemElement) : true)
|
||||
//&& itemElement.parentNode == this.placeholder[0].parentNode // only rearrange items within the same container
|
||||
) {
|
||||
|
||||
$(itemElement).mouseenter();
|
||||
|
||||
this.direction = intersection == 1 ? "down" : "up";
|
||||
|
||||
if (this.options.tolerance == "pointer" || this._intersectsWithSides(item)) {
|
||||
$(itemElement).mouseleave();
|
||||
this._rearrange(event, item);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
// Clear emtpy ul's/ol's
|
||||
this._clearEmpty(itemElement);
|
||||
|
||||
this._trigger("change", event, this._uiHash());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var parentItem = (this.placeholder[0].parentNode.parentNode &&
|
||||
$(this.placeholder[0].parentNode.parentNode).closest('.ui-sortable').length)
|
||||
? $(this.placeholder[0].parentNode.parentNode)
|
||||
: null,
|
||||
level = this._getLevel(this.placeholder),
|
||||
childLevels = this._getChildLevels(this.helper),
|
||||
previousItem = this.placeholder[0].previousSibling ? $(this.placeholder[0].previousSibling) : null;
|
||||
|
||||
if (previousItem != null) {
|
||||
while (previousItem[0].nodeName.toLowerCase() != 'li' || previousItem[0] == this.currentItem[0]) {
|
||||
if (previousItem[0].previousSibling) {
|
||||
previousItem = $(previousItem[0].previousSibling);
|
||||
} else {
|
||||
previousItem = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var newList = document.createElement(o.listType);
|
||||
|
||||
this.beyondMaxLevels = 0;
|
||||
|
||||
// If the item is moved to the left, send it to its parent level
|
||||
if (parentItem != null &&
|
||||
(o.rtl && (this.positionAbs.left + this.helper.outerWidth() > parentItem.offset().left + parentItem.outerWidth()) ||
|
||||
!o.rtl && (this.positionAbs.left < parentItem.offset().left))) {
|
||||
parentItem.after(this.placeholder[0]);
|
||||
this._clearEmpty(parentItem[0]);
|
||||
this._trigger("change", event, this._uiHash());
|
||||
}
|
||||
// If the item is below another one and is moved to the right, make it a children of it
|
||||
else if (previousItem != null &&
|
||||
(o.rtl && (this.positionAbs.left + this.helper.outerWidth() < previousItem.offset().left + previousItem.outerWidth() - o.tabSize) ||
|
||||
!o.rtl && (this.positionAbs.left > previousItem.offset().left + o.tabSize))) {
|
||||
this._isAllowed(previousItem, level, level + childLevels + 1);
|
||||
if (!previousItem.children(o.listType).length) {
|
||||
previousItem[0].appendChild(newList);
|
||||
}
|
||||
previousItem.children(o.listType)[0].appendChild(this.placeholder[0]);
|
||||
this._trigger("change", event, this._uiHash());
|
||||
}
|
||||
else {
|
||||
this._isAllowed(parentItem, level, level + childLevels);
|
||||
}
|
||||
|
||||
//Post events to containers
|
||||
this._contactContainers(event);
|
||||
|
||||
//Interconnect with droppables
|
||||
if ($.ui.ddmanager) $.ui.ddmanager.drag(this, event);
|
||||
|
||||
//Call callbacks
|
||||
this._trigger('sort', event, this._uiHash());
|
||||
|
||||
this.lastPositionAbs = this.positionAbs;
|
||||
return false;
|
||||
|
||||
},
|
||||
|
||||
_mouseStop: function (event, noPropagation) {
|
||||
|
||||
// If the item is in a position not allowed, send it back
|
||||
if (this.beyondMaxLevels) {
|
||||
|
||||
this.placeholder.removeClass(this.options.errorClass);
|
||||
|
||||
if (this.domPosition.prev) {
|
||||
$(this.domPosition.prev).after(this.placeholder);
|
||||
} else {
|
||||
$(this.domPosition.parent).prepend(this.placeholder);
|
||||
}
|
||||
|
||||
this._trigger("revert", event, this._uiHash());
|
||||
|
||||
}
|
||||
|
||||
// Clean last empty ul/ol
|
||||
for (var i = this.items.length - 1; i >= 0; i--) {
|
||||
var item = this.items[i].item[0];
|
||||
this._clearEmpty(item);
|
||||
}
|
||||
|
||||
$.ui.sortable.prototype._mouseStop.apply(this, arguments);
|
||||
|
||||
},
|
||||
|
||||
serialize: function (options) {
|
||||
|
||||
var o = $.extend({}, this.options, options),
|
||||
items = this._getItemsAsjQuery(o && o.connected),
|
||||
str = [];
|
||||
|
||||
$(items).each(function () {
|
||||
var res = ($(o.item || this).attr(o.attribute || 'id') || '')
|
||||
.match(o.expression || (/(.+)[-=_](.+)/)),
|
||||
pid = ($(o.item || this).parent(o.listType)
|
||||
.parent(o.items)
|
||||
.attr(o.attribute || 'id') || '')
|
||||
.match(o.expression || (/(.+)[-=_](.+)/));
|
||||
|
||||
if (res) {
|
||||
str.push(((o.key || res[1]) + '[' + (o.key && o.expression ? res[1] : res[2]) + ']')
|
||||
+ '='
|
||||
+ (pid ? (o.key && o.expression ? pid[1] : pid[2]) : o.rootID));
|
||||
}
|
||||
});
|
||||
|
||||
if (!str.length && o.key) {
|
||||
str.push(o.key + '=');
|
||||
}
|
||||
|
||||
return str.join('&');
|
||||
|
||||
},
|
||||
|
||||
toHierarchy: function (options) {
|
||||
|
||||
var o = $.extend({}, this.options, options),
|
||||
sDepth = o.startDepthCount || 0,
|
||||
ret = [];
|
||||
|
||||
$(this.element).children(o.items).each(function () {
|
||||
var level = _recursiveItems(this);
|
||||
ret.push(level);
|
||||
});
|
||||
|
||||
return ret;
|
||||
|
||||
function _recursiveItems(item) {
|
||||
var id = ($(item).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/));
|
||||
if (id) {
|
||||
var currentItem = { "id": id[2] };
|
||||
if ($(item).children(o.listType).children(o.items).length > 0) {
|
||||
currentItem.children = [];
|
||||
$(item).children(o.listType).children(o.items).each(function () {
|
||||
var level = _recursiveItems(this);
|
||||
currentItem.children.push(level);
|
||||
});
|
||||
}
|
||||
return currentItem;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toArray: function (options) {
|
||||
|
||||
var o = $.extend({}, this.options, options),
|
||||
sDepth = o.startDepthCount || 0,
|
||||
ret = [],
|
||||
left = 2;
|
||||
|
||||
ret.push({
|
||||
"item_id": o.rootID,
|
||||
"parent_id": 'none',
|
||||
"depth": sDepth,
|
||||
"left": '1',
|
||||
"right": ($(o.items, this.element).length + 1) * 2
|
||||
});
|
||||
|
||||
$(this.element).children(o.items).each(function () {
|
||||
left = _recursiveArray(this, sDepth + 1, left);
|
||||
});
|
||||
|
||||
ret = ret.sort(function (a, b) { return (a.left - b.left); });
|
||||
|
||||
return ret;
|
||||
|
||||
function _recursiveArray(item, depth, left) {
|
||||
|
||||
var right = left + 1,
|
||||
id,
|
||||
pid;
|
||||
|
||||
if ($(item).children(o.listType).children(o.items).length > 0) {
|
||||
depth++;
|
||||
$(item).children(o.listType).children(o.items).each(function () {
|
||||
right = _recursiveArray($(this), depth, right);
|
||||
});
|
||||
depth--;
|
||||
}
|
||||
|
||||
id = ($(item).attr(o.attribute || 'id')).match(o.expression || (/(.+)[-=_](.+)/));
|
||||
|
||||
if (depth === sDepth + 1) {
|
||||
pid = o.rootID;
|
||||
} else {
|
||||
var parentItem = ($(item).parent(o.listType)
|
||||
.parent(o.items)
|
||||
.attr(o.attribute || 'id'))
|
||||
.match(o.expression || (/(.+)[-=_](.+)/));
|
||||
pid = parentItem[2];
|
||||
}
|
||||
|
||||
if (id) {
|
||||
ret.push({ "item_id": id[2], "parent_id": pid, "depth": depth, "left": left, "right": right });
|
||||
}
|
||||
|
||||
left = right + 1;
|
||||
return left;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
_clearEmpty: function (item) {
|
||||
|
||||
var emptyList = $(item).children(this.options.listType);
|
||||
if (emptyList.length && !emptyList.children().length) {
|
||||
emptyList.remove();
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
_getLevel: function (item) {
|
||||
|
||||
var level = 1;
|
||||
|
||||
if (this.options.listType) {
|
||||
var list = item.closest(this.options.listType);
|
||||
while (!list.is('.ui-sortable')) {
|
||||
level++;
|
||||
list = list.parent().closest(this.options.listType);
|
||||
}
|
||||
}
|
||||
|
||||
return level;
|
||||
},
|
||||
|
||||
_getChildLevels: function (parent, depth) {
|
||||
var self = this,
|
||||
o = this.options,
|
||||
result = 0;
|
||||
depth = depth || 0;
|
||||
|
||||
$(parent).children(o.listType).children(o.items).each(function (index, child) {
|
||||
result = Math.max(self._getChildLevels(child, depth + 1), result);
|
||||
});
|
||||
|
||||
return depth ? result + 1 : result;
|
||||
},
|
||||
|
||||
_isAllowed: function (parentItem, level, levels) {
|
||||
var o = this.options,
|
||||
isRoot = $(this.domPosition.parent).hasClass('ui-sortable') ? true : false;
|
||||
|
||||
// Is the root protected?
|
||||
// Are we trying to nest under a no-nest?
|
||||
// Are we nesting too deep?
|
||||
if (!o.isAllowed(parentItem, this.placeholder) ||
|
||||
parentItem && parentItem.hasClass(o.disableNesting) ||
|
||||
o.protectRoot && (parentItem == null && !isRoot || isRoot && level > 1)) {
|
||||
this.placeholder.addClass(o.errorClass);
|
||||
if (o.maxLevels < levels && o.maxLevels != 0) {
|
||||
this.beyondMaxLevels = levels - o.maxLevels;
|
||||
} else {
|
||||
this.beyondMaxLevels = 1;
|
||||
}
|
||||
} else {
|
||||
if (o.maxLevels < levels && o.maxLevels != 0) {
|
||||
this.placeholder.addClass(o.errorClass);
|
||||
this.beyondMaxLevels = levels - o.maxLevels;
|
||||
} else {
|
||||
this.placeholder.removeClass(o.errorClass);
|
||||
this.beyondMaxLevels = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}));
|
||||
|
||||
$.mjs.nestedSortable.prototype.options = $.extend({}, $.ui.sortable.prototype.options, $.mjs.nestedSortable.prototype.options);
|
||||
})(jQuery);
|
44
src/Orchard.Web/Core/Navigation/Scripts/navigation-admin.js
Normal file
44
src/Orchard.Web/Core/Navigation/Scripts/navigation-admin.js
Normal file
@ -0,0 +1,44 @@
|
||||
|
||||
(function ($) {
|
||||
|
||||
var populate = function (el, prefix) {
|
||||
var pos = 1;
|
||||
|
||||
// direct children
|
||||
var children = $(el).children('li').each(function (i, child) {
|
||||
if (!prefix) prefix = '';
|
||||
child = $(child);
|
||||
|
||||
// apply positions to all siblings
|
||||
child.find('.navigation-position > input').attr('value', prefix + pos);
|
||||
|
||||
// recurse position for children
|
||||
child.children('ol').each(function (i, item) { populate(item, prefix + pos.toString() + '.') });
|
||||
|
||||
pos++;
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
$('.navigation-menu > ol').nestedSortable({
|
||||
disableNesting: 'no-nest',
|
||||
forcePlaceholderSize: true,
|
||||
handle: 'div',
|
||||
helper: 'clone',
|
||||
items: 'li',
|
||||
maxLevels: 6,
|
||||
opacity: .6,
|
||||
placeholder: 'navigation-placeholder',
|
||||
revert: 50,
|
||||
tabSize: 30,
|
||||
tolerance: 'pointer',
|
||||
toleranceElement: '> div',
|
||||
|
||||
stop: function (event, ui) {
|
||||
// update all positions whenever a menu item was moved
|
||||
populate(this, '');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
})(jQuery);
|
BIN
src/Orchard.Web/Core/Navigation/Styles/images/move.gif
Normal file
BIN
src/Orchard.Web/Core/Navigation/Styles/images/move.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 897 B |
57
src/Orchard.Web/Core/Navigation/Styles/navigation-admin.css
Normal file
57
src/Orchard.Web/Core/Navigation/Styles/navigation-admin.css
Normal file
@ -0,0 +1,57 @@
|
||||
.navigation-menu ol ol {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
padding-left: 30px; /* gap between each level */
|
||||
}
|
||||
|
||||
.navigation-menu ol.sortable, .navigation-menu ol.sortable ol {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.navigation-menu ol.sortable {
|
||||
}
|
||||
|
||||
.navigation-menu li {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
}
|
||||
|
||||
.navigation-menu li div {
|
||||
border: 1px solid #ccc;
|
||||
cursor: move;
|
||||
padding: 3px 10px 3px 30px;
|
||||
margin: 2px;
|
||||
background: #eee;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.navigation-menu li div:hover {
|
||||
background: #eee url(images/move.gif) no-repeat 10px 10px;
|
||||
}
|
||||
|
||||
.navigation-text
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
.navigation-position
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.navigation-url
|
||||
{
|
||||
}
|
||||
|
||||
.navigation-actions
|
||||
{
|
||||
}
|
||||
|
||||
/* style for the dynamically created placeholder */
|
||||
.navigation-menu li.navigation-placeholder
|
||||
{
|
||||
background: #dadada;
|
||||
}
|
@ -3,40 +3,22 @@
|
||||
@using Orchard.Core.Navigation.Models;
|
||||
@using Orchard.Core.Navigation.ViewModels;
|
||||
|
||||
@{ Layout.Title = T("Navigation").ToString(); }
|
||||
@{
|
||||
Layout.Title = T("Navigation").ToString();
|
||||
Style.Include("navigation-admin.css");
|
||||
|
||||
Script.Require("jQueryUI_Sortable");
|
||||
Script.Include("jquery.mjs.nestedSortable.js");
|
||||
Script.Include("navigation-admin.js");
|
||||
}
|
||||
|
||||
@using (Html.BeginFormAntiForgeryPost()) {
|
||||
<table class="items">
|
||||
<colgroup>
|
||||
<col id="Text" />
|
||||
<col id="Position" />
|
||||
<col id="Url" />
|
||||
<col id="Actions" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<td scope="col">@T("Text")</td>
|
||||
<td scope="col">@T("Position")</td>
|
||||
<td scope="col">@T("Url")</td>
|
||||
<td scope="col"></td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>@{
|
||||
var menuPartEntryIndex = 0;
|
||||
foreach (var menuPartEntry in Model.MenuItemEntries) {
|
||||
var i = menuPartEntryIndex;
|
||||
<tr>
|
||||
<td><input type="text" class="text-box" name="@Html.NameOf(m => m.MenuItemEntries[i].Text)" value="@menuPartEntry.Text" /></td>
|
||||
<td><input type="text" class="text-box" name="@Html.NameOf(m => m.MenuItemEntries[i].Position)" value="@menuPartEntry.Position" /></td>
|
||||
<td>@if (!menuPartEntry.IsMenuItem) {<input type="text" class="text-box disabled" disabled="disabled" value="@menuPartEntry.Url" /> } else {<input type="text" class="text-box" name="@Html.NameOf(m => m.MenuItemEntries[i].Url)" value="@menuPartEntry.Url" />}</td>
|
||||
<td><input type="hidden" name="@Html.NameOf(m => m.MenuItemEntries[i].MenuItemId)" value="@menuPartEntry.MenuItemId" />@Html.ActionLink(T("Delete").Text, "Delete", new { id = menuPartEntry.MenuItemId }, new { @class="remove", itemprop="RemoveUrl UnsafeUrl" })</td>
|
||||
</tr>
|
||||
++menuPartEntryIndex;
|
||||
}
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
<fieldset class="actions"><button type="submit" class="button">@T("Update All")</button></fieldset>
|
||||
|
||||
<div class="navigation-menu">
|
||||
@RenderMenuItems(Model.MenuItemEntries, 0)
|
||||
</div>
|
||||
|
||||
<fieldset class="actions"><button type="submit" class="button">@T("Save All")</button></fieldset>
|
||||
}
|
||||
|
||||
<h2>@T("Add New Item")</h2>
|
||||
@ -66,4 +48,56 @@
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@helper RenderMenuItems(IList<MenuItemEntry> menuItems, int index) {
|
||||
|
||||
@:<ol>
|
||||
|
||||
// store current level to detect lowerb or upper level
|
||||
int currentLevel = Model.MenuItemEntries[index].Position.Split('.').Length - 1;
|
||||
bool first = true;
|
||||
|
||||
for (int i = index; i < Model.MenuItemEntries.Count; i++) {
|
||||
|
||||
var menuPartEntry = Model.MenuItemEntries[i];
|
||||
var level = menuPartEntry.Position.Split('.').Length - 1; // 0 is for root level
|
||||
|
||||
if (level > currentLevel) {
|
||||
// render sub level, then continue to next element
|
||||
@RenderMenuItems(menuItems, i)
|
||||
|
||||
var j = i;
|
||||
while (j < Model.MenuItemEntries.Count && Model.MenuItemEntries[j].Position.Split('.').Length - 1 > currentLevel) { j++; };
|
||||
i = j - 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (level == currentLevel) {
|
||||
if(!first) {
|
||||
@:</li>
|
||||
}
|
||||
|
||||
first = false;
|
||||
|
||||
@:<li class="navigation-menu-item" data-index="@i">
|
||||
|
||||
<div>
|
||||
<span class="navigation-text"><input type="text" class="text-box" name="@Html.NameOf(m => m.MenuItemEntries[i].Text)" value="@menuPartEntry.Text" /></span>
|
||||
<span class="navigation-position"><input type="text" class="text-box" name="@Html.NameOf(m => m.MenuItemEntries[i].Position)" value="@menuPartEntry.Position" /></span>
|
||||
<span class="navigation-url">@if (!menuPartEntry.IsMenuItem) {<input type="text textMedium" class="text-box disabled" disabled="disabled" value="@menuPartEntry.Url" /> } else {<input type="text" class="text-box textMedium" name="@Html.NameOf(m => m.MenuItemEntries[i].Url)" value="@menuPartEntry.Url" />}</span>
|
||||
<span class="navigation-actions"><input type="hidden" name="@Html.NameOf(m => m.MenuItemEntries[i].MenuItemId)" value="@menuPartEntry.MenuItemId" />@Html.ActionLink(T("Delete").Text, "Delete", new { id = menuPartEntry.MenuItemId }, new { @class = "remove", itemprop = "RemoveUrl UnsafeUrl" })</span>
|
||||
</div>
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// done with current level
|
||||
if (level < currentLevel) {
|
||||
@:</li>
|
||||
break;
|
||||
}
|
||||
}
|
||||
@:</ol>
|
||||
}
|
||||
|
@ -277,6 +277,9 @@
|
||||
<Content Include="Common\Views\Body.Editor.cshtml" />
|
||||
<Content Include="Contents\Module.txt" />
|
||||
<Content Include="Contents\Views\Admin\CreatableTypeList.cshtml" />
|
||||
<Content Include="Navigation\Scripts\jquery.mjs.nestedSortable.js" />
|
||||
<Content Include="Navigation\Scripts\navigation-admin.js" />
|
||||
<Content Include="Navigation\Styles\navigation-admin.css" />
|
||||
<Content Include="Navigation\Styles\images\menu.navigation.png" />
|
||||
<Content Include="Navigation\Styles\menu.navigation-admin.css" />
|
||||
<Content Include="Reports\Module.txt" />
|
||||
@ -483,6 +486,11 @@
|
||||
<ItemGroup>
|
||||
<Content Include="Common\Views\Body-Small.Editor.cshtml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Navigation\Scripts\Web.config">
|
||||
<SubType>Designer</SubType>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
|
Loading…
Reference in New Issue
Block a user