SUG Bangalore Kick Off!

We had our kick off session of the Sitecore User Group Bangalore yesterday (28 March 2015) and a big thank you to everyone who helped make it a success!

The session started with a brief introduction by David Brown, Engagement Manager at Verndale, followed by an Introductory Session to Sitecore 7.2 with MVC, using TDS and Glassmapper by me.

We had 12 attendees at the session with a couple of attendees joining in remotely.

Following is the recording of the session, and the presentation used.

Unfortunately, we went over the anticipated 2 hours and yet fell short of time to be able to cover glassmapper in detail. So we will organize a glassmapper specific session in an upcoming event!

Looking forward to the next session! Date to be announced soon!

Next SUG

Meanwhile – please do join our group and participate in this poll, to determine the timing of the next session!

Few of pictures from this meetup!

DSCN2934 DSCN2938

15 min break! :)
15 min break! 🙂
Advertisements

Open items from bucket search in main content tree in Sitecore

Sitecore now provides us with this very useful ways of searching for items which are organized within item buckets.
We ran into a requirement where we didn’t want multiple tabs to open as and when one clicked on a search result, and we wanted the search result item to open in the main content tree instead.
This would enable the content authors to locate items in the item tree and create subitems / manipulate them. Even though the bucket search results page does allow creation of subitems (provided insert options are set), this provides a simpler means of browsing through subitems in a more effective manner.

To be able to achieve this, we need a config update and corresponding code update.

Code:

using Sitecore;
using Sitecore.Buckets.Pipelines.UI.LaunchResultPipeline;
using Sitecore.Data;
using Sitecore.Data.Items;
using System;

namespace MySite.SitecoreProcessors
{
    public class LaunchSitecoreResultMainWindow : LaunchSitecoreResult
    {
        protected override void LaunchResult(LaunchResultArgs args)
        {
            if (!string.IsNullOrEmpty(args.IndexableId))
            {
                ID itemId = ID.Parse(args.IndexableId);
                Item myItem = Context.Database.GetItem(itemId);

                if (myItem != null)
                {
                    Context.ClientPage.SendMessage(this, String.Concat(
                        new object[] {"item:load(id=", myItem.ID, ",language=", myItem.Language, ",version=", myItem.Version, ")"}));
                }
            }
        }
    }
}

Here’s the config update:

    <sitecore>
      <processors>
        <uiLaunchResult>
          <processor desc="sitecore">
            <patch:attribute name="type">MySite.SitecoreProcessors.LaunchSitecoreResultMainWindow, MySite</patch:attribute>
          </processor>
        </uiLaunchResult>
      </processors>
    </sitecore>

So now, when we search for an item within a bucket, and click on a search result, it will open in the main content editor.

2015-03-16_022715

2015-03-16_022957

Single Select Tree in Sitecore

Consider the situation of a field in sitecore meant to allow selecting a state, and the data items in sitecore are organized by country.

2015-03-15_225216

In this situation, it is most convenient for the content author to be able to navigate through the items in a static tree structure (yes static – the drop tree makes it a little easy to just escape out and lose where you were at navigating!).

Which is why, we came up with the need for a treelist – which allows single item selection.

This can be achieved in 2 ways:

Add validation on the existing TreeList control:
This can be done using the validation field on the sitecore field in question. The following regular expression should help achieve this:

^$|^{[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}\}$

2015-03-15_225547

2015-03-15_225304

Here’s how the validation message shows up – to note here – this validation message comes up only on item save, as opposed to while adding the multiple items in the field.

2015-03-15_225324

Create a new control and add validation / transform view:

If you did have additional requirements – say sorting the items in the treelist a certain custom way in addition to restricting the number of selections to 1, you could go all out and create a new control, inheriting from the existing treelist control.
I went in and grabbed the existing code of the treelist using a reflector, and updated the code as was needed.
Below are the updates that were made (the remaining code of Sitecore.Shell.Applications.ContentEditor.TreeList were left in as is)

namespace MySite.SitecoreFields
{
    public class SingleSelectTree : TreeList
    {
        ...
        ...

        [Category("Data")]
        [Description("If set to Yes, allows only 1 item to be selected in the control")]
        public bool RestrictSingleSelection
        {
            get
            {
                return this.GetViewStateBool("RestrictSingleSelection");
            }
            set
            {
                this.SetViewStateBool("RestrictSingleSelection", value);
            }
        }

        ...
        ...

        protected new void Add()
        {
            if (Disabled)
                return;
            string viewStateString = GetViewStateString("ID");
            TreeviewEx treeviewEx = FindControl(viewStateString + "_all") as TreeviewEx;
            Assert.IsNotNull(treeviewEx, typeof(DataTreeview));
            Listbox listbox = FindControl(viewStateString + "_selected") as Listbox;
            Assert.IsNotNull(listbox, typeof(Listbox));
            if (treeviewEx != null)
            {
                Item selectionItem = treeviewEx.GetSelectionItem(Language.Parse(this.ItemLanguage), Sitecore.Data.Version.Latest);
                if (selectionItem == null)
                {
                    SheerResponse.Alert("Select an item in the Content Tree.", new string[0]);
                }
                else
                {
                    if (HasExcludeTemplateForSelection(selectionItem))
                        return;
                    if (ItemSelected(selectionItem, listbox))
                    {
                        SheerResponse.Alert("You cannot select more than one item.", new string[0]);
                    }
                    else if (IsDeniedMultipleSelection(selectionItem, listbox))
                    {
                        SheerResponse.Alert("You cannot select the same item twice.", new string[0]);
                    }
                    else
                    {
                        if (!this.HasIncludeTemplateForSelection(selectionItem))
                            return;
                        SheerResponse.Eval("scForm.browser.getControl('" + viewStateString + "_selected').selectedIndex=-1");
                        ListItem listItem = new ListItem { ID = GetUniqueID("L") };
                        Sitecore.Context.ClientPage.AddControl(listbox, listItem);
                        listItem.Header = GetHeaderValue(selectionItem);
                        listItem.Value = listItem.ID + (object)"|" + selectionItem.ID;
                        SheerResponse.Refresh(listbox);
                        TreeList.SetModified();
                    }
                }
            }
        }

        private bool ItemSelected(Item item, Listbox listbox)
        {
            Assert.ArgumentNotNull(listbox, "listbox");
            if (item == null)
                return true;
            if (!RestrictSingleSelection)
                return false;
            return (from Control control in listbox.Controls
                    select control.Value.Split('|')).Count() > 1;
        }

        ...
        ...

        private void SetProperties()
        {
            Guid tempGuid;
            string @string = StringUtil.GetString(new string[1]
              {
                this.Source
              });
            if (@string.StartsWith("query:"))
            {
                if (Sitecore.Context.ContentDatabase == null || this.ItemID == null)
                    return;
                Item current = Sitecore.Context.ContentDatabase.GetItem(this.ItemID);
                if (current == null)
                    return;
                Item obj = null;
                try
                {
                    obj = LookupSources.GetItems(current, @string).FirstOrDefault();
                }
                catch (Exception ex)
                {
                    Log.Error("Treelist field failed to execute query.", ex, (object)this);
                }
                if (obj == null)
                    return;
                this.DataSource = obj.Paths.FullPath;
            }
            else if (Guid.TryParse(@string, out tempGuid))
                this.DataSource = this.Source;
            else if (this.Source != null && !@string.Trim().StartsWith("/", StringComparison.OrdinalIgnoreCase))
            {
                this.ExcludeTemplatesForSelection = StringUtil.ExtractParameter("ExcludeTemplatesForSelection", this.Source).Trim();
                this.IncludeTemplatesForSelection = StringUtil.ExtractParameter("IncludeTemplatesForSelection", this.Source).Trim();
                this.IncludeTemplatesForDisplay = StringUtil.ExtractParameter("IncludeTemplatesForDisplay", this.Source).Trim();
                this.ExcludeTemplatesForDisplay = StringUtil.ExtractParameter("ExcludeTemplatesForDisplay", this.Source).Trim();
                this.ExcludeItemsForDisplay = StringUtil.ExtractParameter("ExcludeItemsForDisplay", this.Source).Trim();
                this.IncludeItemsForDisplay = StringUtil.ExtractParameter("IncludeItemsForDisplay", this.Source).Trim();
                this.AllowMultipleSelection = string.Compare(StringUtil.ExtractParameter("AllowMultipleSelection", this.Source).Trim().ToLowerInvariant(), "yes", StringComparison.InvariantCultureIgnoreCase) == 0;
                this.RestrictSingleSelection = string.Compare(StringUtil.ExtractParameter("RestrictSingleSelection", this.Source).Trim().ToLowerInvariant(), "yes", StringComparison.InvariantCultureIgnoreCase) == 0;
                this.DataSource = StringUtil.ExtractParameter("DataSource", this.Source).Trim().ToLowerInvariant();
                this.DatabaseName = StringUtil.ExtractParameter("databasename", this.Source).Trim().ToLowerInvariant();
            }
            else
                this.DataSource = this.Source;
        }
    }
}

Additionally you would need the corresponding sitecore updates in the Core database to add the new control:

2015-03-16_011545

You’d need the corresponding config updates here:

<sitecore>
  <!-- New control added - Single Select Tree -->
  <controlSources>
    <source mode="on" namespace="MySite.SitecoreFields" assembly="MySite" prefix="contentExtension" />
  </controlSources>
</sitecore>

And the control should now be available:

2015-03-16_011844