cancel
Showing results for 
Search instead for 
Did you mean: 

Adding YUI Widgets Using Webscripts

stevericker
Champ in-the-making
Champ in-the-making
Hello All,

We're adding a YUI widget (a treeview) as a dashlet.  But we have some questions as to how to do this correctly using webscripts.  There seem to be several examples of similar things built into Share, but we get lost as we try to plow through all the technologies that are involved (e.g., YUI, Freemarker, webscripts, Share).

Here's what we've tried:

- Built a webscript called "treenav" (treenav.get.desc.xml, *.get.html.ftl, *.get.head.ftl, *.get.js)
- Made the <family> a dashlet in the descriptor
- Added all the YUI treeview javascript code to the response template, treenav.get.html.ftl (see below)

<html><head></head><body>Test dashlet<div id="treeDiv1">gee</div><script type="text/javascript">//<![CDATA[var tempobject = [ { type: "text", label: "node1" } ];//instantiate the TreeView control:var tree = new YAHOO.widget.TreeView("treeDiv1", tempobject);//render ittree.draw();//]]></script></body></html>‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
- Registered it
- Added the dashlet to a dashboard
- It works (the YUI treeview shows up)

Here's one question:

- It doesn't seem like adding the javascript to the response template (*.get.html.ftl) is all that elegant (and kind of messes up the MVC pattern)
- But the YUI treeview seems to need its target (the <DIV> tag where the treeview will go) before being instantiated
- So putting the javascript in the controller (treenav.get.js) or in a client side file (treenav.js) doesn't seem to work
- Is there a more correct way to do this?

Here's another question:

- We want to try to get some user site information while we're building the treeview in the response template (treenav.get.html.ftl)
- When we try to use "remote.call" in our javascript, we get the error "remote is not defined" (in Firebug)
- But the remote object seems accessible per http://wiki.alfresco.com/wiki/Surf_Platform_-_Freemarker_Template_and_JavaScript_API#remote?
- Is it not possible to use the root object "remote" within javascript embedded in the response template?

And a final, more general, question:

- Let's say, from our controller script, we put data in our model root object
- How can we access that model root object data from our response template w.o. using a Freemarker interpolation (${somedata})?
- In particular, if we have javascript in our response template, can we get access to the model root object?

