Sunday, 15 September 2019

Open infinity.json of your AEM page with Bookmarklet

In AEM we are often required to open .infinity.json of any page specially in author mode to see the node data tree structure in json format. infinity selector with json extension is provided by AEM OOTB for such use cases.

This is also helpful when you are debugging something related to content authored and don't want to open the page content structure in CRXDE and open each node manually till you reach that particular component node inside jcr:content of the page because it is time consuming.

Furthermore if you use .tidy.infinity.json, it will write your json data in neat and tidy way (See SS at the bottom of the post). tidy selector is also provided OOTB by AEM for tidy representation.

To use this we usually copy the editor url in new tab and append .tidy.infinity.json to the url and remove .html extension. How about if you can do this in just 1 click?

The answer is bookmarklet. A bookmarklet is a bookmark stored in a browser but instead of having a page url, it contains the JavaScript code in its URL. On click of these bookmarks, the JavaScript code executes onto your page and can modify it similar to what you would do from developer console.

So i created this very simple bookmarklet which you can run on any editor page and open infinity.json of that page in new tab in just 1 click.

javascript:(function(){ 
    var currurl = window.location.href; 
    if(currurl.indexOf('editor.html') > -1){ 
        var arr = currurl.split('.html'); 
        var newurl = arr[0].replace('/editor','')+arr[1]+'.tidy.infinity.json'; 
        window.open(newurl , '_blank'); 
    }
})();

The above logic only works in author mode as you can see i am checking if current url contains editor.html. You can modify this as per your requirement to work in publish as well.

How to use this?  

1. Click on Add page from bookmarks toolbar (similar to what you do to add any bookmark).
2. Give any Name and in the URL field copy the above code (See SS below)-



3. That's it. Now your bookmarklet is ready. To run on any page, just click on it and it will open its infinity json for yo in new tab.

See screenshots below for reference-


Thursday, 17 January 2019

Touch UI - Hide/Show fields inside coral-3 multifield in AEM by coral dropdown

This post shows how to hide/show fields inside multifield in the Touch UI dialog of AEM.
The resourceType used here for composite multifield, selection dropdown, textfield and numberfield are coral 3 ui components. For ex: granite/ui/components/coral/foundation/form/multifield and it has been tested in aem 6.3.

This method uses granite:class attribute added as property to add class in the fields and granite:data node with data key-value added as property to add data attributes in the fields.
Implemented 4 steps are mentioned below: 

1. Add granite:class attribute to the selection field as shown below
 granite:class : cq-dialog-dropdown-showhide1


2. Add granite:data node inside selection field with data key-value added as property as shown below:
cq-dialog-dropdown-showhide-target1 : .list-option-listfrom-showhide-target



3. Add granite:class attribute to each of the fields which you want to show/hide based on 
dropdown selection which matches the data-target attribute of selection field as shown below:
granite:class : list-option-listfrom-showhide-target1


4. Add granite:data node inside each of the fields which you want to show/hide with showhidetargetvalue key 
and value equal to dropdown options value as shown below:
  showhidetargetvalue : textval



