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. Tried this in AEM Cloud SDK and it did not work. It would be great if that could be extended.
    Best
    Martin

    ReplyDelete