Font Awesome auto complete editor for EPiServer

Mattias Olsson 24.04.2015 01:46:29

Credits

http://www.mogul.com/en/about-mogul/blog/font-awesome-dropdown-for-episerver-edit-mode

Specification

I created this as a protected module that contains the following components:

  • A dojo mixin with a method that creates a memory store from the Font Awesome stylesheet parsing.
  • A custom dojo/dijit editor inheriting from my mixin and EPiServer's AutoCompleteSelectionEditor.
  • A custom attribute to use on a content type property.

This is what it looks like if you search for an icon. If you leave the field empty and just click the arrow it will give you all icons in a scrollable list.

Folder structure in VS


Dojo/dijit editor


_FontAwesomeMixin.js
First of all I created a mixin to use in my editor. I call it _FontAwesomeMixin and it contains a method to create a memory store from the included Font Awesome stylesheet. Note that the stylesheet needs to be local to be able to access the property cssRules, we cannot use a cdn hosted version:

define([
    "dojo/_base/declare",
    "dojo/store/Memory",
    'xstyle/css!../styles/font-awesome.min.css'
],
function (
    declare,
    memorystore
) {
    return declare("geta-epi-cms.editors._FontAwesomeMixin", null, {
        _createMemoryStore: function () {
            var fontAwesomeStylesheet = this._getFontAwesomeStylesheet();
            var memoryStoreData = [];

            if (fontAwesomeStylesheet != null) {
                for (var i = 0; i < fontAwesomeStylesheet.cssRules.length; i++) {
                    var rule = fontAwesomeStylesheet.cssRules[i];

                    if (!rule.selectorText || rule.selectorText.indexOf("::before") == -1) {
                        continue;
                    }

                    var selectorTexts = rule.selectorText.split(",");

                    for (var j = 0; j < selectorTexts.length; j++) {
                        var selectorText = this._trimString(selectorTexts[j]).substring(1).replace("::before", "");
                        var iconName = selectorText.substring(3);
                        var label = '<i class="fa fa-lg fa-fw ' + selectorText + '"></i> ' + iconName;
                        memoryStoreData.push({ id: selectorText, name: iconName, label: label });
                    }
                }

                memoryStoreData.sort(this._sortFunc);
            }

            return new memorystore({ data: memoryStoreData });
        },

        _getFontAwesomeStylesheet: function () {
            for (var i = 0; i < document.styleSheets.length; i++) {
                try {
                    var sheetInfo = document.styleSheets[i];

                    if (sheetInfo.href.indexOf('font-awesome') > -1) {
                        return sheetInfo;
                    }
                } catch (e) {

                }
            }

            return null;
        },

        _sortFunc: function(a, b) {
            if (a.id < b.id) {
                return -1;
            }

            if (a.id > b.id) {
                return 1;
            }

            return 0;
        },

        _trimString: function (str) {
            return str.replace(/^\s+|\s+$/g, '');
        }
    });
});


FontAwesomeAutoSuggestEditor.js

This is the actual editor that inherits from the mixin above and from EPiServer's AutoCompleteSelectionEditor. It's quite simple. The only thing it does is to call the _createMemoryStore and set two configuration variables defined in dijits _AutoCompleterMixin.

define([
    "dojo/_base/declare",
    "geta-epi-cms/editors/_FontAwesomeMixin",
    "epi/shell/form/AutoCompleteSelectionEditor"
],
function (
    declare,
    _FontAwesomeMixin,
    AutoCompleteSelectionEditor
) {
    return declare("geta-epi-cms.editors.FontAwesomeAutoSuggestEditor", [_FontAwesomeMixin, AutoCompleteSelectionEditor], {
        labelAttr: "label",
        labelType: "html",

        postMixInProperties: function() {
            this.inherited(arguments);
            this.store = this._createMemoryStore();
        }
    });
});


Property attribute
This is the code for the property attribute to use on content type properties:

[AttributeUsage(AttributeTargets.Property, AllowMultiple=false)]
public class FontAwesomeSelectionAttribute : Attribute, IMetadataAware
{
    public void OnMetadataCreated(ModelMetadata metadata)
    {
        var extendedMetaData = metadata as ExtendedMetadata;

        if (extendedMetaData == null)
        {
            return;
        }

        extendedMetaData.ClientEditingClass = "geta-epi-cms.editors.FontAwesomeAutoSuggestEditor";
        extendedMetaData.CustomEditorSettings["uiWrapperType"] = UiWrapperType.Floating;
    }
}


module.config
The configuration for my module looks like this:

<module productName="Geta EPi Cms UI" clientResourceRelativePath="" loadFromBin="false">
    <dojo>
        <paths>
            <add name="geta-epi-cms" path="ClientResources/Scripts" />
        </paths>
    </dojo>
</module>


Example
To use this on a content type property, all that's needed is to decorate a string property with the FontAwesomeSelectionAttribute:

[FontAwesomeSelection]
[Display(Name = "Icon", Order = 100)]
public virtual string IconCssClass { get; set; }