Extension for ClassicUI

Customize an object's functions menu: CSMenu

Content Script can be used to perform changes to the standard object function menus, by adding new options or removing existing ones. This feature is enabled by defining a Content Script that “filters” the object menu and performs the desired modifications. The “amgui” service provides a user-friendly interface to perform modifications to the menu object.

As for most other features configured through the Content Script Volume, a convention-over-configuration approach has been adopted.

The target container in which to place the Content Scripts is CSMenu. The first level under this container identifies the objects to which the customizations are applied. The naming convention is one of the following:

  • D<nodeID>

  • S<subtype>

where nodeID identifies the node unequivocally and subtype identifies a specific object subtype on Content Server.

csvolumestruct

Examples:

D2000 will change the function menu of the Enterprise Workspace

S144 will change the function menu of Document type objects (subtype: 144)

The following example shows a menu customization script that includes:

  • fetching the original menu

  • filtering the original menu entries (removing entries that match a specific expression)

  • adding a divider row to split menu entries

  • adding a submenu

  • adding a custom menu entry to the new submenu

  • returning the modified menu

E.g.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
def csMenu = amgui.getCSMenu() //retrive the current object's menu
try{
    def node = docman.getNodeFast(nodeID)
    /**
    A filter is a closure that returns true if the menu item shall be kept, false otherwise.
    In the filter function scope the object "it" represent the menu item.
    A menu item has the following properties:
    - name (string)
    - url (string)
    - openInNewTab (boolean ) *available only on 10.5
    - order (decimal)
    **/
    csMenu.filter {it.name == "Open"}
    csMenu.appendDivider() //use appendDivider(position) to specify a position

    def submenu = csMenu.appendSubMenu("My sub-menu") //use appendSubMenu(name, position) to specify a position
        submenu.appendItem("My menu item", "${url}?func=ll&objAction=properties&objId=${nodeID}&nextUrl=${params?.nextUrl?.encodeURL()}")
}catch(e){
    log.debug("Unable to apply changes to add items menu",e)
}

return amgui.returnCSMenu(csMenu)
Property Type Description
name String Label of the menu entry (only for menu items and submenus)
openInNewTab Boolean If true opens a new target browser window (only for menu items)
position String The order of the entry in the menu (available for menu items, submenus and dividers)
url String The target URL (only for menu items)

Notice that all operations are performed either through the amgui service or the CSMenu and CSSubMenu objects.

Return the proper value

The last operation performed in a CSMenu script should always be a call to the “returnCSMenu(...)” API of the amgui service

Customize a space's add-items menu: CSAddItems

Content Script can be used to perform changes to a container’s Add Item menu, by adding new options or removing existing ones. This feature is enabled by defining a Content Script that “filters” the menu and performs the desired modifications. The “amgui” service provides a user-friendly interface to perform modifications to the menu object.

As for most other features configured through the Content Script Volume, a convention-over-configuration approach has been adopted.

The target container in which to place the Content Scripts is CSAddItems. The first level under this container identifies the objects to which the customizations are applied. The naming convention is one of the following:

  • D<nodeID>

  • S<subtype>

where nodeID identifies the node unequivocally and subtype identifies a specific object subtype on Content Server.

csvolumestruct

Examples:

D2000 will change the add items menu of the Enterprise Workspace

The following example shows a menu customization script that includes:

  • filtering the original menu entries (removing entries that match a specific expression)

  • adding a custom menu entry

  • returning the modified menu

E.g.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
try{
    //The current space
    def node = docman.getNodeFast(nodeID)
    /**
        Other possibile filter examples:
        it.name == "Folder"
        it.subtype == 0
    **/
    amgui.filterAddItems {
        it.name == "Folder"
    }
    /**
        Other possibile filter examples:
        it.name  == "Folder"
        it.subtype == 0
    **/
    amgui.filterAddItems ({false}, true)
    amgui.addBrowseViewAddItem(
        amgui.newBrowseViewAddItemsMenu().builderUrl().setImg("${img}folder_icons/folder5.gif")
                                                      .setName("My new object")
                                                      .setPromoted(true)
                                                      .setUrl("${url}?func=ll&objAction=create&objType=0&parentId=${node.ID}&nextUrl=${params?.myUrl?.encodeURL()}").create()
    )
}catch(e){
    log.debug("Unable to apply changes to add items menu",e)
}

return amgui.returnAddItemsMenus()

Invoke a Content Script

The url of the menu entry could be used to pass parameters to a custom Content Script that will perform the desired operations.

Return the proper value

The last operation performed in a CSAddItems script should always be a call to the “returnAddItemsMenu(...)” API of the amgui service

Customize a space's buttons bar: CSMultiButtons

Multi-action buttons can be added, removed or modified by using an approach similar to the CSMenu customization. In this case, customization scripts should be added in the CSMultiButtons container. The container structure is the same as the one described for the CSMenu.

As for most other features configured through the Content Script Volume, a convention-over-configuration approach has been adopted.

The target container in which to place the Content Scripts is CSMultiButtons. The first level under this container identifies the objects to which the customizations are applied. The naming convention is one of the following:

  • D<nodeID>

  • S<subtype>

where nodeID identifies the node unequivocally and subtype identifies a specific object subtype on Content Server.

csvolumestruct

Examples:

D2000 will change the buttons bar menu of the Enterprise Workspace

E.g.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
try{
    amgui.addBrowseViewMultiItemButton(
        amgui.newBrowseViewMultiItemButton()
            .builder()
             .setOrder(1100)
             .setJavascriptFunctionName('runContentScript')
             .setJavascriptFile("anscontentscript/js/contentScriptMultifileBar.js")
             .setImageMap("anscontentscript/contentscriptmultifilebar.png")                                            
             .setImageXPos(0)
             .setImageYPos(0)
             .setImageXPosAlternative(-268)
             .setImageYPosAlternative(0)
             .setDisplayName('My button')
             .create()
    )
    /**
        Properties that can be used to filter the buttons bar:
        - action (the request handler to be executed e.g. ll.ProcessMultiCopy)
        - Order
        - Name
        - DisplayName
        - ExecutesOnClient

    **/
    amgui.filterBrowseViewMultiItemButton {it.name == "mybutton"}

}catch(e){
    log.debug("Unable to apply changes to add multi items buttons bar",e)
}
return amgui.returnBrowseViewMultiItemButtons()

where the following fields are mostly relevant:

Property Type Description
ImageMap String The path of the image map file (in the Support folder) containing the button icon
ImageXPos, ImageXPos2, ImageYPos, ImageYPos2 Integer The coordinates of the portion of the image map to use for the button (normal and on mouse over)
Order String The order of the button in the menu bar
Type String The button type (should be “Content Script”)
ExecutesOnClient boolean If the button logic is on the client side (should be “true”)
DisplayName String The button label
Name String The name of the button
JavascriptFile String The javascript resource in which the function controlling the button behavior is defined
JavascriptFunctionName String The javascript function defined in the JavascriptFile that controls the button behavior

Invoke a Content Script

A sample Javascript file (contentScriptMultifileBar.js) is located in the Content Script Module support folder. Create a customized version of this file when adding new actions.

Customize a space's displayed columns: CSBrowseViewColumns

Content Scripts located in the CSBrowseViewColumns container can be used to perform modifications to how columns are presented in the standard Content Server Browse View.

The modifications can be limited to specific portions of Content Server. This feature is enabled by defining a Content Script that “filters” the browse view columns configuration and performs the desired modifications. The “amgui” service provides a user-friendly interface to perform the modifications.

As for most other features configured through the Content Script Volume, a convention-over-configuration approach has been adopted.

The target container in which to place the Content Scripts is CSBrowseViewColumns. The first level under this container identifies the objects to which the customizations are applied. The naming convention is one of the following:

  • D<nodeID>

  • S<subtype>

where nodeID identifies the node unequivocally and subtype identifies a specific object subtype on Content Server.

csvolumestruct

Examples:

D2000 will change the columns visible in the Enterprise Workspace

The following example shows a browse view columns customization script that includes:

  • create a new column using the builder

  • filtering the original columns list (removing entries that match a specific expression)

  • adding the column to the view

  • returning the modified columns list

E.g.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
try{
    /** 
    A browse view column is quite a complex object. The amgui service provides you with a builder in order to help you in creating it.
    **/
    def columnBuilder = amgui.newBrowseViewColumn().builder()

        .setColumnName("type")  // Column name corresponds to the property 
                                //from the browse view row that will be used 
                                //to populate the column.
        .setDisplayName("Type") // Column display name is the label used for the column.
        .setAlignment("left")
        .setSortable(true)      // If sortable the Javascript sorting 
                                //function will look for a property named: 
                                // columnName+'SortStr' or columnID+'SortStr' 
                                // to perform sorting
        .setColumnEMWidth(1.0)
        .setDisplayAsLink(true)
        .setNewWindow(true)
        .setUrl("${url}?param=%value%")      // The url to be opened. 
                                             // The following placeholder 
                                             // can be used in the expression:
                                             // %value%, %objid%, %rawvalue%, %nexturl%"

        .setFormatValueMask("Type :%value%") // The format mask to be used to 
                                             // present the column value.
                                             // The following placeholder 
                                             // can be used in the expression: 
                                             // %value%, %objid%, %rawvalue%, %nexturl%"
    /**
    A filter is a closure that returns true if the column shall be kept, false otherwise.
    In the filter function scope the object "it" represent the column object.
    For default columns the only attribute available is columnID (string) which might have one out the following values (checkBoxColumn, typeColumn, nameWthPrmtdCmdsColumn  ("name with promoted commands column"), sizeColumn, 
    dataidColumn, dateColumn, arbitraryColumn, columnWithURL, userColumnWithURL)

    All the other columns have the following properties:
    DisplayAsLink (boolean), DisplayValue (string), NewWindow (boolean), NewWindowTitle (string), URL (string), alignment (string), columnID (string), columnName (string), displayName (string)

    **/
    amgui.filterBrowseViewColumn {
        it.columnID != "dateColumn"
    }
    amgui.addBrowseViewColumn(columnBuilder.create())

}catch(e){
    log.debug("Unable to apply changes to add items menu",e)
}

