Oracle® Fusion Middleware Portal Development Guide for Oracle WebLogic Portal 10g Release 3 (10.3.5) Part Number E14243-08 |
|
|
View PDF |
This chapter discusses how to localize, extend, and modify the Dynamic Visitor Tools (DVT).
Note:
The information and examples in this section assume that you are familiar with both JavaScript and the Dojo toolkit. Dojo is used extensively in the DVT implementation.
This chapter includes the following sections:
This section explains how to localize the out-of-the-box DVT components and how to localize any custom components that you develop (widgets, visual surfaces, alerts, and so on).
The DVT uses resource bundles for localization. A resource bundle is a JavaScript object in JSON format that specifies properties and values, where the values are the strings to be localized. For example, the DVT bundle Alert.js
looks like this:
{ okBtnLabel: 'Ok', cancelBtnLabel: 'Cancel' }
In this case, OK
and Cancel
are localizable strings. The property names (also called message keys) are used to reference these localizable values in JavaScript code. For more information, see Section 10.1.3, "Localizing Custom Widgets."
Resource bundles can also contain string templates that allow variable substitution. For example, the pageSizeLabel
property shown below includes a variable "${0}":
{ selectTitle:"Change the number of items to view", pageSizeLabel:"Show ${0} Items" }
All resource bundles for the DVT are located here:
<web_project
>/dvt/l10n/com/bea/wlp/dvt/uikit/nls
You create locale-specific folders under the nls
folder. The locale-specific folder names follow a standard naming convention. They are lower case, and a hyphen separates the language code from the optional country code. For example, en-us
is the code for United States English and en-au
is the code for Australian English. Figure 10-1 shows some of the DVT resource bundles under the nls
folder in a web project. The nls/ja
folder contains resource bundles localized for the Japanese language.
Tip:
For more background information on the way locale-specific files are structured, see the Dojo Toolkit Documentation topic "Internationalization (i18n)."
If you wish to localize the DVT for a language that is not supported out-of-the-box, do the following:
Copy the <web_project
>/dvt/l10n/com/bea/wlp/dvt/uikit/nls
folder to your project. To do this, right-click the folder and select Copy to Project.
Create the appropriately named locale-specific folder under the nls
folder.
Copy the resource bundles from one of the existing locale folders to the new folder.
Translate the resource bundles.
This section explains how to localize custom widgets that you write for the DVT. All classes that require localized strings must include the _Localizable
base class. This class provides a set of localization methods that:
Register localization modules
Load message bundles
Perform string substitutions
To add _Localizable
to a class, use the dojo.declare
statement in the class that you wish to localize. For example:
wlp_dvt_dojo.declare( "com.bea.wlp.dvt.uikit.Alert", [com.bea.wlp.dvt.uikit.UIKitWidget, com.bea.wlp.dvt.util._Localizable], { ....
This statement includes _Localizable
as a "mixin," making its methods available to the Alert class. For more information on mixins, see Section 10.2, "Extending the DVT with Mixins."
When using the _Localizable
class, note the following conventions:
The message bundle for a widget must be located under the <web_project
>/dvt/l10n
folder, in a directory structure patterned after the package of the class. For example, the message bundle for the class com.foo.Bar.js
must be placed in: <web_project
>/dvt/l10n/com/foo/nls/Bar.js
.
Within a widget class (or its template), reference message bundles with an alias called messages
. For example, for the following message bundle, the expression ${messages.selectTitle}
returns the string "Change the number of results per page."
{ selectTitle:"Change the number of results per page.", search:"Enter a '${0}' search query." }
For information on customizing the message alias, see Section 10.1.4.2, "Customizing Message Aliases."
Extend _Localizable
if you want to customize how L10N modules are loaded and customize the message alias described previously in Section 10.1.3, "Localizing Custom Widgets."
DVT localization resource bundles are located by default in <web_project
>/dvt/l10n
. You can specify a different location by specifying a value for the l10nModules
property. You can do this either in the _Localizable
constructor or by setting the l10nModules
property at the class level, before the constructor. The _Localizable
constructor takes this form:
constructor: function(args, node) { }
The args
parameter is an array, and it can take two optional elements, l10nModules
and/or messagePropertyAliases
(described in the next section). The l10nModules
property takes the form of an array of objects. For example:
args[l10nModules] = [{module: "module1", prefix: "path/to/module1"}, {module: "module2", prefix: "path/to/module2"},...]
This form specifies the path where the resource bundles for each specified module are located. Note that the value of prefix
is a path relative to the web application root. You can also specify this property as a property of the widget (before the constructor) like this:
l10nModules: [{module: "module1", prefix: "path/to/module1"}, {module: "module2", prefix: "path/to/module2"}, ...]
Using the l10nModules
property also helps optimize the loading of modules. If a module with a given prefix is already loaded and a request to load it against a different module name is encountered, the DVT localization framework avoids resending a request for the JavaScript bundle file.
You can change the default value of the messages
alias. The messages
alias lets you reference resource bundle properties conveniently from within a widget, as explained in Section 10.1.3, "Localizing Custom Widgets." You have two options for customizing the message alias. First, you can simply replace the alias with a new name. This option is useful if your widget already contains a variable called messages
. In this case, the alias refers to the existing default location of the message bundles. For example:
messagePropertyAliases = "myMessageAlias"
You can also specify an object array of this form:
messagePropertyAliases: [{alias: "msg1", path: "path.to.bundle1", file:"bundle1"}, {alias: "msg2", path: "path.to.bundle2"}, file:"bundle2", ...]
For a more complete example, see Section 10.1.4.3, "Handling Parameterized Messages."
The object array form lets you specify multiple aliases referring to multiple different resource bundle files. This option lets you avoid duplicating message bundle files and use existing message bundle files without creating new ones.
To use parameterized messages in a widget template, you must override the postMixinProperties()
method of _Localizable
and substitute placeholders with values.
For example, suppose the com.bea.wlp.dvt.uikit.SearchField
widget only needs one localized message and you do not want to define a new message bundle file for that purpose. Instead, the widget can reuse the message bundle file defined for com.bea.wlp.dvt.uikit.ResultsPerPageView
. Furthermore, suppose that the message needs to be parameterized. The following code fragments illustrate how to accomplish this customization:
Here are contents of the SearchField template file (/dvt/com/bea/wlp/dvt/uikit/SearchField.html
). Notice that the message alias is "msg" and not the default "messages." The technique for changing the default is demonstrated in the SearchField.js
file, shown below.
<div class="com_bea_wlp_dvt_uikit_searchBox"> <input type="text" name="search" title="${msg.search}"/> </div>
The ResourcePerPageView resource bundle at /dvt/l10n/com/bea/wlp/dvt/uikit/nls/ResultsPerPageView.js
.
{ selectTitle:"Change the number of results per page.", search:"Enter a '${0}' search query." }
The SearchField widget JavaScript file at /dvt/com/bea/wlp/dvt/uikit/SearchField.js
. Note that this is where the default message property alias is changed from messages
to msg
.
wlp_dvt_dojo.declare ( "com.bea.wlp.dvt.uikit.SearchField", [com.bea.wlp.dvt.util._Localizable, dijit._Templated], {... constructor: function(args, node) { // reset messagePropertyAliases args[messagePropertyAliases] = [{alias: "msg", path:"dvt.l10n.com.bea.wlp.dvt.uikit", file:"ResultsPerPageView"}]; }...
And the SearchField.postMixinProperties()
method:
postMixInProperties: function() { this.inherited(arguments); // Required: the parent function does a lot of the set up work this.msg.search = com.bea.wlp.dvt.util.L10nHelper.substitute(this.msg.search, ["contains"]); }
The result of this customization is that the SearchField "reuses" a message bundle from another module. In this example, the resulting message is: "Enter a contains search query."
The L10nHelper.substitute()
method substitutes placeholders specified in resource bundle messages with values specified in an array. This helper class is located in <web_project
>/dvt/com/bea/wlp/dvt/util
.
You can add functionality to any DVT class by implementing and configuring mixin classes. Mixins provide a way to extend the basic functionality of the DVT without opening and modifying the JavaScript source code provided by WLP. This section includes these topics:
The mixin mechanism is implemented as a DVT extension. Extensions execute arbitrary JavaScript code either before or after specified DVT classes are declared. You enable and specify extensions in the <web_project>
/dvt
/config.js
file. The basic form of an extension, as specified in config.js
, is:
extension: { dvtContentIncludes: [ { pkg:" " /* A package or class name*/ , pre: { ext:" " /* Execute some JavaScript code before pkg classes are delcared */ }, post: { ext:" " /* Execute some JavaScript code after pkg classes are declared. */} } } ], dvtContentExcludes: [" /* Exclude these classes from pkg. */ "] },
The extension object specifies which packages or classes to apply the extension to (dvtContentIncludes
) and which to exclude (dvtContentExcludes
). For example, you can choose to apply an extension to all the classes in a given module, but exclude one or more of them. Therefore, the extension code only applies to the included classes.
The ext
property is a string consisting of JavaScript code. This code only has access to global objects and objects defined within the scope of the code. For example, code specified in the pre
block can only access global variables. Code running in the post
block can access to the same variables that the pre block code can access, plus the newly initialized object specified with the pkg
property.
Both the pre and post code blocks also can access a global object com.bea.wlp.dvt.util._ext
. This object is populated with a copy of all of the properties in the pre and post block objects and the following properties:
module
– In the case of the pre
block, the name of the module that is about to be initialized. In the case of the post
block, the name of the module just initialized.
moduleObj
– The initialized module object. This property only applies to the post
block.
Example 10-1 displays an alert with the name of the module that was just loaded. The alert appears after each DVT class is declared, except the com.bea.wlp.dvt.util.Util
class.
Example 10-1 DVT Extension Example
extension: { enabled: true, dvtContentIncludes: [ { pkg:"com.bea.wlp.dvt", post: { ext:"alert(com.bea.wlp.dvt.util._ext.post.module);" } }], dvtContentExcludes: ["com.bea.wlp.dvt.util.Util"] }
As mentioned previously, this extension mechanism is used by the DVT to implement the mixin feature. The next section discusses this implementation in more detail.
Mixins are implemented as an extension. The mixin extension is defined by default in the <web_project>
/dvt
/config.js
file. Example 10-2 shows the mixin extension implementation. This implementation makes a request for a <
modulename
>Mixin
module and extends the current module with code in <
modulename
>Mixin
. Note that the mixin extension applies to all DVT modules after they are declared, except com.bea.wlp.dvt.Util
, which is excluded.
Tip:
The dojo.extend()
method is used to perform the extension. For more information, refer to Dojo toolkit documentation on this method.
Example 10-2 The Mixin Extension
extension: { // true or false to enable or disable the extension mechanism enabled: true, dvtContentIncludes: [ { pkg:"com.bea.wlp.dvt", post: { ext:"try{"+ "wlp_dvt_dojo.require(com.bea.wlp.dvt.util._ext.module+\"Mixin\", true);"+ "var mixinObj = wlp_dvt_dojo.getObject(com.bea.wlp.dvt.util._ext.module+\"Mixin\");"+ "if(mixinObj) {"+ "if(com.bea.wlp.dvt.util._ext.post && com.bea.wlp.dvt.util._ext.post.keepOldProps) {"+ "var thisModule = wlp_dvt_dojo.getObject(com.bea.wlp.dvt.util._ext.module);" + "for( prop in mixinObj) { " + "if(thisModule.prototype[prop]) { " + "if(!thisModule.prototype.getExtendee) { "+ "thisModule.prototype.getExtendee = function() { "+ "if(!this._wlpInherited) { this._wlpInherited = {};}; return this._wlpInherited; " + "};" + "} "+ " if(!thisModule.prototype._wlpInherited) {"+ " thisModule.prototype._wlpInherited = {};}" + "thisModule.prototype._wlpInherited[prop] = thisModule.prototype[prop];" + "}}};"+ "thisModule = wlp_dvt_dojo.extend(thisModule, mixinObj);}"+ "}catch(e){console.error(e);}", keepOldProps: true } } ], dvtContentExcludes: ["com.bea.wlp.dvt.util.Util"] },
Place your mixin modules (for example, <
modulename
>Mixin
) in the web application in the same directory as the module you wish to extend. See Section 10.2.4, "Mixin Examples" for more information.
The Mixin extension also defines a property keepOldProps
on the post
object. If this property is set to true (the default), properties in the module being extended that might be overwritten as a result of the extension process are preserved. You can access these preserved properties using this.getExtendee().<
propertyName
>
.
In summary, if Mixins are enabled, the DVT will request a <
modulename
>Mixin
class when loading the <
modulename
>
class, and extend <
modulename
>
class with the code in the Mixin class. For example, if a class com.bea.wlp.dvt.uikit.UIKitWidgetMixin
exists, it will be requested when com.bea.wlp.dvt.uikit.UIKitWidget
is loaded.
To enable the mixin feature, you must first enable the extension feature. By default, the extension mechanism is disabled.
In Oracle Enterprise Pack for Eclipse, open the Merged Projects view.
Navigate to <web_project>
/dvt
.
Right-click the file config.js
and select Copy to Project.
Open config.js
in the editor.
Locate the extension
object and set the enabled
property to true
.
Example 10-3 illustrates a mixin class, PortletItemMixin, that adds "_MP" to every portlet item's title by overriding the PortletItem._getItemArray()
method.
Note:
Before you can use mixins, you must enable the extension feature. See Section 10.2.3, "Enabling Mixins."
You can test this mixin example by creating this file with the code in Example 10-3:
<web_app>/WebContent/dvt/com/bea/wlp/dvt/data/item/PortletItemMixin.js
Note:
In practice, WLP only supports reading data from the server, not writing. For instance, WLP supports dojo.data.api.Read, but not dojo.data.api.Write. Example 10-3 illustrates how data that from the server's perspective is read-only can be changed on the client before display.
Example 10-3 Example Mixin Class
wlp_dvt_dojo.setObject("com.bea.wlp.dvt.data.item.PortletItemMixin", { _getItemArray: function(rawItemArray) { if(wlp_dvt_dojo.isArray(rawItemArray)) { var i; var itemArray = []; for(i=0;i<rawItemArray.length;i++) { itemArray[i] = new com.bea.wlp.dvt.data.item.PortletItem(rawItemArray[i]); itemArray[i].title[0] = itemArray[i].title[0] + "_MP"; } return itemArray; } else { throw new Error("_getItemArray expects an array of raw items."); } } });
Example 10-4 illustrates a mixin class that prints a console warning and calls the hitchDvtToLaf()
method in com.bea.wlp.dvt.injector.BighornInjector
. Note the use of this.getExtendee()
to access overwritten properties of the extended module. You can access the extended module in the extension ext property using com.bea.wlp.dvt.util._ext.post.moduleObj
, as explained in Section 10.2.2, "How Mixins are Implemented."
The DVT includes an API for locating and reading data from a data source. This API conforms to the dojo.data.api.Read
and dojo.data.api.Identity
APIs. A data source can be any source of raw data. For example, a data source could be a file, such as a CSV file, a database, or a web service. This section includes these topics:
This section lists the basic features of the DVT Server Data Store:
Fetches data from any server that supports HTTP.
Operates in any web container in which Dojo is installed.
Fetches data in any data format. You can add support for JSON or other data formats using pluggable data format handlers.
Fetches data with any structure through pluggable data type handlers. You can add data type support either at creation or runtime through a registration API. New data types must conform to the com.bea.wlp.dvt.data.item.Item
API. Default support is provided for common WLP types, like portlets, remote portlets, books, pages, desktops, layouts, look and feels, menus, shells, and themes.
Supports pagination and sorting whether on the server or on the client.
Supports search and filtering.
Supports customization either through creation in JavaScript code or through HTML using the Dojo parser.
Can be used with other Dojo UI widgets to display data.
This section presents a basic example that demonstrates how to instantiate and use a ServerDataStore object. The code in Example 10-5 creates an instance of ServerDataStore with a URL parameter specifying the location from which to retrieve the data. For more information on the constructor, see Section 10.3.3, "The Server Data Store Constructor."
The fetch()
method takes a "request" object that encapsulates the function's parameters. (See Section 10.3.4, "Request Object Parameters" for more information.) First, the query
parameter specifies the webapp that contains the data. The queryOptions
parameter specifies parameters that filter the query. In this case, queryOptions
specifies filtering for the title and description attributes of the data. The filtering occurs on the server, because client side filtering is turned off by default. Filtering can only be performed on one parameter per request. In this example, filtering will only be performed on the title attribute. The count
parameter sets the page size of the returned data to 2
. The onComplete
parameter is
a function that is called when all data items on the page are loaded. In this case, onComplete
displays the portlet title and its identity on the page.
Example 10-5 Server Data Store Example in JavaScript
var serverDataStore = new com.bea.wlp.dvt.data.stores.ServerDataStore({ url: "http:/localhost:7001/portal_1/bea/wlp/api/portlet/list" }); serverDataStore.fetch({ query: {webapp: "portal_1"}, queryOptions: {title: "*C*", description: "*c*", ignoreCase: true}, count: 2, onComplete: function(/*Item array*/items, /*Object*/request) { var dataDiv = "<div id=\"dataDivPortlet\">"; //console.log("In test.jsp onComplete items.length " + items.length); dataDiv += "<p><b>Portlets</b></p>"; for(var i=0;i<items.length;i++) { dataDiv += serverDataStore.getValue(items[i], "title") + "<span style=\"font-size:.8em;color:red\"> (Identity: " + serverDataStore.getIdentity(items[i]) +")</span>"; } dataDiv += "</div>"; wlp_dvt_dojo.byId('storePortletData').innerHTML = dataDiv; } });
This section describes properties of an object that you can pass to the ServerDataStore constructor to customize the server data store's behavior.
url – (string) Specifies the server URL from which to retrieve the data.
clientSidePaging – (boolean) Denotes whether to page data on the server or on the client. If false
, every call to the next and previous functions causes a request to be sent to the server URL, configured with the appropriate page number and page size values. If true
, the data is fetched only once from the server, and calls to the next and previous functions page over the data set that resides in memory on the client.
itemType – (object) Optional object that specifies the data type. This specified type overrides any built-in types. ServerDataStore tries to create items of this specified type. The type must support methods defined in com.bea.wlp.dvt.data.item.Item. Declare the type using dojo.declare with a constructor function.
dataFormatHandler – (function) Optional function that handles a given data format with the specified item type of that format. Defaults to a JSON data handler. This function must always return a JSON representation of the data, whatever the input format is.
comparatorMap – For details on this optional parameter, see documentation for dojo.data.util.sorter. This parameter only works on the client side. If clientSidePaging is set to false, sorting occurs only on the current page of data.
The ServerDataStore.fetch() method takes a "request" object that includes the following required and optional parameters:
query – Specifies attributes that qualify a fetch request. This parameter can contain the following attributes:
webapp – (string) The web application from which to retrieve the data.
locale – (string) Any string that is supported by a registered dataFormatHandler. Defaults to JSON format.
queryOptions – Optional parameter that specifies options that modify the query. Currently, this parameter only supports filtering parameters. If you use the WLP REST API to construct the URL end point for the data store, and server-side filtering is enabled, this parameter takes the following options:
title – (string)
description (string)
ignoreCase (boolean)
If both the title and description are specified, title takes precedence. This is because filtering is currently supported for one attribute per request.
If client-side filtering is enabled (setting clientSideFiltering to true in the ServerDataStore constructor), queryOptions can be used to filter any property that the data items contain.
onBegin – Specifies a callback function(size, request). If an onBegin
function is provided, the callback is only called once, before the first onItem
callback is called. The functions parameters are the total number of items identified and the Request object. If the total number is unknown, the size is -1. The size is not necessarily the size of the collection of items returned from the query, because the request might only return a subset of the total set of items with the use of the start and count parameters.
onItem – Specifies a callback function(item, request). If specified, the onItem callback function is called as each item in the result is received. The parameters include the item itself and the Request object.
onComplete – Specifies a callback function(items, request). If provided, the onComplete callback function is called once, after the last onItem callback is called. Note that if the onItem callback is not present, then onComplete is passed an array containing all items that matched the query and the Request object. If the onItem callback is present, then onComplete is called as: function(null, request).
onError – Specifies a callback function(errorData, request). This function is called if an error occurs during the query execution. The onError callback function takes two arguments, an error object and a Request object.
scope – If a scope object is provided, all callback functions (onItem, onComplete, onError, and so on) are invoked in the context of the scope object. In the body of the callback function, the value of the "this" keyword is the scope object. If no scope object is provided, the callback functions are called in the context of the dojo.global(). For example:
onItem.call(scope, item, request)
or
onItem.call(dojo.global(), item, request)
start – (integer) Specifies a number of items in the data store to skip over. If the count parameter is also specified, the data store pages across queries by only returning subsets of the hits for each query.
count – (integer) Specifies the number of items to be returned from the data store. This parameter overrides the value of the pageSize parameter.
sort – Specifies how to sort the items before they are returned. This parameter specifies an array of JavaScript objects that must conform to the following format:
{ attribute: attribute || attribute-name-string, descending: true|false; // Optional. Default is false. }
Note:
When comparing attributes, if an item contains no value for the attribute (undefined), then the default ascending sort logic pushes it to the bottom of the list. In the descending order case, such items must appear at the top of the list. The sort parameter can also be a sort function. In this case, the sort function is called. The sort function accepts requestArgs and a list of items, and it returns a sorted list based on some criteria. The function is executed in the context of the data store object.
Example 10-6 illustrates how to customize the data type that the data store handles. In this example, the itemType attribute is specified in the ServerDataStore constructor. The code for the tests.MyPortletItem class is shown in Example 10-7.
Example 10-6 Server Data Store Example with itemType Specified
var serverDataStorePortletExt = new com.bea.wlp.dvt.data.stores.ServerDataStore({ url: "http://localhost:7001/portal_1/bea/wlp/api/portlet/list", itemType: "tests.MyPortletItem" }); serverDataStorePortletExt.fetch({query: {webapp: "portal_1"}, count: 5, onComplete: function(/*Item array*/items, /*Object*/request) { var dataDiv = "<div id=\"dataDivPortletExt\">"; dataDiv += "<p><b>PortletsExt</b></p>"; for(var i=0;i<items.length;i++) { dataDiv += serverDataStorePortletExt.getValue(items[i], "title") + "</br>"; } dataDiv += "</div>"; wlp_dvt_dojo.byId('storePortletDataExt').innerHTML = dataDiv; } });
Example 10-7 MyPortletItem Class
wlp_dvt_dojo.provide("tests.MyPortletItem"); wlp_dvt_dojo.require("com.bea.wlp.dvt.data.item.PortletItem"); wlp_dvt_dojo.declare("tests.MyPortletItem", com.bea.wlp.dvt.data.item.PortletItem, { _getItemArray: function(/*array of raw items*/rawItemArray) { // summary: // Given an array of raw items, creates typed objects // This method is item type specific if(wlp_dvt_dojo.isArray(rawItemArray)) { // create typed PortletItem objects var i; var itemArray = []; for(i=0;i<rawItemArray.length;i++) { itemArray[i] = new tests.MyPortletItem(rawItemArray[i]); itemArray[i].title[0] = itemArray[i].title + "_MP"; } return itemArray; } else { throw new Error("_getItemArray expects an array of raw items."); } } });
The code in Example 10-7 extends the PortletItem class. By doing so, the class conforms to the com.bea.wlp.dvt.data.item.Item API. This class simply adds the string "_MP" to the end of the title of each portlet.
Instead of changing the data type that the data store expects, you can add a data type to the built-in list of data types that the data store can access by using the function:
registerTypes: function(/*array* types)
The types argument is an array of fully qualified type names that must conform to the com.bea.wlp.dvt.data.item.Item API.
Example 10-8 illustrates how to use a mixin with the pluggable data format handler feature of the data store. This example sets up a data store that consumes data in XML format. This data store consumes look and feel data items that are retrieved in XML. This code sets up a data store with a dataFormat handler that handles XML data.
Example 10-8 Using a Mixin with a Data Format Handler
var serverDataStore = new com.bea.wlp.dvt.data.stores.ServerDataStore({ url: "http://localhost:7001/portal_1/bea/wlp/api/lookandfeel/list", dataFormatHandler: function(data, format) { if(!data) { return null; } if(/xml/i.test(format)) { var json = com.bea.wlp.dvt.util.xmlobjectifier().xmlToJSON(data); return json; } console.error(this.substitute(this.messages.unsupportedDataFormat, ["xml", format])); return null; } });
The mixin used in Example 10-8 sets up a look and feel data item that can handle XML data. Example 10-9 lists the code for the LAFItemMixin class. The ability to handle XML is provided by overriding the isSupported() and getRawItemArray() functions.
Example 10-9
wlp_dvt_dojo.setObject("com.bea.wlp.dvt.data.item.LAFItemMixin", { isSupported : function(/*Object*/data, format) { if(format == "xml") { if(data && data.lookandfeels) { if(data.lookandfeels.length > 0 && data.lookandfeels[0].lookandfeel_details && data.lookandfeels[0].lookandfeel_details.length > 0) { return {isSupported: true, isEmptyData: false}; } else { return {isSupported: true, isEmptyData: true}; } } else { return {isSupported: false, isEmptyData: true}; } } else { return {isSupported: false, isEmptyData: true}; } }, _getRawItemArray : function(/*Object*/data, format) { // This method is item type specific // Each item type knows the structure of data it handles // and after parsing out any top level objects, returns the // raw array of items if(!data) { throw Error(messages.invalidDataItem); } if(!/xml/i.test(format)) { return null; } var arr = data.lookandfeels[0].lookandfeel_details; // massage data to remove unwanted attributes var returnArray = []; for(var i=0;i<arr.length;i++) { returnArray[i] = { label: arr[i].markup_name[0].Text, title: arr[i].title[0].Text, description: arr[i].description[0].Text, created_date: arr[i].created_date[0].Text, modified_date: arr[i].modified_date[0].Text }; } return returnArray; }});