Search option for Sitecore Item icon

Are you one of those who thought that the set icon for a Sitecore item is cumbersome and it will be good to have a search option? Then, this blog post has already evoked your interest. Like you, I'm one of those who wished to have a search functionality to search and select the item icon instead of depending on the cumbersome combobox selection based on category to find the required icon. So, in this blog post I delve into the technical design of the Set Icon functionality and have modified the current functionality by adding an additional search option to the set icon dialog to filter the icons based on search keyword. 

A snapshot of how the modified dialog looks-like:


Note: The select toggle holds the original combobox functionality as-is and is the default.

End-result Video for your eyes only:

Details:

While setting an item icon, the "Set Icon.xml" is invoked and it resides in this location:

<web app root>\sitecore\shell\Applications\Content Manager\Dialogs\Set Icon\

The invoked code-beside type is this: "Sitecore.Shell.Applications.ContentManager.Dialogs.SetIcon.SetIconForm,Sitecore.Client"

Also, one of  my earlier blog posts already covers overriding Sitecore dialog forms. So, in order to override the above Set Icon functionality, setup the project structure as follows with the xml and js file going under the override folder:


Dotpeek to the rescue for above code:


For reference, the overridden Set Icon.xml looks like as follows:


The first gain as a end-result of setting up toggle with two div tags - one with the old select functionality and the second div with the new search functionality is as follows:


Diagrammatic representation of important artifacts:

These are the main artifacts relevant to set icon in the website root folder:

With regard to the technical design, the icons for each category is reside as map coords within a separate html page and these html pages are auto-generated and added to temp folder under the website root during load of set icon dialog and from the next time, the html pages are loaded from the temp folder if present and understandably, regenerated and loaded if not present:


Category and html interrelationship:

Each category is dependent on its own html page in the file system like as follows and based on the category selected, the html is assigned to the Set Icon dialog' scrollbox:


Diagrammatic representation of icon flow:


Also, during the first-time load or if the category-related html page is not present, they are regenerated automatically.  All the icons for each category (part of installation package) is unzipped from the respective zip file present in this location: <web app root>\sitecore\shell\Themes\Standard to <web app root>\temp\IconCache and thereafter the icons are loaded from temp folder location. Note that these zip files are part of the Sitecore installation package:


SOLID principle

Also, I accommodated SOLID design principle in the new search functionality to keep the existing select functionality pristine from the new changes. Here is the new abstract class and child class for Search functionality wherein RenderIcons and DrawIcons are abstract methods overridden by the child class.


Code (with comments) for reference:

////////
///////

Two important methods:
- RenderIcons has a second overload too that is invoked by the first one
- DrawIcons is the most important one that writes the html file as well as the icon image to file system

The DrawIcons method is responsible for arranging icons as areas under a map within respective html page for the category. Unfortunately, working with area is quite a pain, in other words, the dynamic capabilities are limited. In order to understand what I mean you can check the attributes for area in w3schools. So, I decided to build the html dynamically on the server-side based on the entered keyword in the search field. The other issue I had was to find the equivalent Sitecore control for each html control. For instance input text is called Edit and fyi, these controls are part of Sitecore.Web.UI.HtmlControls namespace within Sitecore.Kernel.dll.

Existing DrawIcons method responsibility:

Params:
a. prefix - icon category
b. img - the bitmap name 
c. area - final html file name 

Steps:
1. Get all files related to an icon category 
2. Calculate height of the whole bitmap based on no. of files - image created from this bitmap will be stored to file system as png
3. For each category, start loop for creating the html with map area details
4. Inside the loop, calculate coords for each image along with alt and other area attributes
5. Write area line for each file
6. When all files are traversed, close the map tag
7. Write the html file in the file system for the category since map/area is concatenated and ready to be loaded to respective scrollbox
8. Also store bitmap as png - created in step 2

New DrawIcons method responsibility:

Params:
a. prefix - icon category
b. img - the bitmap name 
c. area - final html file name 

