<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">Blog posts by Tuan Do</title><link href="https://world.optimizely.com/blogs/tuan-do/" /><updated>2017-08-03T06:29:03.0000000Z</updated><id>https://world.optimizely.com/blogs/tuan-do/</id><generator uri="https://world.optimizely.com/blogs/tuan-do/" version="2.0">Optimizely World</generator><entry><title>Limiting items in a ContentArea</title><link href="https://world.optimizely.com/blogs/tuan-do/dates/2017/8/limiting-items-in-a-contentarea/" /><id>https://world.optimizely.com/blogs/tuan-do/dates/2017/8/limiting-items-in-a-contentarea/</id><published>2017-08-03T06:29:03.0000000Z</published><updated>2017-08-03T06:29:03.0000000Z</updated><author><name>ima9ines</name></author><category term="Blog post" /><summary type="html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;h2&gt;Feature&lt;/h2&gt;
&lt;p&gt;The &lt;em&gt;ContentArea&lt;/em&gt; should&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Supported to limits a number of block inside it (for individual &lt;em&gt;ContentArea&lt;/em&gt;).&lt;/li&gt;
&lt;li&gt;When total blocks is over max limited size, the action links section should be hidden.&lt;/li&gt;
&lt;li&gt;When total blocks is over max limited size, editor cannot DnD a block to that &lt;em&gt;ContentArea&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Solution&lt;/h2&gt;
&lt;h3&gt;The attribute&lt;/h3&gt;
&lt;p&gt;By using attribute, we can set individual limited total items for each ContentArea.&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class MaxItemCountAttribute : Attribute
{
    public int Count { get; }

    public MaxItemCountAttribute(int maxItemCount)
    {
        Count = maxItemCount;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;The editor descriptor&lt;/h3&gt;
&lt;p&gt;We needed to extend both &lt;em&gt;ContentArea&lt;/em&gt; and &lt;em&gt;ContentAreaEditor&lt;/em&gt; widgets. Inside the custom editor descriptor, we read the value of attribute and then render it to client side.&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;/// &amp;lt;summary&amp;gt;
/// Editor descriptor that extends the &amp;lt;see cref="ContentAreaEditorDescriptor"/&amp;gt; for a &amp;lt;see cref="ContentArea"/&amp;gt;
/// that marked with &amp;lt;see cref="MaxItemCountAttribute"/&amp;gt; in order to limits total items inside it.
/// &amp;lt;/summary&amp;gt;
[EditorDescriptorRegistration(TargetType = typeof(ContentArea), UIHint = "ContentAreaWithMaxItem")]
public class CustomContentAreaEditorDescriptor : ContentAreaEditorDescriptor
{
    public CustomContentAreaEditorDescriptor()
    {
        ClientEditingClass = "alloy/contentediting/editors/CustomContentAreaEditor";
    }

    public override void ModifyMetadata(ExtendedMetadata metadata, IEnumerable&amp;lt;Attribute&amp;gt; attributes)
    {
        const string maxItemCount = "maxItemCount";
        var maxItemCountAttribute = metadata.Attributes.OfType&amp;lt;MaxItemCountAttribute&amp;gt;().SingleOrDefault();
        if (maxItemCountAttribute != null)
        {
            metadata.EditorConfiguration[maxItemCount] = maxItemCountAttribute.Count;
            metadata.OverlayConfiguration[maxItemCount] = maxItemCountAttribute.Count;
        }

        base.ModifyMetadata(metadata, attributes);

        metadata.OverlayConfiguration["customType"] = "alloy/widget/overlay/CustomContentArea";
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;The custom ContentAreaEditor&lt;/h3&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;define([
// dojo
    "dojo/_base/declare",
    "dojo/dom-style",
// epi
    "epi-cms/contentediting/editors/ContentAreaEditor"
], function (
// dojo
    declare,
    domStyle,
// epi
    ContentAreaEditor
) {
    return declare([ContentAreaEditor], {
        postCreate: function () {
            this.inherited(arguments);
            this._toggleDisplayActionLinks();
        },

        onChange: function (value) {
            this._toggleDisplayActionLinks();
        },

        _setValueAttr: function (value) {
            this.inherited(arguments);
            this._toggleDisplayActionLinks();
        },

        _toggleDisplayActionLinks: function () {
            var display = this._canAddItem();
            this.actionsContainer &amp;amp;&amp;amp; domStyle.set(this.actionsContainer, "display", display ? "" : "none");
            this.tree &amp;amp;&amp;amp; this.tree.set("readOnly", !display);
        },

        _canAddItem: function () {
            // tags:
            //      private

            if (this.maxItemCount == undefined) {
                return true;
            }

            return this.maxItemCount &amp;gt; this.model.get("value").length;
        }
    });
});&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;The custom ContentArea&lt;/h3&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;define([
// dojo
    "dojo/_base/declare",
    "dojo/dom-style",
// epi
    "epi-cms/widget/overlay/ContentArea"
], function (
// dojo
    declare,
    domStyle,
// epi
    ContentArea
) {
    return declare([ContentArea], {
        updatePosition: function () {
            this.inherited(arguments);
            this._toggleDisplayActionLinks();
        },

        executeAction: function (actionName) {
            this._toggleDisplayActionLinks();
            if (actionName === "createnewblock" &amp;amp;&amp;amp; !this._canAddItem()) {
                return;
            }

            this.inherited(arguments);
        },

        _onDrop: function (data, source, nodes, isCopy) {
            // isCopy:
            //      Flag indicating whether the drag is a copy. False indicates a move.
            // tags:
            //      protected extension

            this._toggleDisplayActionLinks();
            if (isCopy &amp;amp;&amp;amp; !this._canAddItem()) {
                return;
            }

            this.inherited(arguments);
        },

        _toggleDisplayActionLinks: function () {
            this.textWithLinks &amp;amp;&amp;amp; domStyle.set(this.textWithLinks.domNode, "display", this._canAddItem() ? "" : "none");
        },

        _canAddItem: function () {
            // tags:
            //      private

            if (this.maxItemCount == undefined) {
                return true;
            }

            return this.maxItemCount &amp;gt; this.getChildren().length;
        }
    });
});&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Start page&lt;/h3&gt;
&lt;p&gt;Add following&amp;nbsp;attributes&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;[UIHint("ContentAreaWithMaxItem")]
[MaxItemCount(5)]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;to &lt;em&gt;MainContentArea&lt;/em&gt; property&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;[Display(
    GroupName = SystemTabNames.Content,
    Order = 320)]
[CultureSpecific]
[UIHint("ContentAreaWithMaxItem")]
[MaxItemCount(5)]
public virtual ContentArea MainContentArea { get; set; }&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Result&lt;/h3&gt;
&lt;p&gt;&lt;span style="text-decoration: underline;"&gt;&lt;em&gt;On-Page Editing&lt;/em&gt; mode&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;When total items inside the ContentArea is 4 (qualified with the max item count), action links section still displayed.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://s-media-cache-ak0.pinimg.com/originals/4e/9f/6b/4e9f6bbdc3234348f97e54484258603e.png" width="1199" alt="action links displayed when not over max size of limited items" height="350" /&gt;&lt;/p&gt;
&lt;p&gt;The action links section in ContentArea is hidden when total items inside that ContentArea is 5.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://s-media-cache-ak0.pinimg.com/originals/c2/5d/44/c25d4433a62732cb3b729c4f7a2a06fa.png" width="972" alt="hide action links in ContentArea on-page editing mode" height="802" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="text-decoration: underline;"&gt;&lt;em&gt;On-Page Editing &lt;/em&gt;mode&amp;nbsp;with popup&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;The action links section in ContentArea is hidden when total items inside that ContentArea are 5&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://s-media-cache-ak0.pinimg.com/originals/75/79/75/757975259c60541b30043a64de922824.png" width="807" alt="hide action links in popup on-page editing mode" height="476" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="text-decoration: underline;"&gt;&lt;em&gt;All Properties&lt;/em&gt; mode&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;The action links section in ContentArea is hidden when total items inside that ContentArea are 5&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://s-media-cache-ak0.pinimg.com/originals/44/6f/78/446f78ec77fdfd07a28c2eab3a529919.png" width="793" alt="hide action links in ContentArea all-properties mode" height="504" /&gt;&lt;/p&gt;
&lt;h2&gt;Related topics&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="/link/cd88002025b544f2ade6441440e24911.aspx"&gt;Show label for a ContentArea when hovering&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/body&gt;
&lt;/html&gt;</summary></entry><entry><title>Show overlay label for ContentArea when hovering in On-Page-Edit mode</title><link href="https://world.optimizely.com/blogs/tuan-do/dates/2017/7/show-overlay-label-for-contentarea-when-hovering-in-on-page-edit-mode/" /><id>https://world.optimizely.com/blogs/tuan-do/dates/2017/7/show-overlay-label-for-contentarea-when-hovering-in-on-page-edit-mode/</id><published>2017-07-28T14:29:36.0000000Z</published><updated>2017-07-28T14:29:36.0000000Z</updated><author><name>ima9ines</name></author><category term="Blog post" /><summary type="html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;p&gt;Following this forum thread - &lt;a href="/link/8cc90d703fb743e1b2805321913b5a86.aspx"&gt;Show overlay label for ContentArea when hovering in On-Page-Edit mode&lt;/a&gt;, I created a custom content area to resolve it (in&amp;nbsp;Alloy MVC template).&lt;/p&gt;
&lt;p&gt;Firstly, to see how a property display its overlay label when hover, inspect its markup code&amp;nbsp;(in this case, I inspected logo on Start page). You will see it used &lt;strong&gt;infomationNode&amp;nbsp;&lt;/strong&gt;to showing:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://s-media-cache-ak0.pinimg.com/originals/f6/7f/b7/f67fb7ffa6fc3a1adf52d1369da22ccc.png" width="1045" alt="informationNode dojo attach point" height="405" /&gt;&lt;/p&gt;
&lt;p&gt;And then, looking in &lt;strong&gt;epi/shell/widget/overlay/Item&lt;/strong&gt; widget source, I found that overlay label value set by following code block:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://s-media-cache-ak0.pinimg.com/originals/87/d1/3a/87d13a6b60a2a41b53bdf522f557502e.png" width="1211" alt="overlay label code block" height="451" /&gt;&lt;/p&gt;
&lt;p&gt;Let's take a look in &lt;strong&gt;ContentArea&lt;/strong&gt; source code (see how to view source code at &lt;a href="/link/ae233441257c43f899c457011f466fdd.aspx"&gt;link&lt;/a&gt;), it extended from &lt;strong&gt;epi/shell/widget/overlay/Item&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;img src="https://s-media-cache-ak0.pinimg.com/originals/5f/fe/a0/5ffea0ed15eb26e959e4ddbd332b60ab.png" width="498" alt="ContentArea source" height="283" /&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;and also had it own template:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://s-media-cache-ak0.pinimg.com/originals/83/3c/e9/833ce98cc48b9a8db5ca0a98ca1d7c50.png" width="709" alt="default ContentArea template" height="490" /&gt;&lt;/p&gt;
&lt;p&gt;The above template missed &lt;strong&gt;informationNode&lt;/strong&gt; section, so that, nothing displayed when hover a ContentArea property in Edit mode. Well, to show overlay label for ContentArea, we just needed to add that section to ContentArea's template, like that&lt;/p&gt;
&lt;p&gt;&lt;img src="https://s-media-cache-ak0.pinimg.com/originals/6a/1c/5e/6a1c5ecc604138f2059eb5063257d67e.png" width="715" alt="ContentArea with template have informationNode" height="458" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="text-decoration: underline;"&gt;&lt;strong&gt;Let's do it step by step&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Create custom content area editor descriptor (under "/Business/EditorDescriptors/" folder)&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;/// &amp;lt;summary&amp;gt;
/// Editor descriptor that extends base editor descriptor for &amp;lt;see cref="ContentArea"/&amp;gt; in order to show overlay label when hovering in On-Page-Edit mode
/// &amp;lt;/summary&amp;gt;
[EditorDescriptorRegistration(TargetType = typeof(ContentArea), UIHint = "CustomContentArea")]
public class CustomContentAreaEditorDescriptor : ContentAreaEditorDescriptor
{
    public override void ModifyMetadata(ExtendedMetadata metadata, IEnumerable&amp;lt;Attribute&amp;gt; attributes)
    {
        base.ModifyMetadata(metadata, attributes);

        metadata.OverlayConfiguration["customType"] = "alloy/widget/overlay/CustomContentArea";
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create custom content area template (under "&lt;span&gt;/ClientResources/Scripts/widget/templates/&lt;/span&gt;" folder), named "CustomContentArea.html"&lt;/p&gt;
&lt;pre class="language-html"&gt;&lt;code&gt;&amp;lt;div class="epi-overlay-blockarea"&amp;gt;
    &amp;lt;div class="epi-overlay-item-container"&amp;gt;
        &amp;lt;div class="epi-overlay-bracket"&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div data-dojo-attach-point="containerNode" class="epi-overlay-blockarea-container"&amp;gt;
        &amp;lt;span data-dojo-attach-point="informationNode" class="epi-overlay-item-info"&amp;gt;&amp;lt;/span&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div data-dojo-attach-point="actionsNode" class="epi-overlay-blockarea-actionscontainer"&amp;gt;
        &amp;lt;div data-dojo-attach-point="actionsNodeControls" class="epi-overlay-blockarea-actions"&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create custom content area widget (under "/ClientResources/Scripts/widget/overlay/" folder), named "CustomContentArea.js"&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;define([
// dojo
    "dojo/_base/declare",
// epi
    "epi-cms/widget/overlay/ContentArea",
// resources
    "dojo/text!../templates/CustomContentArea.html"
], function (
// dojo
    declare,
// epi
    ContentArea,
// resources
    template
) {
    return declare("alloy.widget.overlay.CustomContentArea", [ContentArea], {
        templateString: template
    });
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For example, add UIHint for MainContentArea&amp;nbsp;property of Start page&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;[Display(
    GroupName = SystemTabNames.Content,
    Order = 320)]
[CultureSpecific]
[UIHint("CustomContentArea")]
public virtual ContentArea MainContentArea { get; set; }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In additional, we have another way to marked all ContentArea properties to rendered with custom editor (without added [UIHint("CustomContentArea")] attribute for each)&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;/// &amp;lt;summary&amp;gt;
/// Editor descriptor that extends base editor descriptor for &amp;lt;see cref="ContentArea"/&amp;gt; in order to show overlay label when hovering in On-Page-Edit mode
/// &amp;lt;/summary&amp;gt;
[EditorDescriptorRegistration(TargetType = typeof(ContentArea), EditorDescriptorBehavior = EditorDescriptorBehavior.OverrideDefault)]
public class CustomContentAreaEditorDescriptor : ContentAreaEditorDescriptor&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, here is the result when edit Start page&lt;/p&gt;
&lt;p&gt;&lt;img src="https://s-media-cache-ak0.pinimg.com/originals/3e/e0/73/3ee0732ea16d0ee5ea62d9a531d5c39a.png" width="637" alt="custom content area show overlay label when hovering in on-page-edit mode" height="447" /&gt;&lt;/p&gt;
&lt;h2&gt;Related topics&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="/link/216188c9af974124a6566bc65fd6b597.aspx"&gt;Limiting items in a ContentArea&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/body&gt;
&lt;/html&gt;</summary></entry></feed>