Hopefully this is not too longwinded.  But any help on the above would be really appreciated and would really help us as we try to continue to figure out how best to use the platform (by the way, we're using Alfresco Share 3.2r community w. Tomcat).  It seems like our troubles and questions are probably due to some misunderstandings we have about webscripts.

Thank you!
19 REPLIES 19

pqr
Champ in-the-making
Champ in-the-making
Hi steve

Ans 1
To follow MVC pattern better, put your YUI treeview, in the client side .js file.

And it doesnt work for you – then please confirm that, your changes in *.js files do reflect *-min.js file as Share will consider minified javascript file.(This might be one reason)


Ans 3

I am not sure,,,, but I dont think you can use model object in javascript,,

stevericker
Champ in-the-making
Champ in-the-making
Niketa,

Thanks for your help.  Unfortunately putting the YUI treeview javascript code into the client side *.js file (and into *-min.js while adding <script> references to those files in *.get.head.ftl) causes this error in Firebug (where the offending command is "tree.draw()" and "treenav" is our code, not YUI code):
H is nullanonymous()          treeview-min.js (line 😎treenav.js()         treenav.js (line 37)[Break on this error] }else{H.expand();H=(H.children.length||n…&&!C.isFunction(this[E])){this[E]=G[E];\n                     treeview-min.js (line 😎‍‍‍‍‍‍
It seem like the problem is that *.js gets executed in the <head> of the rendered page before the <div> tag in the <body> is defined, so there ends up being no place for YUI to put the treeview?

I'm not sure if the treeview widget is somehow special, but I see that there are other YUI widgets being used throughout Share w.o. any trouble.  I took the beginner's approach and just tried to slap up a YUI widget like I would outside of a Surf/Share/webscript application.

Thanks in advance for any other thoughts.

zaizi
Champ in-the-making
Champ in-the-making
Take a look at the other examples in Share. You can use the YUILoaderHelper to fire once the required script files are loaded and elements are available.

Alfresco.util.ComponentManager.register(this);Alfresco.util.YUILoaderHelper.require(["button", "menu", "container"], this.onComponentsLoaded, this);‍‍

The javascript in *.get.js get executed within Alfresco server. The remote.call method is available there. It is not available in browser client side javascript. Although they are both javascript files, they are executed in two completely different contexts and the functions / objects available to them are completely different.

In your client side javascript define a javascript object with a constructor. In your response template initialise your custom object like you've initialised the tree. When it is initalised in the client side your code can call back to Alfresco webscript to fetch data model for the tree (or this can be included in the constructor).

stevericker
Champ in-the-making
Champ in-the-making
Zaizi,

Thank you very much for your suggestions and comments.  Real helpful that you spelled out that the javascript "remote.call" is only available with server side javascript, which for us would be the controller script of the webscript that is our new dashlet (and not available from any client side javascript including script that we embed within our response template).

Your last suggestion worked.  We put the constructor in our client side *.js file (which we then add to *.get.head.ftl):
var tempobject = [ { type: "text", label: "node1" } ];//instantiate the TreeView control:var tree = new YAHOO.widget.TreeView("treeDiv1", tempobject);‍‍‍‍‍‍
For our response template, we just define the element (<DIV>) and then render (initialize?) the tree within some embedded script:
<html>    <head>    </head>    <body>    Test dashlet    <div id="treeDiv1">tree</div>    <script type="text/javascript">//<![CDATA[    //render it    tree.draw();    //]]></script>    </body>    </html>‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

This is probably just a mental block but the problem is that we still can't think of a way to access Share server information (like a list of all of the Share sites)?  Here're the things we tried that DON'T work:

- from our response template (*get.html.ftl), using javascript, tried to access "remote.call" (which doesn't work for the reasons you explained)
- also from our response template (*.get.html.ftl), using javascript, tried to access the model (model.somevariable as populated from the controller)

Our constructor for the treeview is essentially still on the client side (now in a *.js file which is included via *.get.head.ftl as mentioned above).  So it's still not clear how we could get access to "remote.call" or the model from there?  The only way it seems that the model can be accessed is via Freemarker (which would make sense because the Freemarker engine is server side)?  If that's the case though, we can't seem to pass that information back to any client side javascript (which is where all the YUI widget configuration is happening).

We tried to look at some of the examples but couldn't see anything where server side javascript root objects (for example remote.call) needed to be passed to client side javascript.  Most of the examples (like the my-sites webscript/dashlet) seem to pass the model to the Freemarker template (not javascript embedded in that).  We also looked at some YUI widgets (like buttons) but those seem to have some kind of Alfresco "wrapper" around them and have special constructors (like Alfresco.util.createYUIButton).  There doesn't seem to be something like that for a treeview.  (We're still investigating YUILoader / YUILoaderHelper.)

I guess the basic question now boils down to: how do you pass server side information (where you have access to a big API) over to client side javascript (when building a Share dashlet)?

Darn, are we just missing something basic in our understanding?  Thanks again.

mikeh
Star Contributor
Star Contributor
The key part you're missing is to populate the client-side JavaScript object by getting Freemarker to generate the code.
For example, documentlist.get.html.ftl is similar to:
<script type="text/javascript">//<![CDATA[   new Alfresco.DocumentList("${args.htmlid}").setOptions(   {      siteId: "${page.url.templateArgs.site!""}",      containerId: "${template.properties.container!"documentLibrary"}",      usePagination: ${(args.pagination!false)?string},      showFolders: ${(preferences.showFolders!false)?string},      simpleView: ${(preferences.simpleView!false)?string},      highlightFile: "${page.url.args["file"]!""}",      vtiServer: ${vtiServer}   }).setMessages(      ${messages}   );//]]></script>‍‍‍‍‍‍‍‍‍‍‍‍‍‍
As you can see, the client-side Alfresco.DocumentList class is being passed parameters through the setOptions() function; parameters which are generated at runtime via Freemarker directives; in turn populated either by the Surf framework or from the web-tier controller script documentlist.get.js. Parameters page.*, template.* and args.* are examples of the former, preferences.* and vtiServer the latter.

Thanks,
Mike

zaizi
Champ in-the-making
Champ in-the-making
Two options.

Option 1:
In your server side controller javascript get a list of Share sites, etc. and other information using objects / functions available. See http://wiki.alfresco.com/wiki/JavaScript_API. Add them to the model and in your freemarker add pass them through to the client side javascript constructor.

In *.get.head.ftl
var shareSites = [{ "sites": <#list sites as site>"${site.name}" <#if site_has_next>,</#if></#list> } ];var tempobject = [ { type: "text", label: "node1" } ];//instantiate the TreeView control:var tree = new YAHOO.widget.TreeView("treeDiv1", tempobject, shareSites);‍‍‍‍‍‍‍‍‍‍

This lets you pass the information from the model to the client side javascript. The Freemarker template prints out the model.

This easy and is pretty static in the sense the user will have to refresh the page to list any new sites.

Option 2:
You use client javascript code to call a remote Alfresco web script to load the information in dynmically. This is more work. YUI provides Connection Manager (http://developer.yahoo.com/yui/connection/) for these purposes. Alfresco provide a nice wrapper utility to call web scripts more easily. The following example client side javascript function does an AJAX call to a webscript to get a list of events for the Calendar.

      _loadData: function()      {         Alfresco.util.Ajax.request(         {            url: Alfresco.constants.PROXY_URI + "calendar/eventList",            dataObj:            {               "site": this.siteId            },            successCallback:            {               fn: this.onDataLoad,               scope: this            },            failureMessage: Alfresco.util.message("load.fail", "Alfresco.CalendarView")         });      },‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

stevericker
Champ in-the-making
Champ in-the-making
Mike and Zaizi,

Thanks a ton!  Both those solutions seem really powerful and straightforward:

- Populate client-side JavaScript using Freemarker (which has access to the model)
- From client-side JavaScript, obtain server side information through a data webscript

…The light bulb finally turned on inside!  I'll study the examples as well.  Thanks again.

zladuric
Champ on-the-rise
Champ on-the-rise
I can only agree with Steve, this really lit the bulb above my head! Is something this simple and explanatory available on the wiki? Didn't see it till now.

Anyway, I have an additional question regarding js.
I would like to do a remote call or an AJAX call to the repo from share, but I'm having problems with my arguments passing. I made a .json.ftl webscript in /alfresco, which takes a GET argument (site name) and returns some custom metadata as JSON. Now, when I call it via /alfresco directly, it works. But when I call the webscript from Share I get the following error in the logs
"…freemarker.core.InvalidReferenceException: Expression companyhome.childByNamePath["Sites/"+args.company+"/documentLibrary"] is undefined on line 3, column 8 in…"
Now, I don't understand what I'm doing wrong. Can you please post an example of a remote call with an argument passed correctly?

stevericker
Champ in-the-making
Champ in-the-making
Zlatko,

Could you post the code?  I've done a lotta trial and error stuff and maybe it's something that I've come across.

Steve