To avoid any confusion, the cq_dialog xml i created is pasted below-

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" 
xmlns:granite="http://www.adobe.com/jcr/granite/1.0" 
xmlns:cq="http://www.day.com/jcr/cq/1.0" 
xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
    jcr:primaryType="nt:unstructured"
    jcr:title="Multi ShowHide Component"
    sling:resourceType="cq/gui/components/authoring/dialog"
    helpPath="https://www.adobe.com/go/aem6_3_docs_component_en#Image - HTL">
    <content
        jcr:primaryType="nt:unstructured"
        sling:resourceType="granite/ui/components/foundation/container">
        <layout
            jcr:primaryType="nt:unstructured"
            sling:resourceType="granite/ui/components/foundation/layouts/tabs"
            type="nav"/>
        <items jcr:primaryType="nt:unstructured">
            <multi
                jcr:primaryType="nt:unstructured"
                jcr:title="Multi"
                sling:resourceType="granite/ui/components/foundation/section">
                <layout
                    jcr:primaryType="nt:unstructured"
      sling:resourceType="granite/ui/components/foundation/layouts/fixedcolumns"
                    margin="{Boolean}false"/>
                <items jcr:primaryType="nt:unstructured">
                    <custom
                        jcr:primaryType="nt:unstructured"
      sling:resourceType="granite/ui/components/foundation/container">
                        <items jcr:primaryType="nt:unstructured">
                            <heading
                                jcr:primaryType="nt:unstructured"
      sling:resourceType="granite/ui/components/foundation/heading"
                                class="coral-Heading coral-Heading--4"
                                level="{Long}4"
                                text="Composite Multifield"/>
                            <well
                                jcr:primaryType="nt:unstructured"
      sling:resourceType="granite/ui/components/foundation/container">
                                <layout
                                    jcr:primaryType="nt:unstructured"
      sling:resourceType="granite/ui/components/foundation/layouts/well"/>
                                <items jcr:primaryType="nt:unstructured">
                                    <fieldenter
                                        jcr:primaryType="nt:unstructured"
      sling:resourceType="granite/ui/components/coral/foundation/form/multifield"
                                        composite="{Boolean}true">
                                        <field
                                            jcr:primaryType="nt:unstructured"
      sling:resourceType="granite/ui/components/coral/foundation/container"
                                            fieldLabel="Products Container"
                                            name="./products">
      <items jcr:primaryType="nt:unstructured">
                                            <listFromMulti
      granite:class="cq-dialog-dropdown-showhide1"
                                            jcr:primaryType="nt:unstructured"
      sling:resourceType="granite/ui/components/coral/foundation/form/select"
                                            fieldLabel="Select Multi showhide"
                                            name="listFromMulti">
      <items jcr:primaryType="nt:unstructured">
                                            <text
                                            jcr:primaryType="nt:unstructured"
                                            text="Text field"
                                            value="textval"/>
                                            <num
                                            jcr:primaryType="nt:unstructured"
                                            text="Num field"
                                            value="numval"/>
                                            </items>
                                            <granite:data
                                            jcr:primaryType="nt:unstructured"
      cq-dialog-dropdown-showhide-target1=".list-option-listfrom-showhide-target1"/>
                                            </listFromMulti>
                                            <multitext
      granite:class="list-option-listfrom-showhide-target1"
                                            jcr:primaryType="nt:unstructured"
      sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
                                              fieldLabel="Multi Text"
                                              name="multitext"
                                              showhidetargetvalue="textval">
                                              <granite:data
                                                jcr:primaryType="nt:unstructured"
                                                showhidetargetvalue="textval"/>
                                              </multitext>
                                              <multinum
      granite:class="list-option-listfrom-showhide-target1"
                                              jcr:primaryType="nt:unstructured"
      sling:resourceType="granite/ui/components/coral/foundation/form/numberfield"
                                              fieldLabel="Multi Num"
                                               name="multinum"
                                               showhidetargetvalue="numval">
                                               <granite:data
                                               jcr:primaryType="nt:unstructured"
                                               showhidetargetvalue="numval"/>
                                               </multinum>
                                            </items>
                                        </field>
                                    </fieldenter>
                                </items>
                            </well>
                        </items>
                    </custom>
                </items>
            </multi>
        </items>
    </content>
</jcr:root>

Now to toggle fields using selection dropdown inside composite multifield independently, use below jquery logic 
written in a js file inside clientlibs folder of component with category cq.authoring.dialog .
 
(function(document, $) {
    "use strict";

    // when dialog gets injected
    $(document).on("foundation-contentloaded", function(e) {
        // if there is already an inital value make sure the 
  //according target element becomes visible
        showHideHandler($(".cq-dialog-dropdown-showhide1", e.target));
    });

    $(document).on("change", ".cq-dialog-dropdown-showhide1", function(e) {
        showHideHandler($(this));
    });

    function showHideHandler(el) {
        el.each(function(i, element) {
                // handle Coral3 base drop-down
                Coral.commons.ready(element, function(component) {
                    showHideCustom(component, element);
                    component.on("change", function() {
                        showHideCustom(component, element);
                    });
                });
        })
    }

    function showHideCustom(component, element) {
         // get the selector to find the target elements. 
         //its stored as data-.. attribute
       var target = $(element).data("cq-dialog-dropdown-showhide-target1");
       var $target = $(target);
       var elementIndex = $(element).closest('coral-multifield-item').index();

       if (target) {
         var value;
         if (component.value) {
           value = component.value;
         } else {
           value = component.getValue();
         }
         $(element).closest("coral-multifield-item").find(target)
         .each(function(index) {
            var tarIndex = $(this).closest('coral-multifield-item').index();
            if (elementIndex == tarIndex) {
                $(this).not(".hide").parent().addClass("hide");
                $(this).filter("[data-showhidetargetvalue='" + value + "']")
                .parent().removeClass("hide");
            }
         });
        }
    }

})(document, Granite.$);

The screenshot of how the dialog looks like and how it toggle fields is shown below- 


You can also find this component in my github project here .