Category Archives: Share

Don’t put minus sign in component names for Alfresco dashlets and other page components

I’m writing a dashlet which won’t fire its’ onReady method. It just sits there, never getting called.

Googling it I ran into my own blog post which essentially says: call your dashlet with new Alfresco.Dashlet(“html_element_id”);. If your html_element_id is undefined or anything, dashlet will never get this element ready so it won’t fire.

But my new dashlet is on Alfresco 4.2 – which means it’s instantiated automatically. Then I found out what the problem was: a minus sign in the element id. I had an id like this: template_x002e_functions_x002e_custom-dashboard_x0023_default. See the minus sign in there? That made YUI not aware of the element id and your dashlet would not fire.

How to create Alfresco Share dashlet that does not use authentication

Back to Part I: How to create an Alfresco page that uses no authentication

This post is trying to explain in few short steps how to create an Alfresco dashlet. It was inspired by this question on StackOverflow.

Basically, a dashlet is consisting of a few files (usually 3-4 + internalization files), most of them placed in tomcat shared loader (the usual way I deploy Alfresco extensions). Here are  the typical files we would create:

<TOMCAT>/shared/classes/alfresco/web-extension/site-webscripts/my-dashlet/my-dashlet.get.desc.xml
<TOMCAT>/shared/classes/alfresco/web-extension/site-webscripts/my-dashlet/my-dashlet.get.html
<TOMCAT>/shared/classes/alfresco/web-extension/site-webscripts/my-dashlet/my-dashlet.get.js
<TOMCAT>/shared/classes/alfresco/web-extension/site-webscripts/my-dashlet/my-dashlet.get.properties
<TOMCAT>/shared/classes/alfresco/web-extension/site-webscripts/my-dashlet/my-dashlet.get_de.properties
<TOMCAT>/share/components/dashlets/my-dashlets.css
<TOMCAT>/share/components/dashlets/my-dashlet.js
<TOMCAT>/share/components/dashlets/my-dashlet-min.js

We could do with just the first two, so let’s try. (Alfresco used one more file in versions prior to 4, but the differences are minor. If you run into that, ask me or at the Alfresco forums.)

The first file is my-dashlet.get.desc.xml. When starting, Alfresco will pick up the *desc.xml files from site-webscripts folder and get its configuration. The GET part of the name says that this component will answer to a GET HTTP call. If you named it my-dashlet.post.desc.xml, you would not be able to access the component via GET method.

Anyway, the file:

<webscript>
  <shortname>My Dashlet</shortname>
  <description>Example dashlet</description>
  <family>user-dashlet</family>
  <url>/components/dashlets/my-dashlet</url>
</webscript>

The URL part is the most important thing here – if you remember, in our page template, we reserved a region for such a dashlet.

Now, the second file, my-dashlet.get.html.ftl is the actual HTML that we will use. We can simply say something like this:

<@markup id="html">
  <@uniqueIdDiv>
    <div class="dashlet my-class">
      <div class="title">My Dashlet</div>
        <div class="body">Hello world!</div>
      </div>
    </@>
 </@>

If you now copy the two files in their folders and refresh Share webscripts (http://localhost:8080/share/service/index, click on Refresh webscripts), you would see this dashlet when trying to customize user dashboard.

You can even access the component directly, by going to http://localhost:8080/share/components/dashlets/my-dashlet – you would only get the component (dashlet), not the whole page.

We could make things a bit more fun, you could replace the html content with this:

<@markup id="html">
  <@uniqueIdDiv>
    <div class="dashlet my-class">
      <div class="title">${msg("header.title")}</div>
        <div class="body">${msg("text.hello")}</div>
      </div>
    </@>
 </@>

And then add another file or two, my-dashlet.get.properties (with the default messages) and my-dashlet.get_de.properties (with German language messages).
The default, my-dashlet.get.properties, contains this:

header.title=My dashlet
text.hello=Hello world

The other file could look like this:

header.title=Meine dashlet

If you deploy the two files to their places and refresh the webscripts, you’d get the same result. However, if you change your language setting in the browser and place German above English, you’d get slightly different dashlet title. (That’s how you internationalize dashlets.)

To make things pretty, you would add a CSS call in the html.ftl file, and to make things useful, you could also include some client-side Javascript. Just add the links to them in the my-dashlet.html.ftl file:

<@markup id="css" >
 <#-- Link to your CSS file -->
 <@link rel="stylesheet" type="text/css" href="${url.context}/res/components/dashlets/my-dashlet.css" group="dashlets"/>
</@>
<@markup id="js">
 <#-- Your JavaScript file. You actually only need the my-dashlet-min.js file (unless in development mode), but we usually keep the original source in my-dashlet.js there so we can change it later.
-->
 <@script type="text/javascript" src="${url.context}/res/components/dashlets/my-dashlet.js" group="dashlets"/>
</@>

<@markup id="widgets">
<!-- Now let's initialize those two thingies - put them in the <head> of the page --> 
 <@createWidgets group="dashlets"/>
</@>
<@markup id="html">
 <@uniqueIdDiv>
   <div class="dashlet my-class">
     <div class="title">${msg("header.title")}</div>
       <div class="body">${msg("text.hello")}</div>
     </div>
  </@>
</@>

What you put in the CSS in JS files is…well, out of scope :) .

Now, to make things more dynamic, we could also use something dynamic: we can make a servers-side javascript file my-dashlet.get.js which will be able to show us something dynamic.

Let’s say we want to know what’s the time on the server. We can put this in the JS file:

model.currentTime = new Date();

You see, we placed a currentTime variable into the page modelNow we can use that variable in our HTML template. Put this under our Hello world line:

<p>Current time on the server is ${currentTime?string.medium}.</p>

That’s basically it. You can also call the repository backend unauthenticated, you just need to define the backend webscripts with <authentication>none</authentication> – and you could access some of the public data this way. But that’s another matter for another post and another poster.

Hopefully this made creating some dashlets easier to someone.

How to create an Alfresco Share page that doesn’t use authentication

Here are a few steps and explanations on how to create an Alfresco Share page that do not require authentication.  I’ve read this question on StackOverflow, and I decided I could spare some 15 minutes to write an answer.

So, I’ll write on how to create a basic page, and also how to put one simple component – or a dashlet, on it. The page could even be supported with Alfresco repository (backend) guest webscripts, but that’s out of the scope of this article.. I’m basing this post on Tomcat installation of Alfresco 4.0+, and placing scripts in the extensions folder.

Part I. Page

In Surf (framework Alfresco Share was built on), you can extend a page is done in three files. First, just create the empty files, and later on, we can add some content to it. The files:

<TOMCAT>/shared/classes/alfresco/web-extension/site-data/pages/my-page.xml
<TOMCAT>/shared/classes/alfresco/web-extension/site-data/template-instances/my-page.xml
<TOMCAT>/shared/classes/alfresco/web-extension/templates/org/alfresco/my-page.ftl

The first xml file is a simple declaration of a new page, Alfresco will pick this up on start and add this page to the Share context (share webapp). It should hold something like this:

<?xml version='1.0' encoding='UTF-8'?>
 <page>
 <title>Sample No-auth Page</title>
 <title-id>page.my-page.title</title-id>
 <description>Sample page for guests</description>
 <description-id>page.my-page.description</description-id>
 <template-instance>my-page</template-instance>
 <authentication>none</authentication>
 </page>

The most important part here is the authentication: none part – now anybody can access that page. Also, you say that the template-instance to use is my-page.xml file in template-instances folder. You can internationalize this, notice the page.my-page.title).
The second file is a template-instance file my-page.xml, it defines what components we will put on this page.

<?xml version='1.0' encoding='UTF-8'?>
  <template-instance>
    <template-type>org/alfresco/my-page</template-type>
    <components>
      <component>
         <region-id>my-dashlet</region-id>
         <url>/components/dashlets/my-dashlet</url>
      </component>
    </components>
  </template-instance>

This file defines two important things. The first is the Freemarker template for the page. The second is the url and region our component will use. So, to add more dashlets, add more components like this, but each has it’s own region-id, even if the url-s are the same.

Basically, with templateHeader, templateBody and templateFooter macros, we got some usual HTML we don’t have to write ourselves, and with the regions, we can place our page components (dashlets) to this page.

Now for the last file: Freemarker template for the page. This is the closest thing to an actual page we will be using:

<#include "include/alfresco-template.ftl" />
<@templateHeader>
</@>
<@templateBody>
 <@markup id="alf-hd">
   <div id="alf-hd">
     <h2>My page header</h2>
     <p>This is some lame page header. Normally, we would have put another component here, like Alfresco's header or something.</p>
   </div>
 </@>
 <@markup id="bd">
   <div id="bd">
     <div class="yui-t1" id="my-page">
       <div id="yui-main">
         <div class="yui-b" id="alf-content">
           <@region id="my-dashlet" scope="template" />
         </div>
         <div class="yui-b">
           <p>This is some (not-really)static HTML we'll include in our page. Usually, we'd put more components here (more dashlets or page elements like that).</p>
         </div>
       </div>
     </div>
   </div>
 </@>
</@>
<@templateFooter>
</@>

The important thing is to set the Freemarker macro @region here, and set it to our custom dashlet. We should also make sure that the dashlet with the corresponding URL.

If we restart Alfresco now, we would be able to access this page, although possibly with an error about missing component (our dashlet).

http://localhost:8080/share/page/my-page – try it and see some of this text and !

On to Part II. Simple dashlet without authentication.

Alfresco document library path encoding

I am developing a Share dashlet that should point the user to some document library spaces in Alfresco. You need to doubly-encode the path:

encodeURIComponent(encodeURIComponent("My local path/With croatian letters/šđćčž"));

Why is this? Because if you only encode once, the spaces and slashes will be encoded – but the extra characters will be encoded with those special characters and the document library filter won’t be able to get it. I assume that this is because the doclib filter will take your given path, then call a remote webscript with it to get the space contents. But if your name has special characters, this doesn’t get decoded well on the way.

Standard disclaimer: this post is only for purposes of me having to write it down and then possibly remember it better next time.

Why won’t my dashlet fire?

I was developing a new dashlet for my clients’ Alfresco installation, MyOffice.

Update: there’s an extension of this post here. If you put a minus sign in your HTML element ID, it will also not fire.

So I had a client-side javascript where I extended the Alfresco.dashlet class (that’s how I construct my objects lately).  So my code was something like…

(function () {
/*blah*/
Alfresco.dashlet.ChangeRequestClient = function(htmlId) {
return Alfresco.dashlet.ChangeRequestClient.superclass.constructor
.call(this,
"Alfresco.dashlet.ChangeRequestClient", htmlId, ["json", "button", "menu"]);
}
YAHOO.extend(Alfresco.dashlet.ChangeRequestClient,
Alfresco.component.Base,
{
/*blah*/
onReady: function blah (htmlId) {
/*blah till the end*/
})();

I was constructing this, the script was firing up, the constructor did its job, but my onReady function didn’t work. So I checked and checked and checked. And what I found was that I was calling the script with

new Alfresco.dashlet.ChangeRequestDashlet();

And now my onReady was waiting for undefined or something to be ready, which was never.

Lesson learned:

Always call your dashlets with “${args.htmlid}” parameter!

 

 

Alfresco Document Library filters

In my customization work with Alfresco Share, I was asked to change the default width of document library filters section (the left-hand part of the document library).

For all those searching for the way like I did, it’s done by editing the file alfresco-resizer.js (usually placed in $TOMCAT_HOME/webapps/share/js ). You just need to change the property called:

DEFAULT_FILTER_PANEL_WIDTH.

Remember to minify the file again and deploy the minified version.

Alfresco Dashlet Resizer

I’m working on a product based on Alfresco Community Edition, the opensource document management platform. We’re using Alfresco Share aplication as a frontend. I’m doing a lot of customizations on it, some in forms of new Share dashlets.

One of the things that has been bugging me is how to make dashlets resizeable. So, for others still possibly looking for this issue, I’m posting the answer here.

To make a dashlet resizeable, you need to two bits of code in your dashlet.get.html.ftl:

1. Add this piece of JavaScript to instantiate the Resizer object:

[code lang="html"]<script type="text/javascript">//<![CDATA[

new Alfresco.widget.DashletResizer("${args.htmlid}", "${instance.object.id}");

//]]></script>[/code]

2. Your dashlet needs a div with a class of “body”.

Make it look for dashlet height:

[code lang="freemarker"]<div class="body scrollableList" <#if args.height??>style="height: ${args.height}px;"</#if>>[/code]