gsp « Intelligrape Groovy & Grails Blogs

Posts Tagged ‘ gsp ’

Grails GSP tag: grep

Posted by on October 31st, 2012

The other day I was reading the Grails docs and I came across a useful GSP tag: grep. I have been using Grails for over 3 years now but just recently got to see this new tag which has eased my life a bit in situations where the list of objects have to be filtered and iterated at the same time to perform some operations on them. The GSP ‘grep’ tag (equivalent to the ‘grep’ method in Groovy) filters the list on a given condition and iterates over the filtered list allowing you to do some operations on the objects (or whatever you want to do with the filtered objects).

I will give you a small example: Suppose we have a list of Person objects. You want to display the names starting with A, B, C and so on in different color schemes. How would you do it?

One implementation is to send different lists from the controllers (this would mean sending 26 lists i.e. one list for each character in the English alphabet) and render them in different color schemes. The other way would be to iterate over the Persons list in the GSP and have  different <g:if>…<:g:elseif> statements (for each character).

There is another smarter way: you could also use the ‘findAll‘ method of the List in the GSP <g:each> tag’s ‘in’ attribute i.e <g:each in=${personList.findAll {it.name.startsWith(‘A’)}} var=”person”> … </g:each>.

Similarly, we can use ‘grep’ tag here. We can filter out the list like this: <g:grep in=”${personList.name}” filter=”~/^A.*/”> … </g:grep>.

Notice the use of ‘name‘ field of the Person object in the ‘in‘ attribute of the grep tag. Also, the attribute ‘filter’ takes many forms of filter options; here we are using regex to filter the persons with the name starting with ‘A’.

I am not saying that this tag provides some new functionality which we could not have achieved by any other means but this tag makes it easier to filter out the lists on some specific parameters.

You can read more about this tag here. Also you can read about the Groovy GDK’s grep method usage here to see how and in what scenarios you can use this tag.

Hope this helps !!

- Abhishek Tejpaul
abhishek@intelligrape.com

Posted in Grails

Getting started with jQuery Mobile

Posted by on September 15th, 2012

JQuery mobile provides set of features which are supported on almost all smartphones such as touch UI, ajax navigation, animated page transitions. Building jQuery mobile page is very simple, here’s how:

  1. A jQuery Mobile site must start with an HTML5 ‘doctype’ to take full advantage of all of the framework’s features.
  2. First of all you need jQuery, jQuery mobile, mobile theme stylesheets from CDN.
  3. Reference all styles & scripts in the head of page.
  4. <!DOCTYPE html>
    <html>
    <head>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Page Title</title>
    <link rel="stylesheet" href="css/jquery.mobile-1.1.1.css"/>
    <script src="js/jquery-1.8.0.min.js"></script>
    <script src="js/jquery.mobile-1.1.1.min.js"></script>
    </head>
  5. A meta viewport tag in the head sets the screen width to the pixel width of the device.
  6. Inside body of html page a div with data-role of page is used as a wrapper for whole page.
  7. For header bar add a div with data-role of header.
  8. For content region add a div with a data-role of content & add content between this div.
  9. <body>
    <div data-role="page">
            <div data-role="header">
                    Header
            </div>
            <div data-role="content">
                    <p>This is jquery mobile test page</p>
            </div>
            <div data-role="footer">
                   ©intelligrape
            </div>
    </div>
    </body>
    
  10. There are many features provided by jQuery mobile. Here i am explaining one of them which is list. For list, simply add ul tag with attribute data-role of listview between

    .
  11. To make it look like an inset module add an attribute data-inset=”true”.
  12. For dynamic search filter just add another attribute data-filter=”true”.
  13. <div data-role="content">
        <ul data-role="listview" data-inset="true" data-filter="true">
              <li>Blue</li>
              <li>Black</li>
              <li>Green</li>
              <li>Yellow</li>
              <li>White</li>
        </ul>
    </div>
    