return amgui.returnBrowseViewColumns()

The following properties are available for each column object (they are managed through a builder the CSBrowseViewColumnBuilder obtained :

Property Type Description
isDefault boolean True if the column has a Javascript definition
sortable boolean True if the column has a Javascript definition
DisplayAsLink boolean The value of the column will be wrapped into an HTML link
DisplayValue String The column's value
NewWindow boolean If DisplayAsLink = true, opens the link in a new window
NewWindowTitle String If DisplayAsLink = true, the title of the window in which link will be opened
Url String If DisplayAsLink = true, the URL to be used for building the link
alignment String Column alignement. One out: 'left', 'right', 'center'
columnID String Column unique identifier
columnName String Column name
displayName String Column name as it will be displayed in the page
displayName String Column name as it will be displayed in the page

Filtering columns - lines from 39 to 41

A filter is a closure that returns true if the column shall be kept, false otherwise.

Default Columns

Default columns are columns for which a Javascript column definition exists. Default columns Javascript definitions can be found in webnode/browse.js file. The following default columns definition should exist in your environment:

Value Description
checkBoxColumn Used for selecting multiple nodes
typeColumn Represents the node's type in the form of a web-icon
nameWthPrmtdCmdsColumn Name with promoted commands column
sizeColumn Size of the document or number of items in the space
dataidColumn Node's unique system identifier
dateColumn Node's last modification date
arbitraryColumn Template for other columns (ABSTRACT)
columnWithURL Template for other columns (ABSTRACT)
userColumnWithURL Node's owner

The amgui service features a method that can help you in creating your own custom column Javascript definition on the basis of a template that is stored in the Content Script Volume (CSVolume:CSGui:BrowseViewColumnDefinition). The custom Javascript column's definition can be rendered, for example, as part of a customview, an appearance or a Content Script

1
2
3
4
5
6
7
8
9
amgui.getBrowseViewColumnDefinition(
                                    String columnID, //The id of the column
                                    Map templateContext, // A map to be used as model for
                                                         // the column's definition template
                                    [,CSDocument param ] // An optional template document.
                                                         // If none is provided the default
                                                         // CSVolume:CSGui:BrowseViewColumnDefinition
                                                         // will be used
                                    )

Here below a real-world usage example. The Script is used to create a custom view within the space in which is stored.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
jsAddCell = """
        var cell;

        try
        {

            cell = rowStruct.insertCell( cellCount++ );
            cell.className = this.cellClassName;
            if ( true === this.nowrap )
            {
                cell.style.whiteSpace = 'nowrap';
            }
            cell.innerHTML = this.getCellValue( dataRow, rowNo );


        }
        catch(e)
        {
            exceptionAlert( e, "Issue occured in browse.js/htmlColumn.AddCell." );
        }
        return cellCount;
"""

jsGetCellValue ="""
    var val = dataRow[ 'pstatus' ];
    if ( val == undefined )
    {
        val = "";
    }
    return val;
"""

def customView = docman.getTempResource("customView", ".html")

customView.content.withWriter{
    it << amgui.getBrowseViewColumnDefinition("pstatus",
                                              ["jsAddCell":jsAddCell, "name":"Status", "jsGetCellValue":jsGetCellValue, "cellWidth":"10%"])
}
def cv = docman.createCustomView(self.parent, "customView", customView.content)
cv.setIsHidden()
cv.update()

For default columns (listed in the table above) the only attribute available is columnID (string).

Customize a space content view: CSBrowseView

Content Scripts located in the CSBrowseView container can be used to perform modifications on the content of a browse view.

The target container in which to place the Content Scripts is CSBrowseView. The first level under this container identifies the objects to which the customizations are applied. The naming convention is one of the following:

  • D<nodeID>

  • S<subtype>

where nodeID identifies the node unequivocally and subtype identifies a specific object subtype on Content Server.

csvolumestruct

The following example shows a browse view customization script that will iterate on each row in the browse view and perform modifications for objects of subtype 43200 (Content Scripts)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
try{

    /**
        Properties that can be used to filter the browse view rows:
        - dataId (Numeric)
        - name (String/Html will be rendered inside an 'a' tag)
        - link (String)
        - size (String/Html e.g. '1 KB')
        - date (String e.g. 
        - imgStr (String) 
        - imgLargeStr (String)
        - imgThumbnailStr
        - promotedCmds (Html)
        - modifiedImgs (Html)
        - imgStatus (String)
        - statusName (String)


    **/
    amgui.filterBrowseView { row ->

        // Just for Content Scripts
        if(row.type == "43200"){
            row.checked = true
            row.name = "${row.name.toUpperCase()}"
            row.promotedCmds = """ <div style="font-weight:bold;background-color:#EFEFEF;padding:10px;">${row.promotedCmds} </div>"""
            row.modifiedImgs =  "<img src='${img}webnode/new.gif' />"

            row.imgStatus  = "${img}webnode/new.gif"
            row.statusName = "Ready to be executed"
            row.link ="http://www.answermodules.com/products/content-script"
            row.size = "not so big afterall..."

            row.date = amgui.formatDateForBrowseView(new Date())  //This is a shortcut to format data

            row.imgStr = "${img}anscontentscript/lib/img/icons/product-design.png"
            row.imgLargeStr = "${img}anscontentscript/lib/img/icons/product-design_large.png"
            row.imgThumbnailStr = "http://www.answermodules.com/img/content-script/content-script-banner.png"
        }

        // This to be sure that the rows will be rendered
        return true
    }
}catch(e){
    log.debug("Unable to filter browse view rows for node {}", nodeID, e)
}
return amgui.returnBrowseViewRows()

Filtering rows - lines from 20 to 42

The filtering closure passed as parameter to the amgui.filterBrowseView(...) method should return a boolean value of “true”. If “false”, the row will not be rendered.

Add a new row

It is possible to add new rows from scratch by using the amgui.addBrowseViewRow(...) method. A blank row template can be obtained through the amgui.newBrowseViewRow() method

The following properties are available for filtering or modification on each row object that is being iterated:

Property Type Description
dataId Numeric The node's unique identifier
name String/HTML The node's name Html will be rendered inside an 'a' tag
link String The link to be associated to the node's name
size String/HTML The node's side e.g. '1 KB'
date String The node's last modification date
imgStr String The url for the node's icon
imgLargeStr String The url for the node's icon when the node is featured
imgThumbnailStr String The url for the node's thumbnail
promotedCmds HTML The HTML code containing links to the node's promoted functions (can be any HTML)
modifiedImgs HTML The HTML code to be used to notify users that the node's has been modified
imgStatus String The url for the node's status icon
statusName String The node's status name

Create a custom column backed by Content Script: CSDataSources

Since version 1.5 Content Scripts can be used as Column Data sources. Content Scripts placed in the CSDataSources Template Folder will automatically be available as Column Data Sources.

csvolumestruct

The CSDataSource scripts will automatically be invoked by Content Server for each node of the system, and the resulting value will be used as a column value.

Return the proper value

A CSDataSource Content Script MUST always return a String object.

In the Content Script code, the execution context will be enriched by the framework with the following information related to the current node:

  • volumeID

  • parentID

  • dataID

  • createDate

  • modifyDate

As per standard column data sources the developer is in charge of defining and implement a reliable updating strategy. Most of the time the task can be accomplished implementing either a synchronous or an asynchronous (see Managing events) event script.

As a matter of fact, Content Script features two different APIs that can be used to update columns' datasources values.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
docman.updateColumnValue( CSNode node, //The node for which you want to update the column's value
                          String dataSourceId, // The standard identifier for the column's datasources
                          String columnValue // The new value for the column
                         )

docman.updateContentScriptColumnValue( CSNode node, //The node for which you want to update the column's value
                          String scriptName, // The name of the Content Script script that serves
                                             // datasource
                          String columnValue // The new value for the column
                         )

The first one is supposed to be used with standard columns’ datasources, the latter with Content Script backed columns' datasources.

The updateContentScriptColumnValue takes as secondo parameter the name of the Script used to implement the column’s datadasouce.

The updateColumnValue method takes as second parameter a dataSourceIdentifier, which can be easily determined inspecting the ExtendedData column’s value of the corresponding Column object on the DTree table (property “dataSource”).

E.g.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
def exData = sql.runSQL( """ select ExtendedData EXT
                             from   DTree
                             where  DataId = %1 """, 
                         false,
                         false,
                         -1,
                         2109 //The column object DataId
                        ).rows[0].EXT
out << extData.getMapFromOscript().dataSource //Returns sys_CreateDate
                                              //(on most of the systems)