Wednesday, August 27, 2014

Configuration Visibility of Profile Cards Button in Content Editor

Usually visibility of buttons in Sitecore content editor is configured via QueryState of command, but there are few exceptions. One of this exceptions is Profile Cards button that allows you to edit the Profile Cards associated with item.chart_radar

Despite there is command declared for this button:

<command name="item:personalize" type="Sitecore.Shell.Applications.WebEdit.Commands.PersonalizeItem,Sitecore.Client"/>

and there is overridden method QueryState which usually is used to control command visibility.

But this method is not used for showing this button in content editor. Instead of it, button is rendered directly as control by Sitecore.Shell.Applications.ContentManager.Editor.RenderProfileCards . This method checks visibility by calling getItemPersonalizationVisibility pipeline.

So, if you need to show/hide Profile Cards button in Sitecore Content Editor then overriding of QueryState for item:personalize command will not take any effect. You should write you own processor for getItemPersonalizationVisibility pipeline.

Thursday, August 21, 2014

Sitecore MVC and Ajax.BeginForm: How to replace whole view with received HTML code

Ajax.BeginForm easily allows you to work add HTML code returned by view to page. It is easy to do by defining Ajax option UpdateTargetId

UpdateTargetId =
"DivContainer"
But there are only three options how received HTML content should be placed to view (InsertionMode AjaxOption):
  1. InsertionMode.InsertAfter
  2. InsertionMode.InsertBefore
  3. InsertionMode.Replace
Unfortunately, even InsertionMode.Replace mode don’t replace whole HTML element with new code, it replaces only content of this element

$(update).html(data); //jquery.unobstrusive-ajax.js
With ASP.Net MVC it is ok. You can control place where you are rendering your partial view:
<div id="DivContainer">
    @Html.Action("Action","Controller")
</div>
Then you are able to set UpdateTargetId = "DivContainer" and your form will be completely replaced.
BUT! It is not possible to do with Sitecore MVC when your view is added to some placeholder on page. Even if you wrap your view with some element
<div id="DivContainer">
@using (Ajax.BeginForm("Action", "Controller", null, new AjaxOptions {      UpdateTargetId = "DivContainer", InsertionMode = InsertionMode.Replace ….      
</div>
you’ll get a lot of wrapped divs after few updating of form:
<div id="DivContainer">
<div id="DivContainer">
<div id="DivContainer">
@using (Ajax.BeginForm("Action", "Controller", null, new AjaxOptions {      UpdateTargetId = "DivContainer", InsertionMode = InsertionMode.Replace ….      
</div>
</div>
</div>
It can break your design of JavaScript on page.
There is one solution how you are able to avoid it. Insertion HTML received by Ajax is controlled by jquery.unobstrusive-ajax.js. It is JavaScript file and you can easily modify it. For Sitecore MVC views I suggest to add additional insertion mode:
mode = (element.getAttribute("data-ajax-mode") || "").toUpperCase();
        $(element.getAttribute("data-ajax-update")).each(function (i, update) {
            var top;
            switch (mode) {
            case "BEFORE":
                top = update.firstChild;
                $("<div />").html(data).contents().each(function () {
                    update.insertBefore(this, top);
                });
                break;
            case "AFTER":
                $("<div />").html(data).contents().each(function () {
                    update.appendChild(this);
                });
                break;
            case "REPLACEWITH":
                $(update).replaceWith(data);
                break;
            default:
                $(update).html(data);
                break;
            }
        });

It will replace whole HTML element, but not only content of it.
And also you should pass corresponding html attribute to your form:
@using (Ajax.BeginForm("Action", "Controller", null, new AjaxOptions {
UpdateTargetId = "DivContainer"}new { enctype = "multipart/form-data", data_ajax_mode = "replacewith" }
Now you can do not worry about nested containers after Ajax updating of views on your Sitecore MVC application.
For future: I plan to implement my own  Ajax.BeginForm helper with similar abilities targeted on Sitecore.