AEM 6530 - Touch UI Assets Console add Metadata while Uploading Files

Goal


Show simple Metadata Form in the Upload Dialog of Touch UI Assets Console; With this extension users can add metadata while uploading files

For AEM 63 check this post

Demo | Package Install | Github


Metadata Form in Upload Dialog



Metadata Validation



Metadata in Properties



Metadata in CRX



Solution


1) Login to CRXDE Lite (http://localhost:4502/crx/de), create folder /apps/eaem-assets-file-upload-with-metadata

2) Metadata form shown in Upload Dialog is an Authoring Dialog; Create the dialog /apps/eaem-assets-file-upload-with-metadata/dialog, add metadata form nodes



3) Create node /apps/eaem-assets-file-upload-with-metadata/clientlib of type cq:ClientLibraryFolder, add String[] property categories with value dam.gui.coral.fileupload String[] property dependencies with value underscore

4) Create file (nt:file) /apps/eaem-assets-file-upload-with-metadata/clientlib/js.txt, add

            fileupload-with-metadata.js

5) Create file (nt:file) /apps/eaem-assets-file-upload-with-metadata/clientlib/fileupload-with-metadata.js, add the following code

(function($, $document) {
    var METADATA_DIALOG = "/apps/eaem-assets-file-upload-with-metadata/dialog.html",
        METADATA_PREFIX = "eaem",
        UPLOAD_LIST_DIALOG = ".uploadListDialog.is-open",
        ACTION_CHECK_DATA_VALIDITY = "ACTION_CHECK_DATA_VALIDITY",
        ACTION_POST_METADATA = "ACTION_POST_METADATA",
        dialogAdded = false;
        url = document.location.pathname;

    if( url.indexOf("/assets.html") == 0 ){
        handleAssetsConsole();
    }else if(url.indexOf(METADATA_DIALOG) == 0){
        handleMetadataDialog();
    }

    function handleAssetsConsole(){
        $document.on("foundation-contentloaded", handleFileAdditions);
    }

    function handleMetadataDialog(){
        $(function(){
            _.defer(styleMetadataIframe);
        });
    }

    function registerReceiveDataListener(handler) {
        if (window.addEventListener) {
            window.addEventListener("message", handler, false);
        } else if (window.attachEvent) {
            window.attachEvent("onmessage", handler);
        }
    }

    function styleMetadataIframe(){
        var $dialog = $("coral-dialog");

        if(_.isEmpty($dialog)){
            return;
        }

        $dialog.css("overflow", "hidden");

        $dialog[0].open = true;

        var $header = $dialog.css("background-color", "#fff").find(".coral3-Dialog-header");

        $header.find(".cq-dialog-actions").remove();

        $dialog.find(".coral3-Dialog-wrapper").css("margin","0").find(".coral-Dialog-content").css("padding","0");

        registerReceiveDataListener(postMetadata);

        function postMetadata(event){
            var message = JSON.parse(event.data);

            if( message.action !== ACTION_CHECK_DATA_VALIDITY ){
                return;
            }

            var $dialog = $(".cq-dialog"),
                $fields = $dialog.find("[name^='./']"),
                data = {}, $field, $fValidation, name, value, values,
                isDataInValid = false;

            $fields.each(function(index, field){
                $field = $(field);
                name = $field.attr("name");
                value = $field.val();

                $fValidation = $field.adaptTo("foundation-validation");

                if($fValidation && !$fValidation.checkValidity()){
                    isDataInValid = true;
                }

                $field.updateErrorUI();

                if(_.isEmpty(value)){
                    return;
                }

                name = name.substr(2);

                if(!name.indexOf(METADATA_PREFIX) === 0){
                    return
                }

                if(!_.isEmpty(data[name])){
                    if(_.isArray(data[name])){
                        data[name].push(value);
                    }else{
                        values =  [];
                        values.push(data[name]);
                        values.push(value);

                        data[name] = values;
                        data[name + "@TypeHint"] = "String[]";
                    }
                }else{
                    data[name] = value;
                }
            });

            sendValidityMessage(isDataInValid, data);
        }

        function sendValidityMessage(isDataInValid, data){
            var message = {
                action: ACTION_CHECK_DATA_VALIDITY,
                data: data,
                isDataInValid: isDataInValid
            };

            parent.postMessage(JSON.stringify(message), "*");
        }
    }

    function handleFileAdditions(){
        var $fileUpload = $("dam-chunkfileupload"),
            $metadataIFrame, $uploadButton, validateUploadButton,
            metadata;

        $fileUpload.on('change', addMetadataDialog);

        $fileUpload.on('dam-fileupload:loadend', postMetadata);

        function sendDataMessage(message){
            $metadataIFrame[0].contentWindow.postMessage(JSON.stringify(message), "*");
        }

        function addMetadataDialog(){
            if(dialogAdded){
                return;
            }

            dialogAdded = true;

            _.debounce(addDialog, 500)();
        }

        function addDialog(){
            var $dialog = $(UPLOAD_LIST_DIALOG);

            if(!_.isEmpty($dialog.find("iframe"))){
                $dialog.find("iframe").remove();
            }

            var iFrame = '<iframe width="550px" height="450px" frameborder="0" src="' + METADATA_DIALOG + '"/>',
            $dialogContent = $dialog.find("coral-dialog-content");

            $metadataIFrame = $(iFrame).appendTo($dialogContent.css("max-height", "600px"));
            $dialogContent.find("input").css("width", "30rem");
            $dialogContent.closest(".coral3-Dialog-wrapper").css("top", "30%").css("left", "50%");

            addValidateUploadButton($dialog);
        }

        function addValidateUploadButton($dialog){
            var $footer = $dialog.find("coral-dialog-footer");

            $uploadButton = $footer.find("coral-button-label:contains('Upload')").closest("button");

            validateUploadButton = new Coral.Button().set({
                variant: 'primary'
            });

            validateUploadButton.label.textContent = Granite.I18n.get('Upload');

            validateUploadButton.classList.add('dam-asset-upload-button');

            $footer[0].appendChild(validateUploadButton);

            $uploadButton.hide();

            validateUploadButton.hide();

            validateUploadButton.on('click', function() {
                checkDataValidity();
            });

            $metadataIFrame.on('load', function(){
                validateUploadButton.show();
                dialogAdded = false;
            });

            registerReceiveDataListener(isMetadataValid);
        }

        function isMetadataValid(event){
            var message = JSON.parse(event.data);

            if( (message.action !== ACTION_CHECK_DATA_VALIDITY)){
                return;
            }

            if(message.isDataInValid){
                return;
            }

            metadata = message.data;

            validateUploadButton.hide();

            $uploadButton.click();
        }

        function checkDataValidity(){
            var message = {
                action: ACTION_CHECK_DATA_VALIDITY
            };

            sendDataMessage(message);
        }

        function postMetadata(event){
            var detail = event.originalEvent.detail,
                folderPath = detail.action.replace(".createasset.html", ""),
                assetMetadataPath = folderPath + "/" + detail.item.name + "/jcr:content/metadata";

            //jcr:content/metadata created by the DAM Update asset workflow may not be available when the below post
            //call executes; ideally, post the parameters to aem, a scheduler runs and adds the metadata when metadata
            //node becomes available
            $.ajax({
                type : 'POST',
                url : assetMetadataPath,
                data  : metadata
            })
        }
    }

})(jQuery, jQuery(document));

6) #223 is for demo purposes only; in real world implementations, the metadata node created by DAM Update Asset workflow may not exist yet, when the ajax post metadata call executes. Replace this direct call with a servlet temporarily storing the form metadata and update the metadata node (when it becomes available) in a scheduler or listener

2 comments:

  1. This is awesome! Is there a version of this that works with AEM Cloud Services instances?

    ReplyDelete
  2. Did you find its AEM as a cloud service version?

    ReplyDelete