4

Expanding on this question I wanted to make the template id configurable so I can have different buttons active for different templates without duplicating that code. I created a new button in Sitecore that inherits from /sitecore/templates/System/Ribbon/Large Button which has a field called Enabled On Template but I can't find a way to pass this through the javascript and into the class that inherits from PipelineProcessorControlStateRequest<ItemContext>. I tried overriding the custom button's AddAttributes method and added the field's value as an attribute however it is not available in context.button.attributes in the canExecute method of my javascript. Is there a built in way to pass values from the button's item to a pipeline processor control state request?

Here's what I tried that didn't work:

namespace Common.CustomSitecore.Speak.Controls
{
    public class UpdateButton : Sitecore.ExperienceEditor.Speak.Ribbon.Controls.LargeButton.LargeButton
    {
        public UpdateButton(RenderingParametersResolver renderingParametersResolver) : base(renderingParametersResolver)
        {
        }

        protected override void InitializeControl(RenderingParametersResolver resolver)
        {
            if(ResolveContentItem()?.TemplateId != "{MyId}")
               this.IsVisible = false;

            base.InitializeControl(resolver);
        }

        protected override void AddAttributes(HtmlTextWriter output)
        {
            //I also tried prefixing this with "data-sc-" because the html for 
            //attributes that the button ends up having seem to have that
            output.AddAttribute("EnabledOnTemplate", DataSourceItem[Constants.EnabledOnTemplateFieldId]);

            base.AddAttributes(output);
        }
    }

    public static class ControlsExtension
    {
        public static HtmlString UpdateButton(this Sitecore.Mvc.Controls controls, Rendering rendering)
        {
            Sitecore.Diagnostics.Assert.ArgumentNotNull(controls, "controls");
            Sitecore.Diagnostics.Assert.ArgumentNotNull(rendering, "rendering");
            var largeButton = new UpdateButton(controls.GetParametersResolver(rendering));
            return new HtmlString(largeButton.Render());
        }
    }
}

Js:

define(["sitecore", "/-/speak/v1/ExperienceEditor/ExperienceEditor.js"], function (Sitecore, ExperienceEditor) {
    Sitecore.Commands.MyCustomCommand =
    {
        canExecute: function (context) {
            if (!ExperienceEditor.isInMode("edit")) {
                return false;
            }
            //Here I wanted to read the attribute I added however it does not
            //seem to be attached to the button. After that I was going to create a
            //new item context to use the with the request but since I can't even 
            //seem to read it here I think this approach is a dead end because
            //context.button.attributes.EnabledOnTemplate is undefined
            context.currentContext.EnabledOnTemplate = context.button.attributes.EnabledOnTemplate;

            return context.app.canExecute("Custom.CanExecute", context.currentContext);
        }
    };
});

2 Answers 2

2

This feels like a ton of hacking to pass some parameters. I opted to pass the ribbon id instead of individual field values because I ended up needing more parameters.

Adding the id of the ribbon button to attributes:

namespace Common.CustomSitecore.Speak.Controls
{
    public class UpdateButton : Sitecore.ExperienceEditor.Speak.Ribbon.Controls.LargeButton.LargeButton
    {
        public UpdateButton(RenderingParametersResolver renderingParametersResolver) : base(renderingParametersResolver)
        {
        }

        protected override void InitializeControl(RenderingParametersResolver resolver)
        {
            if(ResolveContentItem()?.TemplateId != "{MyId}")
               this.IsVisible = false;

            base.InitializeControl(resolver);
        }

        protected override void AddAttributes(HtmlTextWriter output)
        {
            //I also tried prefixing this with "data-sc-" because the html for 
            //attributes that the button ends up having seem to have that
            output.AddAttribute("data-sc-ribbonButton", DataSourceItem.ID.ToString().UrlEncode());

            base.AddAttributes(output);
        }
    }

    public static class ControlsExtension
    {
        public static HtmlString UpdateButton(this Sitecore.Mvc.Controls controls, Rendering rendering)
        {
            Sitecore.Diagnostics.Assert.ArgumentNotNull(controls, "controls");
            Sitecore.Diagnostics.Assert.ArgumentNotNull(rendering, "rendering");
            var largeButton = new UpdateButton(controls.GetParametersResolver(rendering));
            return new HtmlString(largeButton.Render());
        }
    }
}

Accessing it and passing it to the request via javascript:

