cancel
Showing results for 
Search instead for 
Did you mean: 

'Add new comment' form retrieval

nicolabeghin
Champ in-the-making
Champ in-the-making
Hi everyone
I'm integrating Alfresco in a WebDynPro java in a SAP system.
I want to manage docs comments in alfresco (for many reasons not in the SAP system).
I've already developed a webscript to get HTML-formatted comments, starting from the existing org/alfresco/repository/comments/comments.get (JSON-based), but I'm unable to get a form to add new comments (I don't want to send SOAP/REST request from the WebDynPro because I want full-featured comments with HTML markup).

Any ideas if this is feasible? I need to understand if it's possible to get just the form markup OR a single page with the only possibility of adding new comments

[EDIT] I think org/alfresco/components/form/form.get is the way to go, I'm inspecting the issue to understand what .ftl needs to be included to make it work completely

Thanks, nicola
21 REPLIES 21

arnoldschrijve1
Champ on-the-rise
Champ on-the-rise
I am not sure of your exact requirement. From what I understand you are building a UI in WebDynPro on top of the Alfresco repository, but want to use html to render the comments control and communicate to the repository.

You could take a peek at how the comments control is rendered in Alfresco Share. The rendering occurs almost completely client-side in <share-webapp-dir>/components/comments/comments-list.js where rest-style calls are made to the repository to retrieve comment data.
I don't know anything about WebDynPro and whether you can/want to use YUI for rendering, but it may be of help to you.

nicolabeghin
Champ in-the-making
Champ in-the-making
Thanks Arnold, yes I looked up the code and found the Alresco.CommentsList AJAX function so I'm trying to create a webscript/portlet for the rendering of the comments but I'm experiencing issues with the include of files (I've been told it's because I'm referencing some script in the Share tier in the Alfresco tier).. any clues about this?
I wrote some more in https://forums.alfresco.com/en/viewtopic.php?f=36&t=12872
I don't know what to do more

<#include "comments-list.get.head.ftl">
<!– Comments List –>
<link rel="stylesheet" type="text/css" href="http://172.18.101.35:8080/share/res/components/comments/comments-list.css" />
<script type="text/javascript" src="http://172.18.101.35:8080/share/res/components/comments/comments-list.js"></script>
<#if nodeRef??>
   <#assign el=args.htmlid?js_string>
   <script type="text/javascript">//<![CDATA[
      new Alfresco.CommentsList("${el}").setOptions(
      {
         nodeRef: "${nodeRef?js_string}",
         siteId: <#if site??>"${site?js_string}"<#else>null</#if>,
         maxItems: ${maxItems?js_string},
         activity: <#if activityParameterJSON??>${activityParameterJSON}<#else>null</#if>,
         editorConfig:
         {
            inline_styles: false,
            convert_fonts_to_spans: false,
            theme: "advanced",
            theme_advanced_buttons1: "bold,italic,underline,|,bullist,numlist,|,forecolor,|,undo,redo,removeformat",
            theme_advanced_toolbar_location: "top",
            theme_advanced_toolbar_align: "left",
            theme_advanced_resizing: true,
            theme_advanced_buttons2: null,
            theme_advanced_buttons3: null,
            theme_advanced_path: false,
            language: "${locale?substring(0, 2)?js_string}"
         }
      }).setMessages(
         ${messages}
      );
   //]]></script>
   <div id="${el}-body" class="comments-list">

      <h2 class="thin dark">${msg("header.comments")}</h2>

      <div id="${el}-add-comment">
         <div id="${el}-add-form-container" class="theme-bg-color-4 hidden"></div>
      </div>

      <div class="comments-list-actions">
         <div class="left">
            <div id="${el}-actions" class="hidden">
               <button class="alfresco-button" name=".onAddCommentClick">${msg("button.addComment")}</button>
            </div>
         </div>
         <div class="right">
            <div id="${el}-paginator-top"></div>
         </div>
         <div class="clear"></div>
      </div>

      <hr class="hidden"/>

      <div id="${el}-comments-list"></div>

      <hr class="hidden"/>

      <div class="comments-list-actions">
         <div class="left">
         </div>
         <div class="right">
            <div id="${el}-paginator-bottom"></div>
         </div>
         <div class="clear"></div>
      </div>

   </div>
</#if>

arnoldschrijve1
Champ on-the-rise
Champ on-the-rise
Yes, the comments-list webscript lives in the Share web-tier and your WebDynPro app probably connects directly to the repository tier (you could also make a call through the web-tier, but I wouldn't consider that best-practice). This means you have to create the webscript here and also place script references and imported files at the proper locations.

Assuming you are using the extension directory you can create the webscript at WEB-INF/class/alfresco/extension/templates/webscripts/com/yourcompany/comments-list
Create the files:
- comments-list.get.desc.xml
- comments-list.get.html.ftl
- comments-list.get.js

The FTL file is mostly the same as the one that exists in Share, but with added script references (the *.get.head.ftl convention doesn't work in repo-tier) something like this:
<script type="text/javascript" src="/alfresco/com/mycompany/comments-list/comments-list.js"></script> (placed directly in alfresco webapp dir, or in /src/web dir in a SDK project).

comments-list.get.js is a bit trickier. It imports alfresco-util.js. I would create a new file in your webscript dir and implement just those functions that are called from comments-list.get.js. You'll have to review the functions that are called and adapt them where they contain share-specific code or make remote calls to the repository (with remote.connect). Since you are in the repository tier now, you have direct access to the code called in these webscripts and you could aggregate it in comments-list.get.js

Something similar needs to be done in the client-side comments-list.js. It needs a bunch of YUI script references in your code to work correctly (all placed below src/web or webapp dir as before). Remember also that it derives from Alfresco.component.Base, so you need to include alfresco.js as well. Then finally there are some calls to Alfresco.constants.URL_SERVICECONTEXT on the Share web-tier that need to be pointed to your new webscript in the repo tier.

So, there is some work involved, but then you should be able to get it up and running. Good luck!

nicolabeghin
Champ in-the-making
Champ in-the-making
Thanks Arnold, that's what I made in the last days (included all the files you suggested) and copied the .js controller and imported Alfresco.Util and created the .tpl files but it seems like a web of inextricable inter-related dependencies and I can't figure out if there's some easier (and cleaner..) solution for this. I'll try with you suggestion keeping only the required part of Alfresco.util.

Of course I made the whole thing on the alfresco server, I'm merely loading the webscript from an iframe in my webdynpro java.

Thanks again A LOT for your help!

nicolabeghin
Champ in-the-making
Champ in-the-making
I've trimmed down alfresco-util.js (removing unused methods and the initial include to surf-doclist.lib.js).
Just 2 things I can't figure out
  • how to replace
    remote.connect("alfresco").get('/api/metadata?nodeRef=' + nodeRef);
    (seems like a webservice call to REST API, but is there a way to map each REST API to a local method?)

  • where is defined the local variable page (page.url etc) ?
Here's the trimmed-down version of alfresco-util.js (that I will embed in comments-list.get.js

var this_AlfrescoUtil = this;

var AlfrescoUtil =
{

   error: function error(code, message, redirect)
   {
      status.code = arguments.length > 0 ? 500 : code;
      status.message = message || 'An error occured';
      status.redirect = arguments.length > 2 ? redirect : true;
      throw new Error(message);
   },

   /**
    * Looks for a parameter in a "safe" way that works in all "environments".
    * Meaning it will look in "page" and "template" if they do exist and not fail /crash if they don't.
    *
    * Looks for an argument in the following order/locations:
    * 1. args[name]
    * 2. page.url.args[name]       
    * 3. page.url.templateArgs[name]
    * 4. template.properties[name]
    * 5. a) if defaultValue has been passed in that is used
    *    b) otherwise the parameter is treated as required and an error is thrown
    *
    * @param name
    * @param defaultValue
    * @return the value for the parameter
    */
   param: function param(name, defaultValue)
   {
      var value;
      if (args[name] && args[name].length != 0)
      {
         value = args[name];
      }
      else if (this_AlfrescoUtil.hasOwnProperty("page") && page.url.args[name] && page.url.args[name].length != 0)
      {
         value = page.url.args[name];
      }
      else if (this_AlfrescoUtil.hasOwnProperty("page") && page.url.templateArgs[name] && page.url.templateArgs[name].length != 0)
      {
         value = page.url.templateArgs[name];
      }
      else if (this_AlfrescoUtil.hasOwnProperty("template") && template.properties[name] && template.properties[name].length != 0)
      {
         value = template.properties[name];
      }
      else if (arguments.length > 1)
      {
         value = defaultValue;
      }
      else
      {
         AlfrescoUtil.error(400, 'Parameter "' + name+ '" is missing.', true);
      }
      model[name] = value;
      return value;
   },

   getMetaData: function getMetaData(nodeRef, defaultValue)
   {
      var result = remote.connect("alfresco").get('/api/metadata?nodeRef=' + nodeRef);
      if (result.status != 200)
      {
         if (defaultValue !== undefined)
         {
            return defaultValue;
         }
         AlfrescoUtil.error(result.status, 'Could not load meta data ' + nodeRef);
      }
      result = eval('(' + result + ')');
      return result;
   },
};

arnoldschrijve1
Champ on-the-rise
Champ on-the-rise
On the first point:

The remote.connect makes a call to the webscript webapps/alfresco/WEB-INF/classes/alfresco/templates/webscripts/org/alfresco/repository/metadata/metadata.get.js. There is not much code there, and the freemarker template just returns the result from the js. So you could include the code in your own script and omit the cross-webscript call.

I am not sure and haven't tested it, but it seems that remote.connect should still work for cross-webscript calls in the alfresco repo tier.

arnoldschrijve1
Champ on-the-rise
Champ on-the-rise
On the second issue:

You can try removing page variable altogether as it is not available in repo tier and instead use url.args (url as in http://myurl?myarg={myarg}) and url.templateArgs (http://myurl/{myarg}/mymorestuff)

nicolabeghin
Champ in-the-making
Champ in-the-making
THANKS a lot, I'll apply your suggestions.
Thanks again
nicola

nicolabeghin
Champ in-the-making
Champ in-the-making
It's a nightmare, hope you can give me some hint..

I keep getting a
04240078 Wrapped Exception (with status template): 04243325 Failed to execute script '/com/companyx/comments/comments-list.get.js (in repository store workspace://SpacesStore/Homepage dell'azienda/Dizionario dei dati/Web Script)': 04243324 Invalid node ref - does not contain forward slash: alfresco-util.js
calling the URL
http://127.0.0.1:8080/alfresco/service/com/companyx/components/comments/list?nodeRef=workspace://Spa...

by merely including my custom alfresco-util.js (which, btw, does not invoke any method by itself..)
I can't understand why he's trying to automatically create a NodeRef while I'm not invoking any method in AlfrescoUtil (and the URL qualification should be ok as I see with Chrome Inspector it's the same format used for retrieving the comments from the webservice
http://127.0.0.1:8080/share/service/components/node/workspace/SpacesStore/4b7198b9-5356-446d-a1a2-74...

alfresco-util.js

<import resource="surf-doclist.lib.js">

var this_AlfrescoUtil = this;

var AlfrescoUtil =
{

   error: function error(code, message, redirect)
   {
      status.code = arguments.length > 0 ? 500 : code;
      status.message = message || 'An error occured';
      status.redirect = arguments.length > 2 ? redirect : true;
      throw new Error(message);
   },

   /**
    * Looks for a parameter in a "safe" way that works in all "environments".
    * Meaning it will look in "page" and "template" if they do exist and not fail /crash if they don't.
    *
    * Looks for an argument in the following order/locations:
    * 1. args[name]
    * 2. page.url.args[name]       
    * 3. page.url.templateArgs[name]
    * 4. template.properties[name]
    * 5. a) if defaultValue has been passed in that is used
    *    b) otherwise the parameter is treated as required and an error is thrown
    *
    * @param name
    * @param defaultValue
    * @return the value for the parameter
    */
   param: function param(name, defaultValue)
   {
      var value;
      if (name in url.templateArgs) value=url.templateArgs[name];
      // if (args[name] && args[name].length != 0)
      // {
      //    value = args[name];
      // }
      // else if (this_AlfrescoUtil.hasOwnProperty("page") && page.url.args[name] && page.url.args[name].length != 0)
      // {
      //    value = page.url.args[name];
      // }
      // else if (this_AlfrescoUtil.hasOwnProperty("page") && page.url.templateArgs[name] && page.url.templateArgs[name].length != 0)
      // {
      //    value = page.url.templateArgs[name];
      // }
      // else if (this_AlfrescoUtil.hasOwnProperty("template") && template.properties[name] && template.properties[name].length != 0)
      // {
      //    value = template.properties[name];
      // }
      else if (arguments.length > 1)
      {
         value = defaultValue;
      }
      else
      {
         AlfrescoUtil.error(400, 'Parameter "' + name+ '" is missing.', true);
      }
      model[name] = value;
      return value;
   },
  
   getRootNode: function getRootNode()
   {
      var rootNode = "alfresco://company/home",
         repoConfig = config.scoped["RepositoryLibrary"]["root-node"];

      if (repoConfig !== null)
      {
         rootNode = repoConfig.value;
      }
      return rootNode;
   },
   
   getNodeDetails: function getNodeDetails(nodeRef, site, options)
   {
     AlfrescoUtil.error(500, 'Noderef is '+nodeRef+' while site is '+site, true);
    return null;
      if (nodeRef)
      {
         var url = '/slingshot/doclib2/node/' + nodeRef.replace('://', '/');
         if (!site)
         {
            // Repository mode
            url += "?libraryRoot=" + encodeURIComponent(AlfrescoUtil.getRootNode());
         }
         var result = remote.connect("alfresco").get(url);

         if (result.status == 200)
         {
            var details = eval('(' + result + ')');
            if (details && (details.item || details.items))
            {
               DocList.processResult(details, options);
               return details;
            }
         }
      }
      return null;
   },
   
   getMetaData: function getMetaData(nodeRef, defaultValue)
   {
//   var result=search.findNode(nodeRef);
     var result = remote.connect("alfresco").get('/api/metadata?nodeRef=' + nodeRef);
      if (result.status != 200)
      {
         if (defaultValue !== undefined)
         {
            return defaultValue;
         }
         AlfrescoUtil.error(result.status, 'Could not load meta data ' + nodeRef);
      }
      result = eval('(' + result + ')');
      return result;
   },

};

comments-list.get.js
(I deliberately commented any method invocation to be sure no AlfrescoUtil method is invoked explicitly, then even tried to comment out the inclusion of surf-doclist.lib.js)

<import resource="alfresco-util.js">

function getActivityParameters(nodeRef, defaultValue)
{
   var cm = "{http://www.alfresco.org/model/content/1.0}",
      metadata = AlfrescoUtil.getMetaData(nodeRef, {});
   if (metadata.properties)
   {
      if (model.activityType == "document")
      {
         return (
         {
            itemTitle: metadata.properties[cm + 'title'] || metadata.properties[cm + 'name'],
            page: 'document-details',
            pageParams:
            {
               nodeRef: metadata.nodeRef
            }
         });
      }
      else if (model.activityType == "folder")
      {
         return (
         {
            itemTitle: metadata.properties[cm + 'title'] || metadata.properties[cm + 'name'],
            page: 'folder-details',
            pageParams:
            {
               nodeRef: metadata.nodeRef
            }
         });
      }
      else if (model.activityType == "link")
      {
         var lm = "{http://www.alfresco.org/model/linksmodel/1.0}";
         return (
         {
            itemTitle: metadata.properties[lm + "title"],
            page: 'links-view',
            pageParams:
            {
               linkId: metadata.properties[cm + "name"]
            }
         });
      }
      else if (model.activityType == "blog")
      {
         return (
         {
            itemTitle: metadata.properties[cm + 'title'] || metadata.properties[cm + 'name'],
            page: 'blog-postview',
            pageParams:
            {
               postId: metadata.properties[cm + "name"]
            }
         });
      }
   }
   return defaultValue;
}

function main()
{
   // AlfrescoUtil.param('nodeRef', null);
   // AlfrescoUtil.param('site', null);
   // AlfrescoUtil.param('maxItems', 10);
   // AlfrescoUtil.param('activityType', null);
//   model.nodeRef = null;
     status.code=403;
     status.message='Unable to get nodeRef';
     status.redirect=true;

//   if (model.nodeRef) {
   // if (!model.nodeRef)
   // {
   //    // Handle urls that doesn't use nodeRef
   //    AlfrescoUtil.param('postId', null);
   //    if (model.postId)
   //    {
   //       // translate blog post "postId" to a nodeRef
   //       AlfrescoUtil.param('container', 'blog');
   //       model.nodeRef = AlfrescoUtil.getBlogPostDetailsByPostId(model.site, model.container, model.postId, {}).nodeRef;
   //    }
   //    else
   //    {
   //       AlfrescoUtil.param('linkId', null);
   //       if (model.linkId)
   //       {
   //          // translate link's "linkId" to a nodeRef
   //          AlfrescoUtil.param('container', 'links');
   //          model.nodeRef = AlfrescoUtil.getLinkDetailsByPostId(model.site, model.container, model.linkId, {}).nodeRef;
   //       }
   //    }
   // }
      
   //    var documentDetails = AlfrescoUtil.getNodeDetails(model.nodeRef, model.site);
   //    if (documentDetails)
   //    {
   //       var activityParameters = getActivityParameters(model.nodeRef, null);
   //       if (activityParameters)
   //       {
   //          model.activityParameterJSON = jsonUtils.toJSONString(activityParameters);
   //       }
   //    }
   // }
   //    else
   //    {
   //       // Signal to the template that the node doesn't exist and that comments therefore shouldn't be displayed.
   //       model.nodeRef = null;
   //   status.code=403;
   //   status.message='Unable to get nodeRef';
   //   status.redirect=true;
   //    }
}

main();

just for the sake of clarity this is the webscript descriptor

<webscript>
  <shortname>Comments component</shortname>
  <description>Displays comments for a node</description>
  <url>/com/companyx/components/comments/list</url>
  <transaction>required</transaction>
  <authentication>user</authentication>
</webscript>

Please not that I'm loading the files in the Repository -> Data dictionary -> Web script -> com -> companyx -> comments

Thanks again for your invaluable help.
Getting started

Tags


Find what you came for

We want to make your experience in Hyland Connect as valuable as possible, so we put together some helpful links.