Steps:
0. Get all Categories as a list/array
1. Calculate height of the whole bitmap based on no. of files in the list - image created from this bitmap will be stored to file system as png
2. For whole list, start loop for creating the html with map area details
3. Inside the loop for each file, calculate coords for each image along with alt and other area attributes
4. Write area line for each file
5. When the whole list is traversed, close the map tag
6. Write the html file in the file system that has map/area concatenated (for whole list) and loaded to the new complete scrollbox
7. Also store bitmap as png - created in step 1

Site Icon.xml:

This file is deployed to \sitecore\shell\override\Applications\Content Manager\Dialogs\Set Icon folder.


SetIcon.js

In the same location as the above xml file, the js file has the new js functions for toggle effect:


Code-beside Search button click event handler

The instantiated object (in the event handler) is from the new child class holding the search logic:


icons_Complete.html

The new change creates a html file named icons_Complete.html in the same website temp folder alongside other html files but with just the searched results every time the user clicks the Search button. If the search text is blank and the search button is clicked, icons across all categories are displayed. Enter a keyword and press the search button to filter based on the keyword. In other words, the icons_Complete.html gets regenerated every time.

Github

Summary of technical information

All icons are stored as map/areas in html files here in this location with same folder name as the category name in the combo box:

<web app root>\temp

The images (part of Sitecore installer) sit under a sub-folder named IconCache like as follows:

Base image location: <web app root>\temp\IconCache

An example of above explanation can be visually seen here in your file system wherein Business is one of the combo box category name:

Image location: <web app root>\temp\IconCache\Business\32x32

Two issues:

1. Office white images appear white since gray background is not set yet

2. Search button doesn't work for second time, modal has to be re-opened for results to reflect in the scrollbox

Common Error(s)

Here below is one type of error(ysod  while opening the Set Icon dialog) that bothered me and the reason is due to the fact that the html construct of <input type="text"..... /> is not liked by Sitecore. In other words, my xml looked like this:

<input type="text" name="SearchText" ID="SearchText" Placeholder="Search by Icon name..." />

instead of this: 

<Edit name="SearchText" ID="SearchText" Placeholder="Search by Icon name..." />

Associated Code-beside declaration:

protected  Input SearchText { get; set; }

Note that in the above case, Edit is of base type Input so, code-beside is fine with Input instead of Edit and it is the markup that is at fault.

To overcome such type of errors, you can find the relevant control type from Sitecore.Web.UI.HtmlControls namespace in Sitecore.Kernel.dll and use the same type in markup and code-beside.

YSOD:

Server Error in '/' Application.

The CodeBeside class includes the property 'SearchText', but its type (Sitecore.Web.UI.HtmlControls.Input) is not compatible with the type of control (Sitecore.Web.UI.XmlControls.GenericControl). (method: Sitecore.Web.UI.Sheer.ClientPage.CreateControls()).

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.Exception: The CodeBeside class includes the property 'SearchText', but its type (Sitecore.Web.UI.HtmlControls.Input) is not compatible with the type of control (Sitecore.Web.UI.XmlControls.GenericControl). (method: Sitecore.Web.UI.Sheer.ClientPage.CreateControls()).

Source Error:

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.


Stack Trace:

[Exception: The CodeBeside class includes the property 'SearchText', but its type 
(Sitecore.Web.UI.HtmlControls.Input) is not compatible with the type of control 
(Sitecore.Web.UI.XmlControls.GenericControl). 
(method: Sitecore.Web.UI.Sheer.ClientPage.CreateControls()).]
   Sitecore.Diagnostics.Error.Raise(String error, String method) +133
   Sitecore.Web.UI.Sheer.ClientPage.BindControls() +1466
   Sitecore.Web.UI.Sheer.ClientPage.CreateControls() +189
   Sitecore.Web.UI.Sheer.ClientPage.OnInit(EventArgs e) +505
   System.Web.UI.Control.InitRecursive(Control namingContainer) +454
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, 
Boolean includeStagesAfterAsyncPoint) +1714



Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.8.9214.0

Comments