Server-side framework
A plug-in receives HTTP requests for specific menus from a client and responds with the menu feed in JSON format. The response is marked as content type application/JSON.The request URL for the menu feed provider is under the /wps/contenthandler or /wps/mycontenthandler URLs, depending on whether the request is coming from a currently-logged-in user context. The request URL might carry portal URL navigational state, but does require a specific query string to access the menu feed provider. The specific query string to get to the default JSON feed provider is:
?uri=menu:<specific menu name>&navID=<navigation node OID or custom unique name> [&windowID=<portlet window control ID on the page> ]where:
- navID is either the serialized string-format ObjectID or the custom unique name of a portal navigation node (a portal page), which is being displayed when the menu is being requested. This parameter provides a context for the menu feed provider to use when building the menu, so we know which theme to use, because the theme is tied to the page either explicitly or by inheritance.
- windowID is optimized and is the serialized string-format ObjectID of a portlet window control on the page specified by pid. This parameter is only necessary for menus containing portlet-level actions, in other words, skin menus. This parameter must be a serialized ObjectID. A custom unique name does not work for the portlet window id.
WebSphere Portal provides three ready-to-use menu definition files with the Portal 8.0 Optimized Theme:
- pageAction
- skinAction
- moreActions
These files exist in WebDAV, under a menuDefinitions directory within the root for the theme root. The root is set in theme metadata under the metadata entry name com.ibm.portal.theme.template.ref. Other files is that directory are JSON syntax but are not used by the JSON menu framework
JSON menu definition file syntax
For more details about JSON itself, see the JSON home page.
The JSON syntax of a menu definition file consists of an array of JSON objects, where the array is indicated by outer enclosing opening and closing brackets [ ]. Each JSON object is enclosed in braces ({ }) and separated by commas:
[ // optional one-line comment { JSON object 1 (first menu item) }, /* optional multi-line comment */ { JSON object 2 (second menu item) }, ... ]We can add comments in this file using a portal-specific extension to JSON syntax.
The final object in the array does not have a comma between its curly brace and the ending array closing bracket.
The order of the objects in the array within the menu definition file determines the order of appearance of the items in the menu on the client.
Each object within the array is an individual self-contained menu item definition, or a reference to a theme optimization module that can provide additional in-line JSON menu definition file markup. This contributed JSON is included in-line as though it was in the menu file itself.
Each object consists of multiple comma-separated JSON members, each of which has a name and a value that are separated by a colon. The member name is always a string in quotation marks. The values can be strings, Booleans, nested objects, or arrays, depending on the member name. Some member names can have only certain values, as defined in the following table.
Each menu item definition must have a type entry, which defined that particular menu entry item.
Important: All entry names are case-sensitive.
The folowing menu item names and values are acceptable values for the type entry.
- "type" : "Header"
- Defines a label for subsequent entries in the menu. Typically displayed on the client UI as highlighted and outdented, although this is controlled by the style applied to the menu items. A header in the menu is typically not clickable.
More title object entries, within the titles value, for other languages can be added.
An itemClass member can be added for controlling the appearance of the header.
{ "type" : "Header", "titles" : [{"lang":"en","value":"<English text>"}, {"lang":"de", "value" : "German text"},...] }
- "type" : "Separator"
Defines a separator between menu items. A separator might show as a space, a line, or other appearance depending on the style applied to the menu.
A separator does not typically need any other members, although an itemClass can be added for appearance control.
{ "type" : "Separator", }
- "type" : "DynamicMenuitem"
Potentially clickable and having an action the DynamicMenuitem item has an id member whose value is a plug-in name. The menu feed provider uses this id to retrieve an instance of the named operation, which is then queried for sufficient information to build the menu feed content for this menuitem. Several plug-ins are supplied ready-to-use by WebSphere Portal for use in the default menu definitions, and these can be reused by custom-written menus and themes.
This plug-in provides its own indicater of whether it is active, including access control permission for the current user, and provides its own localized title and optionally a description, and an actionHttpMethod value, for the menu feed provider to use when building the menu for this item. The OperationURI for this operation plug-in becomes the actionUrl in the corresponding menu entry. Other object members are allowed as well, including actionFn, actionHttpMethod, visibilityFn, itemClass, and metadata. A markupId member can be added to create an id on the html tag for the resulting menu item.
If the isActive() method returns false when called by the menu feed provider code, the menu item is present in the menu feed, but has a "visibility" : false boolean member added to the feed. This boolean member indicates to the client-side code that this operation should not be presented to the user, and the client-side code does not include this item in the final rendered menu.
Optionally, a moduleArgs member might also be specified. This member is a string of query parameter-format names and values separated by ampersands (&). If present, these arguments are passed to the plug-in when the feed provider accesses the plug-in to build the current menu entry.
{ "type" : "DynamicMenuitem", "id" : "operations.framework.plugin.name" }
- "type" : "StaticMenuitem"
Potentially clickable and having an action.This item is typically used to insert a menu item that has a client-side implementation, rather than a server-side implementation.
Allows the menu feed definition file author to completely specify an arbitrary menu item entry. All necessary information must be provided by the menu definition file, because there is no corresponding operation for a StaticMenuitem. The id parameter is optional and is ignored by the menu feed provider code for a StaticMenuitem, although it is not flagged as a syntax error if it is present.
Other optional members might be added as needed.
{ "type" : "StaticMenuitem", "titles" : [{"lang" : "en", "value" : "My English menu item text"}, {"lang" : "de", "value" : "Mein menu item text auf Deutsch"}, ... ], "descriptions" : [{"lang" : "en", "value" : "My English menu item longer description flowing beautiful prose"}, {"lang" : "de", "value" : "Mein menu item longer description flowing beautiful prose auf Deutsch"}, ... ], "actionUrl" : "http://www.myco.com/wps/myportal/some_useful_url", "actionHttpMethod" : "POST", "actionFn" : "client_method_to_override_actionUrl", "metadata" : { "navID" : "${navID}", "some_name" : "some_value", "some_other_name" : "${SubVar_From_Request_Query_Parms}" } "markupId" : "my.item.markupId" }
- "type" : "ModuleRef"
A menu definition file has an id member whose value is the name of a plug-in. This plug-in must have a contribution of the menu type, and a subcontribution of the JSON type. The menu feed provider uses the value of the id member in this JSON object to retrieve a reference to the JSON subcontribution within the menu contribution for that module. This JSON subcontribution must be valid stand-alone JSON menu definition markup, including the surrounding array opening and closing brackets. The menu feed provider strips the array opening and closing brackets and inserts this contributed markup in-line into the menu feed response as though it was included in the main definition file.
Points by name at a plug-is that provides additional JSON format and menu definition file syntax markup, which the feed provider places inline in the menu feed and that replaces the ModuleRef entry.
Optionally, a moduleArgs member can be added. If present, the value of the moduleArgs member is passed as arguments to retrieve the JSON menu definition file markup from the plug-in.
{ "type" : "ModuleRef", "id" : "Theme Optimization Framework module name" }
- "type" : "Submenu"
Defines a placeholder in the current menu where a new sublevel menu is attached. This item allows for multiple tiered menus. There is no enforced limit to the nesting level. The submenu is retrieved by an independent additional menu request to the JSON menu feed provider when the submenu entry in the displayed menu is hovered over.
The menu is appended to the one side as screen position dictates. A submenu is fetched in a separate subsequent request by the client.
A submenu names the source of its menu content with either an id or a moduleId member, and must have a titles member to provide the text for the placeholder menu item, and might optionally have a descriptions member.
The only difference between these two members is how the next request is processed, when the submenu is expanded and the client code retrieves the expansion menu feed in a new HTTP request:
- for an id, the next request is treated as naming a menu definition file where the id value is the file name and the extension is .json.
- for a moduleId, the next request is treated as naming a plug-is that provides the necessary JSON markup. This request is accessed as though a menu definition file had specified it
{ "type" : "ModuleRef", "id" : "moduleId_value" }
A moduleArgs member might also be added. If present with a moduleRef member within a SubMenu entry, the value of the moduleArgs member is appended to the URL that is built as the id of the menu item. This value is used as the menu reference from the client for retrieving the menu markup for the cascaded submenu.
{ "type" : "SubMenu", "id" : "name_of_submenu_definition_JSON_file", "titles" : [{"lang" : "en", "value" : "My English sub-menu item text"}, {"lang" : "de", "value" : "Mein sub-menu item text auf Deutsch"}, ... ], "descriptions" : [{"lang" : "en", "value" : "My English sub-menu item longer description flowing beautiful prose"}, {"lang" : "de", "value" : "Mein sub-menu item longer description flowing beautiful prose auf Deutsch"}, ... ] } or { "type" : "SubMenu", "moduleId" : "name_of_theme_opt_framework_module_which_contributes_submenu_definition_JSON_", ... }
Valid members in a JSON menu definition file
Member name Value and example syntax Comments type "Header", "Separator", "DynamicMenuitem", "StaticMenuitem", "ModuleRef", Submenu" Determines the type of menu item created by this menu definition file object id String For a DynamicMenuitem or a ModuleRef, the id member is required. For a Submenu, either id or moduleId is required.
- DynamicMenuitem
- The id is the name of the plug-is that is accessed by the menu feed provider to get the actionUrl (which is the OperationURI of the operation), the localized title and description, and the isActive method of the operation, which indicates whether the action is active and also accessible by the current user. The actionUrl is sent to the server in a separate request if the user clicks on this menuitem in the rendered menu.
- ModuleRef
- The id is the name of the plug-is that is accessed to retrieve additional menu file definition markup.
- Submenu
- The id is present, it is the name of the menu that is requested by the client in an HTTP menu request to create the submenu list of items.
titles Array of objects, each of which has these members: a "lang" defines the language for that title entry, and a "value" contains the string for that language for the title.
"titles" : [ {"lang":"en", "value":"Title in English"}, {"lang":"de", "value":"Title auf Deutsch"}, ... ]
Used only for header, StaticMenuitem, and Submenu entries. The list of languages provided covers only the necessary languages that the users of a portal might need. A DynamicMenuitem retrieves the title from the corresponding plug-in. The plug-in is required to implement the Localized interface, and provide localized strings for appropriate languages. A Separator has no text associated with it. A ModuleRef is replaced by other markup. descriptions Same as titles. "descriptions" : [ {"lang":"en", "value":"Title in English"}, {"lang":"de", "value":"Title auf Deutsch"}, ... ] Optional for all types. If present, this member is interpreted by the default client code as hover help text over the menu item. itemClass String Optional for all types. This member is the style class name that should be applied to the menu item. If present, this should be a class name that is present in the style sheet associated with the theme for the menu. enabled Boolean true or false Optional for all types. Defaults to true. This member indicates whether the menu item should be clickable on the client side. True equates to active, false equates to not active. enableFn String Optional for all types. If present, this member is the name of a JavaScript function to execute on the client to determine if this menu item is active. The complete menu feed JSON object for this menu item is passed as an argument to the function. The result from this function call overrides the "enabled" setting.
actionUrl String For a StaticMenuitem, either the actionUrl or the actionFn must be present. If actionUrl is present, it might be an absolute URL or a relative URL, or a query string that is appended to the current request URL or tag value. Not required for a DynamicMenuitem. Not useful for any other type. Invoking the actionFn takes precedence over an actionUrl if both are present.
actionHttpMethod String, with normal HTTP values "GET", "POST", "PUT", "DELETE" and so on. Defaults to "GET". Optional for all object types. If present on a DynamicMenuitem, this will override any action provided by the Operation Framework plug-in. actionFn String For a StaticMenuitem, either the actionUrl or the actionFn must be present. If actionFn is present, this member should be the name of a JavaScript function to execute on the client when the menu item is clicked. The complete menu feed JSON object for this menu item is passed as an argument to the function. Invoking the actionFn will take precedence over an actionUrl if both are present. visibilityFn String Optional for all types, but not useful for Separator or ModuleRef. For a DynamicMenuitem or StaticMenuitem, if visibilityFn is present, this member should be the name of a JavaScript function to execute on the client to determine whether this menu item is active. The complete menu feed JSON object for this menu item is passed as an argument to the function. metadata Embedded object, where the only value types are Strings. Ex: "metadata": { "name1" : "value1", "name2" : "${substitution-variable}", ... } Optional for all types. If present, this member must be a simple embedded object with only String values. No deeper object nesting or arrays are allowed as values. If substitution variables are present, in the form ${variableName}, then these values are substituted from query parameters on the received menu request. Multiple query parameters can be in a string, but only one pass is made through the string. moduleId String Optional for a Submenu, but only applicable for a Submenu. If present instead of an id in a Submenu entry, this member should be the name of a module like the id of a ModuleRethat is accessed by the client in a separate direct request if the Submenu item is expanded by the user. The format of the menu item built by this is {"type":"Submenu", "id" : "moduleRef:", ... }. The client code makes a request to the server using this is that is a variation of the normal menu request: ?uri=menu:moduleRef:". The feed provider code handles this request by invoking the named module as though there were a menu feed definition file containinged a ModuleRef wito that id. moduleArgs String, in the format of an HTTP request query parameter set, but without a leading ampersand (the menu feed provider prepends an ampersand). If there are multiple query parameters, insert an ampersand between each parameter after the first. Example: foo=bar&foo2=bar2&...Optional for a Submenu, but only applicable for a Submenu. If present with a moduleId, then the URI built by the menu feed provider for the Submenu entry in the feed looks like {"type" : "Submenu", "id" : "moduleRef:moduleId_value&moduleArgs_value", ... }. If present with an id in the Submenu, the URI looks like the previous example but without the moduleRef: prefix for the id and arguments. markupId Arbitrary string, used to create an id in the html tag that defines the menu item. Optional. Useful only for DynamicMenuItem and StaticMenuItem menu entries. Variable substitution is supported for this item, so the ${windowID} can be used to make unique instances of an id for each portlet when rendered.
Writing a menu definition file for a modularized theme
We can write a new menu definition file for a new theme using the server-side feed provider and client-side JavaScript. If the ready-use 8.0 theme is copied and altered into a new customized theme, the same JSON menu files can be used, or can be altered as necessary. If any new client-side functions are referenced from menu items then these new JavaScript features need to be created and referenced.
The JSON menu feed provider looks for the JSON menu definition files in a menuDefinitions directory in the theme root in WebDav.
Use the existing menu definitions files as samples, and use tools such as jsonlint to prevalidate the JSON syntax.
The JSON syntax is restrictive for menu definition files except that comments are allowed.
When debugging, use the trace string com.ibm.wps.jsonmenu.*=all on the server.
Parent: Menu framework
Related: