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:
Let’s see this thing in action.
I created an item for testing:
I right-clicked on our new item to launch its context menu, and then clicked on the ‘Copy As Json’ menu option:
I pasted the following from my clipboard into Notepad++:
If you can think how this, or something similar could be useful, please drop a comment.
Nice .. ~
[…] https://sitecorejunkie.com/2013/03/25/copy-sitecore-item-field-values-to-your-clipboard-as-json/ […]