Change user preferred locale using spring’s SessionLocaleResolver

Posted by on May 11th, 2012

Here we are going to talk about a scenario where there are some records in database which are specific to locale and they need to be displayed as per user’s current locale at number of places.Also user can change its preferred locale.

For this I preferred to set the user’s locale in the session object. There are two ways to do this :-

1. Add attribute “lang” to the request and it will be available to session automatically.

For example: whenever user clicks on the link, the language will change to English and the user will remain on the same page.


<g:link controller="${params.controller}" action="${params.action}" params="${params+[lang:'en']}">English</g:link>
/*Add different languages here*/

2.Also set default locale in the session in case, it is not set.

For that add following to any Filters :-


if (!session.'org.springframework.web.servlet.i18n.SessionLocaleResolver.LOCALE') {
LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request);
localeResolver.setLocale(request, response, new Locale('en'));

}

This sets the locale in spring’s SessionLocaleResolver class. Session always refer for the locale from here only.

Now one can check the locale wherever session is available. For example in GSPs:


<g:if test="${session.'org.springframework.web.servlet.i18n.SessionLocaleResolver.LOCALE'.toString()=='en'}">

Note: This implementation is useful to set locale in session (for accessing many times). Otherwise locale is available directly from current request as given below:-

import org.springframework.web.servlet.support.RequestContextUtils as RCU
Locale locale=RCU.getLocale(request)

Hope this helped!
Nitesh Goel
[Intelligrape Software Pvt. Ltd.]

RequestContextUtils
Posted in Grails

Using TagLib to avoid changes due to change in URLMappings

Posted by on February 14th, 2011

Recently, I used Taglib to centralize the effect of URL mapping related changes of my grails application.

def userPageLink = {attrs, body ->

def user = User.read(attrs.id)

out << g.link(controller: 'user', action: 'show', params: [name: user.name]) {body()}
}

So wherever I need a link to user page, I can use this Taglib instead of g:link.

<hys:userPageLink id="${user.id}">${user.name}</hys:userPageLink>

Advantage:


Whenever I change the URL Mappings, there is no need to update all the g:link in all my gsp files. I would just update my taglib to cater to new URL Mapping.

Posted in Grails

Grails taglib and JavaScript file

Posted by on January 16th, 2011

We use internationalization feature in grails using message tag in GSP pages. However arbitrary Groovy/Grails (e.g. tags) code can not be used in JavaScript as they are not executed on server side. To overcome this I used the following way :

Declare a JSON object in js file or any where else so that this object is global one. Create a global JavaScript function that can populate this JSON object. Here is the sample code:


var i18nmessages={};

function updateConfigurationMap(newConfigurationMap) {
	for(key in newConfigurationMap){
		i18nmessages[key] = newConfigurationMap[key];
	}
/*
	//or in jQuery way
	jQuery.each(newConfiguration, function(key, val) {
		i18nmessages[key] = val
	});
*/
}

Now you can write code like below inside HTML head tag in GSP pages to populate the i18nmessages JSON map:


<script type="text/javascript">

 updateConfigurationMap({

   noResultError : '${message(code:'project.noResultError'')}.encodeAsHTML()',

   rangeError : '${message(code:'project.rangeError', args:[50, 100]).encodeAsHTML()}',

   ajaxCallUrl : '${createLink(controller:'myController', action: 'myAction')}',

   deleteImagePath : '${resource(dir:'images', file:'myimage.png')}'

 });

</script>

After execution of the above GSP code considering that the JavaScript code written above has executed, you can use messages like this in javascript :


function findResult(){
	alert("Error occurred during processing : "+i18nmessages.noResultError)
}

function getRemoteData(dataToSend){
       /*  note that you can not use createLink grails tag here  */
	jQuery.get(i18nmessages.ajaxCallUrl+"?"+dataToSend, function(response){
		// Process response here.
	})
}

function insertDeleteImage(){
       /* As you can not use resource tag of grails here */
	jQuery('selector').append("<img src='"+ i18nmessages.deleteImagePath +"' />")
}

Obviously there is a drawback with this approach that the JavaScript for setting messages can not be cached in browser. But the advantage is that you are free to use arbitrary Server side code to generate messages. As you have noticed in above code snippet the URL for ajax call and image paths generated using Grails tags can not be used inside the js files.

Another idea will be to create separate js files name ending with language suffix(e.g. *-en.js, *-sv.js etc) for each language your app support. Populate the i18nmessages there. Use appropriate js file depending on the request locale(e.g. session.'org.springframework.web.servlet.i18n.SessionLocaleResolver.LOCALE'). This way you can enable caching of js files in browser but you are limited to messages with static content only.



Please share your ideas how you solved this situation.


Cheers!
~~Bhagwat Kumar~~
bhagwat(at)intelligrape(dot)com

Cheers!
~~Bhagwat Kumar~~
bhagwat(at)intelligrape(dot)com
http://twitter.com/bhagwatkumar
http://in.linkedin.com/in/bhagwatkumar

Request Mocking to use groovyPagesTemplateEngine in backend threads

Posted by on December 27th, 2010

We have a setup where a backend thread, fired by the Spring Events, does some processing, generates a PDF and emails the result to the user.
The code we were using to generate the HTML from a GSP to be converted to a PDF using iText was as follows :

        def webRequest = RequestContextHolder.getRequestAttributes()
        def originalOut = webRequest.out
        try {
            def sw = new StringWriter()
            def pw = new PrintWriter(sw)
            webRequest.out = pw
            groovyPagesTemplateEngine.createTemplate("path_to_gsp").make([model:model]).writeTo(pw)
            return sw.toString()
        } finally {
          webRequest.out = originalOut
        }

There was the obvious fallibility of this code that there was no Current Request associated with the backend thread!

After doing some googling around it, I came across a few threads and posts which talked about Request Mocking, which has been used in Grails Template Engine Plugin.  We overcame this by using the code snippet given below to mock the web request

def webRequest = RequestContextHolder.getRequestAttributes()
if(!webRequest) {
          def servletContext  = ServletContextHolder.getServletContext()
          def applicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext)
          webRequest = grails.util.GrailsWebUtil.bindMockWebRequest(applicationContext)
}

However, things didn’t end there. This code broke while working on a WAR environment. The problem was that the MockWebRequest class was part of the “org.springframework:org.springframework.test:3.0.3.RELEASE” jar and had to be included in the BuildConfig.groovy as


dependencies{

runtime 'org.springframework:org.springframework.test:3.0.3.RELEASE'

}

Ensure that the line


mavenCentral()

is not commented in BuildConfig.groovy

We were working on Grails 1.3.4

 

Hope this helps.
Vivek

http://in.linkedin.com/in/svivekkrishna

Posted in Grails

Grails way for rendering the GSP templates: The tmpl namespace.

Posted by on October 1st, 2010

Today while working on a project, I paired up with my colleague (Uday)  and we found that we can render a gsp template in a different manner also. Grails provide us a “tmpl” namespace for rendering the GSP templates.


The old way that we use to render a gsp template

<g:render template="templateName" model="[books:books, authors:authors]"/>

The other way for  rendering the template.

<tmpl:templateName books=${books}  authors="${authors}"/>

Like me, you also must be wondering that if the template is in some other path like some shared folder “/shared/templateName” then how this <tmpl/> would work?

e.g.

<g:render template="/shared/templateName" model="[books:books, authors:authors]"/>

The answer is: <tmpl:/shared/templateName/>

<tmpl:/shared/templateName books=${books}  authors="${authors}"/>

* you can find the documentation for this on http://www.grails.org/doc/latest/guide/single.html


