Home » Commands » Copy Sitecore Item Field Values To Your Clipboard as JSON

Copy Sitecore Item Field Values To Your Clipboard as JSON

Sitecore Technology MVP 2016
Sitecore MVP 2015
Sitecore MVP 2014

Enter your email address to follow this blog and receive notifications of new posts by email.

With all the exciting things happening around json recently — the Sitecore Item Web API (check out this awesome presentation on the Sitecore Item Web API) and pasting JSON As classes in ASP.NET and Web Tools 2012.2 RC — I’ve been plagued by json on the brain.

For the past few weeks, I’ve been thinking about building a Sitecore client command that copies fields values from a Sitecore item into a string of json via the clipboard, though have been struggling with whether such a command has any utility.

Tonight, I decided to build such a command. Here is what I came up with.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Sitecore.Configuration;
using Sitecore.Data.Fields;
using Sitecore.Data.Items;
using Sitecore.Data.Managers;
using Sitecore.Data.Templates;
using Sitecore.Diagnostics;
using Sitecore.Shell.Framework.Commands;
using Sitecore.Web.UI.Sheer;

using Sitecore.Sandbox.Utilities.Serialization.Base;
using Sitecore.Sandbox.Utilities.Serialization;

namespace Sitecore.Sandbox.Commands
{
    public class CopyItemAsJsonToClipboard : ClipboardCommand
    {
        private const bool AlertIfClipboardCopyNotSupported = true;
        private static readonly CopyToClipboard CopyToClipboard = new CopyToClipboard();

        private Template _StandardTemplate;
        private Template StandardTemplate 
        {
            get
            {
                if(_StandardTemplate == null)
                {
                    _StandardTemplate = GetStandardTemplate();
                }

                return _StandardTemplate;
            }
        }

        private static Template GetStandardTemplate()
        {
            return TemplateManager.GetTemplate(Settings.DefaultBaseTemplate, Context.ContentDatabase);
        }
        
        public override void Execute(CommandContext commandContext)
        {
            Assert.ArgumentNotNull(commandContext, "commandContext");

            if (IsSupported(AlertIfClipboardCopyNotSupported))
            {
                IEnumerable<Field> fields = GetNonStandardTemplateFields(commandContext);
                CopyToClipBoard(GetFieldsAsJson(fields));
            }
        }

        private static string GetFieldsAsJson(IEnumerable<Field> fields)
        {
            Assert.ArgumentNotNull(fields, "fields");
            IList<string> list = new List<string>();
            foreach(Field field in fields)
            {
                list.Add(string.Format("\"{0}\":\"{1}\"", field.Name, EscapeNewlines(field.Value)));
            }

            return string.Concat("{", string.Join(",", list), "}");
        }

        private static string EscapeNewlines(string value)
        {
            Assert.ArgumentNotNull(value, "value");
            return ReplaceSubstrings
            (
                value,
                new KeyValuePair<string, string>[] 
                { 
                    new KeyValuePair<string, string>("\n", "\\n"),
                    new KeyValuePair<string, string>("\r", "\\r")
                }
            );
        }

        private static string ReplaceSubstrings(string source, IEnumerable<KeyValuePair<string, string>> oldNewValues)
        {
            Assert.ArgumentNotNull(source, "source");
            Assert.ArgumentNotNull(oldNewValues, "oldNewValues");
            foreach (KeyValuePair<string, string> oldNewValue in oldNewValues)
            {
                source = source.Replace(oldNewValue.Key, oldNewValue.Value);
            }

            return source;
        }

        private IEnumerable<Field> GetNonStandardTemplateFields(CommandContext commandContext)
        {
            return GetNonStandardTemplateFields(GetItemWithAllFields(commandContext));
        }

        private IEnumerable<Field> GetNonStandardTemplateFields(Item item)
        {
            Assert.ArgumentNotNull(item, "item");
            return GetNonStandardTemplateFields(item.Fields);
        }

        private IEnumerable<Field> GetNonStandardTemplateFields(IEnumerable<Field> fields)
        {
            Assert.ArgumentNotNull(fields, "fields");
            return fields.Where(field => !IsStandardTemplateField(field));
        }

        private static void CopyToClipBoard(string json)
        {
            if(!string.IsNullOrEmpty(json))
            {
                SheerResponse.Eval(GetCopyToClipBoardJavascript(json));
            }
        }

        private static string GetCopyToClipBoardJavascript(string json)
        {
            Assert.ArgumentNotNullOrEmpty(json, "json");
            return string.Format("window.clipboardData.setData('Text', '{0}')", json);
        }

        public override CommandState QueryState(CommandContext commandContext)
        {
            Assert.ArgumentNotNull(commandContext, "commandContext");
            Item item = GetItemWithAllFields(commandContext);
            bool makeEnabled = CopyToClipboard.QueryState(commandContext) == CommandState.Enabled && HasFields(item);

            if (makeEnabled)
            {
                return CommandState.Enabled;
            }

            return CommandState.Disabled;
        }

        private static bool HasFields(Item item)
        {
            Assert.ArgumentNotNull(item, "item");
            return item.Fields.Any();
        }

        private static Item GetItemWithAllFields(CommandContext commandContext)
        {
            Assert.ArgumentNotNull(commandContext, "commandContext");
            Item item = GetItem(commandContext);

            if (item != null)
            {
                item.Fields.ReadAll();
            }
            
            return item;
        }

        public bool IsStandardTemplateField(Field field)
        {
            Assert.ArgumentNotNull(StandardTemplate, "StandardTemplate");
            return StandardTemplate.ContainsField(field.ID);
        }

        private static Item GetItem(CommandContext commandContext)
        {
            Assert.ArgumentNotNull(commandContext, "commandContext");
            Assert.ArgumentNotNull(commandContext.Items, "commandContext.Items");
            Assert.ArgumentCondition(commandContext.Items.Any(), "commandContext.Items", "There must be at least one item in the array!");
            return commandContext.Items.FirstOrDefault();
        }
    }
}

The command above iterates over all fields on the selected item — not including those that are defined in the Standard Template — and builds a string of json containing field names accompanied by their values.

I found this article by John West to be extremely helpful in writing the code above to determine if a field belongs to the Standard Template — this is used when leaving out these fields in our resulting json string.

Further, the command is only enabled when the selected item has fields coupled with the CommandState returned by a call to the QueryState() method on an instance of Sitecore.Shell.Framework.Commands.CopyToClipboard — this object’s QueryState() method checks things we care about, and I wanted to leverage its logic.

I then mapped the command above in a patch include file:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <sitecore>
    <commands>
      <command name="item:copyitemasjsontoclipboard" type="Sitecore.Sandbox.Commands.CopyItemAsJsonToClipboard,Sitecore.Sandbox"/>
    </commands>
  </sitecore>
</configuration>

Now that we have our command, let’s create an item context menu option for it:

copy-as-json-context-menu

Let’s see this thing in action.

I created an item for testing:

jsonify-me-item

I right-clicked on our new item to launch its context menu, and then clicked on the ‘Copy As Json’ menu option:

copy-as-json-context-menu-jsonify

I pasted the following from my clipboard into Notepad++:

json-string

If you can think how this, or something similar could be useful, please drop a comment.

Advertisements

2 Comments

  1. wenhao says:

    Nice .. ~

Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: