Skip to content

Instantly share code, notes, and snippets.

@jacobjones
Last active September 12, 2020 00:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jacobjones/ab73e3858bb11a97ae027b962ed71aee to your computer and use it in GitHub Desktop.
Save jacobjones/ab73e3858bb11a97ae027b962ed71aee to your computer and use it in GitHub Desktop.
A plugin which allows editors to easily move categories within Episerver (https://jakejon.es/blog/a-plugin-to-move-categories-in-episerver)
<%@ Page Language="c#" CodeBehind="MoveCategories.aspx.cs" AutoEventWireup="False" Inherits="AlloyDemoKit.AddOns.MoveCategories.MoveCategories" Title="Move Categories" %>
<%@ Register TagPrefix="EPiServerUI" Namespace="EPiServer.UI.WebControls" Assembly="EPiServer.UI, Version=11.23.0.0, Culture=neutral, PublicKeyToken=8fe83dea738b45b7" %>
<asp:content contentplaceholderid="MainRegion" runat="server">
<asp:Panel runat="server" CssClass="EP-systemMessage" ID="errorPanel" Visible="false">
<asp:Literal runat="server" ID="errorText" />
</asp:Panel>
<div class="epi-formArea epi-paddingVertical-small">
<div class="epi-size15">
<div>
<asp:Label AssociatedControlID="sourceList" Text="Category" runat="server" />
<asp:DropDownList ID="sourceList" runat="server"/>
</div>
<div>
<asp:Label AssociatedControlID="destinationList" Text="Destination" runat="server" />
<asp:DropDownList ID="destinationList" runat="server"/>
</div>
<div class="epi-buttonContainer">
<EPiServerUI:ToolButton id="saveButton" DisablePageLeaveCheck="true" OnClick="Move_Click" runat="server" SkinID="Save" text="Move" ToolTip="Move the specified category" />
</div>
</div>
</div>
</asp:content>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Web.UI.WebControls;
using EPiServer;
using EPiServer.DataAbstraction;
using EPiServer.PlugIn;
using EPiServer.Security;
using EPiServer.ServiceLocation;
using EPiServer.Shell.WebForms;
namespace AlloyDemoKit.AddOns.MoveCategories
{
[GuiPlugIn(
DisplayName = "Move Categories",
Description = "Move Categories",
RequiredAccess = AccessLevel.Administer,
Area = PlugInArea.AdminMenu,
Url = "~/AddOns/MoveCategories/MoveCategories.aspx")]
public partial class MoveCategories : WebFormsBase
{
private readonly Injected<CategoryRepository> _categoryRepository = default(Injected<CategoryRepository>);
protected override void OnPreInit(EventArgs e)
{
base.OnPreInit(e);
MasterPageFile = UriSupport.ResolveUrlFromUIBySettings("MasterPages/EPiServerUI.master");
SystemMessageContainer.Heading = "Move Categories";
SystemMessageContainer.Description = "Move a category (and it's descendants) to anywhere within the category tree.";
}
protected override void OnLoad(EventArgs e)
{
if (!PrincipalInfo.HasAdminAccess)
{
Response.Clear();
Response.StatusCode = (int)HttpStatusCode.Unauthorized;
return;
}
base.OnLoad(e);
if (!IsPostBack) {
Setup();
}
}
private void Setup()
{
// Hide any errors
errorPanel.Visible = false;
errorText.Text = null;
var root = _categoryRepository.Service.GetRoot();
var items = new List<ListItem>();
GetCategories(root, items, 0);
sourceList.DataSource =
items.Where(x => !x.Value.Equals(root.ID.ToString(), StringComparison.OrdinalIgnoreCase));
sourceList.DataValueField = nameof(ListItem.Value);
sourceList.DataTextField = nameof(ListItem.Text);
sourceList.DataBind();
destinationList.DataSource = items;
destinationList.DataValueField = nameof(ListItem.Value);
destinationList.DataTextField = nameof(ListItem.Text);
destinationList.DataBind();
}
private static void GetCategories(Category category, ICollection<ListItem> items, int depth)
{
items.Add(new ListItem
{
Text = $"{new StringBuilder().Insert(0, "⁠—", depth)}{category.Description ?? category.Name}",
Value = category.ID.ToString()
});
if (category.Categories == null)
{
return;
}
foreach (var child in category.Categories)
{
GetCategories(child, items, depth + 1);
}
}
private void ShowError(string message)
{
Setup();
errorPanel.Visible = true;
errorText.Text = message;
}
protected void Move_Click(object sender, EventArgs e)
{
var source = Request.Form[(string) sourceList.UniqueID];
var destination = Request.Form[(string) destinationList.UniqueID];
if (string.IsNullOrEmpty(source))
{
ShowError("No category selected.");
return;
}
if (string.IsNullOrEmpty(destination))
{
ShowError("No destination category selected.");
return;
}
int sourceId;
int destinationId;
if (!int.TryParse(source, out sourceId))
{
ShowError("Invalid category selected.");
return;
}
if (!int.TryParse(destination, out destinationId))
{
ShowError("Invalid destination category selected.");
return;
}
var category = _categoryRepository.Service.Get(sourceId);
if (category == null)
{
ShowError("Could not retrieve the specified category.");
return;
}
if (category.Parent.ID == destinationId)
{
ShowError("Category already lives under the specified destination.");
return;
}
category = category.CreateWritableClone();
// Update the parent
category.Parent = _categoryRepository.Service.Get(destinationId);
_categoryRepository.Service.Save(category);
Setup();
}
}
}
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace AlloyDemoKit.AddOns.MoveCategories {
public partial class MoveCategories {
/// <summary>
/// errorPanel control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Panel errorPanel;
/// <summary>
/// errorText control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Literal errorText;
/// <summary>
/// sourceList control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.DropDownList sourceList;
/// <summary>
/// destinationList control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.DropDownList destinationList;
/// <summary>
/// saveButton control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::EPiServer.UI.WebControls.ToolButton saveButton;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment