Skip to content
PDF

Version 2.9.0 (Ceresio) - Release notes

Release Date End of AMP(*) End of Life
2020-12-21 2023-12-21 2024-12-21

(*) Active Maintenance Period

The present document contains information regarding product enhancements, fixed issues and known issues related to AnswerModules Modules Suite version 2.9.0.

No Warranties and Limitation of Liability

Every effort has been made to ensure the accuracy of the features and techniques presented in this publication. However, AnswerModules accepts no responsibility and offer no warranty whether expressed or implied, for the accuracy of this publication.

Module Suite Compatibility Matrix

OpenText Content Server MS 2.9.0
Content Suite 16.2 EP6 X
Content Suite 16.2 EP7 X
Content Suite 20.2 X
Content Suite 20.3 X
Content Suite 20.4 X
Content Suite 21.1 X

Major Changes in version 2.9.0

Content Script

Extension for Core Share (NEW)

Programmatically manage sharing of content through Core Share

Extension for OAuth Services (NEW)

Manage OAuth2 authentication flow(s) in Content Script

//Get accesstoken and redirect the user on this same script if authorization
//is required
token =  oauth.getAccessToken("default", "${url}/runcs/${self.ID}", [:])
if(!token.accessToken && token.accessTokenUrl){
    redirect token.accessTokenUrl
    return
}

rest = csws.getHttpBuilder("https://api.zoom.us/v2/users")
result = rest.get(){
    request.headers['Authorization'] = "Bearer ${token.accessToken}"
}
out << result

Extended logging functionality

  • Added Content Script API to initialize separate Content Script log appenders.
  • Additional log files can be accessed directly from the Content Script Editor.

Other improvements

  • Map/Reduce framework support has been optimized.
  • 50+ New APIs added across different endpoints.

Beautiful WebForms

Improved SmartUI compatibility for widgets.

  • ItemReference Popup: now supports SmartUI variant for selection popup and contextual menu.

example 1

Smart Pages

"CSSmartMenu" has become "CSSmartView"

CSSmartMenu, the folder within the Content Script volume that allowed you to manage menu extensions for SmartView browsing views, has been renamed to CSSmartView. This change reflects the fact that, as of this release, it will allow to control numerous new customizations to various SmartView features, and not only limited to the menus.

  • CSSmartView:Columns: it's now possible to add/remove columns from/to browsing views using Content Scripts stored in the aforementioned folder. E.g.

    example 1

    //In the execution context of this script:
    // - nodesColumns ( a map that associates nodes' ids with their columns definitions). Tipically contains a single entry
    // - nodes: the list of nodes records. Tipically contains a single item.
    // - req: the original REST request record
    // - envelope: the current REST API call envelope
    
    nodesColumns[3156087]?.add([type:43200, data_type:43200, name:"Add. Information", sort_key:"type", key:"_am_info"])
    
    //Must return the revised nodeColumns
    return nodesColumns
    
  • CSSmartView:Actions: it's now possible to add custom actions to a node's menu lazy loaded set of actions . E.g.

    example 2

    /**
    This script receives the following variables in the execution context:
    
    - actions: a map that associates the node id to the list of available actions
    E.g.
        "12345": {
            "data": {
                "Classify": {
                    "content_type": "application/x-www-form-urlencoded",
                    "method": "POST",
                    "name": "Add RM Classification",
                    "href": "/api/v2/nodes/2891606/rmclassifications",
                    "body": "{\"displayPrompt\":false,\"enabled\":false,\"inheritfrom\":false,\"managed\":false}",
                    "form_href": ""
                },
                "initiatedocumentworkflow": {
                    "content_type": "",
                    "method": "",
                    "name": "",
                    "href": "",
                    "body": "initiate_in_smartview",
                    "form_href": "",
                    "wfList": [
    
                    ]
                },
                "zipanddownload": {
                    "content_type": "",
                    "method": "POST",
                    "name": "Zip and Download",
                    "href": "/api/v2/zipanddownload",
                    "body": "",
                    "form_href": ""
                },
                "RemoveClassification": {
                    "content_type": "application/x-www-form-urlencoded",
                    "method": "POST",
                    "name": "Remove Classificfation",
                    "href": "/api/v2/nodes/2891606/rmclassifications",
                    "body": "",
                    "form_href": ""
                }
            },
            "map": {
                "default_action": "open"
            },
            "order": [
                "initiatedocumentworkflow",
                "Classify",
                "RemoveClassification",
                "zipanddownload"
            ]
        }
    }
    
    - req: the current HTTP request
    - envelope: the REST API request's envelope
    
    By changing the support variable "actions" you can make visible actions defined by scripts in CSVolume:CSSmartView:Commands
    
    **/
    
    actions[3156106].data["am_release"] = [
        body:"am_release"
    ]
    actions[3156106].order.add("3156106")
    
  • CSSmartView:Commands: it's now possible to define multiple commands in the same script and group them in the same sub-menu. E.g.

    example 2

    //Commands scripts can now return a list
    return [
        [
            am:[
                exec:[
                    mode:"group"// (1) This command will act as our flyout
                ]
            ]
            ,scope: "multiple"
            ,group: "info"
            ,flyout: "am_group" // (2) This command will act as our flyout
            ,baricon: null
            ,icon: null
            ,name: "Try Module Suite"
            ,command_key: "am_group"
            ,signature: "am_group"
        ],
        [
            am:[
    
                confirmation:[
                    required:false,
                    title:"",
                    message:""
                ],
                panel:[
                    width:40,
                    cssClass:"",
                    slides:[
                        [
                            title:"",
                            script:null
                        ]
                    ]
                ],
                key:[
                    code: 83
                    ,message:""
                    ,nogui:false
                ],
                exec:[
                    mode:"script"
                    ,script: 2644067
                    ,params:[
    
                    ]
                    ,refresh_on_success:true
                    ,on_success_action:""
                    ,newtab:false
                    ,url:""  
                ]
            ]
            ,baricon: null
            ,icon: null
            ,name: "Content Script"
            ,command_key: "am_content_script"
            ,signature: "am_content_script"
            ,scope: "multiple"
            ,flyout:"am_group"
            ,selfBlockOnly: false
        ]
        ...
    ]
    
    • CSSmartView:Commands: Content Script scripts executed as commands can now return execution information to the caller. E.g.

    example 4

    //Script code...
    //Once done...notify caller
    json([message:[type:'success', text:"Get the Module Suite. You won't need anything else.", details:"The Module Suite is a comprehensive framework of highly innovative solutions dedicated to OpenText™ Content Server, and includes all the tools you will need to extend, customize, and enrich your Content Server experience."]])
    
    • CSSmartView:Override: It is now also possible to enhance the information associated with nodes with column information injected via Module Suite.
      E.g.

    example 4

    def drawStatusBar = { node ->
    
        def statusList = ['Draft', 'Under Revision', 'Approved', 'Published']
        def numSteps = statusList.size()
        def currStep = new Random().nextInt(statusList.size())
        def currStepName = node.name
    
        def stepStyle = "height:100%; width:calc(100% / ${numSteps}); float:left; background-color:#F0AD4E; box-sizing:border-box;"
    
        def stepsHtml = ""
    
        (currStep + 1).times{
            stepsHtml += """<span style="${stepStyle}"></span>"""
        }
    
    
        return """ 
        <div style="text-align:center; font-size:.75em">${currStepName}</div>
        <div style="margin:3px 0; padding:0; height:5px; background-color:#eee;">${stepsHtml}</div>""".toString()
    }
    
    
    
    retVal =  nodes.collect{
        [
            ("D${it.dataid}" as String):[ //The object returned MUST be made of simple types (no GString allowed)
                commands:["am_group", "am_bwf"],
                columns:[
                    // Column defined in CSSmartView:Columns as nodesColumns[3156087]?.add([type:43200, data_type:43200, name:"Add. Information", sort_key:"type", key:"_am_info"])
                    // columns of type 43200 can be used to inject HTML
                    _am_info:drawStatusBar(it)
                ]
            ]
        ]
    }
    return retVal
    

Global revision of Smart Pages widgets

  • Smart Pages widgets have been reviewed in terms of both styling and structure.
  • Smart Pages CSS is now better isolated from Beautiful WebForms CSS. The base CSS class for Smart Pages has been changed from "am-smartui" to "am-smartpage". The "am-smartui" class is now reserved for Beautiful WebForms. NOTE: This may cause breaking changes in custom rules and page templates based on the legacy class.

New Smart Pages widgets

The following widgets have been added to the Smart Pages Editor, and can now be used to build Smart Pages:

  • Button Container: a container-type widget meant to hold regular buttons. Can be configured to display as a button-group.

button container

  • Link Button: a button widget that will open a configured url.

  • Step indicator: a widget to display a process status and execution details.

step indicator

Added support for flexbox on Smart Pages used as Smart View tiles.

Add the CSS helper class "am-page-container-flex" as a custom class within the Smart View Tile configuration to enable flex support on Layout containers and panels within the included Smart Page. This will allow to create tiles that better occupy all the available vertical space.

Revised Tree Widget

Tree Widget has been revised and enhanced with new functionalities.

  • It is now possible to enable the standard Smart UI function menu on tree nodes.
  • It is now easier to bind tree nodes to Smart UI actions.
  • Helper CSS classes have been added to support adding extra columns to the tree nodes.
  • Default tree look & feel is now more similar to Smart UI style.

example 6

    def rootID = params.uiParentID ?: (self.parent.ID as String)


    if( params.widgetConfig ){

        if(rootID?.isLong()){

            def node = docman.getNodeFast( rootID as Long )
            json( [ id          : 'treeWColumns',
                widgetConfig : [
                    //node_tag           : "DIV", // Custom node tag
                    tileLayoutClasses  : "", 
                    tileContentClasses : "", 
                    treeId             : "test",
                    reloadCommands     : ["updateTree"],
                    root               : "${rootID}", 
                    plugins            : [ "wholerow"],
                    theme              : [ 'name'       : 'proton',
                                            'responsive' : true   
                                            ],
                    grid : [
                        columns : [
                            [width : 50, header : "Nodes"],
                            [width : 30, header : "Actions", value : "icon"]
                        ]
                    ],

                    html               : """
    <style type="text/css">
    </style>

    <form class="binf-form-horizontal">
    <div class="binf-form-group">
        <label for="filter" class="binf-control-label binf-col-xs-2" style="padding-top:7.5px">Filter</label> 
        <div class="binf-col-xs-8">
        <input id="filter" name="filter" placeholder="type your filter" type="text" aria-describedby="filterHelpBlock" class="binf-form-control">
        <span  style="margin-left:0px" id="filterHelpBlock" class="binf-help-block">Type a term to filter the tree nodes. Only nodes starting with the entered term will be shown.</span>
        </div>
    </div> 
    </form>


    <script>
        csui.onReady2([
            'csui/lib/underscore',
            'csui/lib/backbone',
            'csui/lib/jquery',
            'csui/lib/radio'
            ], 
            function(_,Backbone, jQ, Radio){

                var amChannel = Radio.channel("ampagenotify");

                amChannel.on("printConsole", function(params){
                    console.log("GOT request "+JSON.stringify(params));
                });

                amChannel.on("smartPage_action", function(action,param){
                    console.log("GOT Page Action request. Action: "+action+ " parameter: "+param);
                });

                jQ("#filter").on("blur", function(){
                    amChannel.trigger("updateTree",{'term':jQ(this).val()})
                })


            });
    </script>"""
                ]
                ] )
            return
        }
    }



    def getNodeContent = { node ->

        def content

        def text = node.name

        content = """<span class="jstree-anchor-cols"> 
                            <span class="jstree-col-main">${text} <span class="csui-table-cell-name-appendix"></span></span>
                            <span class="jstree-col-2">
                                <span>Sample value</span>
                            </span>
                            <span class="jstree-col-4">
                                <span>${node.comment}</span>
                            </span>
                        </span>"""
        return content

    }

    def getHeaderRow = { node ->

        return """<span class="jstree-anchor-cols"> 
                    <span class="jstree-col-main">${node.name}</span>
                    <span class="jstree-col-2">Subtype</span>
                    <span class="jstree-col-4">Description</span>
                    <!--<span class="z-treenode-actions">Actions</span>-->
                </span>"""

    }


    /* Utility function to fetch all children of a node. */

    def fetchChildNodes = { spaceNode, Boolean shouldExpand ->

        def data = spaceNode.childrenFast.collect{ node ->

            retVal = [
                name     : node.name,
                id       : (node.isContainer)?"${node.ID}_node":"${node.ID}_doc",
                text     : getNodeContent(node),
                icon     : "${node.webClass}",
                children : node.isContainer && node.childCount > 0,
                state : [
                    opened : shouldExpand
                ] 
            ]

            if( !node.isContainer ){
                retVal.a_attr = [ 
                                "data-toggle"    : 'command',
                                "data-am-action" : 'Download,Delete,Properties,am_zoom',
                                "data-am-params" : node.ID 
                                ]
            } else {
                retVal.action = 'navigate'
            }
            return retVal

        }?.sort{ it.name }

        return data

    }


    /* Utility function to fetch children of a node in "paged" fashion. */

    def fetchChildNodesPage = { spaceNode, Boolean shouldExpand, Integer pageNumber, Integer pageSize = 10 ->

        nodePage            = spaceNode.getChildrenPage()
        nodePage.pageSize   = pageSize
        nodePage.pageNumber = pageNumber

        nodes = docman.listNodesByPage( nodePage, "name", false, false, false, false)

        def data = nodes.collect{ node->

            retVal =[
                name     : node.name,
                id       : (node.isContainer)?"${node.ID}_node":"${node.ID}_doc",
                icon     : "csui-icon ${node.webClass}",
                text     : getNodeContent(node),
                children : node.isContainer && node.childCount > 0,
                state    : [
                    opened : shouldExpand
                ] 
            ]

            if( !node.isContainer ){
                retVal.a_attr = [ 
                                "data-toggle"    : 'command',
                                "data-am-action" : 'Download,Delete,Properties,am_zoom',
                                "data-am-params" : node.ID 
                                ]
            } 

            return retVal
        }?.sort{ it.name }

        return data

    }



    // MAIN CODE

    if( !(rootID.split("_")[-1] in ["page", "node", "doc"])){

        // This is the root node. The Outline is closed by default

        def node = docman.getNodeFast( rootID as Long )

        docman.getChildrenFast(node)

        data = [
            [
                name     : node.name, 
                icon     : "csui-icon cs_folder_root", 
                id       : "${node.ID}_node",
                text     : getHeaderRow(node),
                children : fetchChildNodes(node, false), 
                state : [
                    opened : true
                ],
                action : 'navigate'
            ]
        ]

    } else {

        data = []

        Boolean shouldExpand = false
        Integer pageSize     = 5

        def idElements     = params.uiParentID.split("_")

        Long space         = idElements[0] as Long
        String spaceType   = ( idElements.size() > 1) ? idElements[-1] : 'node'
        Integer pageNumber = (spaceType == 'page') ? ( idElements[1] as Integer ) : null
        def spaceNode      = docman.getNodeFast( space )

        if( spaceType == 'page' ){
            data = fetchChildNodesPage( spaceNode, shouldExpand, pageNumber, pageSize ) 

        } else if( idElements[-1] == "node" ){
            if( spaceNode.childCount > pageSize ){

                // Paginate children list if it is bigger than 'pageSize'

                Integer numTotalPages = Math.ceil( spaceNode.childCount / pageSize) //spaceNode.childCount % pageSize

                numTotalPages.times{ pageIndex ->

                    def children = true

                    if( pageIndex == 0 ){

                        // Pre-expand the first page    
                        children = fetchChildNodesPage( spaceNode, shouldExpand, 1, pageSize ) 
                    }

                    data.add([
                        name     : "${space}_${pageIndex + 1}_page",
                        id       : "${space}_${pageIndex + 1}_page",
                        icon     : "cs_vfolder",
                        text     : "${(pageIndex * pageSize) + 1} ... ${(pageIndex + 1) * pageSize }",
                        children : children,
                        state    : [
                            opened : shouldExpand
                        ] 
                    ])    
                }

            } else {

                data = fetchChildNodes( spaceNode, shouldExpand )
            }
        }
    }

    if(params.term){
        //This should be consider just an example of a possible filtering solution. Since we are not "expanding" the tree more than one level per each call filtering 
        //as the last operation is not impacting performances very much. 
        filter = { list, term ->
            list.removeAll{ it.children == false && ! it.name.toUpperCase().startsWith( term.toUpperCase() ) }
            list.each{ listElement ->
                if(listElement.children && listElement.children instanceof List){
                    filter(listElement.children, term)
                }

            }
        }
        filter(data, params.term)
    }

    json( data )

All Enhancements in version 2.9.0

ID Scope Description
#000936 Beautiful Webforms Add internationalization support also to widget
#000916 Beautiful Webforms Add and remove button for multifield in modal popup
#000876 Beautiful Webforms Allow feedback from actions performed in embedded forms to show in standard Smart UI feedback panel
#000908 Smart Pages Smart menu: additional menu command in SmartUI override only at the first level
#000928 Beautiful Webforms Item Reference Pop Up browse is in classic view
#000871 Content Script When changing the default CS.log location from the Opentext.ini file the change does not take effect
#000931 Content Script Missing documentation for xecm extension xecm.updateRole(..) API
#000955 Extension - FTP [FTP api] Sending documents in binary mode
#000942 Smart Pages More flexibility is required regarding the logic to use to show a custom action in a menu
#000440 Beautiful Webforms Improve robustness of Jquery Interdependencies widget
#000947 Module Suite Re-import of a Content Script is not supported
#000949 Beautiful Webforms In a set; delete link is missing for the first row
#000910 Smart Pages CSSmartMenu not displayed on Results page

Issues Resolved in version 2.9.0

ID Scope Description
#000951 Beautiful Webforms Click on a submit button display "saving" and there is no way to change the language
#000932 Beautiful Webforms Customizing search string in Smart DropDown
#000906 Beautiful Webforms Datatable widget: if a language file is applied; all the words are translated properly excluding the search box of the columns
#000917 Beautiful Webforms Search/Clear buttons overlapped for Item reference Popup
#000904 Beautiful Webforms Minor CSS issue in User by login widget
#000915 Beautiful Webforms Graphical issue in multifield: plus and minus button are in strange position
#000894 Beautiful Webforms Issue in installation of BWF updated with case sensitive database
#000898 Beautiful Webforms Smartlookup behavior used by Smart Dropdown DB lookup widgets does not support PostgreSQL
#000805 Beautiful Webforms Pattern validation rule is truncated if the model contains parentheses
#000885 Smart Pages Issue Smart View Custom Menu in execution classic mode
#000891 Beautiful Webforms Inconsistent behavior for check-boxes when used with Widget Space Content
#000881 Beautiful Webforms The Item Reference Popup Widget in Library V3 does not render correctly
#000883 Beautiful Webforms Currency Widget anomaly validation on IE
#000923 Beautiful Webforms Smart ViewTask template not displayed correctly on CS 20.3
#000913 Beautiful Webforms Item reference Popup: with v4 library the context menu is the one of Smart UI
#000719 Beautiful Webforms User By login doesn't show the values if is located at the bottom of the page
#000924 Beautiful Webforms Usability issue with DropDown and page scroll
#000751 Beautiful Webforms Item Reference Popup doesn't work properly
#000874 Extension - ZIP Error returning zip resource on Linux
#000892 Beautiful Webforms XSS security vulnerability
#000946 Module Suite Content Script execution audit track flag has been associated to the wrong bit
#000927 Beautiful Webforms Visualization issues with Add Delete Button widget
#000840 Beautiful Webforms OnChangeAction doen't work with V3:SmartView Template - registerInitWidgetCallback
#000922 Smart Pages Low performance in Nodes table tile
#000919 Content Script Issue method grantFullControl on Add Major Version
#000903 Content Script fileName null in the CSVersion object
#000680 Content Script Accessing rendition content on CSVersion result in wrong content
#000925 Content Script Content Script Scheduling administration does not work with PostgreSQL databases
#000896 Beautiful Webforms Issue in Manage Callbacks: on Linux box an error is returned trying to listing the callbacks
#000957 Smart Pages Widget Nodes table - Error on selecting nodes
#000902 Beautiful Webforms Issue widget "go" anchor on library V4
#000958 Content Script Method distagent.mapReduce doesn't work correctly
#000938 Module Suite Library 2.7 and 2.8 included in installation packages
#000921 Smart Pages GoTo option for action button is not working
#000890 Beautiful Webforms Alert javascript when editing a document in the SmartView Task template on IE
#000940 Beautiful Webforms Button label text outside the button
#000937 Content Script Unable to retrieve classifications for an email (subtype 749)
#000962 Beautiful Webforms Server Side validation for Smart DropDown: the field with error is not highlighted
#000909 Beautiful Webforms Panel Arrow wrong direction
#000918 Beautiful Webforms JS Conditional container behavior with multiple field
#000964 Content Script Trace files in REST API call
#000933 Smart Pages Expand tile button not working Smart UI when there is a parameter in the URL
#000929 Content Script Erratic problems related to script execution are recorded in complex applications that make massive use of the runCS API.
#000930 Content Script ContentScript hasTemplate API might rise an error at startup
#000884 Beautiful Webforms Issue Wysing Editor the copied image is duplicated
#000888 Script Console Issue load configuration with database PostgreSQL
#000954 Script Console Regression in RenderForm.cs
#000920 Module Suite Regression in cache.putForUser API
#000882 Smart Pages Custom Menus are not displayed in "Node Browsing Table" when the widget is associated to a Virtual Folder
#000965 Content Script xecm.createWorkspace doesn't work if a multiple attribute of a category is set
#000866 Extension - eSign when executing the esign.addESignNatureToFormStep(form; "Approve and Sign") the module returns an error
#000952 Content Script Error in some methods for Physical Object
#000934 Script Console Script Console slow calling script with RunCS
#000887 Script Console Log not working in Script Console
#000854 Script Console The first attempt to authenticate to the script console always fails with a 403 error
#000970 Beautiful WebForms BWF Studio fails to export a form (for remote usage) if a validity date has not been specified