2019년 7월 26일 금요일

새로운 아이템 생성시 Display Name 업데이트 하기

사이트코어 CMS를 처음 사용하다 보면 Item Name과 Display Name에 대하여 혼돈이 되는 경우가 있다. Item Name은 웹페이지의 URL이 되며 아이템의 고유 이름을 뜻 한다. Display Name은 Content Editor에서 선택적으로 사용되어 Item의 닉네임이라고 생각하면 된다.

Content Editor 또는 xEditor에서 새로운 아이템 (페이지)를 추가하면 사이트코어는 새로운 Dialog 팝업을 오픈하고 Item Name을 입력하면 새로운 페이지가 형성된다. 만약 사용자가 Display Name을 추가하고자 한다면 새로 생성된 아이템으로 이동 후, Display Name 필드를 업데이트 하여야한다. 

이번 포스트에서는 Item을 생성할때 Item Name을 지정함과 동시에 Display Name도 업데이트할 수 있도록 Dialog Layout을 업데이트하고, Layout의 CodeBeside를 업데이트하여 아이템의 Display Name을 업데이트 하도록 하자.

아이템의 지정된 Insert Option은 기본적으로 Message Dialog Popup을 사용하지만 필자는 Insert Layout을 사용하여 Dialog Popup 레이아웃을 업데이트하기로 하였다.

아래는 필자가 업데이트 한 "Add New Item"의 레이아웃이다. 그리고 이 업데이트된 레이아웃을 "/sitecore/shell/override/" 폴더에 저장한다.

- /sitecore/shell/override/AddMasterContentManager.xml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?xml version="1.0" encoding="utf-8" ?>
<control xmlns:def="Definition" xmlns="http://schemas.sitecore.net/Visual-Studio-Intellisense">
  <AddMasterContentManager>
    <Stylesheet Src="SelectItemWithThumbnails.css" DeviceDependant="true" />
    
    <FormDialog ID="Dialog" Icon="Applications/32x32/document_new.png" Header="Add New Item" 
      Text="Enter an item name and display name for the new item" OKButton="Insert">
      <CodeBeside Type="Sitecore.Custom.Component.Core.Library.AddMasterForm,Sitecore.Custom.Component.Core.Library"/>
      <Script>
        Event.observe(window, "load", function() { 
          var focus = function() { $('ItemName').focus(); };
          
          $('Items').observe("click", focus);
          
          $$('#Items a.scItemThumbnail').each(function(thumb) {
            thumb.observe("click", focus);
          });
        });
      </Script>

      <div class="scStretch addMasterContainer">
        <Border Padding="4px 0px 0px 0px">
          <GridPanel Width="100%" Columns="2">
            <Border Padding="0px 4px 0px 0px" Style="white-space:nowrap;" GridPanel.Align="right" NoWrap="true">
              <Literal Text="Item Name:"/>
            </Border>
            <Edit ID="ItemName" GridPanel.Width="100%"/>
            <Border Padding="0px 4px 0px 0px" Style="white-space:nowrap;" GridPanel.Align="right" NoWrap="true">
              <Literal Text="Display Name:"/>
            </Border>
            <Edit ID="DisplayName" GridPanel.Width="100%"/>
          </GridPanel>
        </Border>
      </div>
    </FormDialog>
  </AddMasterContentManager>
</control>

아래는 Insert Option에 지정된 템플릿을 클릭하였을시 새로 생성한 레이아웃을 호출하고 Dialog 필드 값을 더블 파이프 라인 ("||")을 사용하여 Item Name과 Display Name의 값을 구분한다.

- AddMasterForm.cs

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
using System;
using Sitecore.Configuration;
using Sitecore.Diagnostics;
using Sitecore.Web.UI.HtmlControls;
using Sitecore.Web.UI.Pages;
using Sitecore.Web.UI.Sheer;
using System.Text.RegularExpressions;

namespace Sitecore.Custom.Component.Core.Library
{
    public class AddMasterForm : DialogForm
    {
        protected Edit ItemName;
        protected Edit DisplayName;

        protected override void OnLoad(EventArgs e)
        {
            Assert.ArgumentNotNull((object)e, "e");
            base.OnLoad(e);
            if (Context.ClientPage.IsEvent)
                return;
        }

        protected void OK_Click()
        {
            if (this.ItemName.Value.Length == 0)
                SheerResponse.Alert("You must specify a name for the new item.");
            else if (!Regex.IsMatch(this.ItemName.Value, Settings.ItemNameValidation, RegexOptions.ECMAScript))
                SheerResponse.Alert("The name contains invalid characters.");
            else if (this.ItemName.Value.Length > Settings.MaxItemNameLength)
            {
                SheerResponse.Alert("The name is too long.");
            }
            else
            {
                SheerResponse.SetDialogValue(this.ItemName.Value + "||" + this.DisplayName.Value);
                SheerResponse.CloseWindow();
            }
        }

        protected override void OnOK(object sender, EventArgs args)
        {
            Assert.ArgumentNotNull(sender, "sender");
            Assert.ArgumentNotNull((object)args, "args");
            this.OK_Click();
        }
    }
}

아래 코드는 새로운 "item:addmaster" 커맨드로써 "control:AddMasterContentManager" 라는 새로운 레이아웃을 불러들이고 "SetItemDisplayName" method를 통하여 새로 생성된 아이템 "obj2"의 Display Name을 업데이트 한다. 해당 코드는 "Sitecore.Shell.Framework.Commands.AddMaster" 클래스를 수정한것이다.

- AddMasterCommand.cs

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
using Sitecore.Data.Events;
using Sitecore.Data.Items;
using Sitecore.Diagnostics;
using Sitecore.Exceptions;
using Sitecore.Globalization;
using Sitecore.Resources;
using Sitecore.Shell.Framework.Commands;
using Sitecore.Text;
using Sitecore.Web.UI.Sheer;
using System;
using System.Collections.Specialized;

namespace Sitecore.Custom.Component.Core.Library
{
    /// <summary>Represents the AddMaster command.</summary>
    [Serializable]
    public class AddMasterCommand : Command
    {
        /// <summary>Occurs when item created.</summary>
        protected event ItemCreatedDelegate ItemCreated;

        /// <summary>Executes the command in the specified context.</summary>
        /// <param name="context">The context.</param>
        public override void Execute(CommandContext context)
        {
            if (context.Items.Length != 1 || !context.Items[0].Access.CanCreate())
                return;
            Item obj = context.Items[0];
            Context.ClientPage.Start((object)this, "Add", new NameValueCollection()
            {
                ["Master"] = context.Parameters["master"],
                ["ItemID"] = obj.ID.ToString(),
                ["Language"] = obj.Language.ToString(),
                ["Version"] = obj.Version.ToString()
            });
        }

        /// <summary>Queries the state of the command.</summary>
        /// <param name="context">The context.</param>
        /// <returns>The state of the command.</returns>
        public override CommandState QueryState(CommandContext context)
        {
            Error.AssertObject((object)context, nameof(context));
            if (context.Items.Length != 1)
                return CommandState.Hidden;
            if (!context.Items[0].Access.CanCreate())
                return CommandState.Disabled;
            return base.QueryState(context);
        }

        /// <summary>Adds the specified args.</summary>
        /// <param name="args">The arguments.</param>
        protected void Add(ClientPipelineArgs args)
        {
            if (!SheerResponse.CheckModified())
                return;
            Item obj1 = Context.ContentDatabase.GetItem(args.Parameters["Master"]);
            if (obj1 == null)
                SheerResponse.Alert(Translate.Text("Branch \"{0}\" not found.", (object)args.Parameters["Master"]));
            else if (obj1.TemplateID == TemplateIDs.CommandMaster)
            {
                string message = obj1["Command"];
                if (string.IsNullOrEmpty(message))
                    return;
                Context.ClientPage.SendMessage((object)this, message);
            }
            else if (args.IsPostBack)
            {
                if (!args.HasResult)
                    return;
                Item parent = Context.ContentDatabase.Items[StringUtil.GetString(args.Parameters["ItemID"]), Language.Parse(StringUtil.GetString(args.Parameters["Language"]))];
                if (parent == null)
                    SheerResponse.Alert("Parent item not found.");
                else if (!parent.Access.CanCreate())
                {
                    Context.ClientPage.ClientResponse.Alert("You do not have permission to create items here.");
                }
                else
                {
                    Item obj2 = (Item)null;
                    try
                    {
                        string[] inputValue = args.Result.Split(new[] { "||" }, StringSplitOptions.None);
                        string itemName = inputValue[0];
                        string displayName = inputValue[1];

                        if (obj1.TemplateID == TemplateIDs.BranchTemplate)
                        {
                            BranchItem branch = (BranchItem)obj1;
                            obj2 = Context.Workflow.AddItem(itemName, branch, parent);
                            Log.Audit((object)this, "Add from branch: {0}", AuditFormatter.FormatItem((Item)branch));
                        }
                        else
                        {
                            TemplateItem template = (TemplateItem)obj1;
                            obj2 = Context.Workflow.AddItem(itemName, template, parent);
                            Log.Audit((object)this, "Add from template: {0}", AuditFormatter.FormatItem((Item)template));
                        }
                        if (obj2 != null)
                        {
                            SetItemDisplayName(obj2, displayName);
                        }
                    }
                    catch (WorkflowException ex)
                    {
                        Log.Error("Workflow error: could not add item from master", (Exception)ex, (object)this);
                        SheerResponse.Alert(ex.Message);
                    }
                    if (obj2 == null || this.ItemCreated == null)
                        return;
                    this.ItemCreated((object)this, new ItemCreatedEventArgs(obj2));
                }
            }
            else
            {
                UrlString urlString = ResourceUri.Parse("control:AddMasterContentManager").ToUrlString();
                Item parent = Context.ContentDatabase.Items[StringUtil.GetString(args.Parameters["ItemID"]), Language.Parse(StringUtil.GetString(args.Parameters["Language"]))];
                parent.Uri.AddToUrlString(urlString);
                SheerResponse.ShowModalDialog(urlString.ToString(), "500px", "275px", string.Empty, true);

                args.WaitForPostBack();
            }
        }

        public void SetItemDisplayName(Item item, string displayName)
        {
            item.Editing.BeginEdit();
            item.Fields["__Display name"].Value = displayName;
            item.Editing.EndEdit();
            item.Editing.AcceptChanges();
        }
    }
}

그리고, 마지막으로 Patch를 통하여 새로운 업데이트 된 커맨드를 업데이트하여 Sitecore에 적용시킨다.

- z.Sitecore.Patch.config

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<?xml version="1.0"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:set="http://www.sitecore.net/xmlconfig/set/">
  <sitecore>
    <commands>
      <command name="item:addmaster">
        <patch:attribute name="type">Sitecore.Custom.Component.Core.Library.AddMasterCommand, Sitecore.Custom.Component.Core.Library</patch:attribute>
      </command>
    </commands>
  </sitecore>
</configuration>