Concerns, comments or suggestions are always welcome.
Cheers!!!!!
~Chandan Luthra~
chandan(aT)intelligrape(dOt)com
http://in.linkedin.com/in/luthrachandan/

Tags: , ,
Posted in Grails, Groovy

Finding User’s Session Locale in GSP

Posted by on July 14th, 2010

There are situations where you might want to know the Locale of the user as set in the session in your GSP so that you can show text in a particular language/manner. Here the Spring framework’s SessionLocaleResolver can come to the rescue. In one of our recent Grails projects, we did the following in one of our GSPs to display the content accordingly.

Please note that our use-case was like that in which we have fields for different languages in our domain classes. For example:

class MyDomain {
String greetingEnglish
String greetingFrench
}

And now you have to conditionally display the object’s fields based on the user’s locale. If this were a static text, then the Grails in-built i18n support in the form of message bundles would be the ideal solution. But this is a different scenario.

So let’s start by writing the following in your GSP :

<g:set var="lang" value="${session.'org.springframework.web.servlet.i18n.SessionLocaleResolver.LOCALE'}"/>

The above statement returns the ISO Language Code from the session object which is a map. In Grails, the map values can be retrieved by the ‘.’ operator too by passing the keys. These codes are the lower-case, two-letter codes as defined by ISO-639. For example: ‘en’ for English, ‘fr’ for French and so on.

Once you know the locale, you can show the conditional content on your page. It could be something like this:

<g:if test="${lang.startsWith('en')}">
<h1> ${myDomainobject.greetingEnglish} </h1>
</g:if>
<g:elseif test="${lang.startsWith('fr')}">
<h1> ${myDomainobject.greetingFrench}</h1>
</g:elseif>
<g:else>
<h1> Default Greeting </h1>
</g:else>

Hope this will help !!!

- Abhishek Tejpaul

[Intelligrape Software Pvt. Ltd.]

Posted in Grails, HTML-UI-CSS

Injecting Method to trim string length on gsp pages

Posted by on May 3rd, 2010

Restricting the length of a string on gsps is a common scenario in most of our projects.
Groovy’s metaprogramming magic made it too simple for me. I added the following lines of code to Bootstrap.groovy:

Object.metaClass.trimLength = {Integer stringLength ->
 
    String trimString = delegate?.toString()
    String concatenateString = "..."
    List separators = [".", " "]
 
    if (stringLength && (trimString?.length() > stringLength)) {
        trimString = trimString.substring(0, stringLength - concatenateString.length())
        String separator = separators.findAll{trimString.contains(it)}?.min{trimString.lastIndexOf(it)}
        if(separator){
            trimString = trimString.substring(0, trimString.lastIndexOf(separator))
        }
        trimString += concatenateString
    }
    return trimString
}

Now, for an instance of class Person:

class Person {
    String name
 
    String toString(){
        return name
    }
}
 
Person person = new Person(name: "Aman Aggarwal")

I can simply write this code in gsp:

person.trimLength(10)

which renders output:

Aman...

Hope it helps.

~Aman Aggarwal
aman@intelligrape.com

http://www.IntelliGrape.com/

Posted in Grails, Groovy

Creating File Explorer with Context Menu using jQuery File Tree Plugin

Posted by on May 26th, 2009
You can create a customized, fully-interactive file tree using jQuery File Tree plugin Written by Cory S.N. LaViska. For a demo on File Explorer click here.Here are the quick steps to implement it in your application. For advanced information please go to the plugin website where you can find the detailed description of this plugin as well as links to demo, download etc pages.

At first glance this seems to be very lengthy blog but when you start copying and pasting the code shown here into your application you will get this lengthy explanation very useful.

Here is a snapshot of what we are going to achieve in few minutes.

File Explorer with context menu

  1. Install jquery plugin

  2. jQuery File Tree requires jQuery 1.2 or above.If you have already installed this plugin then you can skip this step.
    To install jQuery plugin use the following command :

    grails install-plugin jquery

    To get the list of commands to manage plugins (eg. create, install, uninstall, list of plugins) use the following command :

    grails --help | grep plugin

  3. Download jQuery File Tree plugin files

  4. You can download the required files from the plugins website or Click here to download.

    Unzip the downloaded zip file. The unzipped folder ‘jqueryFileTree’ contains a folder ‘connector’ that you can safely delete because we will write our own connector specific to grails.

  5. place the unzipped folder into web-app folder

  6. Using operating system file explorer tool move/copy the unzipped folder ‘jqueryFileTree’ to the applications web-app folder. If you are not interested in such an easy step then you can move the jqueryFileTree.js file to web-app/js folder, jqueryFileTree.css file to web-app/css and all the files from jQueryFileTree/images to web-app/images folder and correspondingly change the reference to these files in gsp page we will be creating next. I assume you followed the easier way i.e. copied the entire folder into web-app folder.

  7. Decide the controller, action and gsp page

  8. Suppose we have a controller ‘FileBrowser’(…grails-app/controllers/FileBrowserController.groovy) and its ‘showBrowser’ action renders the view (we call it : …/grails-app/views/FileBrowser/FileBrowser.gsp). The controller looks like

    class FileBrowserController {
    //...............
    def showBrowser = {
    //.................
    render( view : 'FileBrowser')
    }
    //................
    }

  9. Create gsp page and customize it

    Here is the contents of “/grails-app/views/FileBrowser/FileBrowser.gsp” file :

    <html>
    <head>
    <title>File Explorer</title>
    <script src=”${createLinkTo(dir: ‘js/jquery’, file: ‘jquery-1.3.2.js’)}” type=”text/javascript”></script>
    <link rel=”stylesheet” href=”${createLinkTo(dir: ‘jqueryFileTree’, file: ‘jqueryFileTree.css’)}”>
    <script src=”${createLinkTo(dir: ‘jqueryFileTree’, file: ‘jqueryFileTree.js’)}” type=”text/javascript”></script>
    <script type=”text/javascript”>

    function YourFunctionToProcessThisFilePath(file){
    alert(‘You selected : ‘+file);
    }

    $(document).ready(function() {
    $(‘#file_list’).fileTree({
    root:’/',    /*DESCRIPTION 1*/
    script: ‘generateFileList.gsp’,    /*DESCRIPTION 2*/
    expandSpeed: 1000,
    collapseSpeed: 1000,
    multiFolder: false
    }, function(file) {
    YourFunctionToProcessThisFilePath(file); /* DESCRIPTION 3*/
    });
    });
    </script>
    </head>
    <h1>File Explorer</h1>
    <body>
    <div id=”file_list”>    <!– DESCRIPTION #4 –>
    <%=”Empty”%>
    </div>
    </body>
    </html>

    • DESCRIPTION #1: absoulute path of the folder which will be treated as root level folder in our file explorer. There exists a potential for malicious individuals to be able to view your entire directory structure by spoofing the root parameter. However you can control this from the script file described in DESCRIPTION #2.
    • DESCRIPTION #2: connector file(server side script) that generates the list of files and subdirectories for the selected folder. This is a gsp file where you get the absolute path of the folder in dir attribute of params map for which the files and subfolders is to be found and output an unsorted list in the following format:
      We will create this gsp page parallel to FileBrowser.gsp i.e. …/grails-app/views/FileBrowser/generateFileList.gsp in Step 6. Later we will move this logic into an action and hence no need of connector script (see step 8).
    • DESCRIPTION #3: this javascript function is called with absolute path to the selectd file whenever a file is clicked in the file browser page.
    • DESCRIPTION #4: The id of the div tag is used in jQuery. So it must match at both places.
  10. Create connector script

  11. Here is the code for connector script "...grails-app/views/FileBrowser/generateFileList.gsp"

    <%
    String dir = params?.dir
    if (dir == null) {
        return;
    }
    /* you can put here your own custom check with dir variable to protect from malicious request.  */
    if(!dir.endsWith(File.separator)){
        dir+=File.separator
    }
    
    File f=new File(dir)
    if (f.exists()) {
        List<File> files=[]
    
        f.eachFile { File file->
            if(!file.hidden)
                files<<file
        }
    
        files.sort{File file-> file.name.toUpperCase()}
        StringBuffer output=new StringBuffer('<ul class="jqueryFileTree" style="display: none;">')
        // All dirs
        files.each{File file->
            if(file.directory){
                output.append("""<li class="directory collapsed"><a href="#" rel="${dir+file.name+File.separator}">${file.name}</a></li>""")
            }
        }
        // All files
        files.each{File file->
            if(file.file){
                int dotIndex = file.name.lastIndexOf('.');
                String ext = dotIndex > 0 ? file.name.substring(dotIndex + 1) : "";
                output.append("""<li class="file ext_${ext}"><a href="#" rel="${dir+file.name}">${file.name}</a></li>""");
            }
        }
        output.append("</ul>");
        println output.toString()
    }
    %>
    
  12. Test Your File Explorer

    It’s time to test your file explorer. If everything went perfectly then you have successfully created your file explorer. Type the url of the action responsible for rendering FileBrowser.gsp.You can also experiment with various Parameters that are passed as an object to the fileTree() function in FileBrowser.gsp. List of Valid options can be found at the pluging website under ‘Configuring the File Tree’ heading.

  13. Moving the connector script  to an action of the controller

    Here is the modified controller FileBrowserController having an action generateFileList. This contains the same code as in generateFileList with few new statements appended and obviously <% and %> has been removed.The modified lines has been shown in different color.

    class FileBrowserController {
    //……………
    def showBrowser = {
    //……………..
    render( view : ‘FileBrowser’)
    }
    def generateFileList={
    String dir = params?.dir
    if (dir == null) {
    return;
    }
    /* you can put here your own custom check with dir variable to protect from malicious request.  */
    if(!dir.endsWith(File.separator)){
    dir+=File.separator
    }

    File f=new File(dir)
    if (f.exists()) {
    List<File> files=[]

    f.eachFile { File file->
    if(!file.hidden)
    files<<file
    }

    files.sort{File file->
    file.name.toUpperCase()
    }

    StringBuffer output=new StringBuffer(‘<ul class=”jqueryFileTree” style=”display: none;”>’)
    // All dirs
    files.each{File file->
    if(file.directory){
    output.append(“”"<li class=”directory collapsed”><a href=”#” rel=”${dir+file.name+File.separator}”>${file.name}</a></li>”"”)
    }
    }
    // All files
    files.each{File file->
    if(file.file){
    int dotIndex = file.name.lastIndexOf(‘.’)
    String ext = dotIndex > 0 ? file.name.substring(dotIndex + 1) : “”
    output.append(“”"<li class=”file ext_${ext}” id=”${dir+file.name}”><a href=”#” rel=”${dir+file.name}”>${file.name}</a></li>”"”)
    }
    }
    output.append(“</ul>”)
    OutputStream out = response.getOutputStream()
    out.write (output.toString().getBytes())
    out.flush()
    out.close()

    }
    }
    //…………….
    }

  14. Making changes to FileBrowser.gsp to use generateFileList action instead of generateFileList.gsp file

    Here are the modified lines of FileBrowser.gsp file (Modified lines shown in different color ) :

    $(document).ready(function() {
    $(‘#file_list’).fileTree({
    root:’/',
    script: “${createLink(action:’generateFileList’)}”, /* you can also explicitly specify the controller */
    expandSpeed: 1000,
    collapseSpeed: 1000,

    After this change, you can test your File Explorer and if everything works perfectly, you can safely delete the file generateFileList.gsp.

  15. Forwarding to an action when a file is clicked

    To do so we will modify FileBrowser.gsp page to include a form and a hidden field for absolute path of the selected file.
    The modified FileBrowser.gsp(with modified lines shown in different color) is now :

    <html>
    <head>
    <title>File Explorer</title>
    <script src=”${createLinkTo(dir: ‘js/jquery’, file: ‘jquery-1.3.2.js’)}” type=”text/javascript”></script>
    <link rel=”stylesheet” href=”${createLinkTo(dir: ‘jqueryFileTree’, file: ‘jqueryFileTree.css’)}”>
    <script src=”${createLinkTo(dir: ‘jqueryFileTree’, file: ‘jqueryFileTree.js’)}” type=”text/javascript”></script>
    <script type=”text/javascript”>

    function YourFunctionToProcessThisFilePath(file){
    //        alert(‘You selected : ‘+file);
    document.getElementById(‘selectedFile’).value = file
    document.getElementById(‘fileBrowserForm’).submit()
    }

    $(document).ready(function() {
    $(‘#file_list’).fileTree({
    root:’/',    /*DESCRIPTION 1*/
    script: “${createLink(action:’generateFileList’)}”, //’generateFileList.gsp’,
    expandSpeed: 1000,
    collapseSpeed: 1000,
    multiFolder: false
    }, function(file) {
    YourFunctionToProcessThisFilePath(file); /* DESCRIPTION 3 */
    });
    });
    </script>
    </head>
    <h1>File Explorer</h1>
    <body>
    <div id=”file_list”>    <!– DESCRIPTION #4 –>
    <%=”Empty”%>
    </div>
    <g:form name=”fileBrowserForm” action=”processThisFile” method=”post”>
    <g:hiddenField name=”selectedFile” />
    </g:form>
    </body>
    </html>

    Now add an action ‘processThisFile’ or whatever you have used as forms action in FileBrowser.gsp file. Here is the modified FileBrowserController :

    class FileBrowserController {
    //……………
    def processThisFile={
    println params.selectedFile
    render(params.selectedFile)
    }

    //…………….
    }

  16. Installing the plugin for Context Menu(Right Click)

    Now we are going to add Context Menu functionality to our File Explorer. For this purpose we will be using one more plugin jQuery Context Menu Plugin Written by Cory S.N. LaViska(same author has written jQuery File Tree plugin). For advanced details go to the plugin website where you can see a demo as well as download necessary files to use this plugin. Click here to download the plugin.

    After you have downloaded the zip file, unzip it and copy it in applications web-app folder as you did for jQuery File Tree Plugin in Step 3.

  17. Create context menu options by Modifying FileBrowser.gsp file

    create a list in FileBrowser.gsp that will be the markup for your context menu:
    Actions are specified in the href attribute, preceeded by a # symbol. When selected, this is what will be passed back to the action parameter in the callback. You can add class attributes to the list items to assist with styling, but they have no functional meaning. Thus, class names do not have to correspond with actions.

    Let’s create a contextMenu (UL with id myFolderMenu) with four options cut, paste, rename and delete also a separator beteween paste and rename option which is displayed whenever a folder is right-clicked. When you click an option from the displayed context menu the javascript function HandleFolderContextMenu is called with parameters action and folderPath. action contains the href attribute excluding # character of the selected context menu option and folderPath contains the absolute path of the selected folder i.e. on which it was right clicked.

    Similarly a contextMenu(UL with id myFileMenu) with two options Open… and Properties which is displayed whenever a file is right-clicked has been created. Like Context Menu for folders, this time HandleFileContextMenu javascript function is called with action and filePath parameters.

    You can follow the similar steps as described in Step 10 to forward request to an action where it will be processed depending on the action and absolute path to the selected file or folder.

    <html>
    <head>
    <title>File Explorer</title>
    <script src=”${createLinkTo(dir: ‘js/jquery’, file: ‘jquery-1.3.2.js’)}” type=”text/javascript”></script>

    <link rel=”stylesheet” href=”${createLinkTo(dir: ‘jqueryFileTree’, file: ‘jqueryFileTree.css’)}”>
    <script src=”${createLinkTo(dir: ‘jqueryFileTree’, file: ‘jqueryFileTree.js’)}” type=”text/javascript”></script>

    <link rel=”stylesheet” href=”${createLinkTo(dir: ‘jquery.contextMenu’, file: ‘jquery.contextMenu.css’)}”>
    <script src=”${createLinkTo(dir: ‘jquery.contextMenu’, file: ‘jquery.contextMenu.js’)}” type=”text/javascript”></script>

    <script type=”text/javascript”>
    function HandleFolderContextMenu(action, folderPath){
    alert(action+’\n\n Folder Path : ‘+folderPath);
    }
    function HandleFileContextMenu(action, filePath){
    alert(action+’\n\n File Path : ‘+filePath);
    }

    function showMenu(){
    $(‘.directory>a’).contextMenu({
    menu: ‘myFolderMenu’
    },
    function(action, el, pos) {
    var folderPath=$(el).attr(‘rel’);
    HandleFolderContextMenu(action, folderPath);
    }
    );
    $(‘.file>a’).contextMenu({
    menu: ‘myFileMenu’
    },
    function(action, el, pos) {
    var filePath=$(el).attr(‘rel’);
    HandleFileContextMenu(action, filePath);
    }
    );
    }

    </script>

    <script type=”text/javascript”>

    function YourFunctionToProcessThisFilePath(file){
    //        alert(‘You selected : ‘+file);
    document.getElementById(‘selectedFile’).value = file
    document.getElementById(‘fileBrowserForm’).submit()
    }

    $(document).ready(function() {
    $(‘#file_list’).fileTree({
    root:’/',    /*DESCRIPTION 1*/
    script: “${createLink(action:’generateFileList’)}”, //’generateFileList.gsp’,
    expandSpeed: 1000,
    collapseSpeed: 1000,
    multiFolder: false
    }, function(file) {
    YourFunctionToProcessThisFilePath(file); /* DESCRIPTION 3 */
    });
    });
    </script>
    </head>
    <h1>File Explorer</h1>
    <body>
    <div id=”file_list”>    <!– DESCRIPTION #4 –>
    <%=”Empty”%>
    </div>
    <g:form name=”fileBrowserForm” action=”processThisFile” method=”post”>
    <g:hiddenField name=”selectedFile” />
    </g:form>
    <ul id=”myFolderMenu” class=”contextMenu”>
    <li class=”copy”><a href=”#copy”>Copy</a></li>
    <li class=”paste”><a href=”#paste”>Paste</a></li>
    <li class=”separator rename”><a href=”#rename”>Rename</a></li>
    <li class=”deleteFolder”><a href=”#deleteFolder”>Delete</a></li>
    </ul>
    <ul id=”myFileMenu” class=”contextMenu”>
    <li class=”open”><a href=”#open”>Open…</a></li>
    <li class=”properties”><a href=”#properties”>Properties</a></li>
    </ul>
    </body>
    </html>

    Finally modify generateFileList action by adding a statement output.append(““) as shown below the modified lines of generateFileList action to get the changes made to FileBrowser.gsp to work. It just calls the showMenu javascript function defined in FileBrowser.gsp which in turn enables the context menu for the explored folder.

    def generateFileList={
    //…………………..
    output.append(“</ul>”)
    output.append(“<script>showMenu(); </script>”)
    OutputStream out = response.getOutputStream()
    out.write (output.toString().getBytes())
    //…………………..
    }

Hope this helps you guys in creating file explorer with context menu.

Bhagwat Kumar
bhagwat@intelligrape.com

Cheers!
~~Bhagwat Kumar~~
bhagwat(at)intelligrape(dot)com
http://twitter.com/bhagwatkumar
http://in.linkedin.com/in/bhagwatkumar