define(["sitecore", "/-/speak/v1/ExperienceEditor/ExperienceEditor.js"], function (Sitecore, ExperienceEditor) {
    Sitecore.Commands.MyCustomCommand =
    {
        canExecute: function (context) {
            if (!ExperienceEditor.isInMode("edit")) {
                return false;
            }

            var button = ExperienceEditor.Common.getElementById(context.button.attributes.name);

            context.currentContext.ribbonButton = button.attributes["data-sc-ribbonButton"].nodeValue;
            return context.app.canExecute("Custom.CanExecute", context.currentContext);
        }
    };
});

Custom context for the request:

namespace Common.CustomSitecore.Speak.Server.Contexts
{
    public class RibbonButtonItemContext : ItemContext
    {
        [JsonProperty("ribbonButton")]
        public string RibbonButton { get; set; }

        [JsonIgnore] private Item ribbonItem;

        //This is basically copied from the Item property with the id used updated and db 
        //that the item is pulled from updated
        [JsonIgnore]
        public Item RibbonButtonItem
        {
            get
            {
                if (ribbonItem != null)
                    return ribbonItem;
                //This might be a dangerous move! There is a database name passed but it's for 
                //the current content item. It might be worth routing this through as an 
                //attribute like the id
                var database = Factory.GetDatabase("core");
                Sitecore.Diagnostics.Assert.IsNotNull(database, "Could not get database, with name core");
                ID result;
                Sitecore.Diagnostics.Assert.IsTrue((ID.TryParse(RibbonButton, out result) ? 1 : 0) != 0, "Could not get item with id:{0} from database: core", RibbonButton);
                if (Language == null)
                    Language = Sitecore.Context.User.Profile.ClientLanguage;
                var language = (Sitecore.Globalization.Language)null;
                if (!string.IsNullOrEmpty(this.Language))
                    language = LanguageManager.GetLanguage(this.Language);
                var version = GetVersion(Version);
                if (language != null && version != null)
                    ribbonItem = database.GetItem(result, language, version);
                if (ribbonItem == null && language != null)
                    ribbonItem = database.GetItem(result, language);
                return ribbonItem ?? (ribbonItem = database.GetItem(result));
            }
        }
    }
}

Request using the custom context:

namespace Common.CustomSitecore.Requests.SharedContent
{
    public class CanExecute: PipelineProcessorControlStateRequest<ItemContext>
    {
        public override bool GetControlState()
        {
            //we now have access to RequestContext.RibbonButton which can be used to get 
            //the ribbon button item from core
            return base.RequestContext.Item.InheritsFrom(Constants.MyTemplateID);
        }
    }
}
1

As far as I see this is not really supported without hacking Sitecore. The LargeButton has his own .js and .cshtml which is collecting the properties from the core database. Exactly in the following folder: \sitecore\shell\client\Sitecore\Speak\Ribbon\Controls\LargeButton.

If you have look in the LargeButton.cshtml then you can see it uses the LargeButton class from the Sitecore.ExperienceEditor.Speak.Ribbon.Controls.LargeButton.

What you could do

Create your own button based on the LargeButton, you need the following then:

  1. Create the button rendering item in core database based on /sitecore/client/Applications/ExperienceEditor/Common/Layouts/Renderings/Ribbon/LargeButton item
  2. Create your own .cshtml and .js based on the files what I mentioned above
  3. Implement your own Ribbon Control at the end where you can have access to the Rendering Parameters and add new attributes, something like this:

    public class CustomLargeButton : RibbonIconButtonBase
    {
        public CustomLargeButton()
        {
        }
    
        public CustomLargeButton(RenderingParametersResolver parametersResolver)
            : base(parametersResolver)
        {
        }
    
        protected override void InitializeControl(RenderingParametersResolver parametersResolver)
        {
            base.InitializeControl(parametersResolver);
            this.Attributes["data-sc-mycustomattribute"] = renderingParametersResolver.GetString("MyCustomAttribute", string.Empty);
        }
    }
    
3
  • How do I actually access the value set on data-sc-mycustomattribute in my class that inherits PipelineProcessorControlStateRequest<ItemContext> in the linked question? Note that the code block with the class UpdateButton is already my custom ribbon button. I see the attributes set in the js when doing it the way I have it, I'm just not positive how to get them and then send them to ee requests (i.e. Custom.CanExecute).
    – Teeknow
    Commented Feb 28, 2018 at 17:22
  • @Teeknow you are right, I did not read it carefully. I will recheck. Commented Feb 28, 2018 at 18:08
  • I can't edit my comment at this point but I meant I see the attributes in the html. I'm not able to get them in the js through context.button.attributes.
    – Teeknow
    Commented Feb 28, 2018 at 18:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.