Méthode Swing documentation

Context Object Reference

The Context Object is a Javascript object available throughout the Swing Extensions. In every extension point, the context object can be accessed and its methods called.

The Context Object is composed of public methods (see Public methods), object-specific methods (see Object class methods), and user-specific methods (see User class methods). If the context object is referred to a specific object, an activeObject property is available (see activeObject). To support object panel bulk mode use activeObjects instead. If the context object is inside a supported Editor, the activeDocument property is available (see activeDocument). Starting from version 5.2020.11 if the context object is inside a supported Editor, the activeDocumentV2 property is available (see activeDocumentV2)

Through a new shared object will be available a set of api(s) to handle the document with new logics to support the report case. These api(s) will be supported among Swing, Prime and Swing Mobile.

Public methods

List of methods

Table 1. Parameters

Name

Description

Obtains the application info.

Obtains the area info.

Returns an array containing the string XML fragments obtained from the evaluation in the siteConfig.cfg file of the provided xpath.

Obtains the communication status.

Obtains the component info.

Reads a file given its filename, and returns it in a particular format.

Executes a Methode query.

Reads a user data content given its filename.

Adds a new JSON object to the specified user data content.

Set a new JSON array to the specified user data content.

Obtains a content of a document, given its path

Obtains the current user

Obtains a Methode object, given its id

Obtains a Methode object, given its path

Obtains the Platform information

Obtains a user, given its name

Obtains the list of member names, given a group name

Open a Methode document, given its id

Open the new content dialog, with the selected options

Open a Methode document, given its id, in readonly mode

Opens a popup panel

return the last selected element in the editor context in the form of Object Class instances.

getApplicationInfo

Retrieves the application info and returns a JSON object containing the context and the name of the application.

    {
        context: "/swing",
        name: "Swing"
    }
Syntax
ctx.getApplicationInfo()
Returns

Type

Description

{JSON Object}

A json object containing the context and the name of the application.

Example
var applicationInfo = ctx.getApplicationInfo();

getAreaInfo

Retrieves the area info and returns a JSON object containing the area type and the area name.

    {
        name: "story",
        type: "editor"
    }
Syntax
ctx.getAreaInfo()
Returns

Type

Description

{JSON Object}

A json object containing the area type and the area name.

Example
var areaInfo = ctx.getAreaInfo();

getSiteConfigFragment

Returns an array containing the string XML fragments obtained from the evaluation in the siteConfig.cfg file of the provided xpath.

Syntax
ctx.getSiteConfigFragment(xpath);
Parameters
Table 2. Parameters

Name

Type

Required

Description

xpath

{String}

Yes

{string} xpath - The string xpath to get the siteConfig fragment.

Example
var presetCropsArray = ctx.getSiteConfigFragment('/siteConfiguration/presetCrops');

/*
 presetCropsArray:
  [ "<presetCrops>
	<crop channel="Globe-Web,Globe-Print,Globe-WireNews" favorite="yes" height="719px" name="Homepage-Main" width="107px"/>
    <crop height="667px" name="iPhone 6" width="375px"/>
    <crop height="512px" name="iPad 4" width="384px"/>
   </presetCrops>" ]
*/

getCommunicationStatus

Retrieves the communication status of the application (useful when working in offline mode). The object returned contains the following fields:

  • applicationOnline: true if the application is in online mode, false otherwise.

  • isOnline: true if the application reaches the server and the application is in online mode, false otherwise.

  • offlineServer: enabled : true if the offline server is available, enabled: false otherwise.

  • serverReachable: true if the server is reachable, false otherwise.

    {
        applicationOnline: true,
        isOnline: true,
        offlineServer: {
            enabled: false
        },
        serverReachable: true
    }
Syntax
ctx.getCommunicationStatus()
Returns

Type

Description

{JSON Object}

A json object containing the communication status of the application.

Example
var communicationStatus = ctx.getCommunicationStatus();

getComponentInfo

Retrievest the conponent info and returns a JSON object containing the type and the subType of the current component. e.g.

    {
        type: "objectpanel",
        subType: ""
    }
Syntax
ctx.getComponentInfo()
Returns

Type

Description

{JSON Object}

A json object containing the type and the subType of the current component.

Example
var componentInfo = ctx.getComponentInfo();

readFile

Reads a file given its filename, and returns it in a particular format.

Syntax
ctx.readFile( options, callback )
Parameters
Table 3. Parameters

Name

Type

Required

Description

options

{Object}

Yes

A list of options. See below

callback

{Function}

No

A callback function. See Callback definition for further information.

Important

The options object is a Javascript object with the following properties:

  • filename (mandatory) - The path to the file to read. (Physical path in Méthode, e.g. /SysConfig/Common/Data/Sections.xml).

  • format (default is json) - The format of the returned content, Available formats: json, xml.

  • resolveEntities (default is false) - Boolean value to choose whether to get raw or resolved content, valid only in case the format is xml.

  • asString (default is false) - Boolean value to choose whether to get XML object or String content, valid only in case the format is xml.

Returns

Type

Description

{JSON} or {XML}

The content of the object in the format specified in the options parameter.
From Swing 5.2019.10 and later, this method returns an XML object, to return a String please use the parameter asString.

Example
var file = ctx.readFile( { 'filename': '/SysConfig/Common/Data/Sections.xml',
 'format': 'xml',
 'resolveEntities': true
});

executeQuery

Executes a Methode query given the query content as String, and returns a query result as JSON.

Syntax
ctx.executeQuery( settings, callback )
Parameters
Table 4. Parameters

Name

Type

Required

Description

settings

{String or Object}

Yes

If a string is passed, it represents the query content to be executed. Else, represents a set of arguments.

callback

{Function}

No

A callback function. See Callback definition for further information.

Important

settings can be either a string or a Javascript Object. If it is a string, it represents the query content to be executed. Elsewhere, if a Javascript object is passed, the following properties are supported:

  • query: the query string in Methode format to be executed.

  • limit: The max number of items.

  • view: Catalog view to applied to query result.

Returns

Type

Description

{JSON Object}

The query execution result.

Example
var settings = {
    "limit":70,
    "query":"<?xml version=\"1.0\" encoding=\"utf-8\"?><!DOCTYPE EOMSearch><EOMSearch version=\"1.0\" xmlns=\"http://EidosMedia.com/EOM/SearchEngine\" xmlns:se=\"http://EidosMedia.com/EOM/SearchEngine\" xmlns:q=\"http://EidosMedia.com/EOM/SearchEngine/query\" xmlns:qm=\"http://EidosMedia.com/EOM/SearchEngine/query/macro\" xmlns:qa=\"http://EidosMedia.com/EOM/SearchEngine/query/alias\" xmlns:qui=\"http://EidosMedia.com/EOM/SearchEngine/query/UI\" xmlns:i=\"http://EidosMedia.com/query/interpolate\"><q:Query type=\"INDEX\"><q:Properties><q:MaxResultItems value=\"70\"/><q:Sort on=\"ObjectInfo/created\" type=\"NDESCENDING\"/><q:Index name=\"@meth01_eomjse1\"/></q:Properties><q:Boolean><q:OR><se:Content q:op=\"INC\" xmlns=\"\">obama</se:Content><se:Attributes q:op=\"INC\">obama</se:Attributes></q:OR></q:Boolean></q:Query></EOMSearch>"
  }
var result = ctx.executeQuery(settings);

getUserData

Reads a user data content given its filename. If the file does not exist the system creates it in the following path "eomfs:/Configurations/Profiles/{currentUserName}/{filename}.json", and returns an empty JSON array.

Syntax
ctx.getUserData( filename, callback )
Parameters
Table 5. Parameters

Name

Type

Required

Description

filename

{String}

Yes

The user data file’s name without extension.
The following names are reserved for use by the Swing application. You cannot use these names in your custom code.
- latestqueries
- contacts
- uploads
- todolist
- recents
- favourites

callback

{Function}

No

A callback function. See Callback definition for further information.

Returns

Type

Description

{JSON Array}

The content of user’s data in JSON format or an empty JSON array if is a new file.

Example
var friends = ctx.getUserData('friends');

addUserData

Adds a new JSON object to the specified user data content, denoted by the filename input parameter.

Syntax
ctx.addUserData( filename, data, callback )
Parameters
Table 6. Parameters

Name

Type

Required

Description

filename

{String}

Yes

The user data file’s name without extension.

data

{JSON Object}

Yes

The data object to be added to the user data file.

callback

{Function}

No

A callback function. See Callback definition for further information.

Returns

Type

Description

{JSON Array}

The updated list with the new added data object.

Example
var friends = ctx.addUserData('friends',  {
                 'fullName': 'Carroll Walke'
             });

setUserData

Set a new JSON array to the specified user data content, denoted by the filename input parameter.

Syntax
ctx.setUserData( filename, list, callback )
Parameters
Table 7. Parameters

Name

Type

Required

Description

filename

{String}

Yes

The user data file’s name without extension.

list

{JSON Array}

Yes

The JSON array to replace the current user data content.

callback

{Function}

No

A callback function. See Callback definition for further information.

Returns

Type

Description

{JSON Array}

The updated list with the specified JSON array

Example
var friends = ctx.setUserData('friends', [
                {
                  "fullName": "Mitchell Henson"
                },
                {
                  "fullName": "Carroll Walker"
                },
                {
                  "fullName": "Carla Sargent"
                },
                {
                  "fullName": "Sara Savage"
                },
                {
                  "fullName": "Beach Workman"
                },
                {
                  "fullName": "Courtney Roberts"
                },
                {
                  "fullName": "Abby Hood"
                },
                {
                  "fullName": "Belinda Acosta"
                }
            ]);

getContentByPath

Obtains a content of a document, given its path.

Syntax
ctx.getContentByPath( path, options, callback )
Parameters
Table 8. Parameters

Name

Type

Required

Description

path

{String}

Yes

The path of the object. E.g. 199$/SysConfig/columnCatalogCfg.swing.xml
For paths of databases other than the primary, the database Id must be specified.

options

{Object}

No

An optional list of options. See below

callback

{Function}

No

A callback function. See Callback definition for further information.

Important

The options object is a Javascript object with the following properties:

  • cached (default is false). If true, the document xml is cached and the following times will be retrived from the internal cache.

Returns

Type

Description

{string}

The content of the object as a string.

Example
ctx.getContentByPath('199$/SysConfig/columnCfgCatalogs.swing.xml', { cached: true }, function(err, content) {
    if (err) {
        ctx.showError(err);
        return;
    }
    console.log(content);
});
Note

The method can also be called synchronously, but this usage is not recommended.

getCurrentUser

Obtains the current user.

Syntax
ctx.getCurrentUser( callback )
Parameters
Table 9. Parameters

Name

Type

Required

Description

callback

{Function}

Yes

A callback function. See Callback definition for further information.

Returns

Type

Description

{User object}

An instance of the User Class. See User class methods for further information on the methods available.

Example
ctx.getCurrentUser(function(err,User) {
    if (err) {
        ctx.showError(err);
        return;
    }
    // Do something with the user...
    alert(User.getName());
});
Note

The method can also be called synchronously, but this usage is not recommended.

getObject

Obtains a Methode object, given its id

Syntax
ctx.getObject( id, callback );
Parameters
Table 10. Parameters

Name

Type

Required

Description

id

{String}

Yes

The document id. Format is [<databaseId>$]<loid>.

callback

{Function}

Yes

A callback function. See Callback definition for further information.

Returns

Type

Description

{Object class}

An instance of the Object Class. See Object class methods for further information on the methods available.

Example
ctx.getObject('199$1.0.893734064', function(err, Obj) {
    if (err) {
        ctx.showError(err);
        return;
    }
    // Do something with the object...
    Obj.openReadonly();
});
Note

The method can also be called synchronously, but this usage is not recommended.

getObjectByPath

Obtains a Methode object, given its path

Syntax
ctx.getObjectByPath( path, callback );
Parameters
Table 11. Parameters

Name

Type

Required

Description

path

{String}

Yes

The document path.

callback

{Function}

Yes

A callback function. See Callback definition for further information.

Returns

Type

Description

{Object class}

An instance of the Object Class. See Object class methods for further information on the methods available.

Example
ctx.getObjectByPath('/Globe/Stories/Test.xml', function(err, Obj) {
    if (err) {
        ctx.showError(err);
        return;
    }
    // Do something with the object...
    Obj.openReadonly();
});
Note

The method can also be called synchronously, but this usage is not recommended.

getPlatformInfo

Obtains the Platform information

Syntax
ctx.getPlatformInfo();
Parameters

No parameters required.

Returns

Type

Description

{Object}

A generic Javascript Object containing the platform information. application: The name of the Application ('Swing', 'Prime', 'SwingApp')
copyright: The copyright information

Example
var platformInfo = ctx.getPlatformInfo();

if (platformInfo.application.indexOf('Swing') > -1) {
    // Do something only if it's Swing/SwingApp
}

getUserByName

Obtains a user, given its name.

Syntax
ctx.getUserByName( name, callback )
Parameters
Table 12. Parameters

Name

Type

Required

Description

name

{String}

Yes

The user name to look for.

callback

{Function}

Yes

A callback function. See Callback definition for further information.

Returns

Type

Description

{User object}

An instance of the User Class. See User class methods for further information on the methods available.

Example
ctx.getUserByName( 'user.test1', function(err,User) {
    if (err) {
        ctx.showError(err);
        return;
    }
    // Do something with the user...
    alert(User.getName());
});
Note

The method can also be called synchronously, but this usage is not recommended.

getGroupMembers

Obtains the list of member names, given a group name

Syntax
ctx.getGroupMembers( groupName, callback )
Parameters
Table 13. Parameters

Name

Type

Required

Description

groupName

{String}

Yes

The group name to look for.

callback

{Function}

Yes

A callback function. See Callback definition for further information.

Returns

Type

Description

{JSON Array}

The callback function will be called with the list of users belonging to the requested group, as an array of user names.

Example
ctx.getGroupMembers( 'group.test1', function(err, members) {
    if (err) {
        ctx.showError(err);
        return;
    }
    // Do something with the user names...
    for (var i = 0; i < members.length; i++) {
        console.log(members[i]);
    }
});

openDocument

Open a Methode document, given its id

Syntax
ctx.openDocument( id, callback )
Parameters
Table 14. Parameters

Name

Type

Required

Description

id

{String}

Yes

The document id to open. Format is [<databaseId>$]<loid>.

callback

{Function}

Optional

A callback function. See Callback definition for further information.

Returns

The methods does not return any information. The callback is called when the document is opened.

Example
ctx.openDocument( '199$1.0.893734064', function(err,User) {
    if (err) {
        ctx.showError(err);
        return;
    }

    // Document has opened correctly
});

openNewContentDialog

Open the new content dialog, with the selected options

Syntax
ctx.openNewContentDialog( options, callback )
Parameters
Table 15. Parameters

Name

Type

Required

Description

options

{Object}

Yes

The options with which the dialog is loaded.

callback

{Function}

Optional

A callback function. See Callback definition for further information.

Important

The options parameter is a javascript object in which it is possible to define:

  • contentType (available options are 'story', 'topic', 'dwp', 'dwc', 'topicplan')

  • name

  • channel

  • edition

  • team

  • issueDate

  • template

  • workfolder

Returns

The methods does not return any information. The callback is called when the document is created.

Example
ctx.openNewContentDialog( {
    template: '/SysConfig/Globe/Templates/poll.xml',
    contentType: 'story'
}, function(err,data) {
    if (err) {
        ctx.showError(err);
        return;
    }
    // Document has been created correctly
    alert( data.name );
});

openReadonly

Open a Methode document, given its id, in Readonly mode

Syntax
ctx.openReadonly( id, callback )
Parameters
Table 16. Parameters

Name

Type

Required

Description

id

{String}

Yes

The document id to open. Format is [<databaseId>$]<loid>.

callback

{Function}

Optional

A callback function. See Callback definition for further information.

Returns

The methods does not return any information. The callback is called when the document is opened.

Example
ctx.openReadonly( '199$1.0.893734064', function(err,data) {
    if (err) {
        ctx.showError(err);
        return;
    }

    // Document has opened correctly
});

openPopupPanel

Opens a custom HTML panel developed and specified by the user.

Syntax
ctx.openPopupPanel( panelName );
Table 17. Method information

Method

openPopupPanel

Parameter

{string} panelName - The string panel name.

Returns

undefined

Example
var panelName = 'myTestPanel';
ctx.openPopupPanel( panelName );

getSelection

Retrieves the last selected element in the editor context, for example DWP and Report editor.

Syntax
ctx.getSelection()
Returns

Type

Description

{JSON Object}

A json object containing the last selected element in the contex editor in the form of Object Class instances.

Example
var selection = ctx.getSelection();
Registration of the custom panel

The custom panel must be registered via Javascript. The namespace of reference is the following:

eidosmedia.webclient.extensions.popups

A call to the register method must be done as follows:

eidosmedia.webclient.extensions.popups.register( name, settings );
  • {String} name: the name of the custom popup ( same as the one called from the ctx.openPopupPanel() method.

  • {Object} settings: a javascript object with the settings. It has the following parameters:

    • {String} icon: the icon css class.

    • {String} title: the title of the custom dialog.

    • {String} containerStyle: the style of the container. See info box below.

    • {String} template: the path to the HTML file. It is relative to the application context.

    • {Function} ready: a function which is called when the popup is loaded. The function is called with two parameters:

      • ctx - the Context Object ( with the activeDocument if you are in the Story Editor context )

      • $modal - the jQuery reference to identify the modal. The example below will show some possible uses.

eidosmedia.webclient.extensions.popups.register('testpopup', {
    icon: 'icon-plus',
    title: 'Custom panel title',
    containerStyle: 'background-color:red;',
    template: '/config/templates/customTemplates/testpopup.html',
    ready: function( ctx, $modal ) {
        // Popup is visible.
        console.log( ctx );

        // CUSTOM EXAMPLE
        /*
            In the footer example, we added a 'data-modal-action' to the OK button.
            We now intercept the click inside the modal.
        */

        // Add modal listeners.
        $modal.on('click', '[data-modal-action]', function( event ) {
            var action = $(this).attr('data-modal-action');
            switch(action) {
                case 'ok':
                    alert('Button clicked!');

                    // To close the modal, use $modal.modal('hide');
                    $modal.modal('hide');
                break;
            }
            event.preventDefault();
            event.stopPropagation();


        });

    }
});
Tip

The popup panel is built around a classical Bootstrap Modal. In particular, the HTML code in your template will be placed INSIDE the modal-body.

So, the modal will be basically created as follows:

<div class="modal-header">
  <!-- HEADER CREATED BY SWING -->
</div>
<div class="modal-body" style="<!-- containerStyle info here -->">
  <!-- CUSTOM HTML HERE -->
</div>

No predefined style is given for the footer, but it is recommended to be as follows:

<div class="modal-footer">
  <button class="btn btn-primary" data-modal-action="ok">OK</button>
    <button class="btn" data-dismiss="modal">Cancel</button>
</div>

So, considering that your code is wrapped inside the modal-body, if you want to use a footer, close a </div> and leave the footer html "unclosed".

Example:

My custom html here.
</div> <!--Here we close the modal-body -->
<div class="modal-footer">
    <button class="btn btn-primary" data-modal-action="ok">OK</button>
    <button class="btn" data-dismiss="modal">Cancel</button>
<!-- We don't close the footer since it is closed by the modal dialog. -->

IMPORTANT: as it is a bootstrap modal, by adding data-dismiss="modal" to a button, bootstrap will automatically close the modal.

Shared Object

A set of api(s) to handle the document supporting the report case. These api(s) will be available among Swing, Prime and Swing Mobile.

Document

The shared document object contains a set of api(s) to operate with the document\report editor. These api(s) will refer to the single story editor or the full report stories editor depening on each case.

List of methods
Table 18. Parameters

Name

Description

Save the document \ report

Close the document \ report

Get the document \ report text content

Get the document \ report xml content

Select an element from the editor

Add the specified tags in the document \ report

Clear all occurrences of a set of tags in the document \ report, preserving content

Insert an annotation into a document’s element

Get the document \ report outline

Get the text content of a document based on the xpaths provided \ for report the results will be divided by section

Add specific tags based on the provided xpaths list

save

Save the document in a single editor story case. Save all the report’s documents in the report case.

Accept a single object parameter and returns a promise.

Parameters
Table 19. Object Parameter Fields

Name

Type

Required

Description

close

{Boolean}

Optional

If true close all the report’s documents after save. Ignored in single story editor case.

Syntax
ctx.shared.document.save({ close })
Returns

A promise resolved when the operation is finished

Example
ctx.shared.document.save({close: true})
.then( result => {
    console.log(result)
})
.catch( err => {
    console.error(err);
});
close

Close the current report \ document.

Returns a promise.

Syntax
ctx.shared.document.close()
Returns

A promise resolved when the operation is finished. The promise is rejected if the closing operation is cancelled (for example if the user choose "cancel" on save dirty document alert)

Example
ctx.shared.document.close()
.then( result => {
    // The window is closing, no operation execution granted here
    console.log(result)
})
.catch( err => {
    // Closing operation cancelled
    console.error(err);
});
getTextContent

Returns the complete text content of the document or report. The text has newline at end of each paragraph. Accept an object parameter specifying the hash optional flag.

Parameters
Table 20. Object Parameter Fields

Name

Type

Required

Description

hash

{Boolean}

false

To return a hash of the document / report. To be specified in the addTags api to verify the document changed since getTextContent invocation.

Syntax
ctx.shared.document.getTextContent()
Returns

A promise resolved when the operation is finished

Example
ctx.shared.document.getTextContent()
.then( result => {
    console.log(result)
})
.catch( err => {
    console.error(err);
});
getXmlContent

Returns the xml content of the document or report. In case of report an array of objects with id and xml attributes is returned.

Syntax
ctx.shared.document.getXmlContent()
Returns

A promise resolved when the operation is finished

Example
ctx.shared.document.getXmlContent()
.then( result => {
    console.log(result)
})
.catch( err => {
    console.error(err);
});
selectElement

Select an element from the story editor\report.

Accepts an object parameter to define the selection and returns a promise with information on the selection operation.

Parameters

Name

Type

Required

Description

element

{Object}

Yes

An object with the (optional) property tag for the tag name and an (optional) object property attributes to define the key\values attributes to look up in the selection. If more than one element match the selection criterias the first one will be selected.

Syntax
ctx.shared.document.selectElement(element)
Returns

A promise resolved when the operation is finished and at least one element is selected. The promise is rejected if no elements are selected.

Example
const element = { tag: "byline", attributes: { id: "U77274655343ool" } };
ctx.shared.document.selectElement(element)
.then((res) => {
    console.log(res);
})
.catch((err) => {
    console.error(err);
});
addTags

Add the specified tags in a document or report.

Accept an object parameter specifying the list of tags with related tag name, start, size, attributes (optional) and virtual flag (optional). If the optional virtual flag (true by default) is set to false, the tag will be saved in the document / report. An optional lock flag can be specified. An optional hash parameter can be specified (the one retrieved by the getTextContent api), it will be used to verify if the document / report changed, in case of changes the api will fail. The api returns a promise. If the promise succeeds, it returns a boolean indicating wether any tag has been added.

Parameters
Table 21. Object Parameter Fields

Name

Type

Required

Description

tags

{Array}

Yes

An array of object specifying the tag name, the start and size of text to be tagged and an optional attributes object.

lock

{Boolean}

No

To lock the document, true by default.

hash

{String}

No

To verify the document / report changes since the hash retrieval via getTextContent api.

Syntax
ctx.shared.document.addTags({tags: [{tag: 'mark1', start:0, size:2}, {tag: 'mark2', start:4, size:6, attributes: {class: 'highlight'}}] })
Returns

A promise resolved when the operation is finished

Example
ctx.shared.document.addTags({tags: [{tag: 'mark', start:0, size:2}]})
.then( result => {
    console.log(result)
})
.catch( err => {
    console.err(err);
});
clearTags

Remove all the occurrences of the specified set of tags preserving their content, in a document or report.

Accept an object parameter specifying the list of tags and optionally a lock flag, returns a promise. If the promise succeeds, it returns a boolean indicating wether any occurrence of the tags has been matched and cleared.

Parameters
Table 22. Object Parameter Fields

Name

Type

Required

Description

tags

{Array}

Yes

An array of object specifying the tag name.

lock

{Boolean}

No

To lock the document, true by default.

Syntax
ctx.shared.document.clearTags({tags: [{tag: 'mark'}, {tag:'highlight'}] })
Returns

A promise resolved when the operation is finished

Example
ctx.shared.document.clearTags({tags: [{tag: 'mark'}]})
.then( result => {
    console.log(result)
})
.catch( err => {
    console.err(err);
});
annotateElement

Add an annotation to an element from the story editor\report.

Accepts parameters to define where add the annotation and returns a promise with information on the annotation operation.

Parameters

Name

Type

Required

Description

element

{Object}

Yes

An object with the (optional) property tag for the tag name and an (optional) object property attributes to define the key\values attributes to look up for the annotation. If more than one element match the selection criterias the first one will be annotated.

text

{String}

Yes

The annotation string

options

{Object}

Optional

Additional parameters (see the table below)

Table 23. Option parameter Fields

Name

Type

Required

Description

unwrap

{Boolean}

Optional

If true the selected text element is unwrapped from its parent tag before adding the annotation

Syntax
ctx.shared.document.annotateElement(element, text, options)
Returns

A promise resolved if one element was annotated. The promise is rejected if no elements for annotation are found.

Example
const element = { tag: "mark", attributes: { type: "player" } };
const options = { unwrap: true };
ctx.shared.document
    .annotateElement(element, "This is my annotation", options)
    .then((res) => {
    console.log(res);
    })
    .catch((err) => {
    console.error(err);
    });
getOutline

Returns information on the whole document or report. The information returned is ObjectInfo and optionally text and xml. In case of report an array of object is returned.

Parameters
Table 24. Object Parameter Fields

Name

Type

Required

Description

xml

{Boolean}

No

To get document xml, false by default.

text

{Boolean}

No

To get document text, false by default.

Syntax
ctx.shared.document.getOutline({xml: true, text: false})
Returns

A promise resolved when the operation is finished

Example
ctx.shared.document.getOutline()
.then( result => {
    console.log(result)
})
.catch( err => {
    console.error(err);
});
getTextContentByXpath

Get text content based on the xpath list provided.

Accept an options object containing an array of xpath to collect the text content. The text has newline at end of each paragraph. In the options object it’s possible to specify the hash optional flag. The api returns a promise. If the promise succeeds, it returns an array with the id of the section and an object containing the text content, the attributes of the objects are the list of xpaths provided.

Parameters
Table 25. Object Parameter Fields

Name

Type

Required

Description

xpaths

{Array}

Yes

An array of object specifying the xpath.

hash

{String}

No

To return a hash of text content for each single xpath. To be specified in the addTagsByXpath api to verify the document changed since getTextContentByXPath invocation.

Syntax
ctx.shared.document.getTextContentByXpath({ xpaths: ['/doc/story/grouphead', '/doc/story/summary', '/doc/story/text'], hash: true})
Returns

A promise resolved when the operation is finished

Example
ctx.shared.document.getTextContentByXpath({ xpaths: ['/doc/story/grouphead', '/doc/story/summary', '/doc/story/text'], hash: true})
.then( result => {
    console.log(result)
})
.catch( err => {
    console.err(err);
});
addTagsByXpath

Apply tags based on the xpath list provided.

Accept an options object containing an array of documentList where to apply the tags. An optional lock flag can be specified. For each tag element: If the optional virtual flag (true by default) is set to false, the tag will be saved in the document / report. An optional hash parameter can be specified (the one retrieved by the getTextContentByTags api), it will be used to verify if the document / report changed, in case of changes the api will fail. The api returns a promise. If the promise succeeds, it returns an array with the id of the section and and teh result of the operation for each xpath.

Parameters
Table 26. Object Parameter Fields

Name

Type

Required

Description

documentList

{Array}

Yes

An array of document where to apply the tags.

lock

{String}

No

If true each document will be locked, if not already locked, default true.

Syntax
ctx.shared.document.addTagsByXpath({ documentList: ['/doc/story/grouphead', '/doc/story/summary', '/doc/story/text'], lock: false})
Returns

A promise resolved when the operation is finished

Example
ctx.shared.document.addTagsByXpath({ {
    "lock": false,
    "documentList": [
        {
            "storyId": "33$1.0.1468130003",
            "xpaths": [
                {
                    "xpath": "/doc/section/text",
                    "tags": [
                        {
                            "tag": "mask",
                            "start": 1,
                            "size": 4
                        },
                        {
                            "tag": "mask",
                            "start": 10,
                            "size": 3
                        }
                    ],
                    "hash": true
                }
            ]
        },
        {
            "storyId": "33$1.0.1470737318",
            "xpaths": [
                {
                    "xpath": "/doc/section/text",
                    "tags": [
                        {
                            "tag": "mask",
                            "start": 5,
                            "size": 8
                        },
                        {
                            "tag": "mask",
                            "start": 20,
                            "size": 4
                        }
                    ],
                    "hash": true
                },
                {
                    "xpath": "/doc/story/text",
                    "tags": [
                        {
                            "tag": "mask",
                            "start": 1,
                            "size": 10
                        }
                    ],
                    "hash": true
                }
            ]
        }
    ]
})
.then( result => {
    console.log(result)
})
.catch( err => {
    console.err(err);
});

/* example of return value */ result =
[
    {
        storyId: '33$1.0.1468130003',
        addTagsResult: {
            "/doc/section/text": {
                success: true
            }
        }
    },
    {
        storyId: '33$1.0.1470737318',
        addTagsResult: {
            "/doc/section/text": {
                "success": true
            },
            "/doc/story/text": {
                success: false,
                errorCode: 404,
                errorMessage: 'node element not found'
        }
    }
]

Object class methods

List of methods

Table 27. Parameters

Name

Description

Add the collaborators to an object

Execute an EOMDB action for the current object

Returns the collaborators of an object

Returns the correlations of an object

Returns the object id

Returns the object info

In case of a report or a DWP returns the container of the selected object

In case of a report or a DWP, returns the documents linked.

In case of a report or a DWP, returns the zones and eventually the documents linked to each zone.

Returns the object locker

Returns the metadata of the object

Returns the object name

Returns the object status information

Returns the system attributes of the object, in XML format

Returns the object type

Checks if the object is typeof the given type

Returns the usage tickets of the object

Returns the role information of the object

Returns the virtual attributes of the object, in XML format

Open the current object

Open the current object in Readonly mode

Lock the current object

Unlock the current object

Register to all the EOMDB events of an item

Refresh the current object information

Remove the collaborators of an object

Set the metadata of an object

Update the status of the current object

Set the system attributes of an object

Gets the bundle information of the current object

Unset a metadata field of the current object

Gets the channel copies list of the current object - Restricted for EOM::CompoundStory objects

Create a channel copy of the current object - Restricted for EOM::CompoundStory objects

addCollaborators

Add the collaborators to an object

Parameters
Table 28. Parameters

Name

Type

Required

Description

collaborators

{String or Array}

Yes

A list made of user names.

callback

{Function}

Optional

A callback function. See Callback definition for further information.

Syntax
Object.addCollaborators(collaborators, callback)
Returns

The method returns the an array of collaborators as string.

Example
ctx.getObject('199$1.0.893734064', function(err, Obj) {
    if (err) {
        ctx.showError(err);
        return;
    }
    Obj.addCollaborators(['user.3', 'user.4'], function(err, data){
        if (err) {
            ctx.showError(err);
            return;
        }
        // data is now ['user.1', 'user.2', 'user.3', 'user.4'];
        var User = ctx.getUserByName(data[0]).getInfo()
    });
});

The method can also be called synchronously, but this usage is not recommended.

executeAction

Execute an EOMDB action for the current object

Syntax
Object.executeAction( settings, callback )
Parameters
Table 29. Parameters

Name

Type

Required

Description

settings

{String or Object}

Yes

If a string is passed, it represents the name of the action to execute. Else, represents a set of arguments.

callback

{Function}

Yes

A callback function. See Callback definition for further information.

Important

settings can be either a string or a Javascript Object. If it is a string, it will interpreted as the actionId, and the action will be executed with no other params. Elsewhere, if a Javascript object is passed, the following properties are supported:

  • actionId: the action name. REQUIRED.

  • args: the arguments as a String.

Returns

The method returns the action response.

Example
ctx.getObject('199$1.0.893734064', function(err, Obj) {
    if (err) {
        ctx.showError(err);
        return;
    }
    // Or... Obj.executeAction({ actionId: 'postToTwitter', args: 'arguments here');
    Obj.executeAction('postToTwitter', function(err, data) {
        //.. Do something here.
    });
});

The method can also be called synchronously, but this usage is not recommended.

getId

Returns the object id

Syntax
Object.getId()
Returns

The method returns the object id as a string.

Example
ctx.getObject('199$1.0.893734064', function(err, Obj) {
    if (err) {
        ctx.showError(err);
        return;
    }

    // Well, we already knew that...
    var objectId = Obj.getId();
});

getCollaborators

Get the collaborators of an object

Syntax
Object.getCollaborators(callback)
Returns

The method returns the an array of collaborators as string.

Example
ctx.getObject('199$1.0.893734064', function(err, Obj) {
    if (err) {
        ctx.showError(err);
        return;
    }
    Obj.getCollaborators(function(err, data){
        if (err) {
            ctx.showError(err);
            return;
        }
        // data is now ['user.1', 'user.2'];
        var User! = ctx.getUserByName(data[0]).getInfo()
    });
});

The method can also be called synchronously, but this usage is not recommended.

getCorrelations

Get the correlations of an object

Syntax
Object.getCorrelations(linkName, callback)
Parameters
Table 30. Parameters

Name

Type

Required

Description

linkName

{String}

Optional

The name of the linkName to show.

callback

{Function}

Optional

A callback function. See Callback definition for further information.

Returns

The method returns the an array of correlations as Ctx Objects.

Example
ctx.getObject('199$1.0.893734064', function(err, Obj) {
    if (err) {
        ctx.showError(err);
        return;
    }
    // Without linkName
    Obj.getCorrelations(function(err, data){
    /*
    * With linkName,
    * Obj.getCorrelations('see_also', function(err, data){
    */
        if (err) {
            ctx.showError(err);
            return;
        }

        // data is an array of Objects
        for (var j = 0; j < data.length; j++) {
            console.log(data.getName());
        }
    });
});

The method can also be called synchronously, but this usage is not recommended.

getInfo

Returns the object info

Syntax
Object.getInfo()
Returns

The method returns the object information as JSON.

Example
ctx.getObject('199$1.0.893734064', function(err, Obj) {
    if (err) {
        ctx.showError(err);
        return;
    }

    var objInfo = Obj.getInfo();
    // Obj info is now a JSON containing all the information.
});

getContainer

In the context of DWP and Report editor returns the container of the selected object (activeObject).

Syntax
Object.getContainer()
Returns

The method returns the container in the form of Object Class instances.

Example
    var container = ctx.activeObject.getContainer();
    // container is an Object Class instance.
});

In case of a report or a DWP, returns the documents linked.

Syntax
Object.getLinks(callback)
Returns

The method returns the an array of links in the form of Object Class instances.

Example
ctx.getObject('199$1.0.893734064', function(err, Obj) {
    if (err) {
        ctx.showError(err);
        return;
    }
    Obj.getLinks(function(err, links){
        if (err) {
            ctx.showError(err);
            return;
        }
        // Each link is an Object Class instance.
        // So, it is possible to do so.
        for (var j = 0, ln = links.length; j < ln; j++) {
            console.log( links[j].getLocker() );
        }
    });
});

getZones

In case of a report or a DWP, returns the zones and eventually the documents linked to each zone.

Syntax
Object.getZones(options, callback)
Table 31. Parameters

Name

Type

Required

Description

options

{Object}

Yes

An optional list of options. See below

callback

{Function}

Optional

A callback function. See Callback definition for further information.

Important

The options object is a Javascript object with the following properties:

  • inlcudeLinks - true if each zone must contains also the linked objects

Returns

The method returns an array of zones in the form of Object Class instances.

Example
ctx.getObject('199$1.0.893734064', function(err, Obj) {
    if (err) {
        ctx.showError(err);
        return;
    }
    Obj.getZones({includeLinks: true}, function(err, zones){
        if (err) {
            ctx.showError(err);
            return;
        }
        // Each link is an Object Class instance.
        // So, it is possible to do so.
        for (var j = 0, ln = zones.length; j < ln; j++) {
            console.log( zones[j].getInfo() );

            var links = zones[j].getLinks();

            for (var z = 0, ll = zones.length; z < ll; z++) {
                console.log( links[z].getInfo() );
            }
        }
    });
});

getLocker

Returns the object locker

Syntax
Object.getLocker()
Example
ctx.getObject('199$1.0.893734064', function(err, Obj) {
    if (err) {
        ctx.showError(err);
        return;
    }
    var lockerBy = Obj.getLocker();
});

getMetadata

Returns the metadata of the object

Syntax
Object.getMetadata()
Returns

The method returns the metadata information as String

Example
ctx.getObject('199$1.0.893734064', function(err, Obj) {
    if (err) {
        ctx.showError(err);
        return;
    }
    var objMetadata = Obj.getMetadata();
    var $objMetadata = $.parseXML(objMetadata);
});

getName

Returns the object name

Syntax
Object.getName()
Example
ctx.getObject('199$1.0.893734064', function(err, Obj) {
    if (err) {
        ctx.showError(err);
        return;
    }
    var name = Obj.getName();
});

getStatusInfo

Returns the object statusInformation

Syntax
Object.getStatusInfo()
Example
ctx.getObject('199$1.0.893734064', function(err, Obj) {
    if (err) {
        ctx.showError(err);
        return;
    }
    var statusInfo = Obj.getStatusInfo();
    // Now
    // statusInfo.name is the status name
    // statusInfo.comment
    // statusInfo.identifier is the RGB color
});

getSystemAttributes

Returns the system attributes of the object, in XML format (as string)

Syntax
Object.getSystemAttributes()
Example
ctx.getObject('199$1.0.893734064', function(err, Obj) {
    if (err) {
        ctx.showError(err);
        return;
    }
    var objSysAttr = Obj.getSystemAttributes();
    var $sysAttr = $.parseXML(objSysAttr);
});

Use the refresh method to get up to date object information before call this method.

getType

Returns the object type

Syntax
Object.getType()
Example
ctx.getObject('199$1.0.893734064', function(err, Obj) {
    if (err) {
        ctx.showError(err);
        return;
    }
    var type = Obj.getType();
});

isType

Checks if the object is typeof the given type

Syntax
Object.isType(testtype)
Parameters
Table 32. Parameters

Name

Type

Required

Description

testtype

{String}

Yes

The type to test against the object type.

Returns

The method returns true if and only if the object type is type of the testtype else the method returns false.

Example
ctx.getObject('199$1.0.893734064', function(err, Obj) {
    if (err) {
        ctx.showError(err);
        return;
    }
    var type = Obj.isType('EOM::Story');
});

getUsageTicket

Returns the usage tickets of the object, as an XML String

Syntax
Object.getUsageTicket()
Example
ctx.getObject('199$1.0.893734064', function(err, Obj) {
    if (err) {
        ctx.showError(err);
        return;
    }
    var usageTicket = Obj.getUsageTicket();
    var $usageTicket = $.parseXML(usageTicket);
});

Use the refresh method to get up to date object information before call this method.

getRoles

Returns the roles information of the object, as an XML String

Syntax
Object.getRoles(settings, callback)
Parameters
Table 33. Parameters

Name

Type

Required

Description

settings

{JSON}

Yes

The roles settings to retrieve:

  • {String} roleType (required) - The role type

  • {String} roleName (required) - The role name

callback

{Function}

Optional

A callback function. See Callback definition for further information.

Returns

The method returns the roles information as XML String.

Example
ctx.getObject('199$1.0.893734064', function(err, Obj) {
    if (err) {
        ctx.showError(err);
        return;
    }
    Obj.getRoles({roleType: 'EOM::WebContainerLinks', roleName: '1.0.232702264'}, function(err, role){
        if (err) {
            ctx.showError(err);
            return;
        }
        console.log(role);
    });
});

getVirtualAttributes

Returns the virtual attributes of the object, as an XML String

Syntax
Object.getVirtualAttributes()
Example
ctx.getObject('199$1.0.893734064', function(err, Obj) {
    if (err) {
        ctx.showError(err);
        return;
    }
    var virtualAttributes = Obj.getVirtualAttributes();
    var $virtualAttributes = $.parseXML(virtualAttributes);
});

Use the refresh method to get up to date object information before call this method.

open

Open the current object in editing mode

Syntax
Obj.open( id, callback )
Parameters
Table 34. Parameters

Name

Type

Required

Description

callback

{Function}

Optional

A callback function. See Callback definition for further information.

Returns

The methods does not return any information. The callback is called when the document is opened.

Example
ctx.getObject('199$1.0.893734064', function(err, Obj) {
    if (err) {
        ctx.showError(err);
        return;
    }
    Obj.open(function(err, data) {
        // Callback after the document is opened
    });
});

lock

Lock the current document

Syntax
Obj.lock( callback )
Parameters
Table 35. Parameters

Name

Type

Required

Description

callback

{Function}

Optional

A callback function. See Callback definition for further information.

Returns

The methods does not return any information. The callback is called when the document is locked.

Example
ctx.getObject('199$1.0.893734064', function(err, Obj) {
    if (err) {
        ctx.showError(err);
        return;
    }
    Obj.lock(function(err, data) {
        // Callback after the document is locked
    });
});

unlock

Unlock the current document

Syntax
Obj.unlock( callback )
Parameters
Table 36. Parameters

Name

Type

Required

Description

callback

{Function}

Optional

A callback function. See Callback definition for further information.

Returns

The methods does not return any information. The callback is called when the document is unlocked.

Example
ctx.getObject('199$1.0.893734064', function(err, Obj) {
    if (err) {
        ctx.showError(err);
        return;
    }
    Obj.unlock(function(err, data) {
        // Callback after the document is unlocked
    });
});

openReadonly

Open the current document in Readonly mode

Syntax
Obj.openReadonly( callback )
Parameters
Table 37. Parameters

Name

Type

Required

Description

callback

{Function}

Optional

A callback function. See Callback definition for further information.

Returns

The methods does not return any information. The callback is called when the document is opened.

Example
ctx.getObject('199$1.0.893734064', function(err, Obj) {
    if (err) {
        ctx.showError(err);
        return;
    }
    Obj.openReadonly(function(err, data) {
        // Callback after the document is opened
    });
});

registerToEvents

Register to all the EOMDB events of an item

Syntax
Obj.registerToEvents(eventCallback)
Parameters
Table 38. Parameters

Name

Type

Required

Description

eventCallback

{Function}

Yes

A callback function which is called at any event. See the example for further information.

Example
ctx.getObject('199$1.0.893734064', function(err, Obj) {
    if (err) {
        ctx.showError(err);
        return;
    }

    // Register to all the events.
    Obj.registerToEvents(function(eventName, data) {
        // eventName contains the name of the event
        // "unlock", "lock", "check in"...
        // data contains the information regarding the event.

        // Eventually, if needed, call a refresh for the object.

        Obj.refresh().getLocker();

    });


});

refresh

Refresh the current object information and returns a new Object class.

Syntax
Obj.refresh()
Returns

Type

Description

{Object class}

An instance of the Object Class. See Object class methods for further information on the methods available.

Example
ctx.getObject('199$1.0.893734064', function(err, Obj) {
    if (err) {
        ctx.showError(err);
        return;
    }

    // Perform very complex operations
    // Such as saving the document or setting the document metadata

    // To obtain the new metadata... do this.
    Obj = Obj.refresh();
    Obj.getMetadata();
});

removeCollaborators

Remove the collaborators from an object

Parameters
Table 39. Parameters

Name

Type

Required

Description

collaborators

{String or Array}

Yes

A list made of user names.

callback

{Function}

Optional

A callback function. See Callback definition for further information.

Syntax
Object.removeCollaborators(collaborators, callback)
Returns

The method returns the an array of collaborators as string.

Example
ctx.getObject('199$1.0.893734064', function(err, Obj) {
    if (err) {
        ctx.showError(err);
        return;
    }
    Obj.removeCollaborators(['user.1'], function(err, data){
        if (err) {
            ctx.showError(err);
            return;
        }
        // data is now ['user.1'];
        var User = ctx.getUserByName(data[0]).getInfo()
    });
});

The method can also be called synchronously, but this usage is not recommended.

setMetadata

Set the metadata of an object

Syntax
Obj.setMetadata(options, callback);
Parameters
Table 40. Parameters

Name

Type

Required

Description

options

{Object or Array}

Yes

An object made of xpath and content properties. Can be an array of those properties.

callback

{Function}

Optional

A callback function. See Callback definition for further information.

Example
ctx.getObject('199$1.0.893734064', function(err, Obj) {
    if (err) {
        ctx.showError(err);
        return;
    }

    var request = { xpath: '/ObjectMetadata/General/Priority', content: 'High title'};
    // Or an array
    // var request = [ { xpath: '/ObjectMetadata/General/Priority', content: 'High title'},
                        { xpath: '/ObjectMetadata/General/Priority2', content: 'High title2'}
                        { xpath: '/ObjectMetadata/General/Priority3', content: 'High title3'} ];
    Obj.setMetadata(request, function(err, data) {
        if (err) {
            ctx.showError(err);
            return;
        }
        // Success...
    });
});

The method can also be called synchronously, but this usage is not recommended.

setStatus

Update the status of the current object

Syntax
Obj.setStatus('NewsFlow/Editing', callback);
Obj.setStatus({ name: 'NewsFlow/Editing', comment: 'My comment'}, callback)
Returns

Type

Description

{Object class}

An instance of the Object Class. See Object class methods for further information on the methods available.

Example
ctx.getObject('199$1.0.893734064', function(err, Obj) {
    if (err) {
        ctx.showError(err);
        return;
    }

    Obj.setStatus('NewsFlow/Editing', function(err, data) {
        if (err) {
            ctx.showError(err);
            return;
        }
        // Success...
    });
});

The method can also be called synchronously, but this usage is not recommended.

setSystemAttributes

Set the system attributes of an object

Syntax
Obj.setSystemAttributes(options, callback);
Parameters
Table 41. Parameters

Name

Type

Required

Description

options

{Object or Array}

Yes

An object made of xpath and content properties. Can be an array of those properties.

callback

{Function}

Optional

A callback function. See Callback definition for further information.

Example
ctx.getObject('199$1.0.893734064', function(err, Obj) {
    if (err) {
        ctx.showError(err);
        return;
    }

    var request = { xpath: '/props/title/', content: 'High title'};
    // Or an array
    // var request = [ { xpath: '/props/title/', content: 'High title'},
                        { xpath: '/props/summary/', content: 'Summary'} ];
    Obj.setSystemAttributes(request, function(err, data) {
        if (err) {
            ctx.showError(err);
            return;
        }
        // Success...
    });
});

The method can also be called synchronously, but this usage is not recommended.

cleanMetadataField

Unset a metadata field of the current object

Syntax
Obj.cleanMetadataField(xpath, callback);
Parameters
Table 42. Parameters

Name

Type

Required

Description

option

{String}

Yes

A metadata field xpath to remove.

callback

{Function}

Optional

A callback function. See Callback definition for further information.

Example
ctx.getObject('199$1.0.893734064', function(err, Obj) {
    if (err) {
        ctx.showError(err);
        return;
    }

    Obj.cleanMetadataField('/ObjectMetadata/General/Priority', function(err, data) {
        if (err) {
            ctx.showError(err);
            return;
        }
        // Success...
    });
});

The method can also be called synchronously, but this usage is not recommended.

getBundleInfo

Gets the bundle information of the current object

Syntax
Obj.getBundleInfo(callback);
Parameters
Table 43. Parameters

Name

Type

Required

Description

callback

{Function}

Optional

A callback function. See Callback definition for further information.

Returns

The bundle information:

[
  {
    "id": "99$1.0.287059148",
    "name": "Obama.xml",
    "baseName": "Obama",
    "path": "/Globe/Stories/Globe/Stories/Politics/2019-03-18/Politics/Obama.xml",
    "channel": "Globe-Web",
    "edition": null,
    "section": null,
    "issueDate": "20190318",
    "subFolder": null,
    "workFolder": "/Globe/Politics",
    "channelIdentifier": "Globe-Web"
  },
  {
    "id": "99$1.0.287059376",
    "name": "Obama@Globe-Print-USA.xml",
    "baseName": "Obama@Globe-Print-USA",
    "path": "/Globe/Stories/Globe/Stories/Politics/2019-03-18/Politics/Obama.xml/Obama@Globe-Print-USA.xml",
    "channel": "Globe-Print",
    "edition": "USA",
    "section": null,
    "issueDate": "20190318",
    "subFolder": null,
    "workFolder": "/Globe/Politics",
    "channelIdentifier": "Globe-Print/USA"
  }
]
Example
ctx.activeObject.getBundleInfo(function(err, list) {
    if (err) {
        ctx.showError(err);
        return;
    }
    //Success
});

The method can also be called synchronously, but this usage is not recommended.

getChannelCopiesList

Gets the channel copies list of the current object - Restricted for EOM::CompoundStory objects

Syntax
Obj.getChannelCopiesList(callback);
Parameters
Table 44. Parameters

Name

Type

Required

Description

callback

{Function}

Optional

A callback function. See Callback definition for further information.

Returns

The list of the created channel copies:

[
    {
        "id": "41$1.0.107332121",
        "channel": null,
        "info": {
            "id": "41$1.0.107332121",
            "name": "story.xml",
            "baseName": "story",
            "path": "/Globe/Stories/Art/story.xml",
            "channel": null,
            "edition": null,
            "section": null,
            "issueDate": "20190111",
            "subFolder": null,
            "workFolder": "/Globe/Art",
            "channelIdentifier": "none"
        },
        "master": true
    },
    {
        "id": "41$1.0.107314527",
        "channel": "Globe-Print",
        "info": {
            "id": "41$1.0.107314527",
            "name": "story@Globe-Print.xml",
            "baseName": "story@Globe-Print",
            "path": "/Globe/Stories/Art/story.xml/story@Globe-Print.xml",
            "channel": "Globe-Print",
            "edition": null,
            "section": null,
            "issueDate": "20190111",
            "subFolder": null,
            "workFolder": "/Globe/Art",
            "channelIdentifier": "Globe-Print"
        }
    }
]
Example
ctx.activeObject.getChannelCopiesList(function(err, list) {
    if (err) {
        ctx.showError(err);
        return;
    }
    //Success
});

The method can also be called synchronously, but this usage is not recommended.

createChannelCopy

Create a channel copy of the current object - Restricted for EOM::CompoundStory objects

Syntax
Obj.createChannelCopy(channel, callback);
Parameters
Table 45. Parameters

Name

Type

Required

Description

channel

{String}

Yes

A string containing the channel in form of "Product/Edition".

callback

{Function}

Optional

A callback function. See Callback definition for further information.

Returns

The method returns the object information of the new channel copy as JSON.

Example
ctx.activeObject.createChannelCopy('Product/Edition', function(err) {
    if (err) {
        ctx.showError(err);
        return;
    }
    //Success
});

The method can also be called synchronously, but this usage is not recommended.

User class methods

List of methods

Table 46. Parameters

Name

Description

Returns the user groups

Returns the user info

Returns the usermetadata

Returns the username

Returns the system attributes of the user, in XML format

Returns the user teams.

Sets the system attributes of the user

Sets the metadata of the user

getGroups

Returns the groups which the user belongs to

Warning

The method returns an error for users other than the current one.

Syntax
User.getGroups( [callback] )
Parameters
Table 47. Parameters

Name

Type

Required

Description

callback

{Function}

Optional

A callback function. See Callback definition for further information.

Example
ctx.getCurrentUser(function(err,User) {
    var groups = User.getGroups();
    console.log(teams);
});

The method can be called either synchronously or asynchronously. It is indifferent.

getInfo

Returns the user info

Syntax
User.getInfo( [callback] )
Parameters
Table 48. Parameters

Name

Type

Required

Description

callback

{Function}

Optional

A callback function. See Callback definition for further information.

Returns

The user information in JSON.

{
  "name": "john.doe",
  "description": "Star Software",
  "ucount": 13159,
  "databaseId": 199,
  "id": "1.0.532488046",
  "fullName": "John Doe",
  "phoneNumber": "(01) 5748584456)",
  "mobileNumber": "(001) 5476987496798)",
  "twitter": "johndoe",
  "role": "Reporter",
  "homeEmail": "john.doe@google.com",
  "businessEmail": "john.doe@star.com",
  "statusMessage": "I am available",
  "workDir": "workFolder:///Globe/Art",
  "location": "London",
  "lastLoggedOn": 1494418598,
  "initials": "JD",
  "signature": "john doe",
  "homePath": "/Users/john.doe",
  "calendars": [
    {
      "color": "#32AE0C",
      "id": "U12001806763ERC",
      "name": "UK Holidays",
      "url": "https://www.gov.uk/england-and-wales.ics",
      "icon": "icon-calendar",
      "private": false
    }
  ],
  "status": "busy",
  "disabled": false
}
Example
ctx.getCurrentUser(function(err,User) {
    var userInfo = User.getInfo();
    // Or, if you prefer,
    User.getInfo(function(err, userInfo){
        console.log(userInfo.name);
    });
});

The method can be called either synchronously or asynchronously. It is indifferent.

getMetadata

Returns the user metadata, as a string.

Warning

The method returns an error for users other than the current one.

Syntax
User.getMetadata( [callback] )
Parameters
Table 49. Parameters

Name

Type

Required

Description

callback

{Function}

Optional

A callback function. See Callback definition for further information.

Example
ctx.getCurrentUser(function(err,User) {
    var metadata = User.getMetadata();
    console.log(metadata);
});

The method can be called either synchronously or asynchronously. It is indifferent.

getName

Returns the user name

Syntax
User.getName( [callback] )
Parameters
Table 50. Parameters

Name

Type

Required

Description

callback

{Function}

Optional

A callback function. See Callback definition for further information.

Returns

The user name as string.

Example
ctx.getCurrentUser(function(err,User) {
    var userName = User.getName();
    console.log(userName);
});

The method can be called either synchronously or asynchronously. It is indifferent.

getSystemAttributes

Returns the system attributes of the user, in XML format (as string)

Warning

The method returns an error for users other than the current one.

Syntax
User.getSystemAttributesXML( [callback] )
Parameters
Table 51. Parameters

Name

Type

Required

Description

callback

{Function}

Optional

A callback function. See Callback definition for further information.

Returns

The system attributes of the User, as a XML string.

Example
ctx.getCurrentUser(function(err,User) {
    var systemAttributesXml = User.getSystemAttributes();
    var $sysAttr = $.parseXML(systemAttributesXml);
    console.log(systemAttributesXml);
});

The method can be called either synchronously or asynchronously. It is indifferent.

getTeams

Returns the teams which the user belongs to

Warning

The method returns an error for users other than the current one.

Syntax
User.getTeams( [callback] )
Parameters
Table 52. Parameters

Name

Type

Required

Description

callback

{Function}

Optional

A callback function. See Callback definition for further information.

Example
ctx.getCurrentUser(function(err,User) {
    var teams = User.getTeams();
    console.log(teams);
});

The method can be called either synchronously or asynchronously. It is indifferent.

setSystemAttributes

Sets the system attributes of the user

Warning

The method returns an error for users other than the current one.

Syntax
User.setSystemAttributes( systemAttributes, [callback] )
Parameters
Table 53. Parameters

Name

Type

Required

Description

systemAttributes

{String or object}

Yes

A string or an object to represent the system attributes

callback

{Function}

Optional

A callback function. See Callback definition for further information.

Returns

The system attributes of the User, as a XML string.

Example
ctx.getCurrentUser(function(err,User) {
    var systemAttributes = '<props><principalInfo><email type="business">johndoe@star.comw</email><initials>JD</initials><signature>john doe</signature><statusMessage>I am available</statusMessage><color type="revision" value="#008080"/><color type="annotation" value="#800000"/><location>London</location><email type="home">johndoe@google.com</email><twitter>johndoe</twitter><facebook>aaaa</facebook><mobileNumber>(01) 7834684587438</mobileNumber><phoneNumber>(001) 54753754765375</phoneNumber><status>busy</status><workDir>workFolder:///Globe/Art</workDir><calendar><id>U12001806763ERC</id><icon>icon-calendar</icon><color>#32AE0C</color><name>UK Holidays</name><url>https://www.gov.uk/bank-holidays/england-and-wales.ics</url><private>false</private></calendar></principalInfo><role>Reporter</role><OutputChannels><channel name="Globe-Print"/></OutputChannels></props>';

    User.setSystemAttributes(systemAttributes, function(err, data) {
        if (err) {
            // Do something...
            return;
        }
    );

});

setMetadata

Sets the metadata of the user

Warning

The method returns an error for users other than the current one.

Syntax
User.setMetadata( metadata, [callback] )
Parameters
Table 54. Parameters

Name

Type

Required

Description

metadata

{String or object}

Yes

A string or an object to represent the metadata

callback

{Function}

Optional

A callback function. See Callback definition for further information.

Returns

The system attributes of the User, as a XML string.

Example
ctx.getCurrentUser(function(err,User) {
    var attributes = '<test><secondtest>hello</secondtest></test>';

    User.setMetadata(attributes, function(err, data) {
        if (err) {
            // Do something...
            return;
        }
    );

});

activeObject

In various contexts, such as the toolbars, editors, Diagram workflow, etc., there is an additional property available, named activeObject.

The activeObject is actually an instance of the Object Class and contains all methods of this class. See Object class methods for further information.

To be compliant with object panel bulk mode please use activeObjects array property.

Important

The old activeObj property is being discontinued from Swing 4 and will not be available in Prime. Please use the new activeObject property instead.

activeObjects

Same as activeObject but returned as an array of all selected items. In single mode array length is 1.

activeDocument

*Deprecated: please use activeDocumentV2

Inside the editor context, it is possible to access the activeDocument. Please refer to Editor API methods reference.

activeDocumentV2

Starting form version 5.2020.11 inside the editor context, it is possible to access the activeDocumentV2. Api(s) from this object are cross platform compatible (Swing, Swing Mobile, Prime).

Please refer to Editor API methods reference.

Callback definition

Important

The callback parameter, when specified, is always defined as follows:

// Callback definition
function( err, response ) {
    // This is the "Node.js" callback style.
    // It forces the developer to manage the errors.

    if (err) {
        // Do something...
        return;
    }

    // Real implementation here

}

Basic structure of the Context Object

The Context object is made of a specific list of properties, and a number of publicly available methods.

{
    application: {
        getId: function()
    },
    area: {
        getType: function(),
        getName: function()
    },
    component: {
        getType: function()
    },
    activeObject: {
        // Methods of the single object.
    },
    activeObjects: [{activeObject}] // An array of activeObject
    selection: [ ] // Array of objects. See below.
}
Table 55. Parameters list
Parameter Value type Description Values

application.getId()

String

Returns the application Id.

"swing", …​

area.getType()

String

Returns the area type.

"main" (for the main views), "editor"

area.getName()

String

Returns the area name.

"explorer", "dashboard", "myarea", "liveblogmanagement" (for "main" areas). "story", "gallery" (for editors).

component.getType()

String

Returns the component type.

"toolbar", "grid", "objectpanel"…​

activeObject

Object

Returns an object with a set of methods.

activeObjects

Array

Returns an array of activeObject(s). In bulk selection mode all selected items are returned here as array. In single selection mode array length is 1.

selection

Array of Object

Returns an array with the currently selected items. Each item has the same set of methods available.

Tip

Each context has a different value for these properties.

Custom menu and actions

In Methode Swing it is possible to configure custom menus and custom object actions.

Prepare the plugin to add menus and action

In general, all the extensions of Méthode Swing are places under

{SWING-APP}/plugins

So, all the Javascript described in the following sections should be placed under

{SWING-APP}/app/plugins/{EXTENSION-FOLDER}/{EXTENSION-NAME}.js
Caution

Do not use the word libs as an extension folder. The libs folder is reserved for loading external libs. See the proper documentation to obtain further info on the topic.

Tip

DEBUG MODE: by default, all plugins are aggregated into a single plugins.js file at the Tomcat startup. When creating a plugin, it may be frustrating to restart the Tomcat Server every time a change is made.

To avoid this, set the configuration property debugEnabled to true.

Then, that extension will be loaded on every refresh of the page.

Add a custom menu

In order to add a custom menu to Methode Swing, it is necessary to use the following namespace:

eidosmedia.webclient.extensions.header.newcontentmenu

New menus will be added in the next versions.

The syntax is the following:

eidosmedia.webclient.extensions.header.newcontentmenu.add(name, options);

Where:

  • name [string] is the name of the custom menu, alias a unique identifier.

  • options [optional, object] is a Javascript object containing the properties of the custom actions.

The options parameter can be omitted. In this case, Swing will use the previously registered command with the same name property. See example below.

If options is specified, it must follow the guidelines of a generic Swing command. See Commands documentation for further information.

Example

eidosmedia.webclient.commands.add({
    name: 'complex',
    icon: 'icon-compass',
    label: 'Perform some complex operation...',
    action: function( ctx, params, callback ) {
        if ( ctx.component.getType() === 'menu') {
            alert('hello menu');
            // perform same difficult operations...
            if (callbacks && callbacks.success) {
                callbacks.success( /*...*/ );
            }
        }

    }
});

eidosmedia.webclient.extensions.header.newcontentmenu.add('complex');

Add a custom action to an object

In a conceptually similar way, it is possible to add custom actions to objects. They will be shown in the search results, in the detailed preview of the object, and generally speaking everytime the object is available.

The syntax is the following:

eidosmedia.webclient.extensions.objectactions.add(name, options);

Where:

  • name [string] is the name of the custom menu, alias a unique identifier.

Please note that the name parameter will be also used for the action label localization. The key toolbar.name will be to be used in order to retrieve a translated string from Swing translation files.

  • options [optional, object] is a Javascript object containing the properties of the custom actions.

The options parameter can be omitted. In this case, Swing will use the previously registered command with the same name property. See example below.

If options is specified, it must follow the guidelines of a generic Swing command. See Commands documentation for further information.

Example

eidosmedia.webclient.commands.add({
    name: 'complex',
    icon: 'icon-compass',
    label: 'Perform some complex operation...',
    isActive: function( ctx ) {
        // For some buttons ctx.activeObject is not available.
        return ctx.activeObject && ctx.activeObject.getType() === 'Image';
    },
    action: function( ctx, params, callback ) {
        if ( ctx.component.getType() === 'menu') {
            alert('hello menu');
            // perform same difficult operations...
            if (callbacks && callbacks.success) {
                callbacks.success( /*...*/ );
            }
        }

    }
});

eidosmedia.webclient.extensions.objectActions.add('complex');

Validators

Méthode Swing can be extended by providing the so called validators, that is a set of function to validate the input before it is sent to the Server to be saved.

Location of the Validators extensions

In general, all the extensions of Méthode Swing are places under

{SWING-APP}/plugins

So, all the Javascript described in the following sections should be placed under

{SWING-APP}/app/plugins/{EXTENSION-FOLDER}/{EXTENSION-NAME}.js
Caution

Do not use the word libs as an extension folder. The libs folder is reserved for loading external libs. See the proper documentation to obtain further info on the topic.

Tip

DEBUG MODE: by default, all plugins are aggregated into a single plugins.js file at the Tomcat startup. When creating a plugin, it may be frustrating to restart the Tomcat Server every time a change is made.

To avoid this, set the configuration property debugEnabled to true.

Then, that extension will be loaded on every refresh of the page.

Supported validators

With the evolution of Méthode Swing, more validators will be added. At the moment, the application supports the following validators.

renameFile validator

As the name suggests, the renameFile validator is called whenever the user tries to rename a file. This happens in an opened editor, or in the Explorer area, or during a Worflow/Release action.

To add a renameFile validator, it is necessary to register it inside Swing by calling the following Javascript function, inside your Javascript file:

eidosmedia.webclient.extensions.validators.addValidator('renameFile', function( ctx, onSuccess, onError ) { /* ... */ } );

The function requires three parameters:

  • ctx: The ctx is a JSON object which represents the object’s context. See Basic structure of the Context Object for further details. See the code for further details on the available properties.

  • onSuccess: function to be called when the validation has passed. It wants a single parameter, newName, which is optional. See the code for further details on the parameters.

  • onError: function to be called when the validation failed. It wants a single parameter, errorMessage. See the code for further details.

Example and explanation of parameters

eidosmedia.webclient.extensions.validators.addValidator('renameFile', function( ctx, onSuccess, onError ) {
    // The ctx object contains the following properties.
    // context: 'application'
    // activeObject->getInfo() : {
    //    id: the story id,
    //    newName: the name specified by the user
    //    originalName: the originalName of the file
    // }

    // We obtain the information
    var info = ctx.activeObject.getInfo(); // { id, newName, originalName }

    // SAMPLE IMPLEMENTATION.

    if ( info.newName === "FORBIDDEN.xml" ) {

        // onError = function (errorMessage). Call it with the error message to be shown.
        onError( "This name is absolutely forbidden!" );
        return;
    } else {
        // The parameter is optional. If not passed, the document will be saved with the name specified
        // by the user. Passing the parameter, it is possible to change the name in the validator.
        onSuccess(); // Same as: onSuccess( info.newName );
        // OR
        onSuccess( "VALIDATED_" + info.newName );
    }
});

Editor URL Redirect validator

As the name suggests, the Editor URL Redirect validator is called whenever the user tries to add or edit a url in the Editor Url Redirect.

To add a Editor URL Redirect validator, it is necessary to register it inside Swing by calling the following Javascript function, inside your Javascript file:

eidosmedia.webclient.extensions.validators.addValidator('url-redirect', function( ctx, urlInfo, callback ) { /* ... */ } );

The function requires three parameters:

  • ctx: The ctx is a JSON object which represents the object’s context. See Basic structure of the Context Object for further details. See the code for further details on the available properties.

  • urlInfo: a Javascript object containing all the information regarding the selected url. See the code for further details on the available properties.

  • callback: function to be called when the validation has been completed. See the code to know how to call it.

Example and explanation of parameters

eidosmedia.webclient.extensions.validators.addValidator('url-redirect', function( ctx, urlInfo, callback ) {
    // The ctx object contains the following properties.
    // context: 'editor'
    // area->getName: 'editor-url-redirect',
    // activeObject->getInfo() : the document information.

    // The urlInfo contains the following properties
    // urlInfo: {
    //  type: 'redirect' // or 'permanentredirect', or 'temporaryredirect' or 'forward'
    //  url: the starting url
    //  redirect: the target url
    //  isEditing: true / false ( if the url is a new one or not )
    //}

    // Perform the validation here...
    callback( true ); // Will tell the editor that the validation has passed.
    // callback() or callback( false ) or callback( any falsy value ) will tell the editor that the validation has failed.
}

Editor Extensions

Commands configuration

Méthode Swing allows to add custom commands. Such commands can be launched in different situations, such as external DAM searches, custom Object Panels and widgets. Furthermore, M´thode Swing allows to configure such commands in specific parts of the User Interface (UI) such as, for example, the Toolbar inside the Explorer tab or the Explorer Grid (via Column Catalog).

Prepare the plugin to add commands

In general, all the extensions of Méthode Swing are places under

{SWING-APP}/plugins

So, all the Javascript described in the following sections should be placed under

{SWING-APP}/app/plugins/{EXTENSION-FOLDER}/{EXTENSION-NAME}.js
Caution

Do not use the word libs as an extension folder. The libs folder is reserved for loading external libs. See the proper documentation to obtain further info on the topic.

Tip

DEBUG MODE: by default, all plugins are aggregated into a single plugins.js file at the Tomcat startup. When creating a plugin, it may be frustrating to restart the Tomcat Server every time a change is made.

To avoid this, set the configuration property debugEnabled to true.

Then, that extension will be loaded on every refresh of the page.

Format of a command

A command is represented by a JSON object which should contain at least the following properties:

// Command options
{
    name: "" ,// commandName
    methodeContext: [],
    isActive: function( ctx ) { /* ... */ },
    isEnabled: function( ctx ) { /* ... */ },
    action: function( ctx, params, callback ) { /* ... */ },
    icon: 'icon-compass',
    label: 'My label'
}

name

The unique command name. Please note that the name parameter will be also used for the action label localization. The key toolbar.name will be to be used in order to retrieve a translated string from Swing translation files.

Warning

The command name is mandatory.

methodeContext

The list of applications (JSON Array) where this command should be available, allowed values: swing, desktop (Prime Dashboard), mobile and all.

isActive

The isActive method is used to determine whether a command must be added to the context of reference. That is, for example, whether a custom button should be added to a toolbar.

The isActive method has the Context Object as the only parameters. See Basic structure of the Context Object for further details on the Context Object.

Tip
This is the best place to check for particular privileges.
Warning
Each default Swing context calls the isActive method with different parameters. See Swing default contexts to see the different parameters used by the different Swing contexts.

isEnabled

The isEnabled method is used to determine whether a command must be enabled and disabled according to the current situation. That is, for enable, whether a custom button in a toolbar should be enabled according to the current selection.

The isEnabled method has the Context Object as the only parameters. See Basic structure of the Context Object for further details on the Context Object.

Tip
This is the best place to check for the current selection ( selected items, text selection, etc. according to the context)
Warning
Each default Swing context calls the isEnabled method with different parameters. See Swing default contexts to see the different parameters used by the different Swing contexts.

action( ctx, params, callback )

The action property is a Javascript function which is called when a command is executed.

The parameters are the following:

  • ctx: the Context. See Basic structure of the Context Object for further details on the Context Object.

  • params: a list of params to be passed to the action.

  • callbacks: if available, it is an object containing the success and the error functions.

Warning

Every context inside Méthode Swing calls the commands with different values for the params and the callback arguments. See Swing default contexts to see the different parameters used by the different Swing contexts.

icon

Describes the icon associated with the command.

Tip
The icon property is optional.

label

Describes the label associated with the command.

Tip
The label property is optional.

Register, obtain and execute commands

Commands are, basically, functions that can be called in particular cases. The commands can be associated with specific Swing contexts (such as the Toolbars, or the Grid rows), or can be executed freely from inside the user plugins.

While the basic command format is equal for any case, the command registration is different according to the context of reference. The following paragraphs describe this concept in details.

"Free" command registration and execution

In this case, the user registers a command without associating it with a particular context. For this, all the methods to add, get and execute commands are within the following namespace:

eidosmedia.webclient.commands

Available methods are add, get, exec, defined as follows:

// Add a new command
eidosmedia.webclient.commands.add( command );

// Get the command object
eidosmedia.webclient.commands.get( commandName );

// Execute a command
eidosmedia.webclient.commands.exec( commandName, ... );

add( command )

Adds a command to Méthode Swing. It needs one parameter:

Warning
It is recommended not to use standard names such as edit, save, etc. because there is the risk to override standard Swing commands.
Example
eidosmedia.webclient.commands.add({
    name: 'myCustomCommand',
    icon: 'icon-compass',
    label: 'Perform some complex operation...',
    isActive: function( ctx ) {
        // check privileges...
        return true;
    },
    isEnabled: function( ctx ) {
        // check current selected items...
        return true;
    },
    action: function( ctx, params, callbacks ) {
        if ( ctx.component.getType() === 'toolbar') {
            // perform same difficult operations...
            if (callbacks && callbacks.success) {
                callbacks.success( /*...*/ );
            }
        }

    }
});

get( commandName )

Return a Javascript Object containing all the properties of the command, as defined in the previous set method.

Example
var cmd = eidosmedia.webclient.commands.get( 'myCustomCommand' );

/*
Now cmd is: {
    icon: 'icon-compass',
    label: 'Perform some complex operation...',
    isActive: function( ctx ) {
        // check privileges...
        return true;
    },
    isEnabled: function( ctx ) {
        // check current selected items...
        return true;
    },
    action: function( ctx, params, callback ) {
        if ( ctx.component.getType() === 'toolbar') {
            // perform same difficult operations...
            if (callbacks && callbacks.success) {
                callbacks.success( /*...*/ );
            }
        }

    }
*/

exec( commandName, …​ )

It is the method to execute a particular command.

var result = eidosemdia.webclient.commands.exec('myCustomCommand', ctx, params, callbacks );

The only mandatory param is commandName, which is the name of the command to execute. All the other parameters are passed as-is to the command.

Warning

As said above, Méthode Swing calls the custom commands with three parameters: ctx, params and callback. The nature of these parameters changes according to which context is using the command. See Swing default contexts to see the different parameters used by the different Swing contexts.

Tip

Of course, if the custom commands are used only within your extensions ( and not by default Swing contexts ), it is possible to use any parameter of choice.

Sample
/** in a custom widget, for example */

var btn = document.getElementById('myButton');

$(btn).on('click', function() {
    eidosmedia.webclient.commands.exec('myCustomCommand', 'all', 'my', 'parameters', 'here', true, [ { everything: 'ok' } ]);
});

Registration of a command to a context

See Swing default contexts for further info on how to register and work with different Swing contexts.

Swing default contexts

Explorer Toolbar

Context Object properties for the Explorer Toolbar

The Object Panel context has the following values:

Table 56. Parameters list
Parameter Values Description

area.getType()

"main"

area.getName()

"explorer"

component.getType()

"toolbar"

activeObject.getId()

String

Return the ID of the current folder / query opened in the Explorer.

activeObject.getInfo()

JSON

Return the info of the current folder / query opened in the Explorer.

activeObject.getType()

JSON

Return the type of the current folder / query opened in the Explorer.

activeObject.invalidate() (additional)

(void)

Invalidates all the changes and refresh the content of the current folder / query.

selection

JSON Array

Returns an array with the currently selected items in the folder/query. Each item has the same set of methods available.

Associate commands to the toolbar

It is possible to register the command with the commands.add method ( see add( command ) for futher details ).

Then the commands must be associated to the toolbar as follows:

eidosmedia.webclient.actions.explorer.toolbar.addButton({
    action: "COMMAND NAME",
    label: "Label",
    icon: "Icon"
});

or, it is possible to pass directly the command object to the same function, e.g. :

eidosmedia.webclient.actions.explorer.toolbar.addButton({
    name: "cox.resetPriority",
    isActive: function( ctx ) { /* ... */ },
    isEnabled: function( ctx ) { /* ... */ },
    action: function( ctx, params, callbacks ) { /* ... */ },
    icon: 'icon-compass',
    label: 'My label'
});
Tip

The toolbar actions are called without a params and a callbacks parameter.

Grid Items

These values are valid for any grid. At the moment, only the Explorer grid is managed.

Context Object properties for the Grid Item

The Object Panel context has the following values:

Table 57. Parameters list
Parameter Values Description

component.getType()

"grid-item"

component.getId()

String

Not available

activeObject.getId()

String

Return the ID of the current item (grid row).

activeObject.getInfo()

JSON

Return the info of the current item (grid row).

activeObject.getType()

JSON

Return the type of the current item (grid row).

selection

JSON Array

Not available (empty array)

It is possible to register the command with the commands.add method ( see add( command ) for futher details ).

Then the commands must be associated to the grid item as follows:

eidosmedia.webclient.actions.explorer.grid.addEditor({
    action: "COMMAND NAME",
    label: "Label",
    icon: "Icon"
});

or, it is possible to pass directly the command object to the same function, e.g. :

eidosmedia.webclient.actions.explorer.grid.addEditor({
    name: "cox.resetPriority",
    isActive: function( ctx ) { /* ... */ },
    isEnabled: function( ctx ) { /* ... */ },
    action: function( ctx, params, callbacks ) { /* ... */ },
    icon: 'icon-compass',
    label: 'My label'
});

Object panel

Context Object properties for the ObjectPanel

The Object Panel context has the following values:

Table 58. Parameters list
Parameter Values Description

component.getType()

"objectpanel"

component.getId()

String

The id of the ObjectPanel DOM Element ( e.g. '#em-metadata-area' )

activeObject.getId()

String

Return the ID of the current object

activeObject.getInfo()

JSON

Return the info of the current object

activeObject.getType()

JSON

Return the type of the current object

selection

JSON Array

Not available (empty array)

Additional methods in the Context Object for Object Panel.
Table 59. Parameters list
Method Available in

activeObject.getUniqueMetadataId()

preFillForm - postFillForm - preSave - postSave - onClose

activeObject.setReadonly()

preFillForm - postFillForm - preSave - postSave - onClose

activeObject.showLoading()

preFillForm - postFillForm - preSave - postSave - onClose

activeObject.hideLoading()

preFillForm - postFillForm - preSave - postSave - onClose

activeObject.getMetadataXML()

preFillForm - postFillForm - preSave - validate - postSave - onClose

activeObject.setMetadataXML()

preFillForm - onClose

activeObject.getImage()

onImageProcessing

activeObject.setFieldValue()

postFillForm - preSave

activeObject.getFieldValue()

postFillForm - preSave

activeObject.refreshMetadata()

postFillForm - postSave - onClose

activeObject.saveMetadata()

preFillForm - postFillForm - onClose

activeObject.refreshPanel()

onUpdatesAvailable - onEvent

getUniqueMetadataId()

Return the same unique id used in the HTML panel whenever a -<%=uniqueMetadataId%> has been used to generate a unique Id.

The syntax is the following:

var uniqueId = ctx.activeObject.getUniqueMetadataId(); // e.g "5";
var uniqueId = ctx.activeObject.getUniqueMetadataId(); // e.g "5";
// In this way we ensure that the only the current custom panel is referenced
$('#myCustomPanel-' + uniqueId) // ...
setReadonly()

Creates a readonly layer over the object Panel. The syntax is the following:

ctx.activeObject.setReadonly( [value] );

Value can be true (default) or false.

showLoading(), hideLoading()

Shows or hides a loading element. The syntax is the following:

ctx.activeObject.showLoading( options);
{object} options - An object containing an optional message to display during the loading process, a color and backgroundColor of the text message.

ctx.activeObject.hideLoading( );

getMetadataXML()

Return the current metadata XML as a document object.

setMetadataXML( metadataXML )

Sets the the new metadata XML ( only in the preFillForm and onClose method ).

getImage()

Returs a Promise resolved with the current active object image raw data

setFieldValue( data-id, value)

Sets programmatically a value to the field having the data-id provided. Value MUST be in the format expected by DTD.

Use always this method to set programmatically a value to be compatible with bulk mode.

getFieldValue( data-id )

Get the current value from the field having data-id. The returned field value is in the format expected by DTD.

Use always this method to get programmatically a value to be compatible with bulk mode.

refreshMetadata()

Refresh the current Metadata.

Warning

This will cause a reload of the objectPanel, and consequently a call to "preFillForm" and "postFillFrom" methods.

refreshPanel()

Refresh the current Object panel.

saveMetadata()

Saves the current Metadata. Before saving, the "preSave" method is called. After saving, the "postSave" method is called. In bulk mode this method saves metadata for all selected objects even if called from a particular activeObject.

Editor extensions

Méthode Swing Text editor can be extended in multiple parts by adding custom buttons and executing custom actions.

Location of the Editor extensions.

Editor extensions consist in a Javascript (*.js) file loaded with Swing.

In general, all the extensions of Méthode Swing are places under

{SWING-APP}/plugins

So, all the Javascript described in the following sections should be placed under

{SWING-APP}/app/plugins/{EXTENSION-FOLDER}/{EXTENSION-NAME}.js
Caution

Do not use the word libs as an extension folder. The libs folder is reserved for loading external libs. See the proper documentation to obtain further info on the topic.

Tip

DEBUG MODE: by default, all plugins are aggregated into a single plugins.js file at the Tomcat startup. When creating a plugin, it may be frustrating to restart the Tomcat Server every time a change is made.

To avoid this, set the configuration property debugEnabled to true.

Then, that extension will be loaded on every refresh of the page.

Namespaces of the editor extensions

Editor extensions are available under the following namespace:

eidosmedia.webclient.actions.editor

This namespace delves into more sub-namespaces, according to the part of the editor the user want to extend. At the moment, the following namespaces are supported:

eidosmedia.webclient.actions.editor.toolbar // To add buttons and actions in the editor toolbar

eidosmedia.webclient.actions.editor.components // To add buttons and actions in the swing components

The approach to use is the same throughout all the namespaces.

Configure editor actions

Throughout this document, the example will focus on the development of a simple custom command, named custom.PrependText, which will prepend a specific text to the current selection.

To add an editor action, then, it is necessary to follow the steps described below:

1. Add a custom command

The editor extensions follow the same approach of Swing commands.

See the Command configuration paragraph for further details.

Example

eidosmedia.webclient.commands.add({
    name: 'custom.PrependText',
    isActive: function( ctx ) {
        // check privileges...
        return true;
    },
    isEnabled: function( ctx ) {
        // check current selected items...
        return true;
    },
    action: function( ctx, params, callbacks ) {
        if ( ctx.component.getType() === 'toolbar') {
            // perform same difficult operations...
            if (callbacks && callbacks.success) {
                callbacks.success( /*...*/ );
            }
        }

    }
});
Tip

The details of the implementation of the isEnabled and isActive method will be explained later.

2. Register the commands in the different areas

As a second step, the newly created command must be associated to the specific areas of the editor.

2.a Editor toolbar and custom tabs

To add a button to the Editor toolbar, the following namespace must be used

eidosmedia.webclient.actions.editor.toolbar

The method to be used is addButton(settings). See the following example:

/**
 * We now register a new action in the editor toolbar using
 * the proper namespace. In this case we call the addButton
 * method for the toolbar visible in the editor instance. We
 * define a label and an icon for the button and more important
 * we tell the button which command has to trigger using the
 * action property
 */
eidosmedia.webclient.actions.editor.toolbar.addButton({
    action: "custom.PrependText",
    label: "Prepend Xml",
    icon: 'icon-edit',
    tabId: 'custom-tab-id'
});

The addButton method requires a single Javascript object ( settings ) as a parameter. This objects need to have the following properties:

  • action: the name of the previously registered command

  • label: the label associated with the command

  • icon: the icon associated with the command.

Important

Buttons can be placed under custom tabs. See Editor custom tabs for more information.

Important

By defining an order property, it is possible to change the order of the buttons in the toolbar (only for the Editor).

Warning

If you need to use the call the same command from different parts of the editor ( e.g. the toolbar and some components ), or you need to differentiate the components for which the command is available, you can ( and should ) verify the origin of the action by checking the Context Object Component Type. This is detailed in the Verify the component type paragraph.

Editor custom tabs

Swing story editor toolbar is divided in tabs. By default, all the custom buttons are added to a specific "Custom Actions" tab. It is possible, though, to define multiple (2 at maximum) custom tabs and to place the custom buttons accordingly. To add a custom tab, write the following:

/**
 * We now register a new tab in the editor toolbar using
 * the proper namespace. The tab name must be used in the <tabId> property of the custom button.
 */
eidosmedia.webclient.extensions.editor.tabs.add({
    name: 'em-tab-custom',
    label: 'Swing custom actions'
});

To add the button to a tab, use the following syntax:

eidosmedia.webclient.actions.editor.toolbar.addButton({
    action: "custom.PrependText",
    label: "Prepend Xml",
    icon: 'icon-edit',
    tabId: 'em-tab-custom'
});
Important
  • If the registered tab has no associated buttons, it will not be shown.

  • All the custom buttons who do not have a "tabId" property will be added to the usual "Custom Actions" tab.

2.b Editor components

To add a button to the Editor components, the following namespace must be used

eidosmedia.webclient.actions.editor.components

The method to be used is addButton(settings). See the following example:

/**
 * We now register a new action in the editor component using
 * the proper namespace. In this case we call the addButton
 * method for the components available in the editor instance. We
 * define a label and an icon for the button and more important
 * we tell the button which command has to trigger using the
 * action property
 */
eidosmedia.webclient.actions.editor.components.addButton({
    action: "custom.PrependText",
    label: "Prepend Xml",
    icon: 'icon-edit',
    allowReadOnly: false,
    singleItem: true
});

The addButton method requires a single Javascript object ( settings ) as a parameter. This objects need to have the following properties:

  • action: the name of the previously registered command

  • label: the label associated with the command

  • icon: the icon associated with the command.

  • allowReadOnly: if true the button is visible in the component when the story is read only.

  • singleItem: if true the button is visible in a single element of a component with multiple items, for example Collection and Gallery component.

Warning

If you need to use the call the same command from different parts of the editor ( e.g. the toolbar and some components ), or you need to differentiate the components for which the command is available, you can ( and should ) verify the origin of the action by checking the Context Object Component Type. This is detailed in the Verify the component type paragraph.

Warning

singleItem attributte is available only for elements in a Collection and Gallery component. In the action method the second paramater contains the selectedItem object.

2.c Editor components Drop Down menu

It’s possible to add one or more buttons in a drop down menu. In this case the submenu property has to be added to the settings object:

  • submenu: the object containing the buttons to be added in the drop down menu

/**
 * We now register a new drop down menu action in the editor component using
 * the proper namespace. In this case we call the addButton
 * method for the components available in the editor instance. We
 * define a label and an icon for the drow down menu and more important
 * we set the submenu property that contains the button of the drop down menu
 */
eidosmedia.webclient.actions.editor.components.addButton({
    action: "example.customDropDown",
    label: "Custom popup",
    name: "submenu.customDropDown",
    icon: 'icon-copy',
    allowReadOnly: false,
    submenu: {
            videoPreview: {
                action: "example.openVideoPreview",
                label: "Open Video Preview",
                icon: 'fa fa-video-camera'
            },
            customEdit: {
                action: "example.customEditing",
                label: "Custom editing",
                icon: 'icon-edit',
            }
    }
});

Implementation of the editor extensions

The editor extensions are powerful because they make use of an editor-related version of the context object. See Basic structure of the Context Object for further details.

As of any command implementation, it is possible to specify the isActive, isEnabled and action methods.

  • isActive method is called in different points according to the editor part it refers to.

    • For the toolbar the method is called after the story is loaded to determine whether a custom action is available.

    • For the components the method is called when a new component is created ( or an existing one is loaded from the story )

  • isEnabled method is called in different points according to the editor part it refers to.

    • For the toolbar the method is called whenever the user changes the current selection or cursor position.

  • the action is called when the user clicks on the corresponding action button.

Tip

All the methods are called with the same Context Object ( ctx ), which is enhanced for the editor and allows to access the current document ( activeDocument ). See Basic structure of the Context Object foo further details.

Tip

Starting from 5.2020.11 version the same Context Object ( ctx ), is enhanced for the editor, ONLY for the editor of story, and allows to access the current document with a new property ( activeDocumentV2 ). In Swing Mobile App, due to Android platform (ONLY for Android), the activeDocument object is null. The activeDocumentV2 provides the same functionality of activeDocument in an asynchronous fashion way. See Basic structure of the Context Object foo further details.

Warning

In the Editor context, activeObj and selection are NOT available. The available methods are:

  • {ctx}.component.getType(), which returns one of the following values:

    • toolbar for the Editor toolbar

    • image for the Editor Component "Image"

    • video for the Editor Component "Video"

    • More to come…​

  • {ctx}.component.getSubType(), in case a component can embed, in addition to the main type, another type, which returns one of the following values:

    • video for the element "Video"

    • More to come…​

Example the image component can embed also a video element.

In addtion only in teh Editor context the following methods are available for the element info:

  • {ctx}.component.getXPath(), The xpath of the element info

  • {ctx}.component.getAttributes(), The attributes of the element info

Important

The Editor Context Object is enriched by an additional object, named activeDocument, which contains a subset of methods to access the current document. These methods are described in the Editor API paragraph.

Important

Starting from 5.2020.11 version, the Editor Context Object is enriched by an additional object, named activeDocumentV2, which contains a subset of methods to access, in an asynchronous way, the current document. These methods are described in the Editor API paragraph.

Editor API

Suggestions for the Editor extensions

Verify the component type

Since the Editor Context object contains a method

ctx.component.getType();

it is possible to use it in the isEnabled and isActive methods to check the kind of component which is calling the action.

    // EXCERPT FROM THE COMMAND CODE
    isActive: function( ctx ) {
        if ( ctx.component.getType() === 'toolbar') {
            return true;
        }
        return false;
    },
    isEnabled: function( ctx ) {
        // Enabling the action for the editable image only.
        if ( ctx.component.getType() === ctx.activeDocument.CONSTANTS.BLOCK_IMAGE) {
            return true;
        }
        return false;
    },
Tip

Checking the component type is mandatory in case of actions added to the Editor components namespace. Otherwise, the action will be available for all components. It’s possible to use some constants defined in the activeDocument:

ctx.activeDocument.CONSTANTS.BLOCK_IMAGE ctx.activeDocument.CONSTANTS.BLOCK_VIDEO

Use of Editor API and extensions in Object Panel

Only for the Object Panel of an opened story, the activeDocument object of the Editor API is available. So, it is possible, from the Object Panel, to call custom actions and manipulate the current document.

It is suggested, though, to verify if the {ctx}.activeDocument is available to show and hide editor-related parts in the Object Panel. See example below:

// From the object panel API
    ready: function( ctx ) {
        // some other code...
        if ( ctx.activeDocument ) {
            // We are in the Editor.
            $('.custom-editor-metadata-panel').show();

            // Use it to manipulate the document

            var sel = ctx.activeDocument.getSelection();
            // ...

        }
    }

Starting form 5.2020.11 version only for the Object Panel of an opened story, the activeDocumentV2 object of the Editor API is available. So, it is possible, from the Object Panel, to call custom actions and manipulate the current document.

It is suggested, though, to verify if the {ctx}.activeDocumentV2 is available to show and hide editor-related parts in the Object Panel.

To learn how to extend the Object Panel, see Object panel documentation.

Full example of Editor extension

eidosmedia.webclient.commands.add({
    name: "custom.PrependText",
    action: function(ctx, params, callback) {
        var editorApi = ctx.activeDocument;
        // Obtain the current selection
        var sel = editorApi.getSelection();
        // Supposedly check the current selection ( if it a Content Item, ... )
        sel.insertXml('<p>test</p>', 'insertBefore');
    },

    isActive: function( ctx ) {
        // Enables it only for toolbar or Editable Image
        var componentType = ctx.component.getType();
        if ( componentType === 'toolbar' || componentType === 'editableimage' )
            return true;
        else
            return false;
    },

    isEnabled: function( ctx ) {
        var selection = ctx.activeDocument.getSelection();
        var contentItem = sel.getContentItem();

        if ( contentItem ) {
            return true;
        }
        return false;
    }
});

/**
 * We now register a new action in the editor toolbar using
 * the proper namespace. In this case we call the addButton
 * method for the toolbar visible in the editor instance. We
 * define a label and an icon for the button and more important
 * we tell the button which command has to trigger using the
 * action property
 */
eidosmedia.webclient.actions.editor.toolbar.addButton({
    action: "custom.PrependText",
    label: "Prepend Xml",
    icon: 'icon-edit'
});

eidosmedia.webclient.actions.editor.components.addButton({
    action: "custom.PrependText",
    label: "Prepend Xml",
    icon: 'icon-gear'
});

// Example for custom action for a single element in a Collection or Gallery component
eidosmedia.webclient.commands.add({
    name: "example.openVideoPreview",
    action: function(ctx, params, callback) {

        // params contains the selectedItem
        var selectedItem = params.selectedItem;

        // checks selectedItem values

    },

    isActive: function( ctx ) {
        // Handle condition activation
        return true;
    },

    isEnabled: function( ctx ) {
        // Handle condition enable
        return true;
    }
});

/**
 * We now register a new action in the editor components using
 * the proper namespace. We tell the button which command has to trigger using the
 * action property
 */
eidosmedia.webclient.actions.editor.components.addButton({
    action: "example.openVideoPreview",
    label: "Open Video Preview",
    icon: 'icon-facetime-video',
    singleItem: true
});

Override editor’s default counter

Swing editor comes with a default counter for chars and words. On the one hand, it is possible to specify an additional counter under the Editor configuration ; on the other hand, it is possible to completely override the counter behaviour by defining the following function.

eidosmedia.webclient.editor.counter = function( counterInfo, storyInfo, userInfo ) { /* function here */ }
Table 60. Method information

Method

counter

Parameter

{object} counterInfo - An object containing the information about the counter.

  • {integer} chars - the number of chars in the relative contentItem ( the document, unless different configurations )

  • {integer} words - the number of words in the relative contentItem ( the document, unless different configurations )

  • {string} contentItemType - the name of the selected contentItem ( only in case of "contentItem" setting for Editor/Story/Count/Type ).

  • {string} xpath - the xpath of the selected item ( only in case of "contentItem" setting for Editor/Story/Count/Type and a list of conteintItems is configured Editor/Story/Count/contentItems).

  • {string} customLabel - the value for the custom label ( only if specified in the Story editor configuration )

  • {integer} customValue - the value for the custom value ( only if specified in the Story editor configuration )

  • {boolean} currentNodeEmpty - true if the current node is empty

  • {string} occupation - the task occupation value inherited by the document.

Parameter

{object} storyInfo - An object containing the information about the current document.

  • {string} channel - The story channel

  • {various info} - try to use a console.log(storyInfo) to see all the passed information. Please stick to the "classic" properties ( channel, id, name ) for the others may change in the future.

Parameter

{object} userInfo - An object containing the information about the current user.

  • {various info} - try to use a console.log(userInfo) to see all the passed information.

Returns

{String} - the function should return the HTML for the counter area.

So, if the user wants to override the counter behaviour, the eidosmedia.webclient.editor.counter method provides all the available information. The result of the function MUST be a valid HTML which is placed in the "counter area" of the Editor.

Tip
To create a separator, use an empty DIV with the class "em-info-separator" (see examples below).
Warning
If you need to use this features, you’ll probably need to change the Editor > Story > Count configuration to contentItem. See the Story Editor Configuration.

Full working example

The following example warns the user if the number of characters in a particular content item is reaching ( or above ) the maximum level. It only works with the "contentItem" configuration.

(function() {
    eidosmedia.webclient.editor.counter = function( countInfo, storyInfo, userInfo ) {
        var charsStyle = '';
        var html = '';

        var countLimits = {
            'headline': 50,
            'text': 1500
        };

        var countXpathLimits = {
            '/doc/story/grouphead/headline': 10,
        };
        var found = false;

        if (countInfo.xpath) {
            var MAX_CHARS_IN_XPATH = countXpathLimits[ countInfo.xpath ];
            found = MAX_CHARS_IN_XPATH != null;
            if ( MAX_CHARS_IN_XPATH &&
                 countInfo.chars > MAX_CHARS_IN_XPATH ) {
                 charsStyle = 'color: white; font-weight: bold; background-color: red;';
            } else if ( MAX_CHARS_IN_XPATH &&
                        countInfo.chars > (MAX_CHARS_IN_XPATH*0.75) ) {
                // We have gone over the 75% of the allowed number of characters
                charsStyle = 'color: black; font-weight: bold; background-color: orange;';
            }
        }

        if ( !found && countInfo.contentItemType ) {
            var MAX_CHARS_IN_CONTENTITEM = countLimits[ countInfo.contentItemType ];
            if ( MAX_CHARS_IN_CONTENTITEM &&
                 countInfo.chars > MAX_CHARS_IN_CONTENTITEM ) {
                charsStyle = 'color: white; font-weight: bold; background-color: red;';
            } else if ( MAX_CHARS_IN_CONTENTITEM &&
                        countInfo.chars > (MAX_CHARS_IN_CONTENTITEM*0.75) ) {
                // We have gone over the 75% of the allowed number of characters
                charsStyle = 'color: black; font-weight: bold; background-color: orange;';
            }
        }

        html += '<span class="em-info-container" style="' + charsStyle +
                '"><b>Chars:</b> <span id="chars_counter">' + (countInfo.chars || 0) +
                '</span></span>';
        html += '<span class="em-info-container" id="words_counter_box">' +
                '<b>Words:</b> <span id="words_counter">' + (countInfo.words || 0) +
                '</span></span>';

        if ( countInfo.customValue ) {
            html += '<span class="em-info-container"><b id="custom_counter_label">' +
                    countInfo.customLabel + '</b><span id="custom_counter">' +
                    countInfo.customValue + '</span></span>';
        }
        return html;
    }
})();

Loaded document callback action

It is possible to register an action that would be called when the Swing editor has finished loading the current document. This action will be provided with the context object for the editor extensions and will be able to access the current document Editor API (activeDocument) and activeObject.

Example

(function () {
  // Register the after load callback
  eidosmedia.webclient.extensions.editor.afterLoad.register(function (ctx) {
    var team = ctx.getCurrentUserInfo().team;

    // Access the current loaded document
    var node = ctx.activeDocument.getNode({ xpath: "/doc/story/summary/p" });
    node.replaceTextContent("Team: " + team);
  });
})();

General information on the Editor API

Editor API allows the user to perform different operations on the currently opened document. They are available within the Context Object, when the user is editing a Story.

Warning

Editor API are to be considered as a feature in progress. Changes and additions may be made without warning.

Tip

In the source code, we will refer to the Context Object as a generic "ctx" object.

activeDocument

The activeDocument is the entry point of the Editor API. It contains a set of different methods to analyze and manage the currently opened document.

Methods of the activeDocument object

getXmlContent

Returns the complete XML content of the document.

It can be called as

ctx.activeDocument.getXmlContent();
Table 61. Method information

Method

getXmlContent

Parameter

None

Returns

{String} The XML document as a string.

Example
// Obtains the XML of the document.
var xml = ctx.activeDocument.getXmlContent();

// For example, we can parse the XML with jQuery and use it somehow.
var parsedXML = $.parseXML( xml );

// ...
getTextContent

Returns the complete text content of the document.

It can be called as

ctx.activeDocument.getTextContent(options);
Table 62. Method information

Method

getTextContent

Parameter

Optional {object} options - An object containing the some options. It can contains the following properties:

  • Optional {Boolean} includeWhitespaceNodes - true if you want to include the whitespace nodes.

Returns

{String} The text content of the document as a string.

Example
// Obtains the text content of the document.
var options = {};
// Uncomment this line if you want to include witespace nodes
options.includeWhitespaceNodes = true;

var text = ctx.activeDocument.getTextContent(options);

// ...
getMetadata

Returns the complete Metadata of the document as a string.

It can be called as

ctx.activeDocument.getMetadata( callbacks );
Table 63. Method information

Method

getMetadata

Parameter

{object} callbacks - An object containing the callbacks. It contains the following properties:

  • Required {Function} success - the function to be called when the Metadata is retrieved. It has a single parameter, the metadata as a string.

  • Optional {Function} error - the function to be called when an error occurred.

Returns

undefined

Warning

This call is asynchronous. The Metadata string is available only as the parameter of the success callback.

Example
// Obtains the Metadata of the document
ctx.activeDocument.getMetadata({
    success: function( metadata ) {
        // Do something with this...
    },
    error: function( err ) {
        // For example.
        ctx.showError( err.message );
    }
});
getSelection

Returns the current Selection in the active document.

Tip

The current selection is an object of type Selection. See Selection object for further information on available methods.

It can be called as

ctx.activeDocument.getSelection();
Table 64. Method information

Method

getSelection

Parameter

None

Returns

{Selection} The current selection object

Example
// Obtains the current selection.
var sel = ctx.activeDocument.getSelection();

// sel is now a Selection object.
// For example, we can verify that the current selection is a ContentItem

var selNode = sel.getNode();

if ( selNode.nodeType === ctx.activeDocument.CONSTANTS.CONTENTITEM_TYPE ) {
    // Perform a specific action...
}
insertXML

Insert an XML in a specified part of the document.

It can be called as

ctx.activeDocument.insertXML(xml, xpathOptions, insertOptions);
Table 65. Method information

Method

insertXML

Parameter

{String} xml - The xml to insert, as a string.

e.g. <p>Append me</p>

Parameter

{object} xpathOptions - Contains the information on the XPath to append the XML to. It contains the following properties:

  • Required {String / Array} xpath - the xpath to append the xml to, as a string (single xpath) or array (multiple xpaths).

    • NOTE: if xpath is set to the value cursorPosition the new content will be inserted at the cursor position replacing the current selection if not collapsed.

  • Optional {Array} criteria - an array of objects containing the criteria to further detail the node to select. Each object contains the following properties, all required:

    • {String} param the attribute to test (e.g. xsm-preserve). The eom-name is not a valid attribute if specified it will be ignored.

    • {String} condition the operator to use in the selector. Can be equal or contains.

    • {String} value the value to test for.

See example below.

Parameter

{object / string} insertOptions the options to insert the XML in the selected node. If used as an object, it contains the following properties:

  • Optional {String} insertType - determines where to insert the xml with respect to the node. Defaults to append, can be prepend or insertBefore (which both prepend the content to the selected node).

Otherwise, it is possible to directly pass the insertType as a string (append, prepend or insertBefore)

Returns

{Boolean} true if the operation was executed correctly

Warning

At the moment, if the specified xpath in the xpathOptions corresponds to more than one xPath, only the first is taken.

// Prepares the xml.
var xml = '<p>Prepend me</p>';

ctx.activeDocument.insertXml( xml, {
    xpath: 'doc/story/text/superbyline',
    criteria: {
        [
            param: 'xsm-preserve',
            condition: 'equal',
            value: 'true'
        ]
    } },
    'prepend' );

// the xml will be inserted only in the first superbyline tag that satisfy xpath and the additional (optional) criteria


// Prepares the xml.
var xml = '<h1><?EM-dummyText lorem ipsum?></h1>';

ctx.activeDocument.insertXml( xml, {xpath: 'cursorPosition'});

// the xml will be inserted at the cursor position, replacing the current selection if not collapsed.
getDocumentInfo

Returns a subset of information on the current document. The information includes the following information : channel, workfolder, issueDate, templateName, language.

It can be called as

ctx.activeDocument.getDocumentInfo();
Table 66. Method information

Method

getDocumentInfo

Parameter

None

Returns

{JSON Object} Information on the current document

Example
// Obtains the document information.
var documentInfo = ctx.activeDocument.getDocumentInfo();

/*
    documentInfo is now:
    {
        "id": "id",
        "readonly": true,
        "channel": "CHANNEL",
        "workfolder": "WORKFOLDER",
        "issueDate": "ISSUE DATE",
        "templateName": "TEMPLATE NAME",
        "language": "en/uk"
    }

*/

if ( documentInfo.channel === 'Globe-Web' ) {
    // ... do something, for example it can remove a specific custom button.
}
isReadonly

Returns the readonly status of the story

It can be called as

ctx.activeDocument.isReadonly();
Table 67. Method information

Method

isReadonly

Parameter

None

Returns

{Boolean} true if the story is readonly

Example
// Obtains the document information.
var isReadonly = ctx.activeDocument.isReadonly();
saveDocument

Execute the save of the current document.

It can be called as

ctx.activeDocument.saveDocument();
Table 68. Method information

Method

saveDocument

Parameter

Optional {Function} callback - A function invoked if the the document is successfully saved

Warning

If the document is not dirty, the save is not executed, but the callback, if defined, is always invoked.

Example
// Save the current document.
ctx.activeDocument.saveDocument();
getNode

Returns a specific node, as a DocumentNode object, upon the information contained in the XPath

It can be called as

ctx.activeDocument.getNode(xpathOptions);
Table 69. Method information

Method

getNode

Parameter

{object} xpathOptions - Contains the information on the XPath to append the XML to. It contains the following properties:

  • Required {String / Array} xpath - the xpath to append the xml to, as a string (single xpath) or array (multiple xpaths).

  • Optional {object} absolute [default: false] - if true, the search is limited to the absolute XPath.

  • Optional {Array} criteria - an array of objects containing the criteria to further detail the node to select. Each object contains the following properties, all required:

    • {String} param the attribute to test (e.g. eom-name, xsm-preserve)

    • {String} condition the operator to use in the selector. Can be equal or contains.

    • {String} value the value to test for.

Return

{DocumentNode} A document node object containing. See DocumentNode interface object for details on the Document Node object.

Warning

At the moment, if the specified xpath in the xpathOptions corresponds to more than one node, only the first is taken.

Example
// prepare the xpath options
var xpathOptions = {
    xpath: 'doc/story/text',
    criteria: {
      [ param: 'channel',
        condition: 'equal',
        value: 'Globe-Print'
      ]
    }
};

// Obtains the node.
var node = ctx.activeDocument.getNode(xpathOptions);

// Perform actions on the found node
// ...
if (node) {
...

}
insertExternalUrl

Insert an external URL in the document, upon the information contained in the object to insert and in the provided options

It can be called as

ctx.activeDocument.insertExternalUrl(item, insertOptions);
Table 70. Method information

Method

insertExternalUrl

Parameter

{object} item - Contains the information about the object to insert. It contains the following properties:

  • Required {String} url - the url of the object to insert.

  • Required {String} type - the type of the object to insert. The suppoerted type are the following:

    • webimage insert the object in the EOMDB and try to insert the created object as image

    • externalwebpage insert the object as link in the opened document

    • embedurl insert the object as embed code bock if the provided url is a supported embed

Parameter

{object} insertOptions - Contains additional option to insert the object. Right now not used, for future purpose

Return

{Boolean} true if the object has been successfully inserted, false otherwise.

Example
// prepare the object to insert
var item = {
    'url': 'https://images-assets.nasa.gov/image/GSFC_20171208_Archive_e001240/GSFC_20171208_Archive_e001240~orig.jpg',
    'type': 'web::image'
};

// Perform the insert.
ctx.activeDocument.insertExternalUrl(item, {});
insertObject

Insert a list of Methode Object in the document, upon the information contained in the reference object to insert and in the provided insertOptions

It can be called as

ctx.activeDocument.insertObject(reference, insertOptions);
Table 71. Method information

Method

insertObject

Parameter

{object} reference - Contains the information about the object to insert. It contains the following properties:

  • Required {Boolean} full - if true the provided object list containing all the information about the objects to insert, if false, only an idntifier is provided (i.e. path or loid or uuid) and the information about the object is retrieved during insertion.

  • Optional {Boolean} withPath - if true the list of objects identifiers is composed of paths, otherwise of loid or uuid. This parameter is checked only whe the referenceListIds is provided

  • Optional {Array} referenceListIds - The list of objects identifiers to insert. It can be composed of paths, loids or uuids.

  • Optional {Array} referenceListObjects - The list of objects to insert. It is composed of the full object info.

    • NOTE: referenceListIds or referenceListObjects must be provided

Parameter

{object} insertOptions - Contains additional option to insert the object.

  • Required {String} insertionType [insert, embed, link] - The type of insertion that must be performed

  • Optional {Object} templateInfo - Info about the information of the template used to insert the object.

    • Optional {String} name name of the template to use, configured in the dtx. If not specified, the user can subsequently choose which template to use

    • Optional {String} type The type of the object to insert. If not specified it will be obtained from the type of objects to be inserted

Return

{Boolean} true if the objects has been successfully inserted, false otherwise.

Example
// prepare the object to insert
// Two image objects will be inserted using the paths
const reference = {
    full: false,
    referenceListIds: ['/Globe/Images/Foreign/11.obama_family.jpeg', '/Globe/Images/Foreign/1420087334.jpg'],
    withPath: true
}

// Example One
const insertOptionsOne = {
    insertiontype: "insert"
};

// Perform the insert.
ctx.activeDocument.insertObject(reference, insertOptionsOne);

// Example Two
const insertOptionsTwo = {
    insertiontype: "insert",
    templateInfo: {name: "", type: eomeditor.publicapi.TEMPLATE_TYPE.IMAGE}
};

// Perform the insert.
ctx.activeDocument.insertObject(reference, insertOptionsTwo);

// Example Three
const insertOptionsThree = {
    insertiontype: "insert",
    templateInfo: {name: "image web square", type: eomeditor.publicapi.TEMPLATE_TYPE.IMAGE}
};

// Perform the insert.
ctx.activeDocument.insertObject(reference, insertOptionsThree);
setDocumentToBeRefreshed

Some events in Swing are not handled. This API could be useful when some actions are fired and they change the document server side. This way, it’s possible to warn the user that the document should be refresh.

It can be called as

ctx.activeDocument.setDocumentToBeRefreshed(options);
Table 72. Method information

Method

setDocumentToBeRefreshed

Parameter

{object} options - Contains additional option. Right now not used, for future purpose

Return

{Boolean} true if the operation has been successfully executed, false otherwise.

Example
action: function(ctx, params, callback) {

    var editorApi = ctx.activeDocument;

    editorApi.setDocumentToBeRefreshed();
}
switchToChannel(channel)

Switch the document to the specified channel

It can be called as

ctx.activeDocument.getCollectionSelectedItems(attrOptions)
Table 73. Method information

Method

switchToChannel

Parameter

Required {String} channel - A string containing the channel in form of "Product/Edition".

// Switch to channel
ctx.activeDocument.switchToChannel(channel);

Constants of the activeDocument object

The activeDocument object comes with a set of constants to simplify the management of the return values of the different methods.

The constants are available under

activeDocument.CONSTANTS

Currently the following constants are visible:

ctx.activeDocument.CONSTANTS = {
    DUMMY_TYPE: 'DummyText', // Document Node type
    CONTENTITEM_TYPE: 'ContentItem', // Document Node type
    CONTENTBLOCK_TYPE: 'ContentBlock', // Document Node type
    CONTENTNODE_TYPE: 'ContentNode', // Document Node type,
    BLOCK_IMAGE: 'image', // ContentBlock of type Image
    BLOCK_VIDEO: 'video', // ContentBlock of type Video
};

activeDocumentV2

The activeDocumentV2 is an entry point of the Editor API starting form version 5.2020.11. It contains a set of different methods to analyze and manage the currently opened document in an asynchronous way that are cross platform compatible (Swing, Swing Mobile, Prime). Starting from the version 5.2020.11, we reccomend to use activeDocumentV2 and evaluating the migration for existing extensions.

Methods of the activeDocumentV2 object

getXmlContent

Returns the complete XML content of the document or a part of it based on the options parameter.

It can be called as

ctx.activeDocumentV2.getXmlContent(options);
Table 74. Method information

Method

getXmlContent

Parameter

  • Optional {object} options - An object containing the criteria of the portion of the document on which to obtain the xml content:

    • Optional {boolean} uesSelection - if true the xml of the selected node will be returned.

    • Optional {object} xpathOptions - if specified the xml of the idnetified node by information in xpath will be returned. For more info see the same API for the activeDocument object.

      • Required {String / Array} xpath - the xpath to append the xml to, as a string (single xpath) or array (multiple xpaths).

      • Optional {Array} criteria - an array of objects containing the criteria to further detail the node to select. Each object contains the following properties, all required:

        • {String} param the attribute to test (e.g. xsm-preserve). The eom-name is not a valid attribute if specified it will be ignored.

        • {String} condition the operator to use in the selector. Can be equal or contains.

        • {String} value the value to test for.

If options is not specied or if it’s an empty object the xml of the entire docment will be returned.

Returns

{Function} A promise function.

Example
// Obtains the XML of the document.
ctx.activeDocumentV2.getXmlContent({}).then(result => {
    console.log(`V2 async document result: ${result}`);
}).catch(error => {
    console.log(`V2 async document error: ${error}`);
});

// Obtains the XML of the current selection
ctx.activeDocumentV2.getXmlContent({useSelection: true}).then(result => {
    console.log(`V2 async result selection: ${result}`);
}).catch(error => {
    console.log(`V2 async error selection: ${error}`);
});

// Obtains the XML of a specific node
var xpathOptions = {
              'xpath': 'doc/story/text'
};

ctx.activeDocumentV2.getXmlContent({xpathOptions}).then(result => {
    console.log(`V2 async xpath result: ${result}`);
}).catch(error => {
    console.log(`V2 async xpath error: ${error}`);
});
// ...
getTextContent

Returns the complete text content of the document.

It can be called as

ctx.activeDocumentV2.getTextContent();
Table 75. Method information

Method

getTextContent

Returns

{Function} A promise function.

Example
// Obtains the text of the document.
ctx.activeDocumentV2.getTextContent().then(result => {
    console.log(`V2 async document result: ${result}`);
}).catch(error => {
    console.log(`V2 async document error: ${error}`);
});

// ...
replaceXmlContent

Replaces the XML content of a node.

It can be called as

ctx.activeDocumentV2.replaceXmlContent(options);
Table 76. Method information

Method

replaceXmlContent

Parameter

  • Required {object} options - An object containing the criteria of node on which to replace content:

    • Required {String} newContent - the xml content.

    • Required {object} xpathOptions - if specified the xml of the idnetified node by information in xpath will be returned.

      • Required {String / Array} xpath - the xpath to append the xml to, as a string (single xpath) or array (multiple xpaths).

      • Optional {Array} criteria - an array of objects containing the criteria to further detail the node to select. Each object contains the following properties, all required:

        • {String} param the attribute to test (e.g. xsm-preserve). The eom-name is not a valid attribute if specified it will be ignored.

        • {String} condition the operator to use in the selector. Can be equal or contains.

        • {String} value the value to test for.

Return

{Function} A promise function

// prepare the xpath options
var xpathOptions = {
    xpath: 'doc/story/summary',
    criteria: {
        [
            param: 'channel',
            condition: 'equal',
            value: 'Globe-Print'
        ]
    }
};

// REPLACE XML content
ctx.activeDocumentV2.getXmlContent({xpathOptions}).then( content => {
    var newContent = '<summary id="U26664270086oOb"><p>New summary content</p></summary>';
    ctx.activeDocumentV2.replaceXmlContent({newContent, xpathOptions}).then(result => {
        console.log('content replaced')
    });
})

...
//
saveDocument

Execute the save of the current document.

It can be called as

ctx.activeDocumentV2.saveDocument();
Table 77. Method information

Method

saveDocument

Return

{Function} A promise function

Warning

If the document is not dirty, the save is not executed, but the promise is always resolved.

Example
// Save the current document.
ctx.activeDocumentV2.saveDocument().then(result => {
    console.log(`save operation successfully excuted`);
}).catch(error => {
    console.log(`an error occurred saving the document`);
});
insertXmlContent

Insert an XML in a specified part of the document..

It can be called as

ctx.activeDocumentV2.insertXmlContent(options);
Table 78. Method information

Method

insertXmlContent

Parameter

  • Required {object} options - An object containing the criteria of node on which to replace content:

    • Required {String} xmlContent - the xml content to insert.

    • Required {object} xpathOptions - if specified the xml of the idnetified node by information in xpath will be returned.

      • Required {String / Array} xpath - the xpath to append the xml to, as a string (single xpath) or array (multiple xpaths).

      • NOTE: if xpath is set to the value cursorPosition the new content will be inserted at the cursor position replacing the current selection if not collapsed.

      • Optional {Array} criteria - an array of objects containing the criteria to further detail the node to select. Each object contains the following properties, all required:

        • {String} param the attribute to test (e.g. xsm-preserve). The eom-name is not a valid attribute if specified it will be ignored.

        • {String} condition the operator to use in the selector. Can be equal or contains.

        • {String} value the value to test for.

Return

{Function} A promise function

var xpathOptions = {
    xpath: 'cursorPosition'
};
var xmlContent = '<h1><?EM-dummyText lorem ipsum?></h1>';
activeDocumentV2.insertXmlContent({xmlContent, xpathOptions}).then(result => {
    console.log('content has been inserted');
}).catch(error => {
    console.log('content has not been inserted');
});

...
//

Selection object

The Selection Object allows to manipulate the selection. It contains a set of properties and methods described below.

Methods

getNode

Returns the current selected node, as a DocumentNode object.

It can be called as

{SelectionObject}.getNode();
Table 79. Method information

Method

getNode

Parameter

Optional {Object} options Additional options to get the node.

- Set options.getWrappedSection = true if it’s needed to get the section wrapped node

Return

{DocumentNode} A document node object containing the current selection. See DocumentNode interface object for details on the Document Node object.

// Obtains the document selection
var sel = ctx.activeDocument.getSelection();

var selectedNode = sel.getNode();

// Perform actions on the selected node
// ...
getXmlContent

Returns the XML of the current Selection.

It can be called as

{SelectionObject}.getXmlContent();
Table 80. Method information

Method

getXmlContent

Parameter

None

Return

{String} The xml of the current selection as a String

// Obtains the document selection
var sel = ctx.activeDocument.getSelection();

var selectedXml = sel.getXmlContent();

// Perform actions on the selected node
// ...
Tip

Calling {Selection}.getXmlContent() when a ContentBlock node is selected is equal to call {ContentBlock}.getXmlContent() or {Selection}.getNode().getXmlContent().

insertXml

Insert an XML in a specified part of the current selection or replaces the current selection with the new XML.

It can be called as

{SelectionObject}.insertXML(xml, insertOptions);
Table 81. Method information

Method

insertXML

Parameter

{String} xml - The xml to insert, as a string.

e.g. <p>Append me</p>

Parameter

{object / string} insertOptions the options to insert the XML in the selected node. If used as an object, it contains the following properties:

  • Optional {String} insertType - determines where to insert the xml with respect to the node. Defaults to append, can be prepend or insertBefore (which both prepend the content to the selected node), replace (replace the content of the selected node with the provided xml).

Otherwise, it is possible to directly pass the insertType as a string (append, prepend or insertBefore, replace)

Returns

{Boolean} true if the operation was executed correctly

// Obtains the document information.
var xml = '<p>Prepend me</p>';
var sel = ctx.activeDocument.getSelection();

sel.insertXml( xml, 'prepend' );
prepend, append

Insert an XML in a specified part of the current selection. They are shortcuts method for insertXml.

It can be called as

{SelectionObject}.prepend(xml);
{SelectionObject}.append(xml);

See insertXml for further details.

getTextContent

Returns the text content of the current Selection.

It can be called as

{SelectionObject}.getTextContent();
Table 82. Method information

Method

getTextContent

Parameter

Optional {object} options - An object containing the some options. It can contains the following properties:

  • Optional {Boolean} includeWhitespaceNodes - true if you want to include the whitespace nodes.

Return

{String} The text content of the current selection as a String

// Obtains the document selection
var sel = ctx.activeDocument.getSelection();

var options = {};
// Uncomment this line if you want to include witespace nodes
// options.includeWhitespaceNodes = true;
var text = sel.getTextContent(options);

// ...
Tip

Calling {Selection}.getTextContent() when a ContentBlock node is selected an empty string will be returned.

DocumentNode interface

It is the lowest-level object available for manipulating the Active Document. It represents a node within the document. It contains different methods and properties to interact with the node.

Tip

The DocumentNode object is NOT a DOM node, so operation as $(<DocumentNode>) will not work.

Properties

nodeType

Return the node type. Can be one of the following:

  • ContentItem

  • ContentNode

  • ContentBlock

  • DummyText

Tip

Verify the value of this property against the Constants of the activeDocument object to perform the best check.

Tip

Each Document Node type has specific methods. See Types for details on each document node.

var sel = ctx.activeDocument.getSelection();
var selectedNode = sel.getNode();

if ( selectedNode.nodeType === ctx.activeDocument.CONSTANTS.DUMMY_TYPE ) {
    // It is a dummy text...
    sel.append('<p>New text here</p>');
}
contentItem

Returns the contentItem in which the element is contained. It can be one of two values:

  • null, if the element is not part of any contentItem, or it is a contentItem itself.

  • {DocumentNode} ContentItem the document node of type 'ContentItem'. See ContentItem for further details.

Methods

getXmlContent

Returns the XML of the node.

It can be called as

{DocumentNode}.getXmlContent();
Table 83. Method information

Method

getXmlContent

Parameter

None

Return

{String} The xml of the node as a String

// prepare the xpath options
var xpathOptions = {
    xpath: 'doc/story/text',
    criteria: {
       [
        param: 'channel',
        condition: 'equal',
        value: 'Globe-Print'
        ]
    }
};

// Obtains the node.
var node = ctx.activeDocument.getNode(xpathOptions);

// Perform actions on the found node
// ...
if (node) {
    var xmlContent = node.getXmlContent();

}
replaceXmlContent

Replaces the XML content of the current node.

It can be called as

{DocumentNode}.replaceXmlContent();
Table 84. Method information

Method

replaceXmlContent

Parameter

{String} xml - The xml content that replaces the current content node.

Return

{Boolean} True if replacement succeeded

// prepare the xpath options
var xpathOptions = {
    xpath: 'doc/story/summary',
    criteria: {
        [
            param: 'channel',
            condition: 'equal',
            value: 'Globe-Print'
        ]
    }
};

// Obtains the node.
var node = ctx.activeDocument.getNode(xpathOptions);

// Perform actions on the found node
// ...
if (node) {
    var repxml = '<summary id="U26664270086oOb"><p>New summary content</p></summary>';
    node.replaceXmlContent(repxml);
}
getTextContent

Returns the text content of the node.

It can be called as

{DocumentNode}.getTextContent();
Table 85. Method information

Method

getTextContent

Parameter

Optional {object} options - An object containing the some options. It can contains the following properties:

  • Optional {Boolean} includeWhitespaceNodes - true if you want to include the whitespace nodes.

Return

{String} The text content of the node as a String

// prepare the xpath options
var xpathOptions = {
    xpath: 'doc/story/text',
    criteria: {
       [
        param: 'channel',
        condition: 'equal',
        value: 'Globe-Print'
        ]
    }
};

// Obtains the node.
var node = ctx.activeDocument.getNode(xpathOptions);

// Perform actions on the found node
// ...
if (node) {

    var options = {};
    // Uncomment this line if you want to include witespace nodes
    // options.includeWhitespaceNodes = true;

    var text = node.getTextContent(options);

    // ....

}
replaceTextContent

Replace the text of the node with another text.

It can be called as

{DocumentNode}.replaceTextContent(text);
Table 86. Method information

Method

replaceTextContent

Parameter

{String} text - The text to replace with.

Parameter

{object} replaceOptions - Contains additional information about the replace operation.

  • Options {String} format - the format of the string used to replace the selected text (e.g. 'xml')

Returns

{Boolean} true if the operation was executed correctly

Warning

Right now to execute the replace the API use the information in the current selection.
If a text node is selected the replace is executed with success, otherwise an exception is thrown.
It the selection is not collapsed the current selection is removed and the new text is inserted.
If the selection is collapsed the content of the parent node is checked.
If the text node is not the only child of the parent node the new text wil l be inserted at the cursor position.
Otherwise the entire content of the parent node will be replaced with the new text.

// Obtains the current selection.
var sel = ctx.activeDocument.getSelection();
var selectedNode = sel.getNode();

// Replace the text of the current node with simple text
selectedNode.replaceTextContent( 'Simple text' );

// Replace the text of the current node with an xml format
selectedNode.replaceTextContent('<a href="http://www.eidosmedia.com" title="Eidosmedia">Eidosmedia</a>', {'format': 'xml'});
getContentInfo

Returns an object that contains a set of different methods to analyze and manage the current node.

Warning

This method is valid only for content nodes that refers to Methode Content: Images, External content items.
If the selected is not a valid one an exception is thrown.

API functions to get and set system attributes and metadata of an image linked to a story

It can be called as

{DocumentNode}.getContentInfo();
Table 87. Method information

Method

getContentInfo

Parameter

None

Return

{Object} Returns an object with a set of methods.

// Obtains the current selection.
var sel = ctx.activeDocument.getSelection();
var selectedNode = sel.getNode();

// Perform actions on the found node
// ...
if (selectedNode) {
    var ctx = selectedNode.getContentInfo();

    var id = ctx.getId();
    var type = ctx.getType();
    var sysAttributes = ctx.getSysAttributes();
    var usageTickets = ctx.getUsageTickets();
}
getAttributes

Get node attributes.

It can be called as

{DocumentNode}.getAttributes();
Table 88. Method information

Method

getAttributes

Parameter

None

Return

{Array} An array of objects {{name: String, value: String}} that represent all the attributes of the XML node that have a value.

// Obtains the current selection.
var sel = ctx.activeDocument.getSelection();
var selectedNode = sel.getNode();

// Perform actions on the found node
if (selectedNode) {
    var attributes = selectedNode.getAttributes();

    // ...
}
setAttributes

Set attributes to a node.

It can be called as

{DocumentNode}.setAttributes();
Table 89. Method information

Method

setAttributes

Parameter

{Object} options - The object containing information about attributes to set.

  • Required {Array} attributes - an array of objects pair name/value. If the value is empty the attribute will be removed.

Return

{Boolean} True if replacement succeeded

Warning

Don’t use this API to set the channel attribute.
To set the channel attribute it’s mandatory to use the specific API setChannels

// prepare the xpath options
var xpathOptions = {
    xpath: 'doc/story/summary',
    criteria: {
        [
            param: 'channel',
            condition: 'equal',
            value: 'Globe-Print'
        ]
    }
};

// Obtains the node by x path.
var node = ctx.activeDocument.getNode(xpathOptions);

// To obtain the node by selection uncomment the following lines
// var sel = editorApi.getSelection();
// var node = sel.getNode();

var attrOptions = {};
var attributes = [{'name': 'testattr', 'value': 'testvalue'}];
attrOptions.attributes = attributes;

// Perform actions on the found node
// ...
if (node) {
    node.setAttributes(attrOptions);
}
setExternalReference

Set a refence of a Methode object to a node.

It can be called as

{DocumentNode}.setExternalReference();
Table 90. Method information

Method

setExternalReference

Parameter

Required {String} reference - The object containing information about attributes to set.

Parameter

Optional {Object} settings - Additional options to use setting the reference.

  • Optional {Boolean} cover true the image cover the placeholder

  • Optional {Boolean} hardCrop true the image object is hard cropped

  • Optional {Object} tmx tmx information

  • Optional {Object} xtransform xtransform information

Return

{Boolean} True if replacement succeeded

Warning

cover, hardcrop, tmx and xtransform settings are used inserting only images or graphics

var editorApi = ctx.activeDocument;
var sel = editorApi.getSelection();
var node = sel.getNode();

var reference = path o loid of the objects to insert

const settings = {
        cover: true
        hardCrop: false
        tmx: null
        xtransform: null
}
node.setExternalReference( reference, settings );
setChannels

Set channels to a node.

It can be called as

{DocumentNode}.setChannels();
Table 91. Method information

Method

setChannels

Parameter

Required {Array} channels - The array containing the channels to set.

Return

{Boolean} True if set succeeded

// prepare the xpath options
var xpathOptions = {
    xpath: 'doc/story/summary',
    criteria: {
        [
            param: 'highlight',
            condition: 'equal',
            value: 'yes'
        ]
    }
};

// Obtains the node by x path.
var node = ctx.activeDocument.getNode(xpathOptions);

// To obtain the node by selection uncomment the following lines
// var sel = editorApi.getSelection();
// var node = sel.getNode();

var channels = ['Globe-Web'];

// Perform actions on the found node
// ...
if (node) {
    node.setChannels(channels);
}

Types

There are four different DocumentNode types.

ContentItem

Its nodeType can be checked against ctx.activeDocument.CONSTANTS.CONTENTITEM_TYPE.

It has some specific methods:

duplicate

Duplicates a contentItem.

It can be called as

{ContentItem}.duplicate(channel);
Table 92. Method information

Method

duplicate

Parameter

{String} channel - The channel to duplicate the ContentItem to. To duplicate it in more channels, separate them with a comma.

e.g. Globe-Web,Globe-Print

Returns

{Boolean} true if the operation was executed correctly

// Obtains the current selection.
var sel = ctx.activeDocument.getSelection();
var selectedNode = sel.getNode();

if ( selectedNode.nodeType === ctx.activeDocument.CONSTANTS.CONTENTITEM_TYPE ) {
    // it is a ContentItem node. Duplicate itself.
    selectedNode.duplicate( 'Globe-Web,Globe-Print' );
} else {
    // Duplicates the container ContentItem.
    selectedNode.contentItem.duplicate( 'Globe-Web,Globe-Print' );
}
duplicateContent

Copy the content of the ContentItem node into another node.

It can be called as

{ContentItem}.duplicateContent(xpathOptions);
Table 93. Method information

Method

duplicateContent

Parameter

{object} xpathOptions - Contains the information on the XPath to copy the XML to. It contains the following properties:

  • Required {String / Array} xpath - the xpath to append the xml to, as a string (single xpath) or array (multiple xpaths).

  • Optional {Array} criteria - an array of objects containing the criteria to further detail the node to select. Each object contains the following properties, all required:

    • {String} param the attribute to test (e.g. eom-name, xsm-preserve)

    • {String} condition the operator to use in the selector. Can be equal or contains.

    • {String} value the value to test for.

See example below.

Returns

{Boolean} true if the operation was executed correctly

Warning

At the moment, if the specified xpath in the xpathOptions corresponds to more than one node, only the first is taken.

// Obtains the current selection.
var sel = ctx.activeDocument.getSelection();
var selectedNode = sel.getNode();

var xpathOptions = {
    xpath: 'doc/story/text',
    criteria: {
        [
            param: 'xsm-preserve',
            condition: 'equal',
            value: 'true'
        ]
    }
};

if ( selectedNode.nodeType === ctx.activeDocument.CONSTANTS.CONTENTITEM_TYPE ) {
    // it is a ContentItem node. Duplicate its own content.
    selectedNode.duplicateContent( xpathOptions );
} else {
    // Duplicates the content of the container ContentItem.
    selectedNode.contentItem.duplicateContent( xpathOptions );
}
ContentNode

Its nodeType can be checked against ctx.activeDocument.CONSTANTS.CONTENTNODE_TYPE.

It has no specific methods at the moment.

ContentBlock

Its nodeType can be checked against ctx.activeDocument.CONSTANTS.CONTENTBLOCK_TYPE.

Its blockType can be checked against ctx.activeDocument.CONSTANTS.BLOCK_*.

Methods common to all the ContentBlocks
getXmlContent

Returns the XML of the current node.

It can be called as

{ContentBlock}.getXmlContent();
Table 94. Method information

Method

getXmlContent

Parameter

None

Return

{String} The xml of the current selection as a String

// Obtains the document selection
var sel = ctx.activeDocument.getSelection();
var selectedNode = self.getNode();

if ( selectedNode.nodeType === ctx.activeDocument.CONSTANTS.CONTENTITEM_TYPE ) {
    var xml = selectedNode.getXmlContent();
    // ...
}
replaceXmlContent

Replaces the XML content of the current node.

It can be called as

{ContentBlock}.replaceXmlContent();
Table 95. Method information

Method

replaceXmlContent

Parameter

{String} xml - The xml content that replaces the current content node.

Return

{Boolean} True if replacement succeeded

Warning

If the specified xml doesn’t contain a special element an error occurred. A block content can be replaced only with another block content. Right now we can replace only imageElement, videoElement and objectElement

// Obtains the document selection
var sel = ctx.activeDocument.getSelection();
var selectedNode = self.getNode();

if ( selectedNode.nodeType === ctx.activeDocument.CONSTANTS.CONTENTBLOCK_TYPE ) {

    var xml = '<photo-web><fw-photo width="200" height="200"></fw-photo>' +
    '<photo-caption channel="Globe-Web"><?EM-dummyText Insert caption first here?><p><?EM-dummyText Insert caption here?></p></photo-caption></photo-web>';

    var result = selectedNode.replaceXmlContent(xml);
    // ...
}
Image Block

It represents an Image Block. Its blockType can be checked against ctx.activeDocument.CONSTANTS.BLOCK_IMAGE.

copyImage( xpathOptions, settings )

Copies the image into other image elements, maintaining the crop and the transformation information.

It can be called as

{ContentBlock}.copyImage(xpathOptions, settings)
Table 96. Method information

Method

copyImage

Parameter

{object} xpathOptions - Contains the information on the XPath to copy the image to. It contains the following properties:

  • Required {String / Array} xpath - the xpath to append the xml to, as a string (single xpath) or array (multiple xpaths).

  • Optional {Array} criteria - an array of objects containing the criteria to further detail the node to select. Each object contains the following properties, all required:

    • {String} param the attribute to test (e.g. eom-name, xsm-preserve)

    • {String} condition the operator to use in the selector. Can be equal or contains.

    • {String} value the value to test for.

See example below.

Parameter

{object} settings additional options to change the copy Image behaviour.It contains the following properties:

  • Optional {Boolean} cover - If true, applies an effect similar to css background-size:cover property. If omitted, the default value is false.

  • Optional {Boolean} hardCrop - If true, applies the hardCrop parameter to the copied image. If omitted, the default value is false.

  • Optional {Boolean} copy - If true, create a copy of the object before linking the image to the selected placeholder. If omitted, the default value is false.

Returns

{Boolean} true if the operation was executed correctly

Warning

At the moment, if the specified xpath in the xpathOptions corresponds to more than one xPath, only the first is taken.

// Obtains the current selection
var sel = ctx.activeDocument.getSelection();
var selNode = sel.getNode();

// Check if it is an image block

if ( selNode.blockType === ctx.activeDocument.CONSTANTS.BLOCK_IMAGE ) {

    var xpathOptions = {
      'xpath': 'doc/story/text/photo-web/fw-photo',
      'criteria': [
          {'param': 'eomattr',
          'condition': 'equal',
          'value': 'true'}
        ]
    };

    selNode.copyImage(xpathOptions, { 'cover': true, 'hardCrop': false, 'copy': true });
}
changeAlignment( align, settings )

Change the alignment of a block component.

It can be called as

{ContentBlock}.changeAlignment(align, settings)
Table 97. Method information

Method

changeAlignment

Parameter

Required {String} align - The align to set, allow values: left, right, center, fullwidth, background.

Parameter

Optional {object} settings Additional options right now not used for future purpose

See example below.

// Obtains the current selection
var sel = ctx.activeDocument.getSelection();
var selNode = sel.getNode();

// Check if it is an image block
if ( selNode.blockType === ctx.activeDocument.CONSTANTS.BLOCK_IMAGE ) {
    selNode.changeAlignment('center');
}
changeBlockDimensions( dimensions, settings )

Change width and height of a block.

It can be called as

{ContentBlock}.changeBlockDimensions(xpathOptions, settings)
Table 98. Method information

Method

changeBlockDimensions

Parameter

Required {object} dimensions - Contains the width and height to set.

Parameter

Optional {object} settings Additional options right now not used for future purpose

See example below.

// Obtains the current selection
var sel = ctx.activeDocument.getSelection();
var selNode = sel.getNode();

// Check if it is an image block
if ( selNode.blockType === ctx.activeDocument.CONSTANTS.BLOCK_IMAGE ) {
    var dimensions = {'width': 300, 'height': 300};
    selNode.changeBlockDimensions(dimensions);
}
Video Block

It has no specific methods at the moment.

Collection Block

It represents a Collection Block. It can be of three types: insert, embed or link. Its blockType can be checked against ctx.activeDocument.CONSTANTS.BLOCK_COLLECTION_INSERT, ctx.activeDocument.CONSTANTS.BLOCK_COLLECTION_EMBED, ctx.activeDocument.CONSTANTS.BLOCK_COLLECTION_LINK.

setItemAttributes(attrOptions)

Set attributes to an item of a collection .

It can be called as

{ContentBlock}.setItemAttributes(attrOptions)
Table 99. Method information

Method

setItemAttributes

Parameter

{object} attrOptions - Contains the information on the item and attributes to set. It contains the following properties:

  • Required {Array} attributes - an array of objects pair name/value. If the value is empty the attribute will be removed.

  • Optional {Boolean} selected - it true the attributes will be applied to the collection selected item.

  • Optional {Integer} index - the index of THE item to apply the attributes (the index is not zero-based):

Returns

{Boolean} true if the operation was executed correctly

Warning

At least selected or index must be specified, otherwise the attributes will be not applied.

// Obtains the current selection
var sel = ctx.activeDocument.getSelection();
var selNode = sel.getNode();

// Check if it is a collection block

if ( selNode.blockType === ctx.activeDocument.CONSTANTS.BLOCK_COLLECTION_INSERT ||
        selNode.blockType === ctx.activeDocument.CONSTANTS.BLOCK_COLLECTION_EMBED ||
        selNode.blockType === ctx.activeDocument.CONSTANTS.BLOCK_COLLECTION_LINK) {

    var options = {};
    var attributes = [{'name': 'eomtest', 'value': 'test'}, {'name': 'class', 'value': 'testclass'}];
    options.attributes = attributes;
    options.selected = true; // the attributes will be applied to the selected item

    selNode.setItemAttributes(options);
}
getCollectionSelectedItems(attrOptions)

Get the selected items of a collection .

It can be called as

{ContentBlock}.getCollectionSelectedItems(attrOptions)
Table 100. Method information

Method

getCollectionSelectedItems

Parameter

{object} attrOptions - Contains the information on the attributes to search. It contains the following properties:

  • Optional {Array} attributes - an array of objects pair name/value. If empty the selected items will be returned.

Returns

{Boolean} an index array of selected items

// Obtains the current selection
var sel = ctx.activeDocument.getSelection();
var selNode = sel.getNode();

// Check if it is a collection block

if ( selNode.blockType === ctx.activeDocument.CONSTANTS.BLOCK_COLLECTION_INSERT ||
        selNode.blockType === ctx.activeDocument.CONSTANTS.BLOCK_COLLECTION_EMBED ||
        selNode.blockType === ctx.activeDocument.CONSTANTS.BLOCK_COLLECTION_LINK) {

    var options = {};
    // Uncomment this lines if you want to get items with a specific attribute value
    /* var attributes = [{'name': 'lead', 'value': 'test'}];
    options.attributes = attributes; */

    var selectedItems = selNode.getCollectionSelectedItems(options);
}
DummyText

Its nodeType can be checked against ctx.activeDocument.CONSTANTS.DUMMY_TYPE.

It has no specific methods at the moment.

From activeDocument to activeDocumentV2

Follows some examples to compare the use of activeDocument and activeDocumentV2 to perform the same operation.

getXmlContent

Example
// ***** activeDocument ******
// Obtains the current selection.
var sel = ctx.activeDocument.getSelection();

// get the node
var selNode = sel.getNode();

var xmlContent = node.getXmlContent();

// ***** activeDocumentV2 ******
// Obtains the XML of the current selection
ctx.activeDocumentV2.getXmlContent({useSelection: true}).then(result => {
    console.log(`V2 async result selection: ${result}`);
}).catch(error => {
    console.log(`V2 async error selection: ${error}`);
});

// ...

getTextContent

Example
// ***** activeDocument ******
// Obtains the text
var textContent = ctx.activeDocument.getTextContent();

// ***** activeDocumentV2 ******
// Obtains the XML of the current selection
ctx.activeDocumentV2.getTextContent().then(result => {
    console.log(`V2 async result selection: ${result}`);
}).catch(error => {
    console.log(`V2 async error selection: ${error}`);
});

// ...

replaceXmlContent

Example
// ***** activeDocument ******
// prepare the xpath options
var xpathOptions = {
    xpath: 'doc/story/summary',
    criteria: {
        [
            param: 'channel',
            condition: 'equal',
            value: 'Globe-Print'
        ]
    }
};

// Obtains the node.
var node = ctx.activeDocument.getNode(xpathOptions);

// Perform actions on the found node
// ...
if (node) {
    var repxml = '<summary id="U26664270086oOb"><p>New summary content</p></summary>';
    node.replaceXmlContent(repxml);
}

// ***** activeDocumentV2 ******
// prepare the xpath options
var xpathOptions = {
    xpath: 'doc/story/summary',
    criteria: {
        [
            param: 'channel',
            condition: 'equal',
            value: 'Globe-Print'
        ]
    }
};

// REPLACE XML content
ctx.activeDocumentV2.getXmlContent({xpathOptions}).then( content => {
    var newContent = '<summary id="U26664270086oOb"><p>New summary content</p></summary>';
    ctx.activeDocumentV2.replaceXmlContent({newContent, xpathOptions}).then(result => {
        console.log('content replaced')
    });
})

// ...

saveDocument

Example
// ***** activeDocument ******
ctx.activeDocument.saveDocument();

// ***** activeDocumentV2 ******
// Save the current document.
ctx.activeDocumentV2.saveDocument().then(result => {
    console.log(`save operation successfully excuted`);
}).catch(error => {
    console.log(`an error occurred saving the document`);
});

// ...

insertXmlContent

Example
// ***** activeDocument ******
var newXmlContent = '<h1><?EM-dummyText lorem ipsum?></h1>';
var retValue = ctx.activeDocument.insertXml(newXmlContent, {xpath: 'cursorPosition'});

// ***** activeDocumentV2 ******
var xpathOptions = {
    xpath: 'cursorPosition'
};
var xmlContent = '<h1><?EM-dummyText lorem ipsum?></h1>';
activeDocumentV2.insertXmlContent({xmlContent, xpathOptions}).then(result => {
    console.log(`content has not been inserted`);
}).catch(error => {
    console.log(`content has not been inserted ${error}`);
});

// ...

General information on the GalleryEditor API

GalleryEditor API allows the user to perform different operations on the currently opened document. They are available within the Context Object, when the user is editing a Gallery.

Warning

GalleryEditor API are to be considered as a feature in progress. Changes and additions may be made without warning.

Tip

In the source code, we will refer to the Context Object as a generic "ctx" object.

activeDocument

The activeDocument is the entry point of the GalleryEditor API. It contains a set of different methods to analyze the currently opened document.

Methods of the activeDocument object

getXmlContent

Returns the complete XML content of the document.

It can be called as

ctx.activeDocument.getXmlContent();
Table 101. Method information

Method

getXmlContent

Parameter

None

Returns

{String} The XML document as a string.

Example
// Obtains the XML of the document.
var xml = ctx.activeDocument.getXmlContent();

// For example, we can parse the XML with jQuery and use it somehow.
var parsedXML = $.parseXML( xml );

// ...
getObjectsData

Returns an array containing the list of the data of each object present in the active document.

It can be called as

ctx.activeDocument.getObjectsData();
Table 102. Method information

Method

getObjectsData

Parameter

None

Returns

{Array} The array of data infornation of the all the objects present in the active document

Warning

The objects contained in the array are intended as "read only" objects. Any change made on them will not be reflected in the active document.

Example
// Obtains the current selection.
var objectsData = ctx.activeDocument.getObjectsData();
// objectsData is now an array of objects.

Here below an extract of the data contained in each returned object:

{
    "id": "199$1.0.624088073",
    "type": "Image",
    "name": "Official_portrait_of_Barack_Obama-U47037702204ISU-266x200@Globe-Web.jpg",
    "description": "",
    "owner": "user",
    "creator": "user",
    "created": 1457105152,
    "last_modifier": "user",
    "size": 125008,
    "system_attributes": {
        "workfolder": "",
        "template": "",
        "templateName": "",
        "summary": "",
        "wordCount": "",
        "sugCategory": "",
        "channel": "",
        "title": "...",
        "storyType": "",
        "productInfo": {
            "name": "",
            "issueDate": ""
        },
        "imageInfo": {
            "width": 266,
            "height": 200,
            "ptWidth": 63.84000015258789,
            "ptHeight": 48,
            "colorType": "RGB",
            "processTypes": ["resample"]
        },
        "priority": ""
    },
    "system_attributes_xml": "<props><process><type>resample</type></process><title>...</title><summary/><imageInfo>\n<width>266</width>\n<height>200</height>\n<ptWidth>63.84</ptWidth>\n<ptHeight>48.0</ptHeight>\n<xDim>22.52</xDim>\n<yDim>16.93</yDim>\n<dim>2.252cm x 1.693cm</dim>\n<xres>300.0</xres>\n<yres>300.0</yres>\n<colorType>RGB</colorType>\n<fileType>PNG</fileType>\n</imageInfo></props>",
    "usage_ticket": "<?xml version='1.0' encoding='UTF-8'?><tl></tl>"
}
isCroppedImage

Return a boolean value to check if the image is hard cropped.

It can be called as

ctx.activeDocument.isCroppedImage(loid);
Table 103. Method information

Method

isCroppedImage

Parameter

{String} - The loid of the image in the format: {dbId}${loid} (e.g. 199$1.0.624088073).

Returns

{Boolean} true if the image is hard cropped.

// Obtain the cropped information.
var isCropped = ctx.activeDocument.isCroppedImage(loid);

//check the isCropped variable
saveDocument

Execute the save of the current document.

It can be called as

ctx.activeDocument.saveDocument();
Table 104. Method information

Method

saveDocument

Parameter

Optional {Function} callback - A function invoked if the the document is successfully saved

Warning

If the document is not dirty, the save is not executed, but the callback, if defined, is always invoked.

Dwp Editor extensions

Méthode Swing DWP editor can be extended in multiple parts by adding custom buttons and executing custom actions, or configuring custom templates to render DWP linked objects.

Location of the DWP Editor extensions.

DWP Editor extensions consist in a Javascript (*.js) file loaded with Swing.

In general, all the extensions of Méthode Swing are places under

{SWING-APP}/plugins

So, all the Javascript described in the following sections should be placed under

{SWING-APP}/app/plugins/{EXTENSION-FOLDER}/{EXTENSION-NAME}.js
Caution

Do not use the word libs as an extension folder. The libs folder is reserved for loading external libs. See the proper documentation to obtain further info on the topic.

Tip

DEBUG MODE: by default, all plugins are aggregated into a single plugins.js file at the Tomcat startup. When creating a plugin, it may be frustrating to restart the Tomcat Server every time a change is made.

To avoid this, set the configuration property debugEnabled to true.

Then, that extension will be loaded on every refresh of the page.

Namespaces of the DWP editor extensions

DWP Editor extensions are available under the following namespace:

eidosmedia.webclient.actions.dwpeditor

Configure actions

Throughout this document, the example will focus on the development of a simple custom command, named custom.EditDwplink, which will edit a dwp link custom properties.

To add an action, then, it is necessary to follow the steps described below:

1. Add a custom command

The editor extensions follow the same approach of Swing commands.

See the Command configuration paragraph for further details.

Example

eidosmedia.webclient.commands.add({
    name: 'change.dwpLink',
    isActive: function( ctx ) {
        return true;
    },
    isEnabled: function( ctx ) {
        return true;
    },
    action: function( ctx, params, callbacks ) {
       if (callbacks && callbacks.success) {
          callbacks.success( /*...*/ );
       }
   }
});
Tip

The details of the implementation of the isEnabled and isActive method will be explained later.

2. Associated the commands to item toolbar

As a second step, the newly created command must be associated to the item toolbar. To add a button to the item toolbar, the following namespace must be used

eidosmedia.webclient.actions.dwpeditor

The method to be used is addButton(settings). See the following example:

/**
 * We now register a new action in the item toolbar using
 * the proper namespace. In this case we call the addButton
 * method, we define a label and an icon for the button and more important
 * we tell the button which command has to trigger using the
 * action property
 */
eidosmedia.webclient.actions.dwpeditor.addButton({
    action: "change.dwpLink",
    label: "Chane Dwp Link",
    icon: 'icon-globe'
});

The addButton method requires a single Javascript object ( settings ) as a parameter. This objects need to have the following properties:

  • action: the name of the previously registered command

  • label: the label associated with the command

  • icon: the icon associated with the command.

Implementation of the DWP editor extensions

The editor extensions are powerful because they make use of an editor-related version of the context object. See Basic structure of the Context Object for further details.

As of any command implementation, it is possible to specify the isActive, isEnabled and action methods.

  • isActive method is called in different points according to the editor part it refers to.

    • For the toolbar the method is called after the story is loaded to determine whether a custom action is available.

    • For the components the method is called when a new component is created ( or an existing one is loaded from the story )

  • isEnabled method is called in different points according to the editor part it refers to.

    • For the toolbar the method is called whenever the user changes the current selection or cursor position.

  • the action is called when the user clicks on the corresponding action button.

Tip

All the methods are called with the same Context Object ( ctx ), which is enhanced for the editor and allows to access the active object ( activeObject ). See Basic structure of the Context Object for further details.

Warning

In the Editor context, activeDocument and selection are NOT available.

Important

The Dwp Editor Context Object activeObject contains a subset of methods to access the current dwp link information. These methods are described in the Editor API paragraph.

Dwp Editor API

Returns dwp link information.

It can be called as

ctx.activeObject.getLink();
Table 105. Method information

Method

getLink

Parameter

None

Returns

{JSON Object} Dwp link information

Example
var info = ctx.activeObject.getLink();

// info is now:
{
    "name": "230-Short updates.dwc",
    "id": "1.0.36956807",
    "type": "EOM::WebContainer",
    "modified": {
        "type": "DATE",
        "format": "YYYYMMDDHHmmss",
        "value": "20160323133940"
    },
    "last_modifier": "Dario",
    "locked": {
        "type": "DATE",
        "format": "YYYYMMDDHHmmss",
        "value": "20160323133940"
    },
    "locker": "",
    "webType": "dwc-4stories-230",
    "styleSheet": "List",
    "templates": [
        "Grid",
        "List",
        "230-4rows1col"
    ],
    "status_info": {
        "name": "",
        "identifier": "",
        "comment": ""
    },
    "system_attributes": {
        "workfolder": "/Globe/Politics",
        "template": "",
        "templateName": "/SysConfig/Globe/Web/DwcTemplates/public/230/230-4rows1col.dwc",
        "summary": "",
        "wordCount": "",
        "sugCategory": "",
        "channel": "Globe-Web",
        "storyType": "",
        "productInfo": {
            "name": "Globe-Web",
            "issueDate": "20111005"
        },
        "priority": ""
    },
    "system_attributes_xml": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<props><productInfo><name>Globe-Web</name>\r\n<issueDate>20111005</issueDate>\r\n</productInfo>\r\n<workFolder>/Globe/Politics</workFolder>\r\n<templateName>/SysConfig/Globe/Web/DwcTemplates/public/230/230-4rows1col.dwc</templateName>\r\n</props>\r\n",
    "channel": "Globe-Web",
    "pstate": {
        "uuid": "f8c9bd50-ee54-11e0-b51c-542d5e32b6d1",
        "suid": "",
        "loid": "1.0.36956807",
        "retention_time": 0,
        "ucount": 44
    },
    "position": 1
}
getTemplates

Returns the list of dwp link available templates.

It can be called as

ctx.activeObject.getTemplates();
Table 106. Method information

Method

getTemplates

Parameter

None

Returns

{JSON Array} List of dwp link available templates

Example
var templates = ctx.activeObject.getTemplates();

// templates is now:
[{
	"value":"Grid",
	"selected":false
},{
	"value":"List",
	"selected":true
}, {
	"value":"230-4rows1col"
	,"selected": false
}]
getCustomProperties

Returns the list of dwp link custom properties.

It can be called as

ctx.activeObject.getCustomProperties();
Table 107. Method information

Method

getCustomProperties

Parameter

None

Returns

{JSON Array} List of dwp link custom properties

Example
var properties = ctx.activeObject.getCustomProperties();

// properties is now:
[{
	"key": "customTitle",
	"value": "Alternate title"
}, {
	"key": "customDisplayLink",
	"value": "yes"
}, {
	"key": "customMaxResults",
	"value": "10"
}, {
	"key": "customTitleColor",
	"value": "gray"
}]
setCustomProperties

Set the list of dwp link custom properties.

It can be called as

ctx.activeObject.setCustomProperties(properties);
Table 108. Method information

Method

setCustomProperties

Parameter

{JSON Array} List of dwp link custom properties

Returns

None

Example
var properties = [{
	"key": "customTitle",
	"value": "Alternate title"
}, {
	"key": "customDisplayLink",
	"value": "yes"
}, {
	"key": "customMaxResults",
	"value": "10"
}, {
	"key": "customTitleColor",
	"value": "gray"
}];

ctx.activeObject.setCustomProperties(properties);

Custom DWP linked item templates

Méthode Swing DWP editor uses HTML templates to render linked objects. It is possible to configure custom templates to be used based on linked item type.

Editor configuration

In DWP editor configuration can be specified which HTML template should be used to render a specific item linked type.

<WebClientConfiguration>
    ...
    <editor>
        ...
        <webpage>
            ...
            <linkedItemTemplates>
                <linkedItemTemplate>
                    <type>EOM::CompoundStory</type>
                    <template>dwp-story-template.html</template>
                </linkedItemTemplate>
                <linkedItemTemplate>
                    <type>EOM::WebContainer</type>
                    <template>dwp-dwc-template.html</template>
                </linkedItemTemplate>
            </linkedItemTemplates>
        </webpage>
    </editor>
<WebClientConfiguration>

Configured template files will be retrieved from

{SWING-APP}/config/templates/dwp/{TEMPLATE-NAME}

and can be configured outside {SWING-APP}, see the paragraph How to configure DWP linked item templates in external folder.

Templating system

Underscore.JS templating system is used to define templates.

The template is rendered with a main object item, which contains all the information about the item.

// item:
{
    name: 'ART-stories_block.dwc',
    id: '1.0.895409210',
    databaseId: '41',
    type: 'EOM::WebContainer',
    modified: 1524043188,
    last_modifier: 'john.doe',
    locked: 1542709437,
    // empty string if the item is not locked, username of the locker otherwise
    locker: '',
    webType: 'dwc-element-4row3cols',
    styleSheet: null,
    // stylesheet configured for the zone and applied as default
    defaultStylesheet: 'first',
    // selected template
    template: 'stories_block',
    // available templates
    templates: [
        {
            name: 'stories_block',
            path:
                '/SysConfig/Globe/WebV2/DwcTemplates/public/1060/stories_block.dwc'
        },
        {
            name: 'one_story_2_heads',
            path:
                '/SysConfig/Globe/WebV2/DwcTemplates/public/1060/one_story_2_heads.dwc'
        }
    ],
    status_info: {
        name: '',
        identifier: ''
    },
    // thumbnail preview if available, null otherwise
    preview: null,
    channel: 'Globe-Web',
    owner: 'john.doe',
    creator: 'john.doe',
    created: 1500474152,
    size: 243,
    path: '/Globe/WebV2/Web Components/Art/ART-stories_block(1).dwc',
    issueDate: '20150903',
    system_attributes_xml: 'system attributes XML string',
    system_attributes_json: {
        // system attributes as json object
    },
    usage_ticket: 'usage ticket XML string',
    usage_ticket_json: {
        // usage ticket as json object
    },
    attributes: 'attributes XML string',
    attributes_json: {
        // attributes as json object
    },
    virtual_attributes: 'virtual attributes XML string',
    virtual_attributes_json: {
        // attributes as json object
    },
    summary: '',
    dwc: {
        struct: {
            // dwc container structure as json object, see next section
        },
        links: {
            // dwc linked items, see next section
        }
    },
    // Icon class for type
    iconType: 'emui-icon-dwp',
    // Display label for type
    labelType: 'Web Container'
}

DWC

If a linked item is also a container, e.g. a DWC, the object passed to the template will also have a dwc field, containing information about container structure and linked items.

{
    // ...
    dwc: {
        struct: {
            type: 'container',
            path: 'root',
            pageTemplate: 'stories_block',
            depth: 0,
            slots: 12,
            rowspan: 1,
            id: '41$1.0.895409210',
            channel: 'Globe-Web',
            webType: 'dwc-element-4row3cols',
            rows: [
                {
                    dimension: 1,
                    boxesCount: 3,
                    boxes: [
                        {
                            type: 'zone',
                            path: 'root[r0]-zone0',
                            depth: 1,
                            slots: 5,
                            rowspan: 1,
                            sequence: 1,
                            maxItems: 4,
                            styleSheet: '2col-photo-homepage',
                            name: 'box',
                            zoneIndex: 1
                        }
                        // ...
                    ]
                }
            ],
            dimension: 1
        },
        links: {
            box: [
                {
                    depth: 0,
                    slots: 0,
                    rowspan: 0,
                    sequence: 1,
                    maxItems: 1,
                    styleSheet: '1col-photo-tight-homepage',
                    links: [
                        {
                            id: '1.0.740572086',
                            name: 'Story 1',
                            databaseId: '41',
                            channel: 'Globe-Web',
                            webType: 'story',
                            position: 1,
                            type: 'EOM::CompoundStory',
                            modified: 1522759672,
                            last_modifier: 'john.doe',
                            locked: 1524465039,
                            locker: '',
                            status_info: {
                                name: 'NewsFlow/Editing',
                                identifier: 'RGB(255,0,0)'
                            },
                            system_attributes_json: {
                                // system attributes as json object
                            }
                        }
                    ],
                    zoneIndex: 0
                }
                // ...
            ]
        }
    }
}

Following, a very simple example of a custom template for DWC objects:

<%
    function writeLink(link) {
        %>
            <div><%=link.name%></div>
        <%
        // ...
    }

    function writeRow(row) {
        %>
        <div>DWC row</div>
        <ul>
            <%
                _.each(row.boxes, function(box) {
                    if (box.type === 'zone' || box.type === 'container') {
                        %><li>
                            <div>BOX</div>
                            <%
                                var seqObj = _.findWhere(
                                    item.dwc.links[box.name],
                                    { sequence: parseInt(box.sequence) }
                                );
                                _.each(seqObj && seqObj.links, writeLink);
                            %>
                        </li><%
                    }
                });
            %>
            </ul>
        <%
    }
%>
<div>
    <h1>DWC</h1>
    <p>Name <%=item.name%></p>
    <%
        _.each(item.dwc.struct.rows, writeRow);
    %>
</div>

How to configure DWP linked item templates in external folder

Custom DWP linked item templates may be made available to Swing application by defining one or more nested components in Swing web context in server.xml. (for further details on Tomcat 9.x Resources configuration, please refer to Resources configuration).

<Context docBase="com.eidosmedia.webclient.web-app"
    path="/swing" reloadable="false">
    <Resources className="org.apache.catalina.webresources.StandardRoot">
        <PreResources
            className="org.apache.catalina.webresources.DirResourceSet"
            base="/methode/meth01/extension/dwp-templates" readOnly="true"
            webAppMount="/config/templates/dwp" />
    </Resources>
</Context>

Custom editor panels

With Méthode Swing it’s possible to add custom lateral panels to the Editor. The behaviour and the registration is similar to the Object Panel extension, and allows the user to interact with the Editor and the opened document through the use of the Editor Apis.

Registration of a custom panel

To register a new custom panel, use the following namespace

eidosmedia.webclient.extensions.binder

and its function

add( name, options )
Table 109. Method information

Method

add

Parameter

Required {String} name - The name of the custom panel Required {object} options - An object containing the options and the behaviour of the panel. See Properties and methods of the custom panel for details.

Returns

{undefined} undefined

The following is a very simple of a working custom panel.

eidosmedia.webclient.extensions.binder.add( "city-panel", {
    label: "City info",
    icon: 'fa fa-building-o',
    template: 'city-panel.html',
    isActive: function(ctx) {
        return true;
    },
    headerButtons: [{ name: 'refresh', icon: 'icon-refresh', title: 'toolbar.refresh' }],
    init: function(ctx, $container, panelMethods) {
        // Load external sources...
    },
    ready: function(ctx, $container, panelMethods) {
        alert("No man is an island, / Entire of itself. / Each is a piece of the continent, / A part of the main. ... / For whom the bell tolls, / It tolls for thee.");
    },
    closeOnHide: true,
    refreshOnShow: true,
    callReadyOnChangeItem: false,
    /**
     * Method called whenever the user clicks on the refresh button.
     */
    onRefresh: function(ctx, $container, panelMethods) {
        console.error('Clicked on refresh');
    },
    onClose: function(ctx, $container, panelMethods) {
        alert("Don't leave me, please!");
    },
    /**
     * Method called whenever the user changes selection. Available only inside
     * the story editor.
     */
    onChangedPath : function(ctx, $container, panelMethods, pathInfo) {
        console.log(pathInfo);
    }
});

Properties and methods of the custom panel

The following paragraphs describe each of the available properties or methods for the custom panel.

label

[Mandatory] {String} label defines the label visible on the top of the panel when it is selected.

Example
{
    // ...
    label: "For whom the bell tolls",
    // ...
}

icon

[Optional] {String} icon defines the icon of the custom panels. All the most recent Font Awesome icons are available.

Example
{
    // ...
    icon: "fa fa-bell",
    // ...
}

template

[Mandatory] {String} template defines the path of the custom panel HTML template. The templates must be put under the following folder:

{SWING-APP}/config/templates/panels/
Tip
Swing supports Tomcat 9.x, so custom panels can be configured outside {SWING-APP}. See the paragraph How to configure custom panels in external folder for some tips in how to take advantage of this configuration option.
Caution
the path specified in the template option is relative to the /panels/ folder.
Example
{
    // ...
    template: 'bell.html',
    // ...
}

offlineAvailable

[Optional] {Boolean} offlineAvailable determines whether the custom panel is visible or not when the application is offline.

Example
{
    // ...
    offlineAvailable: true,
    // ...
}

localStoryAvailable

[Optional] {Boolean} localStoryAvailable determines whether the custom panel is visible or not when editing a local story.

Example
{
    // ...
    localStoryAvailable: true,
    // ...
}

isActive( ctx )

[Optional] {Function} isActive determines whether the custom panel is visible or not. If not specified, the panel is always visible. This function must return a valid Boolean value to be used. The isActive method has the usual ctx parameter available.

Example
{
    // ...
    isActive: function( ctx ) {
        return ctx.activeObject.getType() === 'EOM::Story';
    },
    // ...
}

init( ctx, $container )

[Optional] {Function} init is called as soon as the panel is initialized, after the isActive method has passed. It has the following parameters:

Table 110. Method parameters
Name Description

ctx

The usual Context Object

$container

The jQuery reference to the container node.

Caution

The init method is called before the template has been loaded, so the $container content is actually empty. Do not use it to add event listeners to DOM objects.

Example
{
    // ...
    init: function( ctx, $container ) {
        // For example, load external sources...
    },
    // ...
}

ready( ctx, $container )

[Optional] {Function} ready is called after the panel has been initialized and the template loaded. It has the following parameters:

Table 111. Method parameters
Name Description

ctx

The usual Context Object

$container

The jQuery reference to the container node.

panelMethods

A small set of common methods to be used inside the panel. The only available method is setMessage( message, icon, element ).

Tip

This is the best place to add event listeners to DOM object and to actually implement the whole panel’s logic.

Example
{
    // ...
    ready: function( ctx, $container, panelMethods ) {
        var _ctx = ctx; // Remember to save the instance, otherwise inside the event it will not work
        $container.off('click', '.my-save-button').on('click', '.my-save-button', function() {
            _ctx.activeDocument.saveDocument();
        });
    },
    // ...
}

refreshOnShow

[Optional] If set to true, the custom panel will refresh ( and call all the subsequent methods, e.g. ready (not _init) ), any time the custom panel tab is selected by the user ( except for the first time ).

closeOnHide

[Optional] If set to true, the onClose method, if available, will be called any time the custom tab loses focus ( another tab is opened ).

callReadyOnChangeItem

[Optional] If set to true, the custom panel will call the ready method, any time the item selection changes.

onClose

[Optional] Method called when the custom panel is closed. This happens when a document is closed, when a different element is selected, or when the custom tab is hidden ( in case of closeOnHide set to true).

The syntax is the following:

onClose( ctx );
Table 112. Method information

Method

onClose

Parameter

{object} ctx - The context object. See Basic structure of the Context Object for further information.

Returns

undefined.

onApplicationStatusChange

[Optional] Method called when the application status change from online to offline or vice versa (triggered only when using the offline functionality).

The syntax is the following:

onApplicationStatusChange(ctx, $container, panelMethods, status);
Table 113. Method information

Method

onApplicationStatusChange

Parameter

{object} ctx - The context object. See Basic structure of the Context Object for further information.

$container

The jQuery reference to the container node.

panelMethods

A small set of common methods to be used inside the panel. The only available method is setMessage( message, icon, element ).

Parameter

{object} status - The application status. The status object is structured as below:

  • applicationOnline: true if the application is in online mode, false otherwise.

  • isOnline: true if the application reaches the server and the application is in online mode, false otherwise.

  • offlineServer: enabled : true if the offline server is available, enabled: false otherwise.

  • serverReachable: true if the server is reachable, false otherwise.

Returns

undefined.

Example
// options object...
{
    onApplicationStatusChange: function( ctx, $container, panelMethods, status ) {
       // For example, we can check the application status
       if (status.isOnline) {
        ....
       }
    }
}

onMessage

[Optional] Method called when the application status change from online to offline or vice versa (triggered only when using the offline functionality).

The syntax is the following:

onMessage(ctx, $container, panelMethods, key, message);
Table 114. Method information

Method

onMessage

Parameter

{object} ctx - The context object. See Basic structure of the Context Object for further information.

$container

The jQuery reference to the container node.

panelMethods

A small set of common methods to be used inside the panel. The only available method is setMessage( message, icon, element ).

key

A string that represents the event notification form the editor instance. For example it can be refreshcurrentitem, when changing between one channel copy and another .

Parameter

{object} message - Contains additional info depending on the key value, in general contains the info about the current document.

Returns

undefined.

Example
// options object...
{
    onMessage(ctx, $container, panelMethods, key, message) {
        if ('key' === 'refreshcurrentitem') {
            console.log('message contains all the information about the current editing story');
        }
    }
}

How to configure custom panels in external folder

Additional objects may be made available to Swing application by defining one or more nested components in Swing web context in server.xml. (for further details on Tomcat 9.x Resources configuration, please refer to Resources configuration).

This is an example of the external custom panels configuration.

<Context docBase="com.eidosmedia.webclient.web-app"
    path="/swing" reloadable="false">
    <Resources
        className="org.apache.catalina.webresources.StandardRoot">
        <PreResources
            className="org.apache.catalina.webresources.DirResourceSet"
            base="/methode/meth01/extension/custompanels" readOnly="true"
            webAppMount="/config/templates/panels" />
    </Resources>
</Context>

Custom insertinfo panels

With Méthode Swing it’s possible to add custom insertinfos to the Editor. The behaviour and the registration is similar to the Object Panel extension.

Registration of a custom insertinfo template

To register a new custom insertinfo template, use the following namespace

eidosmedia.webclient.insertinfo

and its function

add( options )
Table 115. Method information

Method

add

Parameter

Required {object} options - An object containing the options and the behaviour of the custom insertinfo template.

Returns

{undefined} undefined

The following is a very simple of a working custom insertinfo template.

(function() {

		eidosmedia.webclient.insertinfo.add({

		/**
		* name of the custom insertinfo implementation
		*/
		name: "CustomInsertInfo",

		/**
		* path of the html template relative to the insertinfo folder
		*/
		template: "customInsertInfo.html",

		/**
		* An array of insertinfo template configured in the DTX which the custom implementation will be connected.
		*/
		dtxTemplateName: ['Custom Image Size', 'Custom width-height'],
		/**
		*
		* @param ctx: The usual Context Object. See <<ctx>> for further details. It could be empty
		* if only placeholder is inserted.
		* @param htmlTemplate: a String containing the html of
		* the configured template
		*
		* @return a jQuery object with the html to show to the user
		*/
		init: function(ctx, htmlTemplate){

			/*
			* Elaborate the html and return the
			* html to show to the user
			*
			*/

			return $(htmlTemplate);
		},

		/**
		*
		* @param ctx: The usual Context Object. See <<ctx>> for further details. It could be empty
		* if only placeholder is inserted.
		* @param $html: the jQuery representation of the html
		* edited by the user
		*
		* @return an object with key values pairs:
		*    {
		*        "uVariable"  : "value",
		*	 "uVariable2" : "value2"
		*    }
		*/
		getValues: function(ctx, $html){
			/**
			* Elaborate $html object
			**/

			var width = $html.find('#custom_width').val();
			var height = $html.find('#custom_height').val();

			result = {
				"uWidth"  : width,
				"uHeight" : height
			}

			return result;
		}
    });

})();

Properties and methods of the custom insertinfo

The following paragraphs describe each of the available properties or methods for the custom insertinfo.

name

[Mandatory] {String} name defines the name of the custom inserinfo.

{
    // ...
    name: 'CustomInsertInfo',
    // ...
}

dtxTemplateName

[Mandatory] {Array,String} dtxTemplateName An array of insertinfo template configured in the DTX which the custom implementation will be connected.

Tip
String type is still supported only for backward compatibility.
Example
{
    // ...
    dtxTemplateName: ['Custom image size', 'Custom width height'],
    // ...
}

DTX configuration:

{
    <template name="Custom image size" element="fg-photo" mode="inline">
        <photo-group>
            <fg-photo width="{uWidth}" height="{uHeight}"></fg-photo>
            <photo-caption>
                <p xpAttributesSource="/*/iptc/caption/text()">
                	<source xpAttributesSource="/*/iptc/source/text()"><?EM-dummyText Insert caption source?></source>
                	<?EM-dummyText Insert caption here?>
                </p>
                <foto-links></foto-links>
            </photo-caption>
        </photo-group>
    </template>

    <template name="Custom width height" element="fg-photo" mode="inline">
        <photo-group>
            <fg-photo width="{uWidth}" height="{uHeight}"></fg-photo>
            <photo-caption>
                <p xpAttributesSource="/*/iptc/caption/text()">
                    <source xpAttributesSource="/*/iptc/source/text()"><?EM-dummyText Insert caption source?></source>
                    <?EM-dummyText Insert caption here?>
                </p>
                <foto-links></foto-links>
            </photo-caption>
        </photo-group>
    </template>
}
Tip
dtxTemplateName can contain the value of the attribute customInsertInfo of the link element of type insert. In this case the custom implementation will be connected to all the tempplate configured.
{
    <insertInfo type="Image" channel="Globe-Web" container="EOM::CompoundStory,EOM::MediaGallery">
        <link name="Insert" type="insert" customInsertInfo="customLinkInsert">

            <template name="Custom Image One" element="fg-photo" mode="inline">
                <photo-group>
                    <fg-photo width="{uWidth}" height="{uHeight}"></fg-photo>
                    <photo-caption>
                        <p xpAttributesSource="/*/iptc/caption/text()">
                            <source xpAttributesSource="/*/iptc/source/text()"><?EM-dummyText Insert caption source?></source>
                            <?EM-dummyText Insert caption here?>
                        </p>
                        <foto-links></foto-links>
                    </photo-caption>
                </photo-group>
            </template>

            <template name="Custom Image Two" element="fg-photo" mode="inline">
                <photo-group>
                    <fg-photo width="{uWidth}" height="{uHeight}"></fg-photo>
                    <photo-caption>
                        <p xpAttributesSource="/*/iptc/caption/text()">
                            <source xpAttributesSource="/*/iptc/source/text()"><?EM-dummyText Insert caption source?></source>
                            <?EM-dummyText Insert caption here?>
                        </p>
                        <foto-links></foto-links>
                    </photo-caption>
                </photo-group>
            </template

        </link>
    </insertInfo>
}
Caution
all the variables have to be wrapped with brackets (e.g. {uWidth}).

template

[Mandatory] {String} template defines the path of the custom panel HTML template. The templates must be put under the following folder:

{SWING-APP}/config/templates/insertinfo/
Tip
Swing supports Tomcat 9.x, so custom panels can be configured outside {SWING-APP}. See the paragraph How to configure custom insertinfo in external folder for some tips in how to take advantage of this configuration option.
Caution
the path specified in the template option is relative to the /insertinfo/ folder.
Example
{
    // ...
    template: 'customInsertInfo.html',
    // ...
}

init( ctx, htmlTemplate )

[Mandatory] {Function} init is called as soon as the panel is initialized. This function must return a valid jQuery object to be used.

Table 116. Method parameters
Name Description

ctx

The usual Context Object. See Basic structure of the Context Object for further details. It could be empty if only placeholder is inserted.

htmlTemplate

htmlTemplate: a String containing the html of the configured template

Returns

{object} results - An object containig key value pairs of all the variables present in the insertinfo template.

Example
{
    // ...
    init: function( ctx, html ) {
        // Elaborate the html document an return a jQuery html object
        var $html = $(html);

        return $html;
    },
    // ...
}

getValues( params, $html )

[Mandatory] {Function} getValues is called when the user applies the insertinfo. This function must return a valid Object containing all the variables present in the template.

Table 117. Method parameters
Name Description

ctx

The usual Context Object. See Basic structure of the Context Object for further details. It could be empty if only placeholder is inserted.

$html

The jQuery representation of the html edited by the user.

Returns

{object} results - An object containig key value pairs of all the variables present in the insertinfo template.

Example
{
    // ...
    getValues: function( ctx, $html ) {
        /*
		* Elaborate $html object
		*/
		var width = $html.find('#custom_width').val();
		var height = $html.find('#custom_height').val();
		result = {
			"uWidth"  : width,
			"uHeight" : height
		}
		return result;
    },
    // ...
}

How to configure custom insertinfo in external folder

Additional objects may be made available to Swing application by defining one or more nested components in Swing web context in server.xml. (for further details on Tomcat 9.x Resources configuration, please refer to Resources configuration).

This is an example of the external custom insertinfo configuration.

<Context docBase="com.eidosmedia.webclient.web-app"
    path="/swing" reloadable="false">
    <Resources
        className="org.apache.catalina.webresources.StandardRoot">
        <PreResources
            className="org.apache.catalina.webresources.DirResourceSet"
            base="/methode/meth01/extension/insertinfo" readOnly="true"
            webAppMount="/config/templates/insertinfo" />
    </Resources>
</Context>

Channel copy

With Méthode Swing it’s possible to add custom manipulation to the content of a channel copy after his creation.

Registration of a custom manipulation

To register a custom manipulation, use the following namespace

eidosmedia.webclient.extensions.channelCopy

and its function

register( options )
Table 118. Method information

Method

register

Parameter

Required {object} options - An object containing a function that will be invoked to perform the custom manipulation.

Returns

{undefined} undefined

The following is a very simple registration for a custom manipulation.

(function() {


    eidosmedia.webclient.extensions.channelCopy.register(function( data, callback ) {

            // Save the current content of the channel copy
            var xmlElaborated = data.xmlContent;

            try {

                /**
                 * Save the current content of the channel copy. This variable will be used to make some changes to the current content
                 */
                var xmlContent = data.xmlContent;

                /**
                 * Save information about the current channel copy. For example the channel name
                 */
                var copyInfo = data;

                /**
                 * Perform some simple manipulation. In our case add only a new attribute
                 */
                var xml = $.parseXML(xmlContent);
                var $xml = $(xml);
                var $doc = $xml.find('doc');
                $doc.attr('newattr', 'newvalue');

                /**
                 * Serialize the new xml content
                 */
                var serializer = new XMLSerializer();
                var preValue = xmlElaborated.slice(0, xmlElaborated.indexOf('<doc'));
                var result = serializer.serializeToString($doc[0]);

                /**
                 * Save the new xml content
                 */
                xmlElaborated = preValue + result;

                /**
                 * notify a callback if specified
                 */
                if (callback) {
                    callback(xmlElaborated);
                }

            } catch (ex) {
                console.log("Channel copy custom manipulation exception caught", ex);

                if (callback) {
                    callback(xmlElaborated);
                }
            }
    });

})();
Note

The function must be have two parameters. The first one contains info about xml content and the channel object info. The second one it’s a callback that must be invoked after the custom manipulation. Wrap all the custom manipulation with a try…​catch block otherwise the normal process of the channel copy creation will be not performed.

After the custom manipulation the system will perform a validation check of the new content. If the check goes wrong the channel copy will be created with the original content and the user will be notified

Dashboard

Widget Creation - Méthode Swing

Méthode Swing dashboards are extensible with custom widgets.

This document will introduce the use of Méthode Swing SDK for creating and testing the widgets, as well as describe the correct widget structure and provide a complete example of a custom widget creation.

Widget structure

All the widgets are put inside the following path:

{SWING-APP}/app/widgets/{WIDGET-NAME}

Widgets can be configured outside {SWING-APP}. See the paragraph How to configure widgets in external folder for some tips in how to take advantage of this new configuration option.

As you can see, all the widget provided by Méthode Swing are included in this folder.

Each widget folder must contain the following files:

Table 119. Files in {WIDGET-NAME} folder
File name Description

{WIDGET-NAME} .js

The JavaScript file defines the widget’s behaviour.

{WIDGET-NAME} .html

The file represents the visual template of the widget.

{WIDGET-NAME} .less

LESS is a CSS-like language. This file changes the aesthetic appearance of the widget. It is not mandatory.

Caution

It is necessary that the file all have the same name of the folder. It is recommended, although not mandatory, to use lower case characters and, in general, to avoid "unusual" characters.

Tip

DEBUG MODE: by default, all widgets are aggregated into a single widgets.js file at the Tomcat startup. When creating a widget, it may be frustrating to restart the Tomcat Server every time a change is made.

To avoid this, set the configuration property debugEnabled to true.

Then, that widget will be loaded on every refresh of the page.

Note: in debug mode, the widgets are loaded separately and asynchronously; this may occur in a widget not loaded correctly. In this case, simply change tab (e.g. move to "My Area") and back to the Dashboard to have the widget loaded correctly.

JS file

The widget’s Javascript file should be written as follows:

/*
 * Todo List Widget. Used to demonstrate the creation of a custom widget
 */
eidosmedia.webclient.dashboard.widgets.define( {WIDGET-NAME}, function() {

    var settings = {
        title: 'SOME TITLE',
        icon: 'icon-gear'
        // Default settings...
    };

    function onResize() {
        // Method called on the windows resize.
    };

    function loadData() {
        // Method called on the widget loading. Used to retrieve the user's data.
    };

    function updateData() {
        // Used to update the widget's template.
    };

    return {
        settings: settings,
        onResize: onResize,
        loadData: loadData,
        updateData: updateData
    };

});

Basically, is the widget should call the

eidosmedia.webclient.dashboard.widgets.define

function, with the following parameters:

  • {WIDGET-NAME} : the same name used everywhere else in the widget folder.

  • a function which returns a JavaScript object with a set of mandatory methods as described in the following paragraph.

Each widget has a set of default settings, which can be specified under the settings property of the widget.

When the Dashboard is displayed, the widgets specified in the configuration are initialized. The chain of events continues as follows:

  1. First, the dashboard renders the HTML template with status = "init". ( See HTML file for details on how the template is called )

  2. Second, the dashboard calls the widget’s loadData (required) method which should load the widget’s data. ( See loadData for details on how the method is called )

  3. Within the widget loadData method, the widget should call either the dashboard updateBaseData method ( See updateBaseData for further details ), to let the dashboard know that the loading has finished.

Optionally, it is possible to specify the behaviour when the window is resized. (For example, it can be used to retrive the number of visible objects and change the widget’s rendering accordingly).

See onResize for further details on how to manage the resize.

Required methods for the widget
loadData

loadData is the method called by the Dashboard in order to load the Widget data. It must be declared as follows:

loadData: function( settings, ctx ) { ...

The function is called with one parameter:

  • settings - contains the settings specified in the widget configuration. It is a Javascript object.

  • ctx - the Swing context object. See Context object documentation.

Tip

If you specified the settings property in the widget declaration, you can be sure that at least those settings are available. If the user specifies customs settings in Swing configuration, the properties with the same name are overridden by the user configuration.

Important

Within the loadData function, the Javascript context (also known as the this object) is the widgetContext object ( see widgetContext: list of available methods within the widget to know the complete list of methods available ).

Important

It is mandatory that the widget calls the updateBaseData method of the widgetContext object (the this object), otherwise the dashboard as no way of knowing that the widget has finished loading. See updateBaseData for further details.

In general, the method updateBaseData must be called with two parameters:

  • settings: the settings described above.

  • data : the loaded data. It can be whatever you prefer (an array or JSON object). The data is passed to the widget without further elaboration.

This is an example of the TODOLIST widget loadData function.

function loadData( settings, ctx ) {
    var widgetContext = this; // save the widget variable.
    // Get the user todo list
    try {
        /* getUserData is one of the available methods,
           see the proper documentation below for further details */
        widgetContext.getUserData( 'todolist',{
            success: function( data ) {
                // Process List items.

                /* NOTE: IT IS NECESSARY TO CALL THE FOLLOWING METHOD TO LET THE DASHBOARD
                   KNOW THAT THE WIDGET HAS COMPLETED THE DATA LOADING. */
                widgetContext.updateBaseData( settings, data );
            },
            error: function(xhr, textStatus, errorThrown) {
                // Process the error response and show the Widget Error
                var error = widgetContext.processErrorResponse(xhr, textStatus, errorThrown);
                widgetContext.showError(error);
            }
        });
    } catch (ex) {
        widgetContext.showError( { message: ex.message } );
    }
};
Optional methods for the widget
updateData

updateData is the method called by the Dashboard after the widget has been loaded. It is generally used to add listeners for events, button clicks, and anything related.

Caution

Do not confuse updateData (the widget method) with updateBaseData (the widgetContext method).

The widgetContext.updateBaseData() checks if the widget updateData method is available and calls it.

updateData: function( settings, items, ctx ) { ...

The function is called with some parameters:

  • settings - contains the settings specified in the widget configuration. It is a Javascript object.

  • data - the loaded data. It can be whatever you prefer (an array or JSON object). The data is passed to the widget without further elaboration.

  • ctx - the Swing context object. See Context object documentation.

Important

Within the updateData function, the Javascript context (also known as the this object) is the widgetContext object ( see widgetContext: list of available methods within the widget to know the complete list of methods available ).

This is an example of the updateData function.

function updateData( settings, data, ctx ) {
    var widgetContext = this; // save the widget variable.

    // add Listeners to the object.

    var $widget = widgetContext.getWidgetContainer(); //Obtains the jQuery reference to the widget.

    $widget.find('#saveSomething').off('click').on('click', function() {
        // do some elaboration of the data...
        alert('you clicked me');
    });

};
onResize

onResize is the method called by the Dashboard whenever the Browser window is resized. It can be used, for example, to change the number of rows shown.

onResize: function( ) { ...

The method is called without parameters.

Important

Within the onResize function, the Javascript context (also known as the this object) is the widgetContext object ( see widgetContext: list of available methods within the widget to know the complete list of methods available ).

This is an example of the diggfeeds widget onResize function.

function onResize() {
    var widgetContext = this;
    var ROW_PIXEL_HEIGHT = 65;
    var HEADER_PIXEL_HEIGHT = 30;

    var calcElements = function() {
        var widgetHeight = widgetContext.getHeight();
        var totalEl = Math.floor( (widgetHeight - HEADER_PIXEL_HEIGHT) / ROW_PIXEL_HEIGHT);
        return totalEl;
    };

    var totalRow = widgetContext.settings.count;
    var totalNewEl = calcElements.call(this);

    if ( totalNewEl === totalRow ){
        return;
    } else {
        // New quantity of items.
        // Refresh the widget with new items.
        this.settings.count = totalNewEl;
        loadData.call( widgetContext, widgetContext.settings );
    }
};
widgetContext: list of available methods within the widget

The widgetContext object is very important and represents the context ( the this object ) with which the loadData, updateData and onResize methods are called.

It provides a set of common methods which can ( and should ) be used within the widget.

The most important is updateBaseData, which must be called within the widget loadData method as widely described before.

Important

Any of these methods can be accessed with the keyword this within the threed common methods ( loadData, updateData and onResize ).

It is recommended to save the reference into a variable, to be used within the callback functions. For example:

var widgetContext = this;
// ....
widgetContext.updateBaseData( settings, data );
updateBaseData

The method must be called within the loadData method, to let the dashboard know that the widget has finished loading data. It must be called as follows:

widgetContext.updateBaseData( settings, data );
  • settings are the widget’s settings ( provided within the loadData method ), or any setting that you want to pass to the widget.

  • data is the loaded information to be passed to the widget.

Caution
This internal method automatically calls the widget updateData method with the same settings, as described above.
getHeight

Returns the current widget height. Useful in obtaining the widget dimensions for the onResize method.

function onResize() {
    var widgetHeight = this.getHeight();
    // Some elaboration...
}
getWidth

Returns the current widget width. Useful in obtaining the widget dimensions for the onResize method.

function onResize() {
    var widgetWidth = this.getWidth();
    // Some elaboration...
}
getWidgetIcon

Returns the current widget icon as specified in the settings. It is often used inside the widget HTML template, as follows.

Tip
The result of this.getWidgetIcon() and of this.settings.icon are the same.
<h1>
    <%=settings.title%>
    <i class="<%=(widget.getWidgetIcon() || settings.icon)%>"></i>
</h1>
getIcon

getIcon returns the configured icon according to the type.

It is called as follows:

this.getIcon( type );

It returns a string containing the corresponding icon.

    var icon = this.getIcon( 'EOM::Story' ); // Returns 'emui-icon-file-text';
    // Some elaboration...
addDummy

addDummy fills an array with empty elements.

It is called as follows:

addDummy(data, max)
  • data is the array of items

  • max is the array length.

    // data has 30 elements.
    this.addDummy( data, 50 );
    /**
    *  Now data has 50 elements. From Index 30 to index 49, the element is
    * { empty: true }
    */
execute

execute executes specific supported actions.

Supported actions are:

  • newcontent : opens the "New Content" dialog

  • newmessage : opens the "New Message" dialog

  • newstory : creates a new story document with the default configuration

  • newgallery : creates a new gallery document with the default configuration

It is called as follows:

execute( action, options )

The method does not return anything.

    // Open the "new content" dialog.
    this.execute( "newcontent" );
getWidgetContainer

The method returns the jQuery reference to the current widget’s container

Tip
Use this method to quickly look for DOM elements of your widget.
    var $container = this.getWidgetContainer();

    // Search all anchors inside the widget...

    var $links = $container.find('a');
getCurrentUser

The method returns a JSON object with the logged user’s properties. See the example to see the returned properties.

    var currentUser = this.getCurrentUser();

    /** Returns

    {
        "picture": "/WebClient/user/avatar/user_name?token=1fb301ce-1dc3-4f78-9e2c-0b9c2750ff1b",
        "name": "user_name",
        "description": "Eidosmedia top class R&D",
        "config_folder": "eomfs:/Configurations/Profiles/user_name/Config",
        "id": "1.0.417997841",
        "fullName": "Ted Mosby",
        "team": "Globe_Web",
        "phoneNumber": "456",
        "mobileNumber": "123",
        "twitter": "user_name",
        "facebook": "john.doe@r.com",
        "role": "Reporter",
        "homeEmail": "john.doe.home@r.com",
        "businessEmail": "john.doe@r.com2",
        "statusMessage": "Status msgsdsadsadas",
        "workDir": "workfolder:///Globe/Sport",
        "location": "Roma",
        "profileDir": "eomfs:/Configurations/Profiles/user_name",
        "lastLoggedOn": 1423501287,
        "initials": "AP",
        "signature": "John",
        "system_attributes": "SYSTEM ATTRIBUTES",
        "metadata": "",
        "homePath": "/Users/user_name",
        "admin": true,
        "groups": [
            {
                "name": "Administrators",
                "description": "",
                "config_folder": "eomfs:/Configurations/Profiles/Administrators/Config",
                "profile_folder": "eomfs:/Configurations/Profiles/Administrators",
                "categories": [
                    "EOM::Group",
                    "EOM::Configuration",
                    "EOM::Privileges"
                ],
                "isConfiguration": true
            }
        ],
        "calendars": [
            {
                "color": "#0C96D7",
                "id": "U00033812843qQO",
                "name": "World Cup 2014",
                "url": "https://www.google.com/calendar/ical/qlbi1b0rp50vb07rmssnebq694%40group.calendar.google.com/public/basic.ics",
                "icon": "icon-bookmark",
                "private": false
            }
        ],
        "status": "available",
        "teams": [
            "Globe_Team",
            "Globe_Web"
        ]
    }

    **/
getUserLocation

Returns the Backbone Model of the user location.

    var userLocation = this.getUserLocation();
    var latitude = userLocation.get('latitude'); // longitude...
getCurrentLocation

Returns, in a callback, the current location obtained with the browser geolocation API and with Google Maps API.

    this.getCurrentLocation( function(location) {

        // Do something with location...
        // It is an object
        /*
        {
            "latitude": 45.3231,
            "longitude": 9.1321
        }
        */

    });
getConfiguration

Returns an object with specific parts of the configuration. It is called as follows:

 var config = this.getConfiguration();

The result is a JSON object with the following properties:

  • config.isCacheEnabled() : returns true if the cache is enabled.

  • config.language : the current user language

  • config.location : the "location" object configured in the config.json file.

getPersistence

Returns the persistence services that enables to perform cached AJAX call.

 var persistence = this.getPersistence();

An example from the Digg feeds widget:

// Executes an AJAX call to obtain the DIGG feeds.
    persistence.ajax({
        emCache: {
            disabled: !this.getConfiguration().isCacheEnabled(),
            prefix: 'eidosmedia.widget|diggfeeds|',
            ttl: 600,
            safe: true
        },
        url : widgetContext.buildUrl( '/ws/widgets/digg/mostDuggFeed', widgetContext.getAppContext() ),
        data : request,
        success : function(respData) {
            if ( count < respData.length ) {
                respData = respData.splice(0, count);
            }
            response = widgetContext.addDummy(respData, count);

            // Update the widget data with the standard method, as we don't override it.
            widgetContext.updateBaseData( widgetContext.settings, response);
            // Add custom listeners.
            addListeners.call( widgetContext, response );
        },
        error : function(xhr, textStatus, errorThrown) {
            var error = widgetContext
                            .processErrorResponse(xhr, textStatus, errorThrown);
            widgetContext.showError(error);
        }
    });
processErrorResponse, showError

The processErrorResponse method is called to create a useful Javascript object, to be used (often) with the showError method.

The showError method is used to display an error message inside the widget container.

processErrorResponse is called as follows:

var errorObj = this.processErrorResponse( xhr, textStatus, errorThrown );

showError is called as follows:

this.showError( errorObj );

The correct usage for processErrorResponse is inside a jQuery AJAX error callback, as seen in the example:

var widgetContext = this;
// Executes an AJAX call to obtain the DIGG feeds.
$.ajax({
    url: '',
    data: [],
    success : function(respData) {
        // ...
    },
    error : function(xhr, textStatus, errorThrown) {
        var errorObj = widgetContext
                        .processErrorResponse(xhr, textStatus, errorThrown);
        widgetContext.showError( errorObj );
    }
});

showError can be called also without using processErrorResponse, as the example shows:

    this.showError( { message: 'Some error details here' } );
translateWidget

translateWidget translates all the HTML inside the widget container. It uses data-i18n attributes to perform the translation.

this.translateWidget();
getUserData, addUserData, removeUserData, setUserData

This methods allow to get, add, remove, and set specific data inside the user’s profile folder.

Syntax is as follows:

    this.getUserData( name, callbackSettings ); // Obtains the user data.

    this.addUserData( data, name, callbackSettings ); // Add some data to the user's data.

    this.removeUserData( data, name, callbackSettings ); // Remove some data from the user's data.

    this.setUserData( data, name, callbackSettings ); // Set the user data to some value.

In general, the parameters are:

  • data: the data to add, remove, set from the file.

  • name: the name of the file to be stored in the User profile folder, without the extension (e.g. 'recents', 'todolist', …​; it creates a 'recents.json' file into the User profile folder)

  • callbackSettings: a Javascript object with two parameters (success and error, which are both functions), to call the methods asynchronously. If omitted, the call is synchronous.

Examples:

    // assuming that, before, we had a 'var widgetContext = this;'...

    // GET USER DATA

    // Get recents asynchronously (recommended).
    this.getUserData('recents', {
        success: function( recents ) {
            //...
        },
        error: function(xhr, textStatus, errorThrown) {
            var errorObj = widgetContext
                        .processErrorResponse(xhr, textStatus, errorThrown);
            widgetContext.showError( errorObj );
        }
    });

    var recents = this.getUserData('recents'); // Get recents synchronously (not recommended)

    // ADD USER DATA (if the file does not exist, it is created).

    // add a recent to the list (sync).
    this.addUserData( { /* item */ }, 'recents', {
        success: function( newRecents ) {
            // returns the update list of recents
            //...
        },
        error: function(xhr, textStatus, errorThrown) {
            var errorObj = widgetContext
                        .processErrorResponse(xhr, textStatus, errorThrown);
            widgetContext.showError( errorObj );
        }
    });

    // add a recent to the list (async).
    var newRecents = this.addUserData( { /* item */ }, 'recents' );

    // REMOVE USER DATA

    // remove a recent from the list (sync).
    this.removeUserData( { /* item identifier */ }, 'recents', {
        success: function( newRecents ) {
            // returns the update list of recents
            //...
        },
        error: function(xhr, textStatus, errorThrown) {
            var errorObj = widgetContext
                        .processErrorResponse(xhr, textStatus, errorThrown);
            widgetContext.showError( errorObj );
        }
    });

    // add a recent to the list (async).
    var newRecents = this.removeUserData( { /* item */ }, 'recents' );

    // SET USER DATA (overrides the current content with the new one).

    // completely sets the new todo list (sync)
    this.setUserData( [ {}, {}, }{} ], 'todolist', {
        success: function( newTodoList ) {
            // returns the update Todo List
            //...
        },
        error: function(xhr, textStatus, errorThrown) {
            var errorObj = widgetContext
                        .processErrorResponse(xhr, textStatus, errorThrown);
            widgetContext.showError( errorObj );
        }
    });

    // completely sets the new todo list (async).
    var newTodoList = this.setUserData( [ {}, {}, }{} ], 'todolist' );
getPreview

Returns the URL of the server-side generated preview. Useful for Méthode Objects.

var preview = this.getPreview( id ); // e.g. this.getPreview( '0$1.231321421' );
// It returns a valid URL
openPreview

Opens the M&ecute;thode Swing Preview dialog.

this.openPreview( items, options );

The method accepts 2 parameters:

  • items: (object or array), mandatory - a Javascript Object representing the item information returd by query or a folder nativation/ Array including info on the file to load

  • options: (object), not mandatory - a Javascript Object including the preview options.

Important

The options object is a Javascript object with the following properties:

  • loadObject (default is false) - Reloads the item information.

Example:

    this.openPreview( items, { loadObject: true });

HTML file

The HTML template can be as free as desired. The only contraint is that the whole HTML code should be wrapped into a div, such as the following example:

<div>
</div>

The widget can be have a fixed height, a minimum height or can be responsive. This enables the Swing dashboard to adapt according to the screen dimensions.

To have a fixed height widget, specify the height in the style attribute of the div, as follows:

<div style="height:300px;">
<!-- ... -->
</div>

To have a widget with minimum height, specify the min-height in the style attribute of the div, as follows:

<div style="min-height:300px;">
<!-- ... -->
</div>

To have a responsive widget (a widget that occupies the available height), add the class emui-widget-vfill to the div.

<div class="emui-widget-vfill">
<!-- ... -->
</div>
Important

Méthode Swing uses Underscore.JS templating system to enhance the user experience.

See Underscore.JS for further information, or the box below for some useful tips.

Inside the template is then possible to use the Underscore.JS syntax, and use the methods and objects described in the following section.

Available information inside the HTML template

As described above, the HTML template is called with the Underscore.JS template syntax. Inside the HTML template, it is possible to use the following objects:

  • widget: it contains the same methods described in the widgetContext section above. See widgetContext: list of available methods within the widget section for further details on the available methods.

  • settings: it is a Javascript object containing the widget settings as specified in the configuration.

  • data: contains all the data available to the widget( the ones specified in the updateData and loadData method described above ).

  • status: either 'init' or 'loaded', for the first rendering ( before loadData ) and the last one ( after updateData ).

Sample HTML template
<%
    var title = data.title || "";
    title =  '<a href="#explore?query='+ data.id +'" class="emui-link">' + title +'</a>';
%>

<div class="emui-table-gallery emui-widget-vfill">
  <h1>
    <i class="<%=(settings.icon || 'icon-picture')%>"></i><%=title%></h1>
    <div class="list">
    <ul>
        <% _.each(data.items, function( item, index ) {
            var publishedDate = '',
                image = '';
            if (!item.empty) {
              publishedDate = item.publishedDate;
              image = ' style="cursor:pointer;background-image:url(' + widget.getPreview( item.id ) +'); background-size: cover;"  data-preview="image" data-preview-index="' + index + '"';
            }

            var preview = '<div class="image"' + image + '>';
            preview += '<div class="info">' + publishedDate +'</div>';
            preview +='</div>';
         %>
        <li><%=preview%></li>
    <% }); %>
  </ul>
  </div>
</div>

LESS file

Less is a CSS pre-processor, meaning that it extends the CSS language, adding features that allow variables, mixins, functions and many other techniques that allow you to make CSS that is more maintainable, themable and extendable.

LESS finally becomes CSS. Please refer to LESS website for further details.

Variable reference

Méthode Swing provides a set of common variables, as well as a set of predefined colors to maintain the coherence with Méthode Swing color palette.

To include the variable file inside your LESS, insert the following line at the beginning:

@import (reference) "../less/widgets-header.less";

Here follows an excerpt of the available variables:

// -------------------------
@black:                 #000;
@grayDarker:            #080808;
@grayDark:              #999;
@gray:                  #bcbcbc;    // view background
@grayLight:             #d8d8d8;    // body background
@grayLighter:           #e8e8e8;
@grayLighter2:          #f8f8f8;
@grayLightest:          #f8f8f8;
@white:                 #fff;

// Accent colors
// -------------------------
@blue:                  #a5c0dc;
@blueDark:              #4e84bb;
@blueLighter:           lighten(@blueDark, 10%);
@green:                 #77d89a;
@red:                   #9d261d;
@lightRed:              #E24242;
@darkRed:               darken(@lightRed, 10%);
@yellow:                #ffdb80;
@orange:                #ff9f6b;
@pink:                  #c3325f;
@purple:                #7a43b6;

Which can be used as follows:

.selector {
    background-color: @blueDark;
}

Again, please refer to LESS website for further details on how to write LESS files.

How to configure widgets in external folder

Additional widgets may be made available to Swing application by defining one or more nested components in Swing web context in server.xml. (for further details on Tomcat 9.x Resources configuration, please refer to Resources configuration).

This is an example of the external widgets configuration.

<Context docBase="com.eidosmedia.webclient.web-app"
    path="/swing" reloadable="false">
    <Resources
        className="org.apache.catalina.webresources.StandardRoot">
        <PreResources
            className="org.apache.catalina.webresources.DirResourceSet"
            base="/methode/meth01/extension/widgets" readOnly="true"
            webAppMount="/app/widgets" />
    </Resources>
</Context>

Customization

Addition of 3rd parties libs to Swing

In Méthode Swing it is possible to add 3rd-party libraries. Such libraries must be placed under

{SWING-APP}/plugins/libs

All the libraries contained in this folder are loaded separately into Méthode Swing.

Tip

The libraries are loaded asynchronously.

Tip

It is suggested to place each library under a specific folder, e.g:

{SWING-APP}/plugins/libs/exif/exif.js
Warning

Méthode Swing loads ONLY the Javascript (*.js) files in the folder.

Warning

Méthode Swing has no control over the 3rd parties lib. So, an external library could break the application.

Please refer to the log to see which libraries have been loaded.

New content creation dialog

With Méthode Swing it is possible to override the default creation dialog.

Registration of a new content creation dialog

To register a new content creation dialog, use the following namespace

eidosmedia.webclient.extensions.newcontent

and its function

register( contentTypes, options )
Table 120. Method information

Method

register

Parameter

Required {Array} contentTypes - The list of contentTypes for which the specified dialog must be used. See Available content types for details. Required {object} options - An object containing the options and the behaviour of the dialog. See Properties of the creation dialog for details.

Returns

{undefined} undefined

Available content types

When registering the dialog, the content type can be chosen among these options:

  • story

  • gallery

  • liveblog

  • webcontainer

  • webpage

  • topic

  • topicplan

Properties of the creation dialog

The following paragraphs describe each of the available properties or methods for the custom panel.

title

[Optional] {String} title defines the title of the dialog

Example
{
    // ...
    title: "For whom the bell tolls",
    // ...
}

layout

The layout property is optional and allows to have some control on the dialog dimensions. Available values are :

  • fullWidth - the dialog occupies all the screen width.

  • fullHeight - the dialog occupies all the screen height.

  • fullPage - the dialog occupies all the screen width and height.

If necessary, fullWidth and fullHeight properties could be used in addition with width and height properties.

Example
{
    // ...
    layout: "fullPage"
    // ...
}

width, height

If the layout property is not sufficient for your necessities, it is possible to customize the width and the height of the dialog by specifying the respective property.

Example
{
    // ...
    layout: 'fullWidth',
    height: "425px"
    // In this case we have a wide dialog with fixed height.
    // ...
}

css

If the layout property is not sufficient for your necessities, it is possible to customize all the css properties. It works exactly like jQuery.css method. Please refer to jQuery documentation for further information.

Example
{
    // ...
    css: {
        'fontSize': '12px',
        'width': '423px'
    }
}

dialogType

Dialog Type can be one of the following values.

  • full - the dialog is completely custom. It should be used when referencing an external url for the content creation. See Full custom dialog configuration documentation.

  • contained - the dialog is custom, but interacts with Methode Swing. The result is a modal that contains your custom HTML, but has the "Create" button as part of Swing. See Contained custom dialog configuration documentation.

  • template - the dialog is the standard Methode Swing dialog, but the template choice part is custom. See Template custom dialog configuration documentation.

  • tab - the dialog is the standard Methode Swing dialog, template and shape tabs are standard but It’s possible to add one ore more custom tabs. See Tab custom dialog configuration section

Example
{
    // ...
    dialogType: "full"
    // ...
}

Full custom dialog configuration

A "full" custom dialog should be used when the customer has an indipendent Object Creation tool available on another website. The "full" dialog has minimal interaction with Swing, and merely opens an external URL in an iframe.

To activate the "full" custom dialog, dialogType property must be valued at full.

Configuration of a proxy

To allow the use of your external url inside Swing, it is necessary to use a Proxy.

Méthode Swing uses proxies to communicate to external services. This is necessary due to the Same-Origin Policy used by modern browsers.

The same-origin policy restricts how a document or script loaded from one origin can interact with a resource from another origin. Same-origin Policy is used as a means to prevent some of the Cross-site Request Forgery attacks.

— Mozilla Developer Network

Proxies can be configured in Méthode Swing.

<!-- other configuration -->
<proxies>
    <proxy>
        <name>[PROXY-NAME]</name> <!-- e.g. resourcespace -->
        <targetUri>http://192.168.203.129/resourcespace/plugins/api_search/</targetUri> <!-- e.g. destination target Uri -->
        <useTemplate>false</useTemplate>
    </proxy>
</proxies>
Important

The useTemplate param allows to use templates to build the URL. The following is an example of url which uses templates.

<proxies>
    <proxy>
        <name>[PROXY-NAME]</name> <!-- e.g. resourcespace -->
        <targetUri>http://192.168.203.129:{_port}</targetUri> <!-- e.g. destination target Uri -->
        <useTemplate>true</useTemplate>
    </proxy>
</proxies>

The new proxed URL must be called with ALL the parameters in its querystring, e.g.

http://swing/[PROXY-NAME]/users/get?_port=8080&id=userID

Note: if the parameter is missing, the URL will return an HTTP 500 error.

Note: due to the nature of the Template Servlet, in this mode it is not possible to pass arrays as querystrings ( i.e. more than one querystring parameter with the same name ).

Configuration of the url

To point to the external url, it is mandatory to configure the url option. Please notice that, considering that you have just configured the correct proxy for your application, the url will be actually a subset of the Swing url.

{
    // ...
    url: 'http://localhost:9797/swing/newcontentproxy/index.html0
    // ...
}

Closing the dialog

The "full" custom dialog actually includes your custom external url inside a Swing modal dialog. Since there is no interaction between it and your code, the only way for the customer to close the Swing dialog is to put the following code inside their application.

// Creation code of your application..
// At the end of it, put the following code
if (window.top.eidosmedia) {
    window.top.eidosmedia.closeCurrentDialog();
}

Accessing the Context Object

The "full" custom dialog actually includes your custom external url inside a Swing modal dialog. Since there is no interaction between it and your code, the only way for the customer to access the Swing context (with all the limitation of being in another iframe), is the following.

// Creation code of your application..
// At the end of it, put the following code
if (window.top.eidosmedia) {
    var CTX = window.top.eidosmedia.getCTX();
    // Get current user...
    var currentUserName = CTX.getCurrentUser().getName();
    // All methods of the CTX are available (such as getChannels, getWorkfolders, getTemplates)
}

Full example

eidosmedia.webclient.extensions.newcontent.register( ['story'], {
    dialogType: 'full',
    title: 'Custom story creation dialog',
    url: 'http://localhost:8080/swing/testcustomcontent/index.html',
    layout: 'fullPage'
});

The code above will let Swing understand that the operation is done.

Important

This will only work if the external url is Proxied inside Swing using the Proxy configuration.

Contained custom dialog configuration

The contained dialog is used in other to insert custom HTML in the New Content Creation dialog of Swing. The contained dialog is wrapped inside Swing, and uses a custom template. Inside the dialog, it is possible to use the Context Object to retrieve important information. See Context Object (ctx parameter) for further information.

The dialog can be configured with additional properties.

template

[Optional if dialogType is 'full'] {String} template defines the template of the dialog. The template is placed under the following path:

{SWING}/config/templates/newcontent/
Tip
Swing supports Tomcat 9.x, so custom panels can be configured outside {SWING-APP}. See the paragraph How to configure custom dialog in external folder for some tips in how to take advantage of this configuration option.

The template is an HTML file, and there is maximum liberty in its content. Please refer to Contained custom dialog configuration documentation for further information.

Example

{
    // ...
    template: "mycustomnewcontent.html",
    // ...
}

showCreateButton

{Boolean} showCreateButton if true, the Create button is shown in the Modal footer, and the creation process is managed by Swing by calling the getCreationInfo method when the user clicks on the button.

Example

{
    // ...
    showCreateButton: true,
    // ...
}

Full example

eidosmedia.webclient.extensions.newcontent.register( ['story'], {
    template: 'newcustom.html',
    dialogType: 'contained',
    title: 'Custom story creation dialog',
    layout: 'fullPage',
    showCreateButton: true,
    postFillForm: function(ctx, $dialog) {
        // There are some APIs available to list channels, teams,
        // access the metadata of the user, and so on...
    },
    getCreationInfo: function( ctx, dialog, callback ) {
        var $dialog = $(dialog);
        var team = $dialog.find('[data-field-type="team"]').val();
        // ...
        callback({
            team: team,
            channel: channel,
            // ...
        })
    }
});

Methods of the creation dialog in Full or Contained mode

postFillForm

Method called when the dialog and its custom html has been loaded. It can be used to add custom listeners to buttons, make some elaborations, etc..

The syntax is the following:

postFillForm( ctx, dialog );
Table 121. Method information

Method

postFillForm

Parameter

{object} ctx - The context object. See Context Object (ctx parameter) for further information.

Parameter

{DOM object} dialog - The DOM reference to the dialog

Returns

undefined

Example

// options object...
{
    postFillForm: function( ctx, dialog ) {
        var $dialog = $(dialog);

        var _teams = ctx.getTeams();
        var teamHtml = _.map( _teams, function(t) {
            return '<option>' + t.name + '</option>';
        });
        $dialog.find('[data-field-type="team"]').html( _.map() );
        $('.my-custom-button', dialog ).on('click', function() {
            // do something here
        });
    }
}

getCreationInfo

Method called when the user clicks on the "Create" button. In this method, the dialog should return a JSON object with all the information necessary to call the REST api /object/create.

Important

This will be called in the following circumstances:

  • showCreateButton set to true and dialogType either full or contained and user clicks on the create Button

The syntax is the following:

getCreationInfo( ctx, dialog, callback );
Table 122. Method information

Method

getCreationInfo

Parameter

{object} ctx - The context object. See Context Object (ctx parameter) for further information.

Parameter

{DOM object} dialog - The DOM reference to the dialog

Parameter

{Function} callback - The function to be called with the JSON object for the /object/create REST API

Returns

undefined

Example

// options object...
{
    getCreationInfo: function( ctx, dialog, callback ) {
        var $dialog = $(dialog);
        var team = $dialog.find('[data-field-type="team"]').val();
        // ...
        callback({
            team: team,
            channel: channel,
            // ...
        })
    }
}

onCreate

Method called when the user clicks on the "Create" button and the getCreationInfo method is not defined. In this method, the dialog should return a JSON object with the information of the created content.

Important

This will be called in the following circumstances:

  • showCreateButton set to true and dialogType either full or contained and user clicks on the create Button

The syntax is the following:

onCreate( ctx, dialog, callback );
Table 123. Method information

Method

onCreate

Parameter

{object} ctx - The context object. See Context Object (ctx parameter) for further information.

Parameter

{DOM object} dialog - The DOM reference to the dialog

Parameter

{Function} callback - The function to be called with the JSON object with the information of the created content

Returns

undefined

Example

// options object...
{
    onCreate: function( ctx, dialog, callback ) {
        var $dialog = $(dialog);
        var team = $dialog.find('[data-field-type="team"]').val();
        // ...
        callback({
            id: content.id,
            name: content.name,
            // ...
        })
    }
}

Template custom dialog configuration

The template custom dialog overrides the template / shape choice panel inside the standard "New Content" dialog of Swing. Inside the dialog, it is possible to use the Context Object to retrieve important information or use a set of APIs to interact with the creation dialog (see below). See Context Object (ctx parameter) for further information on CTX object.

Important

Starting from version 5.2020.09 the new content creation dialog system has been renewed and redesigned in React with a modern, responsive UI. Due to this change, legacy template dialog customisations won’t work anymore. Template custom dialog is still supported but a refactoring of existing customization is required.

Template configuration object example

{
  // ...
  dialogType: "template",
  template: "mycustomnewcontent.html",
  createContent: function ({inputs, formData, dataConfig, callbacks}) {},
  renderTemplate: function ({loading, error, templates, ctx, dataConfig, callbacks}) {},
  renderShape: function ({loading, error, shapes, ctx, dataConfig, callbacks}) {},
  // ...
}

Configuration properties

dialogType

[Mandatory] {String} Set to "template" for template custom dialog configuration

template

[Mandatory] {String} defines the template of the dialog. The template is placed under the following path:

{SWING}/config/templates/newcontent/
Tip
Swing supports Tomcat 9.x, so custom panels can be configured outside {SWING-APP}. See the paragraph How to configure custom dialog in external folder for some tips in how to take advantage of this configuration option.

The template is an HTML file, and there is maximum liberty in its content.

createContent

[Optional] {Function} If defined, the process to create the content is completely customizable. This function is called on "Submit" button press. If this function is not defined the content is created using the default dialog creation flow.

Table 124. Parameters

Name

Type

Description

inputs

{Object}

Contains the full data set for the inputs controllers (teams, channels, editions, inserts, workfolders, …​)

formData

{Object}

Contains the data currently set by the user or programmatically using the `setFormData`api

dataConfig

{Object}

Contains the full data set about configurations

callbacks

{Object}

Contains a set of functions api to comunicate with the dialog. See the following table for details

Table 125. callbacks object fields api

Name

Description

Parameters

setError

Set an error status for the dialog, It’s possible set an error status for a particular component or display an error alert to the user

{String or Object} A string to display an error alert or an object {input, message} to set an input field in status error

resetErrors

Clear the error status for the dialog

setLoading

Set\unset the dialog in a loading status

{Boolean} Loading status

close

Close the dialog

renderTemplate

{Function} renderTemplate is called multiple times: whenever the dialog is loading data (with loading parameter true), when there is an error (with error parameter defined) or when templates data has been retrieved (loading false, error undefined, templates array filled).

Table 126. Parameters

Name

Type

Description

loading

{Boolean}

True if the dialog is in loading state to retrieve the templates

error

{String}

If an error occured contains the error otherwise will be undefined.

templates

{Array}

Contains the retrieved set of templates based on dialog form inputs.

ctx

{Object}

The CTX object

dataConfig

{Object}

as described above

callbacks

{Object}

Contains a set of functions api to comunicate with the dialog. See the following table for details

Table 127. callbacks object fields api

Name

Description

Parameters

setTemplate

Set the chosen template

{Object} template

setError, resetErrors, setLoading

as described above

as described above

getFormData

Retrieve the data set by the user. Reserved string paramater values are 'name', 'issueDate', 'team', 'edition', 'insert', 'channel', 'location', 'workfolder', 'template', 'shape', 'createTopicFrom', 'conflictResolutionMode', 'moderation', 'summary' or the custom data key stored using setFormData

{String} Form data key

setFormData

Store a custom data to be retrieved using getFormData function or from formData object

{String} Form data key, {Any} Form data value. Be carefully to not override the reserved key values listed in getFormData

renderShape

{Function} renderShape same behavior of the renderTemplate function but with shapes data. setShape function is provided in callbacks parameter to set the chosen shape.

Full example

The full customization example code can be found in {SWING}/config/templates/newcontent/ installation folder. See files newcontentTemplate(.js | .html | .css).

eidosmedia.webclient.extensions.newcontent.register(["story"], {
  dialogType: "template",
  template: "newcontent.html",

  // Optional. Define it only if you need to take control of create content process
  createContent: function ({ inputs, formData, dataConfig, callbacks }) {
    const { setError, resetErrors, setLoading, close } = callbacks;
    // ...
  },

  renderTemplate: function ({
    loading,
    error,
    templates,
    ctx,
    dataConfig,
    callbacks,
  }) {
    const {
      setTemplate,
      setError,
      resetErrors,
      setLoading,
      getFormData,
      setFormData,
    } = callbacks;
    // ...
  },

  renderShape: function ({
    loading,
    error,
    shapes,
    ctx,
    dataConfig,
    callbacks,
  }) {
    const { setShape } = callbacks;
    // ...
  },
});

Tab custom dialog configuration

Using tab custom dialog configuration is possible to add one or more custom tabs inside the standard "New Content" dialog of Swing along with the standard Template and Shape tabs. Inside the tabs you can use the Context Object to retrieve important information or use a set of APIs to interact with the creation dialog (see below). See Context Object (ctx parameter) for further information on CTX object.

Tab configuration object example (2 tabs)

{
  // ...
  dialogType: "tab",
  title: { tab1: "Title Tab", tab2: "Title Tab 2" }
  template: { tab1: "mycustomtab1.html", tab2: "mycustomtab2.html" },
  createContent: function ({inputs, formData, dataConfig, callbacks}) {},
  renderTab: {
    tab1: function ({ inputs, formData, ctx, dataConfig, callbacks }) {},
    tab2: function ({ inputs, formData, ctx, dataConfig, callbacks }) {}
  }
}

Please note that title, template and renderTab are objects having keys tab1, tab2. These keys are used to indentify a specific tab setup. Any string can be used execept the reserved strings template and shape.

Configuration properties

dialogType

[Mandatory] {String} Set to "tab" for tab custom dialog configuration

title

[Mandatory] {Object} defines the title for the custom tabs.

template

[Mandatory] {Object} defines the template for the custom tabs. The templates are placed under the following path:

{SWING}/config/templates/newcontent/
Tip
Swing supports Tomcat 9.x, so custom panels can be configured outside {SWING-APP}. See the paragraph How to configure custom dialog in external folder for some tips in how to take advantage of this configuration option.

The template is an HTML file, and there is maximum liberty in its content.

createContent

[Optional] {Function} If defined, the process to create the content is completely customizable. This function is called on "Submit" button press. If this function is not defined the content is created using the default dialog creation flow.

Table 128. Parameters

Name

Type

Description

inputs

{Object}

Contains the full data set for the inputs controllers (teams, channels, editions, inserts, workfolders, …​)

formData

{Object}

Contains the data currently set by the user or programmatically using the `setFormData`api

dataConfig

{Object}

Contains the full data set about configurations

callbacks

{Object}

Contains a set of functions api to comunicate with the dialog. See the following table for details

Table 129. callbacks object fields api

Name

Description

Parameters

setError

Set an error status for the dialog, It’s possible set an error status for a particular component or display an error alert to the user

{String or Object} A string to display an error alert or an object {input, message} to set an input field in status error

resetErrors

Clear the error status for the dialog

setLoading

Set\unset the dialog in a loading status

{Boolean} Loading status

close

Close the dialog

renderTab

{Function} renderTab can be called multiple times: at tab opening, whenever the dialog is loading data (with loading parameter true), when there is an error (with error parameter defined) or when input data changes.

Table 130. Parameters

Name

Type

Description

inputs

{Object}

Contains the full data set for the inputs controllers (teams, channels, editions, inserts, workfolders, …​)

formData

{Object}

Contains the data currently set by the user or programmatically using the `setFormData`api

ctx

{Object}

The CTX object

dataConfig

{Object}

as described above

callbacks

{Object}

Contains a set of functions api to comunicate with the dialog. See the following table for details

Table 131. callbacks object fields api

Name

Description

Parameters

setTemplate

Set the chosen template

{Object} template

setError, resetErrors, setLoading

as described above

as described above

getFormData

Retrieve the data set by the user. Reserved string paramater values are 'name', 'issueDate', 'team', 'edition', 'insert', 'channel', 'location', 'workfolder', 'template', 'shape', 'createTopicFrom', 'conflictResolutionMode', 'moderation', 'summary' or the custom data key stored using setFormData

{String} Form data key

setFormData

Store a custom data to be retrieved using getFormData function or from formData object

{String} Form data key, {Any} Form data value. Be carefully to not override the reserved key values listed in getFormData

Full example

The full customization example code can be found in {SWING}/config/templates/newcontent/ installation folder. See files newcontentTab(.js | .html | .css).

eidosmedia.webclient.extensions.newcontent.register(["story"], {
  template: { tab1: 'newcontenttab.html', tab2: 'newcontenttab2.html' },
  title: { tab1: 'My first custom tab', tab2: 'Custom Shape' },
  dialogType: 'tab',

  // Optional. Define it only if you need to take control of create content process
  createContent: function ({ inputs, formData, dataConfig, callbacks }) {
    const { setError, resetErrors, setLoading, close } = callbacks;
    // ...
  },

  renderTab: {
      tab1: function({ inputs, formData, ctx, dataConfig, callbacks }) {
        const { setTemplate, setError, resetErrors, setLoading, getFormData, setFormData } = callbacks;
      },
      tab1: function({ inputs, formData, ctx, dataConfig, callbacks }) {}
  }

});

HTML Template

Swing provides a sample template inside the following folder.

{SWING}/config/templates/newcontent/

Please use it as a reference. In general, no restriction is given to the HTML code.

Context Object (ctx parameter)

Inside the different methods in the New Content Dialog configuration, the Context Object is available. See Context object documentation for reference.

Furthermore, the New Content Dialog context object has several specific methods available.

getTemplates

Return the list of templates, given some options. See the example for all the options available.

Syntax

ctx.getTemplates( options, callback );

Parameters

Table 132. Parameters

Name

Type

Required

Description

options

{Object}

Required

A set of options to retrieve the templates. See the example for all the options available.

callback

{Function}

Required

A callback function. See Callback definition for further information.

Returns

Table 133. Parameters

Name

Type

Description

data

{Array}

An array with a list of templates

Example

{
    // ...
    postFillForm: function(ctx, dialog, extraInfo) {

        var options = {
            workfolder: '/Globe/Art', // MANDATORY
            type: 'topic' // optional, the template type for filtering.
            // Could be "story", "gallery", "prs", "pkg"
        }

        // Synchronous way...
        try {
            var templates = ctx.getTemplates(options);
        } catch(ex) {
            // manage error here
        }

        // Better way...
        ctx.getTemplates(options, function(err, data) {
            var $dialog = $(dialog);
            if (err) {
                $dialog.find('.error-message').html(err.message).show();
                return;
            }
            // data is an array of templates...
            /* Like this:

            [
              {
                "id": "199$1.0.21025653",
                "name": "bio",
                "type": "EOM::Story",
                "contentType": "story",
                "path": "/SysConfig/Globe/Templates/bio.xml",
                "isDefault": false,
                "dir": "/SysConfig/Globe/Templates",
                "system_attributes": {
                  "workfolder": "",
                  "templateName": "",
                  "summary": "",
                  "wordCount": "",
                  "sugCategory": "",
                  "channel": "",
                  "edition": "",
                  "storyType": "",
                  "productInfo": {
                    "name": "",
                    "issueDate": ""
                  }
                }
              }, ...
            ]
            */
        });
    }
    // ...
}

Note

The method can also be called synchronously, but this usage is not recommended.

getChannels

Return the list of channels, given some options. See the example for all the options available.

Syntax

ctx.getChannels( options, callback );

Parameters

Table 134. Parameters

Name

Type

Required

Description

options

{Object}

Required

A set of options to retrieve the channels. See the example for all the options available.

callback

{Function}

Required

A callback function. See Callback definition for further information.

Returns

Table 135. Parameters

Name

Type

Description

data

{Array}

An array with a list of channels

Example

{
    // ...
    postFillForm: function(ctx, dialog, extraInfo) {

        var options = {
            showTemplates: truem
            showInserts: true,
            showCalendar: true
        }

        // Synchronous way...
        try {
            var channels = ctx.getChannels(options);
        } catch(ex) {
            // manage error here
        }

        // Better way...
        ctx.getChannels(options, function(err, data) {
            var $dialog = $(dialog);
            if (err) {
                $dialog.find('.error-message').html(err.message).show();
                return;
            }
            // data is an array of channels...
            /* Like this:

            [
                  {
                    "id": "199$0",
                    "name": "Globe-Print",
                    "displayName": "Globe-Print",
                    "type": "print",
                    "isDefault": false,
                    "editions": [
                      {
                        "name": "EUROPE",
                        "_default": false
                      },
                      {
                        "name": "USA",
                        "_default": false
                      },
                      {
                        "name": "ASIA",
                        "_default": false
                      }
                    ],
                    "inserts": [
                      "Insert One",
                      "Insert Two"
                    ],
                    "calendar": {
                      //...
                    },
                    "cobaltSite": false
                  }
                ]
            */
        });
    }
    // ...
}

Note

The method can also be called synchronously, but this usage is not recommended.

getTeams

Return the list of teams, given some options. See the example for all the options available.

Syntax

ctx.getTeams( options, callback );

Parameters

Table 136. Parameters

Name

Type

Required

Description

options

{Object}

Required

A set of options to retrieve the teams. See the example for all the options available.

callback

{Function}

Required

A callback function. See Callback definition for further information.

Returns

Table 137. Parameters

Name

Type

Description

data

{Array}

An array with a list of basefolders

Example

{
    // ...
    postFillForm: function(ctx, dialog, extraInfo) {

        var options = {
            showChannels: truem
        }

        // Synchronous way...
        try {
            var teams = ctx.getTeams(options);
        } catch(ex) {
            // manage error here
        }

        // Better way...
        ctx.getTeams(options, function(err, data) {
            var $dialog = $(dialog);
            if (err) {
                $dialog.find('.error-message').html(err.message).show();
                return;
            }
            // data is an array of teams...
        });
    }
    // ...
}

Note

The method can also be called synchronously, but this usage is not recommended.

getWorkfolders

Return the list of workfolders, given some options. See the example for all the options available.

Syntax

ctx.getWorkfolders( options, callback );

Parameters

Table 138. Parameters

Name

Type

Required

Description

options

{Object}

Required

A set of options to retrieve the workfolders. See the example for all the options available.

callback

{Function}

Required

A callback function. See Callback definition for further information.

Returns

Table 139. Parameters

Name

Type

Description

data

{Array}

An array with a list of workfolders

Example

{
    // ...
    postFillForm: function(ctx, dialog, extraInfo) {

        var options = {
            team: 'Globe_Team', // one of them is necessary, according to your requirements
            contentType: 'story'
        }

        // Synchronous way...
        try {
            var workfolders = ctx.getWorkfolders(options);
        } catch(ex) {
            // manage error here
        }

        // getBaseFolder way...
        ctx.getWorkfolders(options, function(err, data) {
            var $dialog = $(dialog);
            if (err) {
                $dialog.find('.error-message').html(err.message).show();
                return;
            }
            // data is an array of workfolders...
        });
    }
    // ...
}

Note

The method can also be called synchronously, but this usage is not recommended.

getSelectedOptions

Return the data info related to the selected topic item.

Syntax

ctx.getSelectedOptions();

Returns

Table 140. Parameters

Name

Type

Description

data

{Object}

A JSON object with topic item properties

Example

{
    // ...
    postFillForm: function(ctx, dialog, extraInfo) {

        const options = ctx.getSelectedOptions();

       /* options like this:

           {
               channel: "Globe-Web/English",
               edition: "English",
               issueDate: "20200901",               name: "USA 2020 Elections.xml",
               workfolder: "/Globe/Politics"
           }
        */
    }
    // ...
}

createDocument

Create a new document with the options passed. The newly created document is automatically opened.

Syntax

ctx.createDocument( options, callback );

Parameters

Table 141. Parameters

Name

Type

Required

Description

options

{Object}

Required

A set of options to create the document. See the details in the box belox.

callback

{Function}

Required

A callback function. See Callback definition for further information.

Returns

Table 142. Parameters

Name

Type

Description

Object

{Object class}

An instance of the Object Class. See Object class methods for further information on the methods available.

Options

The request to the createDocument method is a JSON with the following properties:

  • name: the file name. It must end with .xml for stories or .pkg for topics.

  • template: the path of the source template. It is mandatory

  • team: the base team

  • channel: the document channel

  • insert: the information on inserts

  • edition: the edition

  • issueDate: if available, the issueDate in the format YYYYMMDD.

  • workfolder: the workfolder of the document

  • path: the document path

  • workStatus: optional to specify the status of the document. The workStatus must be a valid status, reachable from the initial status in which the document is created.

  • attributes: optional to specify the metadata of the document

  • newObjOption: a number describing the behaviour in case of files with the same name. Values are the following:

    • 0 - An error is thrown

    • 1 - The new file is automatically renamed

    • 2 - The file is replaced

    • 3 - A new version is created

Example

{
    // ...
    postFillForm: function(ctx, dialog, extraInfo) {
        var _ctx = ctx;
        // With your custom button...

        $(dialog).on('click', '.create-button', function(event) {
            var request = {
                "name": "TestCreateCustom2.xml",
                "template": "/SysConfig/Globe/Templates/story-external.xml",
                "team": "Globe_Team",
                "channel": "Globe-Print",
                "insert": "Insert One",
                "attributes": "<test>true</test>",
                "workStatus": "NewsFlow/Editing",
                "edition": "EUROPE",
                "issueDate": "20170713",
                "workfolder": "/Globe/Art",
                "newObjOption": 2,
                "path": "workfolder:///Globe/Art"
            };
            ctx.createDocument(request, function(err, Obj) {
                if (err) {
                    ctx.showError(err);
                    return;
                }

                // The document is automatically opened
                // But I can still retrieve its info
                var newId = Obj.getId()

            });
        });
    // ...
}

Note

The method cannot be called synchronously.

createTopic

Create a new topic with the structure passed. Please refer to the REST API documentation for further info: Topic Creation documentation. Please notice that in this case the document is NOT opened.

Syntax

ctx.createTopic( options, callback );

Parameters

Table 143. Parameters

Name

Type

Required

Description

options

{Object}

Required

A set of options to create the document. See the details in the box belox.

callback

{Function}

Required

A callback function. See Callback definition for further information.

Returns

Table 144. Parameters

Name

Type

Description

Object

{Object class}

An instance of the Object Class. See Object class methods for further information on the methods available.

Example

{
    // ...
    postFillForm: function(ctx, dialog, extraInfo) {
        var _ctx = ctx;
        // With your custom button...

        $(dialog).on('click', '.create-button', function(event) {
            var request = {
            "containerType":"TOPIC",
            "source":"",
            "attributes": "<test>true</test>",
            "workStatus": "NewsFlow/Editing",
            "path":"/TestTopicPlan/Topic",
            "name":"I giochi a Rio",
            "description":"I Giochi della XXXI...",
            "correlates" : [ { "containerType": "CORRELATES", "source" : "loid:9$2.0.798314409", "correlationType": "RELATED_IMAGE" }],
            "children":[
                {
                    "containerType":"TOPICITEM",
                    "name":"La città di Rio De Janero",
                    "dueDate":"20160501",
                    "size":"2 colonne",
                    "channel":"Globe-Web",
                    "author":"Mario Rossi",
                    "comment":"This is a topic item comment",
                    "priority":"TASK_PRIORITY_NORMAL",
                    "content":"picture",
                    "workFolder":"/Globe/Sport",
                    "assignment":"test,prova1",
                    "asset":"",
                    "correlates" : [ { "containerType": "CORRELATES", "source" : "loid:9$2.0.798137329", "correlationType": "RELATED_IMAGE" }],
                    "children":[
                        {
                            "containerType":"TOPICSUBITEM",
                            "name":"Rio - Foto",
                            "dueDate":"20160501",
                            "size":"2 colonne",
                            "channel":"Globe-Web",
                            "author":"Mario Rossi",
                            "comment":"This is a sub topic item comment",
                            "priority":"TASK_PRIORITY_LOW",
                            "content":"PICTURE",
                            "workFolder":"/Globe/Sport",
                            "assignment":"test,prova1",
                            "asset":{
                                "source":"loid:9$2.0.795001757"
                            }
                        },
                        {
                            "containerType":"DIVIDER",
                            "source":"",
                            "name":"SUBITEM DIVIDER",
                            "font":{
                                "bold":true,
                                "color":"2558080",
                                "faceName":"Tahoma",
                                "italic":"false",
                                "lineThrough":"false",
                                "size":"14",
                                "underline":"true"
                            }
                        },
                        {
                            "containerType":"TOPICSUBITEM",
                            "name":"Rio - Foto",
                            "dueDate":"20160501",
                            "size":"2 colonne",
                            "channel":"Globe-Web",
                            "author":"Mario Rossi",
                            "comment":"This is a sub topic item comment",
                            "priority":"TASK_PRIORITY_LOW",
                            "content":"PICTURE",
                            "workFolder":"/Globe/Sport",
                            "assignment":"test,prova1",
                            "asset":{
                                "source":"loid:9$2.0.795001794"
                            }
                        }
                    ]
                },
                {
                    "containerType":"DIVIDER",
                    "source":"",
                    "name":"SUBTOPIC DIVIDER",
                    "font":{
                        "bold":true,
                        "color":"000000",
                        "faceName":"Tahoma",
                        "italic":"false",
                        "lineThrough":"false",
                        "size":"14",
                        "underline":"true"
                    }
                },
                {
                    "containerType":"TOPICITEM",
                    "name":"Le zone dei giochi",
                    "dueDate":"20160501",
                    "size":"2 colonne",
                    "channel":"Globe-Web",
                    "author":"Mario Rossi",
                    "comment":"This is a topic item comment",
                    "priority":"TASK_PRIORITY_NORMAL",
                    "content":"picture",
                    "workFolder":"/Globe/Sport",
                    "assignment":"test,prova1",
                    "asset":"",
                    "children": []
                }
            ]
        };
            ctx.createTopic(request, function(err, Obj) {
                if (err) {
                    ctx.showError(err);
                    return;
                }

                // The document is automatically opened
                // But I can still retrieve its info
                var newId = Obj.getId()

            });
        });
    // ...
}

Note

The method cannot be called synchronously.

Callback definition

Important

The callback parameter, when specified, is always defined as follows:

// Callback definition
function( err, response ) {
    // This is the "Node.js" callback style.
    // It forces the developer to manage the errors.

    if (err) {
        // Do something...
        return;
    }

    // Real implementation here

}

Obtain a usable Context Object

For several reason, it could be necessary to use the Swing Context Object. In an iframed custom template, the only way to obtain it is to call

window.top.eidosmedia.webclient.app.getCurrentDocumentContext()

which returns an available CTX. Please refer to Context object documentation for further reference.

How to configure custom dialog in external folder

Additional objects may be made available to Swing application by defining one or more nested components in Swing web context in server.xml. (for further details on Tomcat 9.x Resources configuration, please refer to Resources configuration).

This is an example of the external custom panels configuration.

<Context docBase="com.eidosmedia.webclient.web-app"
    path="/swing" reloadable="false">
    <Resources
        className="org.apache.catalina.webresources.StandardRoot">
        <PreResources
            className="org.apache.catalina.webresources.DirResourceSet"
            base="/methode/meth01/extension/newcontent" readOnly="true"
            webAppMount="/config/templates/newcontent" />
    </Resources>
</Context>

Preview extensions

Preview API can be found under the following namespace:

eidosmedia.webclient.extensions.preview

In such namespaces, three methods are available: openPreview, addContentLoader. They are explained in detail in the following paragraphs.

Location of the custom Preview extensions.

In general, all the extensions of Méthode Swing are places under

{SWING-APP}/plugins

So, all the Javascript described in the following sections should be placed under

{SWING-APP}/app/plugins/{EXTENSION-FOLDER}/{EXTENSION-NAME}.js
Caution

Do not use the word libs as an extension folder. The libs folder is reserved for loading external libs. See the proper documentation to obtain further info on the topic.

Tip

DEBUG MODE: by default, all plugins are aggregated into a single plugins.js file at the Tomcat startup. When creating a plugin, it may be frustrating to restart the Tomcat Server every time a change is made.

To avoid this, set the configuration property debugEnabled to true.

Then, that extension will be loaded on every refresh of the page.

Open preview

To open the preview of an object, you must call the following method:

eidosmedia.webclient.extensions.preview.openPreview( item, options );

The method accepts 2 parameters:

  • item: (object), mandatory - a Javascript Object with item information.

  • options: (object), not mandatory - a Javascript Object including the preview options.

Important

The options object is a Javascript object with the following properties:

  • loadObject (default is false) - Reloads the item information.

Example:

eidosmedia.webclient.extensions.preview.openPreview({ id: '0$1.0.236095983' });

Add custom content

Custom content can be loaded in the lazyLoad part of the preview. To add a custom content, simply call the addCustomContent method as follows:

eidosmedia.webclient.extensions.preview.addCustomContent( name, action );

For example:

eidosmedia.webclient.extensions.preview.addCustomContent( 'mycustomextension', function( ctx, callback ) {
    ctx.activeObject.getMetadata(function(metadata) {
        var videoUrl = $(metadata).find('WireURL').text();
        // We are calling the preview back with the value we want.
        callback( videoUrl );
    });
});

The method has two (mandatory) parameters:

  • name : the name of the custom content

  • action : the function to be called.

The action function has two parameters, ctx, which is the Context Object, and callback, which is the function to call back the preview with the desired value. See Basic structure of the Context Object for further details.

NOTE: to load your custom extension within the preview, simply add the following tag at the beginning of the preview template:

<load id="mycustomextension"/> // Replace mycustomextension with your extension's name

and use the following syntax to call your customextension within the preview:

Result: <%=data.mycustomextension%> // Prints "Result: custom extension! Preview item id: 0$123452324"

Add custom actions

It is possible to add custom actions in preview. To register an action, see how to add a custom command in Swing.

Tip

The action will be passed the Context Object as the first parameter. See Basic structure of the Context Object for further details.

Tip

To add your custom action within the preview, you need to used the data-emaction parameter as follows:

<button data-emaction="mycustomaction">Click me, I'm useful!</button> // Prompts " You clicked on this custom action! ... "
Tip

You can use the loaded information when calling an action. For example, if you want to show and use the userInfo within a custom action, you can do as follows:

<load id="userInfo"/> <!-- Load the user info -->
... <!-- Some awesome preview template -->

<button data-emaction="showcreatorinfo">Click me, I know the document creator!</button>

and, in the plugin folder,

eidosmedia.webclient.commands.add({
    name: 'showcreatorinfo',
    action: function (ctx, params, callbacks) {
        alert( ctx.activeObject.getInfo().userInfo.name + ' is the document creator!' );
    }
});

Uploader extensions

Méthode Swing uploader can be extended with custom behaviour.

Location of the Uploader extensions

In general, all the extensions of Méthode Swing are places under

{SWING-APP}/plugins

So, all the Javascript described in the following sections should be placed under

{SWING-APP}/app/plugins/{EXTENSION-FOLDER}/{EXTENSION-NAME}.js
Caution

Do not use the word libs as an extension folder. The libs folder is reserved for loading external libs. See the proper documentation to obtain further info on the topic.

Tip

DEBUG MODE: by default, all plugins are aggregated into a single plugins.js file at the Tomcat startup. When creating a plugin, it may be frustrating to restart the Tomcat Server every time a change is made.

To avoid this, set the configuration property debugEnabled to true.

Then, that extension will be loaded on every refresh of the page.

Image data extractor

When uploading files to Swing it’s possible to define a image data extractor function which will be called before the load the default metadata from server.

Registration

Important

Image data extractor implementation with eidosmedia.webclient.extensions.objectpanel.addImageDataExtractor method is not supported anymore.

Image data extractor extension was moved to object panel customizations.

Please refer to the onImageProcessing method on Object Panel documentation for further information.

Filename Validation

When uploading files to Swing it’s possible to define a filename validation function which will be called before the actual files are transfered to the server. To add a filename validator, it is necessary to register it inside Swing by calling the following Javascript function, inside your Javascript file:

eidosmedia.webclient.extensions.uploader.validateFilename = function( filename ){}

Parameters

  • "filename": The filename to validate.

Note
The function must the return the new filename.

Implementation Example

eidosmedia.webclient.extensions.uploader.validateFilename = function( filename ) {
    return "VALIDATED_" + filename;
};

Metadata Validation

When uploading files to Swing it’s possible to define a validation function which will be called before the actual files are transfered to the server. To activate this function it’s important to first define the correct validation namespace.

Namespace

Create a javascript file inside the plugin folder defining extending the objectpanel object with a new function called validateMetadata:

eidosmedia.webclient.extensions.objectpanel.validateMetadata = function( ctx, items, callbacks ){}

Parameters

  • "ctx": The ctx is a JSON object which represents the object’s context. Available only in init method. See Basic structure of the Context Object for further details.

  • "items": An array with the objects to be uploaded.

  • "callbacks": An object with success and error functions.

Validate data

Once the validateMetadata function is called it’s possible to cycle through the array of items and for each item work with its XML metadata document.

Caution
If all the checks on the XML documents are valid, call the callbacks.success function to proceed with the upload process; otherwise call the callbacks.error.

Callbacks and parameters

When calling the callbacks.error function it’s mandatory to pass two arguments.

callbacks.error(
    { msgError: 'General Error Message'},
    [{id: 'picId', msgError:'Specific Error Message'}]
 );

The first parameter is an object with the general error message to display after the validation. The second is the items array we received as input in the validateMetadata function but modified with a msgError property for those items (and only for those items) which failed validation.

Final Implementation Example

eidosmedia.webclient.extensions.objectpanel.validateMetadata = function(ctx, items, callbacks){

    var generalValidationOK = true;
    var itemsWithError = [];

    $(items).each(function(i, el){

        var xmlMetadataDoc = el.data.metadata;
        // call external validation method
        var validationOK = _callMyValidationMethod(xmlMetadataDoc);

        if ( !validationOK ){
            generalValidationOK = false;
            el.msgError = 'This item metadata is not valid!'
            itemsWithError.push( el );
        }
    });

    if ( generalValidationOK ){
        callbacks.success();

    } else {

        callbacks.error(
                {msgError: 'Error Message'},
                itemsWithError
        );
        generalValidationOK = true;
    }
};

Import URL: preview and import information.

With Swing it is possible to drag external URLd. Since there can’t be any control on the content of the URL, Swing tries to propose a generic preview, consisting in an iframe pointing to the specific URL.

Then, when trying to import the content, three standard cases may apply:

  • the content is recognized as an image. This will be imported as an image into the EOMDB.

  • the content is recognized as an HTML file. This will be imported as a URL into the EOMDB.

  • the content is not recognized as one of the above. This will be imported but its well-functioning is not guaranteed.

So, Swing allows to specify custom information to provide a more precise response according to the URL passed. It is possible to provide the preview information and the import information. A common use for this possibility is to perform regular expressions and provide additional information according to the url.

Specify preview information

Following the same guidelines of the other extensions, it is possible to specify a custom getPreviewInfoURL behaviour, registering a new uploader extension.

eidosmedia.webclient.extensions.uploader.add('getPreviewInfoURL', function( url, token, getConnectionURL ) { /* ... */ }

The parameters passed are:

  • the url.

  • the Swing application token.

  • the checkConnectionURL, an URL to be called to verify whether the token is valid.

The function must return a oEmbed-like json response, as the following example:

{
    //"version": "1.0",
    "type": "video",
    "importType": "video",
    //"provider_name": "YouTube",
    //"provider_url": "http://youtube.com/",
    //"width": 425,
    //"height": 344,
    //"title": "Amazing Nintendo Facts",
    //"author_name": "ZackScott",
    //"author_url": "http://www.youtube.com/user/ZackScott",
    "html":
        "<object width=\"425\" height=\"344\">
            <param name=\"movie\" value=\"http://www.youtube.com/v/M3r2XDceM6A&fs=1\"></param>
            <param name=\"allowFullScreen\" value=\"true\"></param>
            <param name=\"allowscriptaccess\" value=\"always\"></param>
            <embed src=\"http://www.youtube.com/v/M3r2XDceM6A&fs=1\"
                type=\"application/x-shockwave-flash\" width=\"425\" height=\"344\"
                allowscriptaccess=\"always\" allowfullscreen=\"true\"></embed>
        </object>"
}

What really matters here is the html attribute. This will be used by the Swing preview to show the content of the imported URL. Other parameters are, at the moment, ignored.

Another important attribute is the importType. It can specified either here or in the getImportInfoURL method. Please check the method in the following paragraph.

Specify import information

Following the same guidelines of the other extensions, it is possible to specify a custom getImportInfoURL behaviour, registering a new uploader extension.

eidosmedia.webclient.extensions.uploader.add('getImportInfoURL', function( url, token, getConnectionURL ) { /* ... */ }

The parameters passed are:

  • the url.

  • the Swing application token.

  • the checkConnectionURL, an URL to be called to verify whether the token is valid.

The function must return a Javascript, as the following example

{
    "importType": "picture",
    "filename": "someSpecificFilename"
}

If importType is specified, Swing will know better how to save the content. Otherwise, it will try to check the type attribute and, if no information is provided, the contentType of the url.

It is also possible to "force" a filename. This is especially useful in case of url without extension (e.g. services that return images). In that case, it would be better to specify a valid filename.

Important

If the type is valued as text/html ( the basic contentType of an HTML page ), the content will be imported as URL. Available importTypes are: picture,story,gallery,dwp,dwc,video,audio. This will determine the corresponding workfolder in which the content will be saved.

Important

getPreviewInfoURL and getImportInfoURL methods are optional. If not available, Swing will try to use the oEmbed protocol if available, and an internal preview system if the oEmbed protocol is missing. In that case, the importType will be guessed by the contentType of the URL response, and the preview will likely be an iframe pointing to the URL.

Final Implementation Example

eidosmedia.webclient.extensions.uploader.add('getPreviewInfoURL', function( url, token, checkConnectionURL ) {
    if ( url.match(/mycustomdamextension/ ) {
        return {
            "type": "image",
            "importType": "picture",
            "html":
            "<object width=\"425\" height=\"344\">
                <param name=\"movie\" value=\"http://www.youtube.com/v/M3r2XDceM6A&fs=1\"></param>
                <param name=\"allowFullScreen\" value=\"true\"></param>
                <param name=\"allowscriptaccess\" value=\"always\"></param>
                <embed src=\"http://www.youtube.com/v/M3r2XDceM6A&fs=1\"
                    type=\"application/x-shockwave-flash\" width=\"425\" height=\"344\"
                    allowscriptaccess=\"always\" allowfullscreen=\"true\"></embed>
            </object>"
        }
    } else {
        /* RETURNING NULL OR A FALSY VALUE OR AN OBJECT WITHOUT THE 'HTML' PROPERTY
           WILL RESULT IN SWING USING ITS STANDARD PREVIEW MECHANISM */
        return null;
    }
});

/* Please notice that, having specified the importType inside the
   getPreviewInfoURL method, the following method implementation is redundant */
eidosmedia.webclient.extensions.uploader.add('getImportInfoURL', function( url, token, checkConnectionURL ) {
    if ( url.match(/mycustomdamextension/ ) {
        return {
            "importType": "picture"
        }
    } else {
        /* RETURNING NULL OR A FALSY VALUE OR AN OBJECT WITHOUT THE 'HTML' PROPERTY
           WILL RESULT IN SWING USING ITS STANDARD MECHANISM */
        return null;
    }
});

Custom URL handling

With Méthode Swing it’s possible to add manipulation to a custom url.

Registration of a custom manipulation

To register a custom manipulation, use the following namespace

eidosmedia.webclient.extensions.manageCustomUrl

and its function

register( options )
Table 145. Method information

Method

register

Parameter

Required {object} options - An object containing more than one function that will be invoked to perform the custom manipulation.

Supported functions:

  • "handleUrl": Handle the custom url manipulation according to the area type

  • "getPreviewInfo": Handle the custom url to get preview info according to the area type

Returns

{undefined} undefined

The following is a very simple registration for a custom manipulation.

(function(){

    eidosmedia.webclient.extensions.manageCustomUrl.register({'handleUrl': function( data, ctx, callback ) {

            /**
             * Save the current url
             */
            var uri = data.uri;

            /**
             * Save the handle drop flag
             */
            var handleDrop = false;

            try {

                /**
                 * The area object it's useful to verify if the call come form the editor of the story
                 */
                var area = ctx.area;
                if (area.getType() == 'editor' && area.getName() == 'story') {

                    /**
                     * In our example we decide to handle only the url of eidosmedia site
                     * Change the if statement according to your needs
                     */
                    if (uri == 'https://www.eidosmedia.com/') {
                        var contentTitle = 'Eidosmedia link site';
                        handleDrop = true;

                        /**
                         * Prepare the xml to insert in the current active document context
                         */
                        var xml = '<a href="' + uri + '">' + contentTitle + '</a>';
                        ctx.activeDocument.insertXml(xml);
                    }
                }

                /**
                 * notify a callback, if specified, only if the drop has not been handled so Swing can manage
                 * the url in the standard way
                 */
                if (!handleDrop && callback) {
                    callback(data);
                }

            } catch (ex) {
                console.log("manageCustomUrl-handleUrl custom manipulation exception caught", ex);

                /**
                 * notify a callback, if specified, only if the drop has not been handled so Swing can manage
                 * the url in the standard way
                 */
                if (!handleDrop && callback) {
                    callback(data);
                }
            }
    }, 'getPreviewInfo': function( data, ctx ) {

        /**
         * Save the current url
         */
        var uri = data.uri;
        var currentXml = data.xml;
        var previewInfo;

        try {

            /**
             * The area object it's useful to verify if the call come form the editor of the story
             */
            var area = ctx.area;
            if (area.getType() == 'editor' && area.getName() == 'story') {

                /**
                 * In our example we decide to handle only the url of eidosmedia site
                 * Change the if statement according to your needs
                 */
                if (uri == 'https://www.eidosmedia.com/') {

                    var path = ''; // path of an image in the eomdb;
                    var customIcon = 'fa fa-exclamation-circle'; // the custom icon to use
                    previewInfo = {'path': path, 'icon': customIcon}
                }
            }

        } catch (ex) {
            console.log("manageCustomUrl-getPreviewInfo custom manipulation exception caught", ex);

        }

        return previewInfo;

    }});
})();
Note
  • "handleUrl" Must have three parameters. The first one contains info about the url to handle. The second one is the context where the url has to be handle. The third one it’s a callback that must be invoked if the url doesn’t need custom manipulation, in this case Swing can proceed to handle the url in the standard way.

  • "getPreviewInfo" Must have TWO parameters. The first one contains info about the url to handle. The second one is the context where the url has to be handle. The method must return the preview info.

Wrap all the custom manipulation with a try…​catch block to allow Swing to handle the url if something goes wrong.

Popovers

In Methode Swing it is possible to customize some popovers available in the application

Usage Ticket Popover

Usage Ticket popover is located under the following path:

/{swing-app-folder}/app/templatesUI/popinfo/usageticket-popinfo.html
Caution

Méthode Swing uses Underscore.JS templating system to enhance the user experience.

See Underscore.JS for further information, or the box below for some useful tips.

The template is rendered with a main object:

  • data, which is an object with a single property, usageTickets, which contains all the usage tickets.

Custom OEmbed Providers

In Methode Swing it is possible to configure custom oembed providers.

Prepare the plugin to add custom oembed providers

In general, all the extensions of Méthode Swing are places under

{SWING-APP}/plugins

So, all the Javascript described in the following sections should be placed under

{SWING-APP}/app/plugins/{EXTENSION-FOLDER}/{EXTENSION-NAME}.js
Caution

Do not use the word libs as an extension folder. The libs folder is reserved for loading external libs. See the proper documentation to obtain further info on the topic.

Tip

DEBUG MODE: by default, all plugins are aggregated into a single plugins.js file at the Tomcat startup. When creating a plugin, it may be frustrating to restart the Tomcat Server every time a change is made.

To avoid this, set the configuration property debugEnabled to true.

Then, that extension will be loaded on every refresh of the page.

Add a custom oembed provider

In order to add a custom oembed provider to Methode Swing, it is necessary to use the following namespace:

eidosmedia.webclient.extensions.oembedProviders

The syntax is the following:

eidosmedia.webclient.extensions.oembedProviders.add((customOmbedProviders);

Where:

  • customOmbedProviders [array] is a list of custom oembed providers (oembed provider object) to add to the already available ones.

EmbedProviderObject are defined in this way:

  • name [string] is the name of the custom oembed provider.

  • type [string] [photo | video | rich ] - is the type of the oembed provider.

  • urlschemearray [array] a list of regular expression to matxh the custom url oembed provider.

  • apiendpoint [string] an endpoint url if requetsed by the custom oembed provider. It can be null.

  • extraSettings [object] extra setting needed by the custom oembed provider. It can be null.

Note

It’s possible to configure an oembed provider to use a swing proxy. In this case the apiendpoint value must be the same of the proxy name and the attribute useSwingProxy of the extraSettings object must be set to true, the attribute dataType must be set according to the return value of the embed service that who made the extension has decided to integrate. In general it is set to the json value.

Example

eidosmedia.webclient.extensions.oembedProviders.add(
    [
        {
            name: 'scmptv',
            type: 'video',
            urlschemearray: ['widgets\\.scmp\\.com/video/.+'],
            apiendpoint: null,
            extraSettings: {
                templateRegex: /.*id=(\w+).*/,
                template: '<iframe src="http://widgets.scmp.com/video/video_iframe.php?id=$1" width="100%" allowfullscreen="true" allowscriptaccess="always"' +
                'scrolling="no" frameborder="0" style="max-height: none !important; height: 540px;"></iframe>',
                nocache: 1
            }
        },

        // custom oembed provider that use swing proxy
        {
            name: 'myvideoplace',
            type: 'video',
            urlschemearray: ["myvideoplace\\.tv/.+"],
            apiendpoint: 'mvp', // same of the proxy name
            extraSettings: {
                dataType: 'json',
                useSwingProxy: true
            }

        }
    ]
);

Custom Version Compare handling

With Méthode Swing it’s possible to add manipulation to version compare.

Registration of a custom version compare handling

To register a custom version compare manipulation, use the following namespace

eidosmedia.webclient.extensions.versionCompare

and its function

register( options )
Table 146. Method information

Method

register

Parameter

Required {object} options - An object containing one function that will be invoked to perform the version compare manipulation.

Supported functions:

  • "selectVersion": Select a version number among the avilable ones

Returns

{undefined} undefined

The following is a very simple registration for a version compare manipulation.

(function(){

    eidosmedia.webclient.extensions.versionCompare.register({'selectVersion': ( versions ) => {

            let versionNumber;

            try {

                /**
                 * Select the version number to compare
                 */
                versionNumber = versions[1].version_number;

            } catch (ex) {
                console.log("custom select version exception caught", ex);
            }

            return {versionNumber};
    }});
})();
Note
  • "selectVersion" Must have one parameters. The parameter is mandatory and contains the available versions.

Wrap all the custom manipulation with a try…​catch block to allow Swing to work correctly if something goes wrong.

Styling

Addition of external CSS to Swing

In Méthode Swing it is possible to add external CSS files. Such files must be placed under

{SWING-APP}/plugins/assets

All the files contained in this folder are loaded asynchronously into Méthode Swing.

Tip

It is suggested to place each library under a specific folder, e.g:

{SWING-APP}/plugins/assets/font-test/font-test.css
Warning

By default, these CSS are loaded only at application level as "assets.css". To load and apply the CSS inside the editor context you must put the following line

  • /* @editor */ - for Story Editor

  • /* @dwpeditor */ - for DWP Editor

as the first line of the CSS. Only the CSS files with editors directive (@editor or @dwpeditor) are applied inside the editors, all CSS files with application directive (@app) or without directive are excluded.

Méthode Swing loads ONLY the CSS (*.css) files in the folder. Of course, if the CSS file refer to other files (such as fonts or background images) these will be working properly.

Warning

Méthode Swing has no control over the CSS. So, an external CSS could break the application layout.

Please refer to the log to see which libraries have been loaded.

Context Menu

In Methode Swing it is possible to configure context menus in the Explorer area

Prepare the plugin to add menus and action

In general, all the extensions of Méthode Swing are places under

{SWING-APP}/plugins

So, all the Javascript described in the following sections should be placed under

{SWING-APP}/app/plugins/{EXTENSION-FOLDER}/{EXTENSION-NAME}.js
Caution

Do not use the word libs as an extension folder. The libs folder is reserved for loading external libs. See the proper documentation to obtain further info on the topic.

Tip

DEBUG MODE: by default, all plugins are aggregated into a single plugins.js file at the Tomcat startup. When creating a plugin, it may be frustrating to restart the Tomcat Server every time a change is made.

To avoid this, set the configuration property debugEnabled to true.

Then, that extension will be loaded on every refresh of the page.

Add a context menu

In order to add a custom context menu to Methode Swing, it is necessary to use the following namespace:

eidosmedia.webclient.extensions.contextMenu

The syntax is the following:

eidosmedia.webclient.extensions.contextMenu.add(name, options);

Where:

  • name [string] is the name of the custom menu, alias a unique identifier.

  • options [optional, object] is a Javascript object containing the properties of the custom actions.

The options parameter can be omitted. In this case, Swing will use the previously registered command with the same name property. See example below.

If options is specified, it must follow the guidelines of a generic Swing command. See Commands documentation for further information.

Example

eidosmedia.webclient.commands.add({
    name: 'complex',
    label: 'Perform some complex operation...',
    isActive: function(ctx) {
        return ctx.activeObject.getType() === 'Image';
    },
    action: function( ctx, params, callback ) {
        alert('Performing action on ' + ctx.activeObject.getName());
    }
});

eidosmedia.webclient.extensions.contextMenu.add('complex');

Topics Calendar Filters

Methode Swing allows to customize the filter used inside the Topics Calendar view

Configure a custom filter

Filters are made of an HTML template and a related JS file.

Caution

Default templates are put in the base folder

{SWING-APP}/config/templates/topiclist

Filters can be configured outside {SWING-APP}. See the paragraph How to configure topic filters in external folder for some tips in how to take advantage of this new configuration option.

Important

Topic List Templates are based on the same algorithm of Swing Custom Search Filter, with few minor differences, listed below. Please refer to the Custom search filter documentation for a detailed explanation of the filter inner workings.

Configure the JS file

To add a filter, the JS should be structured as follows.

eidosmedia.webclient.topicList.addFilter( options );

In detail, the options are:

eidosmedia.webclient.topicList.addFilter({
    // @property "template": {string} - the path to the filter template. Path is relative to the 'config/topiclist/' folder.
    // @required
    template: 'topiclistfilter.html',

    /**
     * Function called after loading the template, but BEFORE loading the filter
     * use it to add listeners.
     * @param {ContextObject}
     * @param {Object} options - the a list of options.
     * Please see below for the list of options.
     */
    onLoad: function( ctx, options ) {

    },

    /**
     * Function called after having executed the query.
     * @param {ContextObject}
     * @param {Object} - filterConditions: an object containing all the conditions obtained from the query
     * @param {Array} results - the results of the query
     * @param {Function} callback - the option to call after processing the result.
     * Please see below for the list of options.
     */
    processResults: function( ctx, filterConditions, results, callback ) {
       /*
        Here it is possible to process results,
        elaborate the custom conditions, etc.
        */
    }
});

Each parameter is detailed below.

template

This property defines the template for the filter.

{
    // ...
    template: "test.html",
    // ...
}
Warning

The path of the template starts from the topiclist/ folder.

onLoad

onLoad is a function called when the filter is loaded for the first time. This function is called AFTER the DOM has been filled, so that all the DOM elements of the filter are available. It can be used to add custom listeners for events.

It is called with 2 parameters:

  • ctx: the Context Object. See Context Object documentation for further details. In this case, though, the context object has neither activeObject nor selection, and only contains information on the Swing area.

  • options. It is a Javascript Object with a few properties. See code below for further details.

{
    options: {
        panel: DOMObject, // the DOM reference to the filter container
        data: {
            groups: [], // Array of groups
            topicListCfg: {}, // Topic list configuration as set in Swing main configuration,
            userChannels: [], // Array of channels for the user
            channels: [], // List of all the available channels
            workflows: [], // List of all the workflow steps available
        }
    }
}
{
    onLoad: function( ctx, options ) {
        var $panel = $(options.panel);
        // Put your code here...
    }
}
Tip

Return value of the function is not important.

processResults

The processResults function is called whenever the filter is executed. It is possible to elaborate the results as preferred.

It is called with a few parameters:

( ctx, filterConditions, results, callback )

  • ctx: the Context Object. See Context Object documentation for further details. In this case, though, the context object has neither activeObj nor selection, and only contains information on the Swing area.

  • filterConditions: a list of all the conditions set in the filter. It is an array of all the data-xvalue and data-custom-xvalue available in the filter.

  • results: the list of results of the query

  • callback: the callback to be called with the processed results

{
    // An example used to filter for "Standing Objects"
    processResults: function( ctx, filterConditions, results, callback ) {
        // console.log( filterConditions );
        var ownerTeamFilter = _.findWhere(filterConditions, { conditionKeyword: 'ownerteam' });
        if (ownerTeamFilter && ownerTeamFilter.conditionValue) {
            ownerTeamFilter = ownerTeamFilter.conditionValue.split(',');
            if (ownerTeamFilter.length) {
                var _groups = _.filter(ownerTeamFilter, function( tp ) { return tp.indexOf('-GROUP') > -1; });
                _groups = _.map( _groups, function( gp ) { return gp.replace('-GROUP', ''); } )
                results = _.filter( results, function(tp) {
                    if ( tp.virtual_attributes_json && tp.virtual_attributes_json.va && tp.virtual_attributes_json.va.oteam ) {
                        return _groups.indexOf( tp.virtual_attributes_json.va.oteam ) > -1;
                    }
                    return false;
                });
            }
        }
        callback( results );
    }
}

Configure the HTML File

While creating the HTML, the same mechanism as the Search Filter creation can be used. Both filters share the same keywords, same attributes and operators.

Please refer to the HTML and Keywords reference in the Filter documentation for further information.

How to configure topic filters in external folder

Additional topic filters may be made available to Swing application by defining one or more nested components in Swing web context in server.xml. (for further details on Tomcat 9.x Resources configuration, please refer to Resources configuration).

This is an example of the external filters configuration.

<Context docBase="com.eidosmedia.webclient.web-app"
    path="/swing" reloadable="false">
    <Resources
        className="org.apache.catalina.webresources.StandardRoot">
        <PreResources
            className="org.apache.catalina.webresources.DirResourceSet"
            base="/methode/meth01/extension/topicfilters" readOnly="true"
            webAppMount="/config/templates/topiclist" />
    </Resources>
</Context>

Searching

Search Configuration

Méthode Swing Search is an important component of Swing. It allows to perform searches in different domains (EOMDB, Web…​) and it is highly extendable.

Tip

To completely disable the search, simply add "disabled": true to the configuration.

<search>
    <disabled>true</disabled>
</search>
Tip

To disable the search preview results (so that all query are viewed directly in the Explorer area, if it is available), simply add "disableResultsPreview": true to the configuration.

NOTE: please notice that it works only for EOMDB searches. Other searches will be previewed as always.

<search>
    <disableResultsPreview>true</disableResultsPreview>
</search>
Tip

It is possible to define the click action performed on resultset items by configuring the itemClickAction property.

Allowed values are:

  • preview - click on item displays the preview of the item. (Default)

  • select - click on item selects item. Multi-selection is available. It enables drag’n’drop of single or multiple items to any editor, where allowed. Double click performs item preview.

<search>
    <itemClickAction>select</itemClickAction>
</search>
Tip

It is possible to define a fixed set of "custom queries" available in the top-left dropdown. This offer a practical shortcut to the most common used queries.

It is also possible to choose whether to execute the custom queries automatically or not, with the executeQueryAutomatically parameter.

<search>
    <customQueries>
        <customQuery>
            <id>199$0.1321231231</id>
            <name>First query</name>
        </customQuery>
        <customQuery>
            <id>/Globe/Query/MY_QUERY</id>
            <name>Second query (with path)</name>
        </customQuery>
    </customQueries>
    <executeQueryAutomatically>false</executeQueryAutomatically>
</search>
Tip

It is possible to insert the query path. Use the id property even in case of path.

Tip

It is possible to automatically hide custom filters when a search is performed in candidate.

<search>
    <hideFilterOnSearch>true</hideFilterOnSearch>
</search>

Column catalog configuration

Inside the search configuration, for EOMDB domains, it is possible to configure multiple column catalogs for the results shown in the Swing Explorer View.

<search>
    <!-- ... -->
    <allowMultipleColumnCfg>true</allowMultipleColumnCfg>
    <defaultColumnCfg>methodeResultSetList</defaultColumnCfg>
    <catalogs>
        <catalog>methodeResultSetList</catalog>
        <catalog>methodeResultSetThumbnails</catalog>
        <catalog>SwingResultSet</catalog>
    </catalogs>
</search>
  • allowMultipleColumnCfg (true / false) - If true, the "Explore" button in the search is a dropdown and lists all the configured column catalogs.

  • defaultColumnCfg ("methodeResultSetList") - This is the column catalog used when the user clicks on the "Explore" button. Beware that each domain can override the default by providing a different defaultColumnCfg

  • catalogs a list of available columnCatalog names that will appear in the dropdown. Beware that each domain can override the default by providing a different set of catalogs.

  • databaseIndexes - The databaseIndexes property gives the user the possibility to specify the default index in which the default-folder filter. See Custom filters documentation for further info on the default-folder filter. Configuration of databaseIndexes property should be as follows:

<search>
    <!-- ... -->
    <databaseIndexes>
        <databaseIndex>
            <name>Editorial</name>
            <index>Production@meth01_eomjse1;Wires@meth01_eomjse1</index>
        </databaseIndex>
        <databaseIndex>
            <name>Archive</name>
            <index>Archive@meth02_eomjse1</index>
        </databaseIndex>
    </databaseIndexes>
</search>

Domain configuration

Warning

As far as the Search configuration is concerned, for the parameters found under the <domain> key, no merge will be applied and the hierarchy to be respected is the usual one:
User > Group > SysConfig

Search configuration is included within a single search object:

<search>
    <domains>
        <domain>...</domain>
        <domain>...</domain>
        <domain>...</domain>
    </domains>

It is possible to search within different search domains. Supported domains are:

  • EOMDB - internal database search

  • Web - search on different services ( their availability depends on the APIs. Support for the API may drop without warning )

  • Contacts - search within Méthode users.

  • Pinboard - search within the Pinboard.

  • Social (if available) - search in social networks.

  • Custom - custom search domains specified by the user.

Note
Only EOMDB and Web domains are customizable.
Note

Disable specific domains - It is possible to disable the different searches by setting the specific privileges ( "_PadmaPriv_enableSearchExternalSource", "_PadmaPriv_enableSearchContacts", "_PadmaPriv_enableTemporaryPinboard" )

General domain properties

Each domain has the following properties:

Table 147. Domain configuration: properties
Name Description Values

name

Domain name. Must be unique and without spaces.

type

Domain type. NOTE: there can be multiple EOMDB domains, while it is suggested to have a unique Web domain.

eomdb / web

connectionName

Used only by EOMDB domains, indicates the connection name configured in the MRAS configuration. For backward compatibility the previous <repositoryId> and <repositoryName> is correctly read anyway.

defaultColumnCfg

Used to override the default search defaultColumnCfg property.

showMetadata

Used only by EOMDB domains, if true the results will also contain the "attributes" property. Be aware that this will slow down the search.

false

hidden

If true, domain is hidden from the search

true / false

defaultFor

If specified, in case of specific searches ( e.g. search from image or video placeholder ), the domain with the corresponding searchType will be selected.

image / video

groupResults

For EOMDB domains, if true the results are grouped and sorted according to the type

true / false

label

The domain label

icon

Default icon for the domain

view

For EOMDB databases, it is possible to specify a custom ColumnCatalog. By default, the column catalog is "SwingResultSet" (internal to Swing). See Search templates configuration, usage and creation to understand how the information is used.

itemsPerPage

Number of item per page (quicksearch)

8

disablePagination

If true, no pages are created

true / false

quicksearchLimit

Max number of results in quicksearch mode.

100

openFilter

If a filter is available and the value is true, the filter is opened by default.

false

conditions

It is an array of additional conditions (filters) to be applied to the search. See Conditions configuration for further details.

Default conditions (filter by type)

archives

It is an array of indexes, through which the user can choose. See Indexes configuration (archives) for further details.

Indexes configuration (archives)

Each of them can be configured as follows:

Table 148. Index configuration: properties
Name Description

label

Name used in the search to visually identify the index

archive

The index name. It can contain multiple indexes, separated by a ";" (in this case, all indexes MUST be on the same repository)

repName

The EOMDB repository name. Mandatory for all archives

prefix

If specified, every search with that archive selected will be prepended with this prefix. E.g. in web searches, it is possible to specify "site:www.yoursite.com" as a prefix in order to force the search only on that website.

isDefault

Is true, the index is selected by default

Sample archive configuration
<archives>
    <archive>
        <label>Editorial</label>
        <archive>production@meth01_eomse1</archive>
        <repName>Editorial</repName>
        <isDefault>true</isDefault>
        <visible>true</visible>
        <enabled>true</enabled>
    </archive>
    <archive>
        <label>Wires</label>
        <archive>ap@eomjse3_meth01;nyt@eomjse3_meth01</archive>
        <repName>Wires</repName>
        <isDefault>false</isDefault>
        <visible>true</visible>
        <enabled>true</enabled>
    </archive>
    <archive>
        <label>Archive</label>
        <archive>archive@meth01_eomjse1</archive>
        <repName>Archive</repName>
        <isDefault>true</isDefault>
        <visible>true</visible>
        <enabled>true</enabled>
    </archive>
</archives>
Warning

In case of custom domains (created with a Plugin), it is possible to specify the archives as a function written in the following way:

{
    // ...
    archives: function( ctx, callback ) {
        // Perform same operations...
        callback( [
             { "name": "production", "label": "Editorial",
               "archive": "production@meth01_eomse1",
               "isDefault": true, "visible": true, "enabled": true },
             { "name": "globecms", "label": "GlobeCMS",
               "archive": "globecms@meth01_eomse1",
               "isDefault": false, "visible": true, "enabled": true },
             { "name": "wires", "label": "Wires",
               "archive": "wires@meth01_eomse1",
               "isDefault": false, "visible": true, "enabled": true },
             { "name": "archive", "label": "Archive",
               "archive": "archive@meth01_eomse1",
               "isDefault": false, "visible": true, "enabled": true },
             { "name": "configuration", "label": "Configuration",
               "archive": "configuration@meth01_eomse1",
               "isDefault": false, "visible": true, "enabled": true }
        ]);
    }
}

Conditions configuration

Conditions represent additional specifications added to a query. That is, if the user choose a condition whose value is type:EOM::Story, the results are limited to the EOMDB stories. (In a way, they can be considered as filters).

There are two different types of conditions:

  • default conditions - Such conditions are added in any search that the user performs. They can be seen as permanent filters, or are conditions that always limit or specify the searches that the user makes.

  • alternative conditions - Such conditions, instead, appear in the top right part of the quicksearch form (see picture below). The user can choose among them, to filter the results of a search.

Default conditions

Default conditions should be configured as follows:

<conditions>
    <condition>
        <isDefault>true</isDefault>
        <value>owner:myself</value>
    </condition>
    <condition>
        <isDefault>true</isDefault>
        <value>modified_lastdays:10</value>
    </condition>
    <condition>
        <isDefault>true</isDefault>
        <value>sort:ObjectInfo/modified;D</value>
    </condition>
    <condition>
        <isDefault>true</isDefault>
        <value>metadata:"My/Path=my value"</value>
    </condition>
</conditions>

This sample configuration limits all EOMDB quick-searches to the files whose owner is the current user, and that have been modified in the last 10 days. So, default conditions must have isDefault parameter set to true, and the value parameter set to the condition, as visible in Swing search keywords documentation paragraph.

Tip

All the conditions are put with an AND operator, but within a condition it is possible to specify OR operators. In this case, please put the condition within parenthesis.

Example:

<conditions>
    <condition>
        <!-- other properties here -->
        <value>(owner:myself OR owner:johndoe)</value>
    </condition>
</conditions>
Caution
Conditions are domain-specific. The described conditions are available only for EOMDB domains. For custom domains, it is you that have to code the behaviour.
Alternative conditions

They are configured as follows:

<conditions>
    <condition>
        <label>Story</label>
        <icon>emui-icon-newspaper</icon>
        <value>type:eom::story</value>
    </condition>
    <!-- Other conditions -->
</conditions>
Tip

The same keyword reference table ( Swing search keywords documentation ) can be used also for the Alternative conditions.

Domains: sample configuration

<search>
    <domains>
        <domain>
            <name>eomdblocal</name>
            <type>eomdb</type>
            <label>Local archive</label>
            <icon>emui-icon-database</icon>
            <defaultFor>image</defaultFor>
            <itemsPerPage>8</itemsPerPage>
            <groupResults>false</groupResults>
            <quicksearchLimit>48</quicksearchLimit>
            <useExternalSuggestion>true</useExternalSuggestion>
            <externalSuggestionURL>http://suggestqueries.google.com/complete/search?q={data.value}&client=firefox&callback=?</externalSuggestionURL>
            <conditions>
                <!-- this is a default condition -->
                <condition>
                    <isDefault>true</isDefault>
                    <value>modified_lastdays:10</value>
                </condition>
                <!-- these are the alternative (variable) condition -->
                <condition>
                    <label>Free search</label>
                    <labelkey>search.types.freesearch</labelkey>
                    <icon>icon-search</icon>
                    <value>type:</value>
                </condition>
                <condition>
                    <label>Story</label>
                    <labelkey>search.types.story</labelkey>
                    <icon>emui-icon-newspaper</icon>
                    <value>type:eom::story</value>
                </condition>
                <condition>
                    <label>WireStory</label>
                    <labelkey>search.types.wirestory</labelkey>
                    <icon>icon-file-text</icon>
                    <value>type:wirestory</value>
                </condition>
                <condition>
                    <label>Images</label>
                    <labelkey>search.types.images</labelkey>
                    <icon>icon-picture</icon>
                    <value>type:image</value>
                </condition>
                <condition>
                    <label>Gallery</label>
                    <labelkey>search.types.gallery</labelkey>
                    <icon>emui-icon-pictures</icon>
                    <value>type:eom::mediagallery</value>
                </condition>
                <condition>
                    <label>Audio</label>
                    <labelkey>search.types.audio</labelkey>
                    <icon>icon-music</icon>
                    <value>type:audio</value>
                </condition>
                <condition>
                    <label>Topic</label>
                    <labelkey>search.types.topic</labelkey>
                    <icon>emui-icon-topic</icon>
                    <value>type:eom::topic</value>
                </condition>
                <condition>
                    <label>Search by name</label>
                    <labelkey>search.types.byname</labelkey>
                    <icon>icon-file</icon>
                    <value>param:name:</value>
                </condition>
            </conditions>
            <archives>
                <archive>
                    <name>production</name>
                    <label>Editorial</label>
                    <archive>production@meth01_eomse1</archive>
                    <isDefault>true</isDefault>
                    <visible>true</visible>
                    <enabled>true</enabled>
                </archive>
                <archive>
                    <name>globecms</name>
                    <label>GlobeCMS</label>
                    <archive>globecms@meth01_eomse1</archive>
                    <isDefault>false</isDefault>
                    <visible>true</visible>
                    <enabled>true</enabled>
                </archive>
                <archive>
                    <name>wires</name>
                    <label>Wires</label>
                    <archive>wires@meth01_eomse1</archive>
                    <isDefault>false</isDefault>
                    <visible>true</visible>
                    <enabled>true</enabled>
                </archive>
                <archive>
                    <name>archive</name>
                    <label>Archive</label>
                    <archive>archive@meth01_eomse1</archive>
                    <isDefault>false</isDefault>
                    <visible>true</visible>
                    <enabled>true</enabled>
                </archive>
                <archive>
                    <name>configuration</name>
                    <label>Configuration</label>
                    <archive>configuration@meth01_eomse1</archive>
                    <isDefault>false</isDefault>
                    <visible>true</visible>
                    <enabled>true</enabled>
                </archive>
            </archives>
        </domain>
        <domain>
            <name>web</name>
            <type>web</type>
            <label>Web search</label>
            <icon>icon-globe</icon>
            <itemsPerPage>8</itemsPerPage>
            <useExternalSuggestion>true</useExternalSuggestion>
            <conditions>
                <condition>
                    <label>Free search</label>
                    <icon>icon-circle-blank</icon>
                    <value>type:web</value>
                </condition>
                <condition>
                    <label>News</label>
                    <icon>emui-icon-newspaper</icon>
                    <value>type:news</value>
                </condition>
            </conditions>
            <archives>
                <archive>
                    <name>google</name>
                    <label>Google</label>
                    <icon>icon-google</icon>
                    <archive>google</archive>
                    <isDefault>true</isDefault>
                    <visible>true</visible>
                    <enabled>true</enabled>
                    <exclusive>true</exclusive>
                </archive>
            </archives>
        </domain>
    </domains>
</search>

Swing search keywords documentation

Swing searches can be filtered by using keywords. Such keywords are then elaborated and transformed to create the adequate XML query for the EOMDB.

These keywords can be used within the Swing search, the Swing Explorer Folder filter, and the Swing search filters.

Warning

The supported keywords are meaningful for EOMDB searches only. If you want to use filters for custom domains, feel free to use any keyword you prefer. The filters will be passed in the conditions array of the Search Controller (options parameter). See Search controller documentation for further details.

Available keywords

channel

Returns only the objects of a given channel.

Syntax
channel:(CHANNEL)
userchannel:(CHANNEL)
Values
Table 149. Supported values
Keyword Example Description

CHANNEL

channel:"Globe-Print"

Any string value (with quotes if there is a space).

Tip

userchannel differs from channel in the fact that only the channels relative to the current user are available..

content

Search a specific text in the content of an object.

Syntax
content:"CONTENT"
Values
Table 150. Supported values
Keyword Example Description

CONTENT

content:Test

Any string value (with quotes if there is a space).

contentmetadata

Search for a text in both content and metadata.

Syntax
contentmetadata:"CONTENT"
Values
Table 151. Supported values
Keyword Example Description

CONTENT

contentmetadata:Test

Any string value (with quotes if there is a space).

created_lastdays

Allow to obtain the documents created in the last N days

Syntax
created_lastdays:(VALUE)
Values
Table 152. Supported values
Keyword Example Description

VALUE

created_lastdays:10

Any numeric value.

creator

freexml

Allow to insert a specific xml in the query. Please use it with moderation.

Syntax
freexml:"CONTENT"
Values
Table 153. Supported values
Keyword Example Description

CONTENT

freexml:"<SysAttributes><props><productInfo><issueDate q:op='EXIST'/></productInfo></props></SysAttributes>"

Any string value (with quotes if there is a space). Note: please use single quotes when a double quote is used inside the value.

lastmodifier

Returns the objects last modified by a specific user.

Syntax
lastmodifier:(USER|myself)
Values
Table 154. Supported values
Keyword Example Description

USER

lastmodifier:johndoe

Any string value (with quotes if there is a space). Return the objects modified by the specified user.

myself

lastmodifier:myself

Return the objects modified by the current user

limit

Limits the results to a specific number.

Syntax
limit:(VALUE)
Values
Table 155. Supported values
Keyword Example Description

VALUE

Any numeric value

limit:100

locker, lockedby

Search for objects locked by a given user

Syntax
locker:(USER|myself)
Values
Table 156. Supported values
Keyword Example Description

USER

locker:johndoe

Any string value (with quotes if there is a space). Return the objects locked by the specified user.

myself

locker:myself

Return the objects locked by the current user

Tip

locker, lockedby keywords are totally equivalent.

searchmetadata

Search a specific value in all the metadata.

Syntax
searchmetadata:"CONTENT"
Values
Table 157. Supported values
Keyword Example Description

CONTENT

searchmetadata:Test

Any string value (with quotes if there is a space).

metadata

Search a specific value in a given xpath.

Syntax
metadata:"{X-PATH}={VALUE}"
Values
Table 158. Supported values
Keyword Example Description

CONTENT

metadata:"/Metadata/Editorial/ContentType=RANGE"

See previous example. Note: Quotes are mandatory. If the value contains double quotes, use single quotes instead.

metadatarange

Search a specific value in a given xpath, with the "range" operator ( inside the se:attributes tag )

Syntax
metadatarange:"{X-PATH}={VALUE}"
Values
Table 159. Supported values
Keyword Example Description

"{X-PATH}={VALUE}"

metadatarange:"/Metadata/Editorial/ContentType=RANGE"

See previous example. Note: Quotes are mandatory. If the value contains double quotes, use single quotes instead.

Important

The RANGE value must be in the following format: YYYYMMDDhhmmss;YYYYMMDDhhmmss.

modified_lastdays

Allow to obtain the documents modified in the last N days

Syntax
modified_lastdays:(VALUE)
Values
Table 160. Supported values
Keyword Example Description

VALUE

modified_lastdays:10

Any numeric value.

name

Search an object with a specific filename

Syntax
name:"CONTENT"
Values
Table 161. Supported values
Keyword Example Description

NAME

name:Test

Any string value

range

restrictto

Returns the objects inside a path.

Syntax
restrictto:(VALUE)
Values
Table 162. Supported values
Keyword Example Description

VALUE

Any string value (with quotes if there is a space).

restrictto:"/Globe/Images"

sort

Complete sorting mechanism.

Syntax
sort:"{X-PATH};{VALUE}"
Values
Table 163. Supported values
Keyword Example Description

"{X-PATH};{VALUE}"

sort:"ObjectInfo/modified;ND"

See previous example. Note: Quotes are mandatory. If the value contains double quotes, use single quotes instead.

Tip

In {x-path};{Value}, value can be:

Table 164. Values
Value Description

A

Ascending

D

Descending

NA

Numeric Ascending

ND

Ascending

sortby

Simple descending sort according to a parameter in the ObjectInfo.

Syntax
sortby:(VALUE)
Values
Table 165. Supported values
Keyword Example Description

created

sortby:created

Return the objects sorted by creation date, descending.

modified

sortby:modified

Return the objects sorted by modified date, descending.

status, workflow

Search objects with a given status ( workflow ).

Syntax
status:(VALUE)
Values
Table 166. Supported values
Keyword Example Description

VALUE

status:NewsFlow/Editing

Any string value (with quotes if there is a space).

type

Returns only the objects of a given type.

Syntax
type:(TYPE)
Values
Table 167. Supported values
Keyword Example Description

TYPE

type:EOM::Story

Any string value (with quotes if there is a space). Return the objects of specified type.

usageticket

Allow to search within the usage tickets.

Syntax
usageticket:"tp:{type};;c:{creator};;rng:{range}"
Values
Table 168. Supported values
Keyword Example Description

CONTENT

tp:{type};;c:{creator};;rng:{range}

usageticket:"tp:WebPub;c:alessandropiana;rng:20160420220000__20160421215900"

Tip
  • Type (tp) is the only mandatory field for the usageticket filter. creator (c) and range (rng) are optional.

  • Range (rng) is in the format YYYYMMDDhhmmss__YYYYMMDDhhmmss

  • Separate the fields with a double ; ( ;; ).

  • If the field values have spaces in it, use a double underscore instead of spaces ( __ )

user, creator, owner

Search for objects created by a given user

Syntax
user:(USER|myself)
Values
Table 169. Supported values
Keyword Example Description

USER

user:johndoe

Any string value (with quotes if there is a space). Return the objects created by the specified user.

myself

user:myself

Return the objects created by the current user

Tip

user, creator, owner keywords are totally equivalent.

userchannel

See channel.

workflow

workfolder

Returns the objects inside a workfolder.

Syntax
workfolder:(VALUE)
Values
Table 170. Supported values
Keyword Example Description

VALUE

Any string value (with quotes if there is a space).

workfolder:"/Globe/Images"

Search templates configuration, usage and creation

Méthode Swing uses templates to render the search results.

Configuration of result templates

To use a template, it is necessary to configure the searchTemplate options in the Domain section. See Domain configuration for further details.

Caution

It is HIGHLY discouraged to change the default search themes for Methode types. Their layout can be customized by operating on the specific column catalog (SwingResultSet).

In the ResourceSpace example, we used the following settings:

<searchTemplate>
    <type>rsimage</type>
    <template>search-preview-resourcespace.html</template>
</searchTemplate>
<searchTemplate>
    <type>rstext</type>
    <template>search-preview-resourcespace-text.html</template>
</searchTemplate>
"searchTemplate" : [
    { type: "rsimage", template: "search-preview-resourcespace.html" },
    { type: "rstext", template: "search-preview-resourcespace-text.html" }
]

This settings specifies that we are using two templates for two different types.

Note
We could have used the same template for different types.

Usage and creation of a template

Each template is an HTML file which can be customized according to the user’s necessity.

All the widgets are put inside the following path:

{SWING-APP}/config/templates/search/{TEMPLATE-NAME}

Preview files can be configured outside {SWING-APP}. See the paragraph How to configure search templates in external folder for some tips in how to take advantage of this new configuration option.

Default templates are:

  • src-preview-eom.html for Methode types (used in search, candidate and correlates)

  • src-preview-user.html for type: EOM::User

  • src-preview-webcontent.html for type: web::Content

Customize the templates

Caution

Méthode Swing uses Underscore.JS templating system to enhance the user experience.

See Underscore.JS for further information, or the box below for some useful tips.

The template is rendered with a main object:

  • item, which contains all the information about the item.

item: the item info

The item object inside template contains all the information retrived from the search source. That is, in case of external sources, the one you decide to pass back to the search. In general though, all Méthode objects should have the following properties:

// item: common properties { EXAMPLE }
{
    "id": "1.0.113665564",
    "columns": "SEE BOX BELOW"
    "name": "Obama, Hollande agree on much -- but not Afghanistan.xml",
    "description": "",
    "type": "EOM::Story",
    "owner": "johndoe",
    "creator": "johndoe",
    "created": 1337764225,
    "last_modifier": "johndoe",
    "modified": 1409816672,
    "locker": "",
    "locked": 1423560030,
    "status_info": {
        "name": "NewsFlow/Editing",
        "identifier": "RGB(255,0,0)",
        "comment": ""
    },
    "size": 6898,
    "system_attributes": {
        "workfolder": "/Globe/Politics",
        "templateName": "/SysConfig/Globe/Templates/story.xml",
        "summary": "New French President Francois Hollande told President Barack Obama on Friday that he will stick by his pledge .",
        "wordCount": "998",
        "sugCategory": "",
        "channel": "Globe-Web",
        "storyType": "",
        "productInfo": {
            "name": "Globe-Web",
            "issueDate": "20120524"
        }
    },
    "system_attributes_xml": "XML HERE",
    "createdStr": "20120523091025",
    "modifiedStr": "20140904074432",
    "channel": "Globe-Web",
    "issueDate": "20120524",
    "preview": "/WebClient/api/rest/object/preview?token=12dbbac2-6d8d-445d-8a26-8f79ff0aca84&id=1.0.113665564&fa=lowres"
}

Beyond these properties, ALL the results will at least have the following properties:

// item: other properties which will be always available for ANY object ( also external )
{
   title: 'Object title if available, otherwise equals to filename',
   preview: 'the preview URL which uses the Methode Preview server',
   previewThumbnail: 'the preview URL which uses the Methode Preview Thumbnail server'
   content: 'if not already available, the summary from the system attributes'
}
Important

There is also the eomActions property, which has the HTML of the actions available for the object. If you want to have some actions available for the item, be sure to include this property inside a DOM element whose class is actions somewhere in the template.

item.columns: columnCatalog properties

The EOMDB results come with an additional property, named columns. The property is a JSON array containing the values specified in the ColumnCatalog associated with the search.

The default column catalog applyed by Swing is as follows (this can been overwritten in the columnCfgCatalogs.swing.xml file):

<!-- Swing ResultSet views -->
<catalog name="SwingResultSet" dir="/" type="methodeResultSetList" listable="true">
    <EOMCfgView>
        <props sort="name+type&amp;ascending" activeViewer="off" autoScroll="none" />
        <column fieldId="1" width="300" name="Title" priority="5">
            <choice op="notEmpty" minLength="5">
                <data source="info/system_attributes/props/title" />
                <data source="info/attributes/ObjectMetadata/General/Headline" />
                <data source="info/attributes/Metadata/DocTitle" />
                <data source="info/attributes/ObjectMetadata/iptc/headline" />
                <data source="info/attributes/ObjectMetadata/iptc/caption" />
                <data source="info/attributes/ObjectMetadata/iptc/image_name" />
                <data source="info/attributes/Metadata/Title" />
                <data source="info/attributes/meta/wire/title" />
                <data source="info/attributes/ObjectMetadata/GeneralMetadata/Headline" />
                <data source="info/attributes/meta/wire/title" />
                <data source="info/attributes/ObjectMetadata/iptc/caption" />
                <data source="info/attributes/Metadata/Keywords" />
                <data source="info/attributes/Metadata/DocKeywords" />
                <data source="info/name" />
            </choice>
        </column>
        <column fieldId="2" width="300" name="Summary" priority="5">
            <choice op="notEmpty" minLength="1">
                <data source="info/system_attributes/props/summary" />
                <data source="info/attributes/Metadata/iptc/caption" />
            </choice>
        </column>
        <column fieldId="3" name="Date" source="info/created" width="130" />
        <column fieldId="4" name="Type" width="90" source="info/type" priority="1" />
        <!-- Wires -->
        <column fieldId="5" name="Agency" width="90" priority="4">
            <choice op="notEmpty" minLength="1">
                <data source="info/attributes/ObjectMetadata/iptc/credit" />
                <data source="info/attributes/ObjectMetadata/Source"/>
                <data source="info/attributes/Metadata/Source"/>
            </choice>
            </column>
            <column fieldId="6" name="Category" width="90" priority="4">
            <choice op="notEmpty" minLength="1">
                <data source="info/attributes/ObjectMetadata/iptc/category" />
                <data source="info/attributes/ObjectMetadata/Category"/>
                <data source="info/attributes/Metadata/Category"/>
            </choice>
            </column>
            <!-- Production -->
        <column fieldId="7" name="WorkFolder" source="info/system_attributes/props/workFolder" width="90" priority="4"/>
        <column fieldId="8" name="Channel" source="info/system_attributes/props/productInfo/name" width="90" priority="4"/>

        <column fieldId="9" width="90" priority="4" name="Status">
            <data source="info/status_info/identifier" format="si:colorRect"/>
            <data source="info/status_info/name" format="tk:/$2" priority="3"/>
        </column>
        <column fieldId="10" width="70" priority="3" name="Locker" source="info/locker" format="lk:icon_name"/>
    </EOMCfgView>
</catalog>

Here an example of a record that represents the previous columns property:

[
    {
        "name": "Summary",
        "value": "President Barack Obama is photographed during a presidential portrait sitting for an official photo ...",
        "id": "2"
    },
    {
        "name": "Type",
        "value": " Image",
        "id": "4",
        "priority": "1"
    },
    {
        "name": "Locker",
        "value": "johndoe",
        "id": "10"
    }
]

If desired, it is possible to specify your own column catalog in the search domain configuration of the EOMDB. See Domain configuration for further information.

How to configure the Web Search Domain

To configure the Web Search domain (Google), it is necessary to add the custom apikey in the MRAS configuration file, such as:

<config>
    <restApi>
        <!-- ... -->
        <searchEngines>
            <searchEngine id="google" dataSourceClass="com.eidosmedia.restserver.websearch.google.GoogleCustomSearchDataSource">
                <generic apiKey="YOUR_API_KEY" searchEngineCx="015464143803231643050:kgucpqylmq4"/>
            </searchEngine>
        </searchEngines>
    </restApi>
</config>

How to configure search templates in external folder

Additional search templates may be made available to Swing application by defining one or more nested components in Swing web context in server.xml. (for further details on Tomcat 9.x Resources configuration, please refer to Resources configuration).

This is an example of the external search templates configuration.

<Context docBase="com.eidosmedia.webclient.web-app"
    path="/swing" reloadable="false">
    <Resources className="org.apache.catalina.webresources.StandardRoot">
        <PreResources
            className="org.apache.catalina.webresources.DirResourceSet"
            base="/methode/meth01/extension/search" readOnly="true"
            webAppMount="/config/templates/search" />
    </Resources>
</Context>

Extensions: manipulate the search free text and XML

It is possible to manipulate the free text input BEFORE it is sent to validation and, in case of EOMDB searches, transformed into XML. For EOMDB searches, too, it is possible to add an additional validator to change the query XML just before the execution. The methods are described below.

addTextValidator

eidosmedia.webclient.search.addTextValidator(options);

In detail, the options are:

/**
 * CUSTOM TEXT VALIDATOR
 */
eidosmedia.webclient.search.addTextValidator({
    // @property "domain": {string} - a specific search domain to apply the filter to
    // @required - domain or domainType
    "domain": "eomdblocal",

    // @property "domainType": {string} - if specified, filter is applied to all the domains of the same type
    // @required - domain or domainType
    // "domainType": "eomdb"
}, function( searchInfo ) {
    // Search info contains the following properties:
    // - "textInput" {string} - the current search text.
    // - "conditions": {array of objects} - the conditions currently selected by the user, filters included.

    // Please beware that changes in the conditions made here will NOT be reflected in the search.
    // This methods only allows simple alterations to the search free text.

    var _textInput = searchInfo.textInput;
    // Simple elaboration.
    if ( _textInput === 'obama' ) {
        _textInput = '"Barack Obama"';
    }

    // This method must return the new search text, and only this.
    return _textInput;
});

addXMLValidator

eidosmedia.webclient.search.addXMLValidator(options, callback);

In detail, the options are:

/**
 * CUSTOM XML VALIDATOR
 */
eidosmedia.webclient.search.addXMLValidator({
    // @property "domain": {string} - a specific search domain to apply the filter to
    // @required - domain or domainType
    "domain": "eomdblocal",

    // @property "domainType": {string} - if specified, filter is applied to all the domains of the same type
    // @required - domain or domainType
    // "domainType": "eomdb"
}, function( searchInfo, callback ) {
    // Search info contains the following properties:
    // - "textInput" {string} - the current search text.
    // - "conditions": {array of objects} - the conditions currently selected by the user, filters included.
    // - "queryXML": {string} the final XML of the query

    // Please beware that changes in the conditions made here will NOT be reflected in the search.

    /* IMPORTANT: Please notice the difference with "addTextValidator". This function uses a callback
       to return the value */
    var _queryXML = searchInfo.queryXML;
    // Some elaboration here...
    // This method must call the "callback" with the new XML
    callback( _queryXML );
});

Search: integration of external DAM services

Méthode Swing allows the integration of external Digital Asset Management (DAM) services.

These services can be used within the Swing Quicksearch. It is also possible to elaborate the results received from such services and use them inside Méthode documents.

This document is a step-by-step tutorial on how to integrate an external DAM service. To make this process easer, we are also integrating the "ResourceSpace" service as a complete example.

1. Set up the search proxy

Méthode Swing uses proxies to communicate to external services. This is necessary due to the Same-Origin Policy used by modern browsers.

The same-origin policy restricts how a document or script loaded from one origin can interact with a resource from another origin. Same-origin Policy is used as a means to prevent some of the Cross-site Request Forgery attacks.

— Mozilla Developer Network

Proxies can be configured in Méthode Swing.

<!-- other configuration -->
<proxies>
    <proxy>
        <name>[PROXY-NAME]</name> <!-- e.g. resourcespace -->
        <targetUri>http://192.168.203.129/resourcespace/plugins/api_search/</targetUri> <!-- e.g. destination target Uri -->
        <useTemplate>false</useTemplate>
    </proxy>
</proxies>
Important

The useTemplate param allows to use templates to build the URL. The following is an example of url which uses templates.

<proxies>
    <proxy>
        <name>[PROXY-NAME]</name> <!-- e.g. resourcespace -->
        <targetUri>http://192.168.203.129:{_port}</targetUri> <!-- e.g. destination target Uri -->
        <useTemplate>true</useTemplate>
    </proxy>
</proxies>

The new proxed URL must be called with ALL the parameters in its querystring, e.g.

http://swing/[PROXY-NAME]/users/get?_port=8080&id=userID

Note: if the parameter is missing, the URL will return an HTTP 500 error.

Note: due to the nature of the Template Servlet, in this mode it is not possible to pass arrays as querystrings ( i.e. more than one querystring parameter with the same name ).

Warning

[PROXY-NAME] must be equal to [DOMAIN-TYPE] (described in Domain configuration).

2. Preparing the External DAM integration file

In general, all the extensions of Méthode Swing are places under

{SWING-APP}/plugins

So, all the Javascript described in the following sections should be placed under

{SWING-APP}/app/plugins/{EXTENSION-FOLDER}/{EXTENSION-NAME}.js
Caution

Do not use the word libs as an extension folder. The libs folder is reserved for loading external libs. See the proper documentation to obtain further info on the topic.

Tip

DEBUG MODE: by default, all plugins are aggregated into a single plugins.js file at the Tomcat startup. When creating a plugin, it may be frustrating to restart the Tomcat Server every time a change is made.

To avoid this, set the configuration property debugEnabled to true.

Then, that extension will be loaded on every refresh of the page.

Tip

In our example, it will be placed under {SWING-APP}/app/plugins/resourcespace/resourcespace.js.

Swing Search system is modular. The following paragraph describes in details each module.

Search structure

Swing Search system is modular and consists in three main modules:

  • Search input (domains): the module covering the user input, the search domain, the search archives and the filters available.

  • Search compiler: a compiling system that validates and translates the input into a language which is understandable by the controller. (For example, the EOMDB compiler validates the input and translates a user search, such as "U.S. politics", into a XML for the Méthode Query).

  • Search controller: the module that, effectively, executes the search and retrieves the result.

When the user searches for something, the compiler validates the content. If content is not valid, the search input is warned and the search is not executed (i.e. the search controller is not even called). If the content is valid, the search controller tries to call the external search services and retrives the results.

When the results are available, they are processed by the preview engine that shows a small preview of each result. From that point, according to the current context (e.g. Editor area, …​) and the actions which have been configured, the user can perform some specific operations.

Domain setup

Tip

Domain configuration follows the same properties as shown in the Search Configuration. However, here it must be specified as a Javascript object.

Example

{
    "name": "customtest",
    "type": "customtest",
    "label": "Local archive",
    "icon": "emui-icon-database",
    "itemsPerPage": 8,
    "quicksearchLimit": 48,
    "useExternalSuggestion": true,
    "externalSuggestionURL": "http://suggestqueries.google.com/complete/search?q={data.value}&client=firefox&callback=?",
    "conditions": [
          {
                "isDefault": true,
                "value": "modified_lastdays:10"
          },
          { "label": "Free search", "labelkey": "search.types.freesearch",
            "icon": "icon-search", "value": "type:",
            "type": "" },
          { "label": "Story", "labelkey": "search.types.story",
            "icon": "emui-icon-newspaper", "value": "type:eom::story",
            "type": "story" },
          { "label": "Images", "labelkey": "search.types.images",
            "icon": "icon-picture", "value": "type:image",
            "type": "image" }
    ],
    "archives": [
         { "name": "production", "label": "Editorial",
           "archive": "production@meth01_eomse1",
           "isDefault": true, "visible": true, "enabled": true },
         { "name": "globecms", "label": "GlobeCMS",
           "archive": "globecms@meth01_eomse1",
           "isDefault": false, "visible": true, "enabled": true }
    ]
}
Tip

Please refer to the Search Configuration for a reference of the meaning of each property. Even though the examples are all in XML, the concepts are equal.

To dinamically add a domain to the configuration, it is necessary to call the following Javascript function, inside your Javascript file:

eidosmedia.webclient.extensions.search.addDomain( /** domain settings **/ );

The domain behaviour must be defined in a JavaScript file and put inside the following path:

{SWING-APP}/app/plugins/{PROXY-NAME}

Domain controller can be configured outside {SWING-APP}. See the paragraph How to configure a domain controller in external folder for some tips in how to take advantage of this new configuration option.

Example: ResourceSpace integration

Note
the key searchTemplate will be explained in Search templates configuration, usage and creation.

For our example we don’t need neither conditions nor archives, but the example contains them (commented) to simplify the code reuse.

// Add a new domain in the search dialog.
eidosmedia.webclient.extensions.search.addDomain({
    "name": "resourcespace",
    "type": "resourcespace",
    "label": "ResourceSpace Search",
    "icon": "icon-foursquare",
    "itemsPerPage": 8,
    "useExternalSuggestion": false,
    "searchTemplate" : [
        { type: "rsimage", template: "search-preview-resourcespace.html" },
        { type: "rstext", template: "search-preview-resourcespace.html" }
    ],
    "compiler": function( options, callbacks ) { /* ... SEE BELOW ... */ },
    "controller": function( options, callbacks, ctx ) { /* ... SEE BELOW ... */ },
    "allowImport": false, // Or it can be a function, see below
    "correlateOnImport": true,
    "getImportInfo": function( ctx ) { /* ... SEE BELOW ... */ }

    /* It is possible to add Archives and conditions. Please refer to Domains configuration. */

});

Compiler setup

The Search Compiler validates the user input and translates into the language which is understood by the search controller.

As seen in the Search structure section, the compiler is a middle layer between the search component (a.k.a. the input form) and the search controller (a.k.a. the search engine). The Compiler can be used to perform any transformation of the search input to be passed into the controller, as well as to provide some sort of validation that, in case of not valid arguments, interrupts the search before it starts, so not even calling the server.

Such validation logic can easily be moved inside the search controller, nevertheless the user may find useful to separate the Compiler and the Controller logic.

The Search compiler is a Javascript function called as follows:

// ... other configuration
"compiler": function( options, callbacks ) {
    /* ... CODE HERE ... */
},
// ... other configuration

The compiler is a Javascript function called with two main parameters:

  • options [JSON object] - information about the current search

  • callbacks [JSON object] - function to be called ( success and error)

options

  1. conditions: user specified conditions

  2. archives: subset of domain the user wants to limit the search to

  3. searchType: the specific type of search

The compiler is called with the following options:

{
    "domain": DOMAIN_NAME,
    "input": "my search input",
    "conditions": [ /* Array of conditions */ ],
    "archives": [
        "archive3"
    ],
    "searchType": "image"
}
  • domain contains the domain name

  • input contains the search input

  • conditions contains all the conditions specified by the user (also archive and type, which are just a specific condition.

  • archives lists only the archives selected

  • searchType lists the type selected.

With this information, it is possible to call the service with the specific parameters.

callback

This is the function that is called when the validation is completed.

It MUST be called with the following parameters.

callback( result );

Where result should include at least all the properties of options plus, if an error occurred, the following two properties:

  • error: set to true

  • errorMessage: the error message.

Tip

If you want, you can now add any other property that will be directly passed to the Search Compiler.

So, for example, a compiler that does absolutely nothing would be:

"compiler": function( options, callbacks ) {
    var result = options;
    // Some validation here...
    // Return the result as is to the compiler
    callback( result );
},

and, in case of error:

"compiler": function( options, callbacks ) {
    var result = options;
    // Some validation here...

    // EXAMPLE

    if (options.input === "FORBIDDEN") {
        result.error = true;
        result.errorMessage = "You cannot search for this term";
    }

    callback( result );
},
Important

If you don’t call the callback function, the search will never be executed!

Important

If you don’t pass the required parameters to the Controller, this will not be able to perform the search!

Example: ResourceSpace integration

Resource space does not need any specific validation, so there is nothing to configure and Méthode; Swing will simply go directly to the search Controller.

Controller setup

Controller is the most importart part of the search. Without a controller, the search cannot be executed and the results cannot be retrieved.

To add a controller, it is add a controller property to the Domain setup:

// ... other configuration
"controller" : function( options, callbacks, ctx ) {
    /* ... SEE BELOW ... */
},
// ... other configuration
Note
Different domains of the same type have the same controller. So, it is the user choice to create different types for similar functionalities, or to have a single controller to behave differently according to the options.

The controller is a Javascript function called with three main parameters:

  • options [JSON object] - information about the current search

  • callbacks [JSON object] - function to be called ( success and error)

  • ctx [JSON object] - the classic context object.

options

Same as the compiler options.

callbacks

Callbacks are Javascript function internally used to determine if the search has been successful or not.

The user is not required to know how the callbacks work, but they should be called as follows:

callbacks.success( [PARAMETERS] ); // in case of success.
callbacks.error( [PARAMETERS] ); // in case of error.

where:

  • [PARAMETERS] are either the items (in case of success) or the exception (in case of error) [ in any case, it is a JSON object ].

Success example:

callbacks.success( { items: items } );
Caution
Please maintain the structure of the items are shown in the example (a JSON object with items which is an array of objects).

Error example:

callbacks.error( { message: 'Error during the search' } );

How to build a controller

The following code shows how a controller can be built. The code is well commented and should be easily understandable.

// Add a new controller for the search.
"controller": function( options, callbacks ) {

        var API_KEY = 'V0aRlntBV163dNJK5prQv5E1IXNUwGKudTIGZcq8xissufD8lBpQ2I1TgkRn_Xlvm8RvL_ezBOzTOS4s4IV40g';

        // If the user did not put any input, show an error.
        // In this specific case (resourceSpace), search without terms is allowed,
        // so the following code is commented
        /*
        if (!options.input) {
            callbacks.error( { message: 'No input provided' } );
            return;
        }
        */

        /*
            Archive management
            resourceSpace example did NOT use any archive, so this part is omitted.
            Another example (such as wikipedia), used the archive to build the link, as shown
            in the following (commented) example.
        */

        /*
            // Takes the first archive, or 'en' as default
            var archive = (options.archives && options.archives.length) ? options.archives[0] : 'en';

            // Build the url necessary for wikipedia.
            var url1 = 'http://' + (archive || 'en') +
                       '.wikipedia.org/w/api.php?action=query&list=search&callback=&srsearch=' +
                       encodeURI(options.input) + '&format=json&rawcontinue&srprop=snippet';
        */

        // Prepares the url
        var url = eidosmedia.webclient.app.context + "/resourcespacesearch/";

        // With the try..catch no error will escape!
        try {
            $.ajax({
              url: url,
              data: {
                "key": API_KEY,
                "search": options.input,
                "prettyfieldnames": true,
                "original": true
              },
              success: function( items ) {

                  var response = {};
                  response.items = items || [];
                  // Do something with the response...

                  // Prepare JSON ( see the next paragraph for that ).
                  // If we used a default template, we would have to adapt the response JSON
                  // to Swing Templates, as shown here.
                  /*
                  for( var j in response.items ) {
                      response.items[j].id = response.items[j]["original_link"];
                      response.items[j].type = "rsImage";
                      response.items[j].methodeType = "image";
                      response.items[j].title = response[j].Title;
                      response.items[j].hideStatus = true;
                      response.items[j].preview = response.items[j].content = response.items[j]["original_link"];
                  }*/
                  // OR
                  // If we used a custom template, we could just use the JSON 'as-is'

                  // REMEMBER TO SET AT LEAST ID AND TYPE FOR EACH ITEM.
                  for( var j in response ) {
                      response.items[j].id = response.items[j]["original_link"];
                      response.items[j].type = "rsImage";
                      response.items[j].methodeType = "image";
                  }

                  // Call the successful callback.
                  callbacks.success( response );
              },
              error: function( ex ) {
                  // Call the error callback.
                  callbacks.error( ex );
              }
            });
        } catch( ex ) {
            // Call the error callback.
            callbacks.error( ex );
        }
    }

Controller setup: dynamic page load.

As of Swing 3.0.0, it is possible for custom domain to load only a subset of results. Everytime the user requires additional results, the controller is called again with specific paramers in order to allow the search of the required items only.

To do so, it is necessary to structure the response object adding two additional properties:

  • totalCount : this is the total number of results of the query if there were no limits.

  • resultCount: this is the number of results provided by the current query (e.g. items.length )

This allows Swing to understand that the search is passing a subset of a larger amount of results. The calculation of pages is done automatically.

When the user requires a new page, the controller is called again with the same parameters. However, the options parameter will have an additional property:

  • pageInfo.start : the number of the starting required result ( e.g. the "from" object )

  • pageInfo.end : the number of the end required result ( e.g. the "to" object )

Important

pageInfo is not passed in case of the first page.

Here follows a pseudo-code example:

    // Add a new controller for the search.
    "controller": function( options, callbacks ) {

        // other infos...

        // PAGE MANAGEMENT
        var hasPage = !!options.pageInfo;
        // Prepares the url
        var url = eidosmedia.webclient.app.context + "/resourcespacesearch/";

        var request = {
            "key": API_KEY,
            "search": options.input,
            "prettyfieldnames": true,
            "original": true
        }
        if ( hasPage ) {
            request.from = options.pageInfo.start;
            request.to = options.pageInfo.end;
        }

        // With the try..catch no error will escape!
        try {
            $.ajax({
              url: url,
              data: request,
              success: function( resp ) {
                  var response = {};
                  response.items = resp.items || [];
                  // Do something with the response...

                  if (!hasPage) {
                    // We pass the total amount of results to force dynamic pagination
                    response.totalCount = resp.totalResults;
                    response.resultCount = response.items.length;
                  }

                  // Call the successful callback.
                  callbacks.success( response );
              },
              error: function( ex ) {
                  // Call the error callback.
                  callbacks.error( ex );
              }
            });
        } catch( ex ) {
            // Call the error callback.
            callbacks.error( ex );
        }
    }

4. How to structure results in JSON for Méthode Swing

JSON results must be structured accordingly to be correctly interpreted by Méthode Swing Search. In fact, each item must have an id and a type property. (And a methodeType property if the import is allowed).

Caution

It is certainly possible to specify one of the default Méthode types. However, this is strongly discouraged in order to avoid any possibility of overriding the original behaviour.

Tip

Since the id and type properties are required, it is strongly advised (read: MUST) that:

  • id is unique.

  • type uses a custom prefix (e.g. rs) to avoid name conflicts with Méthode types.

Also, if the allowImport is enabled, the item should specify the correspondent methodeType.

There are several different MethodeType supported values:

  • image: allows import, download and insert.

  • externalwebpage: allows the text analysis / create story from the external webpage

  • htmlblock: allows to insert a Codeblock inside a story. (The HTML code to insert must be in the htmlCode property).

Having said that, the user has two possibilities:

5. Usage and creation of result templates

Documentation for this section is part of the general search documentation and is available here.

6. Import objects in a Méthode document

By specifying the allowImport property to the proper value, Méthode Swing automatically adds the possibility to download the object in the configured workfolder (according to the context: in Explorer Area, the current folder; in Editor Area, the configured workfolder of the current document).

allowImport can be a boolean, or a function which returns true if in that case the import is allowed, false otherwise. It is called with a parameter containing all the information about the item.

Tip

A common use for the function is to verify if to allow the import only for specific types.

    // ... other configuration
    "allowImport": function( ctx ) {
        // Allow import only for images.
        if (ctx.activeObject.getInfo().type.toLowerCase() === 'rsimage') {
            return true;
        }
        return false;
    },
    // ... other configuration

    // OR

    "allowImport": true / false

Furthermore, it is possible to specify the getImportInfo function, which is used to return the Import information. Consider the example:

{
    // ... other configuration
    "allowImport": function( ctx ) {
        // Allow import only for images.
        if (ctx.activeObject.getInfo().type.toLowerCase() === 'rsimage') {
            return true;
        }
        return false;
    },
    // ... other configuration
    "getImportInfo": function( ctx ) {
        var objInfo = ctx.activeObject.getInfo();

        // IMPORTANT. If the "url" is relative, this won't work.
        // To obtain the absolute url, use the ctx.getAbsoluteUrl( url ) method.

        return {
            "url": ctx.getAbsoluteUrl( objInfo.original_url ),
            "filename": objInfo.id + '.png', // See below
            "conflictResolutionMode": 'conflict.user', // See below
            "conflictAlternatives": ['conflict.autoRename', 'conflict.useExisting', 'conflict.replace', 'conflict.newVersion', 'conflict.doNotCreate'], // See below
            "attributes": "Here you can specify the XML metadata",
            "uniqueId": "Specify the uniqueness_string here",
            "info": {
                "otherCustomProperties": "Some value"
            }
        }
    }
}
Caution

The function is not necessary, but if it is specified, it must return a JSON object with two parameters:

  • url : the URL of the downloaded object ( if not present, Méthode Swing will look for the item’s url property, or the id ).

  • info: a JSON object containing some additional metadata about the item. By default, all the item properties are added.

If specified, uniqueId (an optional String value that uniquely identifies a content and is demanded to be unique in a whole repository) property will be added to Méthode Unique Id.

conflictResolutionMode allows to define the default behaviour when importing an item already existing. It can be one of 'conflict.autoRename', 'conflict.useExisting', 'conflict.replace', 'conflict.newVersion', 'conflict.doNotCreate' or a special value 'conflict.user' that shows a dialog and let the user decide how to handle the conflict.

conflictAlternatives is used when conflictResolutionMode is 'conflict.user' and allows to filter the conflict resolution modes proposed to the user.

NOTE: Methode Editorial API Server tries to understand the Methode Type from the URL extension. So, if the url is special (e.g. the result of a call, such as "http://www.myservlet.com/generatePreview.dll?id=dSDAWdsdqw12314", this won’t be recognized as an Image. In these cases, it is necessary to provide a suggested filename by adding the filename property to the getImportInfo result.

Important

The allowImport and the getImportInfo receive the Context Object as the only parameter. For retrocompatibility, all methods and properties available in Methode Swing versions prior to 1.4.3 are still available, but it is strongly discouraged to use them. Instead, refer to Context object in search (ctx parameter) for further info on how to use the Context object.

And that’s it! You can now import your custom content within Méthode. Good luck!

Additional properties

availableKeywords

availableKeywords property is an object structured as follows:

"availableKeywords":{
     "keyword1":{ source:['suggestion1', 'suggestion2'] ,icon:'icon-save' },
     "keyword2":{ source:[], icon: 'emui-icon-area-myarea' },
     "keyword3":{ source:[], icon:null }
}

Each keyword has two properties:

  • source: a array of suggestions for that specific keyword

  • icon: an icon for the suggestion

The result is the following:

Custom keywords (1)
Figure 1. Custom keywords in Swing (1)
Custom keywords (2)
Figure 2. Custom keywords in Swing (2)

Context object in search (ctx parameter)

The Search context has the following values:

Table 171. Parameters list
Parameter Values Description

area.getName()

"search" or "search" according to the position of the search.

area.getContext()

"modal" or "candidate" according to the position of the search.

component.getType()

"querypreview" or "quickpreview" or "contentanalyzer" according to the position in the search.

component.getId()

String

Not available

activeObject.getId()

String

Return the ID of the current object

activeObject.getInfo()

JSON

Return the info of the current object

activeObject.getType()

JSON

Return the type of the current object

selection

JSON Array

Not available (empty array)

Complete Resource Space configuration

/**
 * Plugin name: ResourceSpace
 * The plugin adds the possibility to integrate Resource Space DAM
 */

// Add a new domain in the search dialog.
eidosmedia.webclient.extensions.search.addDomain({
    "name": "resourcespace",
    "type": "resourcespace",
    "label": "ResourceSpace Search",
    "icon": "icon-foursquare",
    "itemsPerPage": 8,
    "allowNoInput": true,
    "useExternalSuggestion": false,
    "searchTemplate" : [{ type: "rsimage", template: "search-preview-image.html" }],
    /* It is possible to add Archives and conditions. Please refer to Domains configuration. */
    "allowImport": function( item ) {
        return true;
    },
    "getImportInfo": function( item ) {
        var objInfo = ctx.activeObject.getInfo();

        return {
            "url": objInfo.original_url,
            "attributes": "Here you can specify the XML metadata",
            "uniqueId": "Specify the uniqueness_string here",
            "info": {
                "otherCustomProperties": "Some value"
            }
        }
    },
    "controller": function( options, callbacks ) {

        var API_KEY = 'V0aRlntBV163dNJK5prQv5E1IXNUwGKudTIGZcq8xissufD8lBpQ2I1TgkRn_Xlvm8RvL_ezBOzTOS4s4IV40g';

        // If the user did not put any input, show an error.
        // In this specific case (resourceSpace), search without terms is allowed,
        // so the following code is commented
        /*
        if (!options.input) {
            callbacks.error( { message: 'No input provided' } );
            return;
        }
        */

        /*
            Archive management
            resourceSpace example did NOT use any archive, so this part is omitted.
            Another example (such as wikipedia), used the archive to build the link, as shown
            in the following (commented) example.
        */

        /*
            // Takes the first archive, or 'en' as default
            var archive = (options.archives && options.archives.length) ? options.archives[0] : 'en';

            // Build the url necessary for wikipedia.
            var url1 = 'http://' + (archive || 'en') +
                       '.wikipedia.org/w/api.php?action=query&list=search&callback=&srsearch=' +
                       encodeURI(options.input) + '&format=json&rawcontinue&srprop=snippet';
        */

        // Prepares the url
        var url = eidosmedia.webclient.app.context + "/resourcespacesearch/";

        // With the try..catch no error will escape!
        try {
            $.ajax({
              url: options.getUrl(),
              data: {
                "key": API_KEY,
                "search": options.input,
                "prettyfieldnames": true,
                "original": true,
                "previewsize": "thm"
              },
              success: function(response) {

                  // Do something with the response...
                  // Prepare JSON ( see the next paragraph for that ).
                  // If we used a default template, we would have to adapt the response JSON
                  // to Swing Templates, as shown here.

                  for( var j in response ) {
                      response[j].id = response[j]["original_link"];
                      response[j].type = "rsImage";
                      response[j].methodeType = "image";
                      response[j].title = response[j].Title;
                      response[j].hideStatus = true;
                      response[j].preview = response[j].content = response[j]["preview"];
                  }
                  // OR
                  // If we used a custom template, we could just use the JSON 'as-is'

                  // REMEMBER TO SET AT LEAST ID AND TYPE AND METHODE TYPE FOR EACH ITEM.
                  //for( var j in response ) {
                  //    response[j].id = response[j]["original_link"];
                  //    response[j].type = "rsImage";
                  //    response[j].methodeType = "image";
                  //}

                  // Call the successful callback.
                  callbacks.success( { items: response } );
              },
              error: function( ex ) {
                  // Call the error callback.
                  callbacks.error( ex );
              }
            });
        } catch( ex ) {
            // Call the error callback.
            callbacks.error( ex );
        }
    }
});

How to configure a domain controller in external folder

Additional domain controllers may be made available to Swing application by defining one or more nested components in Swing web context in server.xml. (for further details on Tomcat 9.x Resources configuration, please refer to Resources configuration).

This is an example of the external domain controller configuration.

<Context docBase="com.eidosmedia.webclient.web-app"
    path="/swing" reloadable="false">
    <Resources
        className="org.apache.catalina.webresources.StandardRoot">
        <PreResources
            className="org.apache.catalina.webresources.DirResourceSet"
            base="/methode/meth01/extension/plugins" readOnly="true"
            webAppMount="/app/plugins" />
    </Resources>
</Context>

Custom Filters

Swing allows to design and add custom filters to your searches.

Configure a custom filter

Filters are made of an HTML template and a related JS file.

Caution

Default templates are put in the base folder

{SWING-APP}/config/templates/search/filters

For custom templates, it is recommended ( read mandatory ) that you put them in a specific folder:

{SWING-APP}/config/templates/search/filters/{TEMPLATE-FOLDER}

Filters can be configured outside {SWING-APP}. See the paragraph How to configure search filters in external folder for some tips in how to take advantage of this new configuration option.

Design the template

The template is a simple HTML file.

There are no real boundaries inside the template, but it is strongly suggested to follow the guidelines below.

There are various attributes to be aware of:

Table 172. Supported attributes
Attribute Description

data-xvalue

This is the main parameter. It is the one that defines the type of filter. See Supported keywords for a list of available filters.

data-preload

In specific cases ( e.g. owner, status, type…​) if the value is true, Swing preloads the component with all the available values. See Supported keywords for a list of the keywords with support data-preload.

data-xprefix

This attribute is used to specify fixed prefix to the rules. For example, see metadata keyword.

data-default

This attribute is used to set a default value for the filter (e.g. a text for the input element, a date for the calendar, etc). The value is also used after a reset.

data-identifier

This attribute is used to identify a field. It is used in the setSearchValue method. See onLoad to see the method in use.

data-operator

Possible values are "AND", "OR", "NOT". If not specified, the condition is added with an AND operator. See the Warning below for further info.

data-block-operator

Possible values are "AND", "OR", "NOT". If not specified, the condition is added with an AND operator. See the Warning below for further info.

Warning

data-operator and data-block-operator are different. data-block-operator should be used ONLY with SELECT MULTIPLE or BOOTSTRAP TAGSINPUT or, in general, with any element which returns multiple values. data-block-operator defines the operator with which the whole selection is added to the query, while data-operator defines which operator is used to join each of the selected values. For example, the following HTML code:

<select multiple data-identifier="custom-select-multiple" data-xvalue="type" data-operator="OR" data-block-operator="AND">
    <option>EOM::Story</option>
    <option>EOM::CompoundStory</option>
    <option>EOM::Webpage</option>
    <option>Image</option>
</select>

The result will be AND ( EOM::Story OR Image ).

And the following:

<select class="form-control" multiple data-identifier="custom-select-multiple" data-xvalue="type" data-operator="NOT" data-block-operator="AND">
    <option>EOM::Story</option>
    <option>EOM::CompoundStory</option>
    <option>EOM::Webpage</option>
    <option>Image</option>
</select>

The result will be AND ( NOT EOM::Story NOT Image ).

Style guidelines

As will be clear from the predefined HTML suggestions, a "filter block" should be created as follows:

<div class="emui-row">
    <div class="emui-title">{BLOCK-TITLE}</div>
    <div class="emui-content">
        {BLOCK-CONTENT}
    </div>
</div>

Inside the block content, it is suggested to use standard HTML5 components, such as:

Input box
<input type="text" class="form-control" data-xvalue="{XVALUE}" placeholder="My placeholder" data-operator="AND"/>
Select, dropdown
<select class="form-control" data-xvalue="{XVALUE}" data-operator="AND">
    <option value="">Any workflow</option>
    <option value="NewsFlow/Editing">NewsFlow/Editing</option>
    <option value="NewsFlow/For Approval"></option>
</select>
Warning
It is important to insert an option without value ( or, better, value set to "" ), so the the user can, if necessary, exclude that particular filter.
Select multiple

Select multiple needs an additional data-block-operator attribute ( if omitted, default is AND ). See the specific paragraph for further information.

<select class="form-control" multiple data-identifier="custom-select-multiple" data-xvalue="type" data-operator="NOT" data-block-operator="AND">
    <option>EOM::Story</option>
    <option>EOM::CompoundStory</option>
    <option>EOM::Webpage</option>
    <option>Image</option>
</select>

The result will be AND ( NOT EOM::Story NOT Image ).

Radio buttons

It is possible to use radio buttons for some reasons, like enabling or disabling some fields. If you want to save the value, add a data-identifier attribute, without data-xvalue. Please stick to Bootstrap 3 syntax for radio buttons.

<!-- Sample radio button -->
<div class="emui-row">
    <div class="emui-title">Options radios</div>
    <div class="emui-content">
        <div class="radio">
          <label>
            <input type="radio" name="optionsRadios" data-identifier="optionsRadios1" value="option1" checked>
            Option one is this and that&mdash;be sure to include why it's great
          </label>
        </div>
        <div class="radio">
          <label>
            <input type="radio" name="optionsRadios" data-identifier="optionsRadios2" value="option2">
            Option two can be something else and selecting it will deselect option one
          </label>
        </div>
        <div class="radio disabled">
          <label>
            <input type="radio" name="optionsRadios" data-identifier="optionsRadios3" value="option3" disabled>
            Option three is disabled
          </label>
        </div>
    </div>
</div>
DatePicker and DateTimePicker components

It is possible to use the "datepicker" component using the following HTML. To use the dateTimePicker, write "datetimepicker" in the data-emui-type attribute.

Warning

It is extremely important to decide where to put the data-xvalue attribute in the case of datepicker or datetimepicker. If, as in the example, it is places in the input field, the value returned is the Date converted in the format specified by the data-format attribute. If, instead, it is placed directly in the div with the data-emui-type attribute, the value returned is a Javascript Date Object. See [range] for a better example of this second usage.

Example with data-xvalue in the input field
<div class="input-append date" data-emui-type="datepicker">
    <input data-format="dd-MM-yyyy" class="form-control" placeholder="Created" data-xvalue="created" type="text" data-operator="AND"></input>
    <span class="add-on"><i data-date-icon="icon-calendar"></i></span>
</div>

In this case, when doing ctx.getSearchValue(), a string with the selected format will be returned.

Example with data-xvalue in the date field
<div class="input-append date" data-emui-type="datepicker" data-xvalue="created" data-operator="AND">
    <input class="form-control" placeholder="Created" type="text"></input>
    <span class="add-on"><i data-date-icon="icon-calendar"></i></span>
</div>

In this case, when doing ctx.getSearchValue(), a Javascript Date Object will be returned. Plus, the calendar will have the localized format specified in the Configuration.

Tip
See [created] for an example of these components.
Bootstrap tagsinput

Swing filters natively support Bootstrap Tags input (Bootstrap Tags Input). Bootstrap Tags Input needs an additional data-block-operator attribute ( if omitted, default is AND ). See the specific paragraph for further information.

<div class="emui-row">
    <div class="emui-title">TYPES</div>
    <div class="emui-content">
        <input type="text" value="" data-role="tagsinput" data-identifier="type-tagsinput" data-xvalue="type" data-operator="OR" data-operator="AND" />
    </div>
</div>

It also requires a Javascript initialization.

{
    // ...
    onLoad: function( ctx, params ) {
        $('[data-identifier="type-tagsinput"]', params.panel).tagsinput({
            typeahead: {
              source: [ "EOM::Story", "Image", "EOM::MediaGallery", "EOM::WebPage" ]
            }
        });
    },
    // ...
}
Reset filter button

A "Reset filter" button is automatically added in the filter template.

Tip

Use the attribute data-default if you want the various filters to have a specific value after reset.

CSS guidelines
Tip
Use the form-control class to fix the width of the components to 100% of the filter panel.

Configure the JS file

To add a filter, the JS file should be structured as follows.

eidosmedia.webclient.search.addFilter( options );

In detail, the options are:

/**
 * CUSTOM FILTER
 * @name: Swing custom filter
 */
eidosmedia.webclient.search.addFilter({
    // @property "domain": {string} - it corresponds to the value configured in the <name> parameter of a specific search domain to apply the filter to
    // @property "domainType": {string} - it corresponds to the value configured in the <type> parameter of one or more searchs domain. So, if specified the filter is applied to all the domains with the same type
    // @required - only one parameter between domain or domainType
	"domain": "eomdblocal",
    // "domainType": "eomdb",

    // @property "template": {string} - the path to the search template. Path is relative to the 'config/search/filters/' folder.
    // @required
    template: 'swing-filter.html',

    /**
     * Function called after loading the template, but BEFORE loading the query
     * use it to add listeners.
     * @param {ContextObject}
     * @param {Object} params - the params of the search element
     * @param {Function} params.setSearchValue(identifier, value) - a method that allows to set a value for a specific field with the specified data-identifier.
     * @param {Node} params.panel - the current DOM node for the search filter panel
     */
    onLoad: function( ctx, params ) {
        // ...
    },

    /**
         * Function called whenever a condition in the search is changed.
         * @param {ContextObject}
         * @param {String} condition - the string with the changed condition
         */
        onConditionChange: function( ctx, condition ) {
            console.log('CONDITION CHANGED');
            console.log(condition)
        },

    /**
     * Function called after loading the query
     * use it to fix the custom elements.
     * @param {ContextObject}
     * @param {Object} params - the params of the search element
     * @param {Node} params.el - the current DOM node analized
     */
    onQueryLoaded: function( ctx, params ) {
        // ...
    },

    /**
     * This function must return the value in the form <key>:<value> for each of the
     * elements configured.
     * @method getSearchValue
     * @param {Object} params - the params of the search element
     * @param {Node} params.panel - the current DOM node for the search filter panel
     * @param {Node} params.el - the current DOM node analyzed
     * @param {String} params.dataId - the value of the data-xvalue attribute
     * @param {String} params.dataIdentifier - the value of the data-identifier attribute
     * @param {Function} getSearchValue() - the method that returns the search value calculated by default.
     * @param {Function} params.setSearchValue(identifier, value) - a method that allows to set a value for a specific field with the specified data-identifier.
     */
    getSearchValue: function( ctx, params ) {
        // ...
    }

});

Each parameter is detailed below.

domain and domainType

The filter can be coupled with either a domain or a domainType. In the latter case, all domain of the same type will share the same filter.

The domain parameter requires the same name configured in the Search configuration. See Domains configuration for further details. Please see the box below for information regarding the default-folder filter.

The domainType parameter can be one of the following: eomdb.

Important

By specifying default-folder as a value for the domain property, it is possible to override the default filter for folders. This is an additional functionality available in Swing.

Under filter/default-folder-filter/ folder, it is possible to find the Swing default folder filter. Please use it as a reference.

template

This property defines the template for the filter.

{
    // ...
    template: "test.html",
    // ...
}
Warning

The path of the template starts from the search/filters/ folder. If you placed the template in a subfolder (e.g. search/filters/testfilter/), the template should be valued as "testfilter/test.html".

onLoad

onLoad is a function called when the filter is loaded for the first time. This function is called AFTER the DOM has been filled, so that all the DOM elements of the filter are available. This function is called BEFORE the query has been loaded. It can be used to add custom listeners for events.

Tip

Unless the filter is heavily customized, the onLoad function can be ignored.

It is called with 2 parameters:

  • ctx: the Context Object. See Context Object documentation for further details. In this case, though, the context object has neither activeObj nor selection, and only contains information on the Swing area.

  • params. It is a Javascript Object with 2 properties:

    • panel: the DOM reference to the filter panel.

    • setSearchValue: a method to set the value of a field in the Search filter. See the following example for further details.

{
    onLoad: function( ctx, params ) {
        var $panel = $( params.panel );
        // Do some things...

        // setSearchValue( identifier, value ) - sets the value of a field which has a 'data-identifier' attribute;
        params.setSearchValue('createdField', '09-08-2015')

    }
}
Tip

Return value of the function is not important.

onUpdateFilterElements

onUpdateFilterElements is a function called whenever the filter elements should be updated.

It is called with the following parameters:

  • ctx: the Context Object. See Context Object documentation for further details. In this case, though, the context object has neither activeObj nor selection, and only contains information on the Swing area.

  • panel: the DOM reference to the filter panel.

  • filters. It is an array of Javascript Object with 2 main properties:

    • identifier: the filter indetifier.

    • value: the related filter value.

{
    onUpdateFilterElements: function( ctx, panel, filters ) {
         for (let j = 0; j < filters.length; j++) {
            const filterElement = filters[j];
            if (filterElement.identifier == 'author') {
                const value = filterElement.value;
            }
        }
    }
}
Tip

Return value of the function is not important.

onConditionChange

onConditionChange is a function called whenever a condition inside the search is changed (the ones on the top left dropdown). It can be used to change the filter HTML according to a specific condition.

It is called with 2 parameters:

  • ctx: the Context Object. See Context Object documentation for further details. In this case, though, the context object has neither activeObj nor selection, and only contains information on the Swing area.

  • params. It is a Javascript Object with 2 properties:

    • panel: the DOM reference to the filter panel.

    • condition. The condition that has changed. (As a string).

{
    onConditionChange: function( ctx, params ) {
        if (params.condition === 'type:image') {
            // I'm selecting, for example the condition image.
            // Show only the part related to the image.
            $(params.panel).find('[data-filter="image"]').show();
        }

    }
}
Tip

Return value of the function is not important.

onQueryLoaded

onQueryLoaded is a function called AFTER the query has been loaded. It can be used to customize behaviour after the query values have been loaded.

Tip

Unless the filter is heavily customized, the onQueryLoaded function can be ignored.

It is called with 2 parameters:

  • ctx: the Context Object. See Context Object documentation for further details. In this case, though, the context object has neither activeObj nor selection, and only contains information on the Swing area.

  • params. It is a Javascript Object with 2 properties:

    • panel: the DOM reference to the filter panel.

    • setSearchValue: a method to set the value of a field in the Search filter. See the following example for further details.

{
    onQueryLoaded: function( ctx, params ) {
        // ...
    }
}
Tip

Return value of the function is not important.

getSearchValue

    /**
     * This function must return the value in the form <key>:<value> for each of the
     * elements configured.
     * @method getSearchValue
     * @param {Object} params - the params of the search element
     * @param {Node} params.panel - the current DOM node for the search filter panel
     * @param {Node} params.el - the current DOM node analyzed
     * @param {String} params.dataId - the value of the data-xvalue attribute
     * @param {String} params.dataIdentifier - the value of the data-identifier attribute
     * @param {Function} params.getSearchValue() - the method that returns the search value calculated by default.
     * @param {Function} params.setSearchValue(identifier, value) - a method that allows to set a value for a specific field with the specified data-identifier.
     */
    getSearchValue: function( ctx, params ) {
        /*
         * ctx object, in this case, contains only info about the current view and tab.
         */

        /*
         *  Use this method ONLY if you need to perform further elaborations ( e.g. in case
         *  you don't want to pass some values, or in case this element is hidden but
         *  you still want to pass it, or in case of multiple connected inputs to produce
         *  a single value ).
         */

        /*
         * IMPORTANT
         * If this value must not be used for the query, return null.
         */

        // EXAMPLE: force Globe/Images folder.
        if ( params.dataId === 'restrictto' ) {
            return 'restrictto:/Globe/Images';
        } else if ( params.dataId === 'created' ) { {
            // EXAMPLE: let's ignore this value
            return null;
        } else {
            // Returns the value as calculated by Swing.
            return params.getSearchValue();
        }
    }
Important

As it will be clear from the Supported keywords paragraph, the filters are built as a set of <key>:<value>. This is done by finding all the DOM elements with data-xvalue attribute, and elaborating their contents.

This is done automatically for simple elements such as the one shown in the documentation. For more complex elements, it is possible to override the default behaviour with this getSearchValue function.

It is called with 2 parameters:

  • ctx: the Context Object. See Context Object documentation for further details. In this case, though, the context object has neither activeObj nor selection, and only contains information on the Swing area.

  • params. It is a Javascript Object with 4 properties:

    • {Node} el: the DOM reference to the current filter ( the element which has the data-xvalue attribute ).

    • {Node} panel: the DOM reference to the filter panel

    • {String} dataId: the value of the data-xvalue attribute. It is the current key which is processed.

    • {String} dataIdentifier - the value of the data-identifier attribute.

    • {Function} getSearchValue: a function which builds the string in the correct format ( <key>:<value> ).

    • {Function} setSearchValue( identifier, value ): a method to set the value of a filter with a specific data-identifier attribute.

Tip

Unless the filter is heavily customized, the getSearchValue function can be ignored.

Warning

If you want a specific filter to be ignored, the return value of the function should be null.

Supported keywords

Warning

The supported keywords are meaningful for EOMDB searches only. If you want to use filters for custom domains, feel free to use any keyword you prefer. The filters will be passed in the conditions array of the Search Controller (options parameter). See Search controller documentation for further details.

Table 173. Supported keywords
Keyword Description

channel, userchannel

Returns only the objects of a given channel. If userchannel is used, only the channels available to the current user are visible.

content

Search a specific text in the content of an object.

contentmetadata

Search for a text in both content and metadata.

created

Given a date, returns the objects created in that period.

created_lastdays

Allow to obtain the documents created in the last N days

creator

See user.

freexml

Allow to insert a specific xml in the query. Please use it with moderation.

issuedate

Given a date, returns the objects whose issue date is in that period.

lastmodifier

Returns the objects last modified by a specific user.

limit

Limits the results to a specific number.

locker, lockedby

Search for objects locked by a given user

metadata

Search a specific value in a given xpath.

metadatarange

Search a specific value in a given xpath, with the "range" operator ( inside the se:attributes tag )

modified

Given a date, returns the objects modified in that period.

modified_lastdays

Allow to obtain the documents modified in the last N days

owner

See user.

range

See metadatarange.

restrictto

Returns the objects inside a path.

sort

Complete sorting mechanism.

sortby

Simple descending sort according to a parameter in the ObjectInfo.

status, workflow

Search objects with a given status ( workflow ).

type

Returns only the objects of a given type.

usageticket

Allow to search within the usage tickets.

user, creator, owner

Search for objects created by a given user

userchannel

channel.

workflow

See status.

workfolder

Returns the objects inside a workfolder.

channel

Returns only the objects of a given channel.

Syntax
channel:(CHANNEL)
userchannel:(CHANNEL)
Values
Table 174. Supported values
Keyword Example Description

CHANNEL

channel:"Globe-Print"

Any string value (with quotes if there is a space).

Tip

userchannel differs from channel in the fact that only the channels relative to the current user are available..

Suggested HTML implementations
Free channel input
<div class="emui-row">
    <div class="emui-title">Channel</div>
    <div class="emui-content">
        <input type="text" class="form-control" data-xvalue="channel" placeholder="Channel" data-operator="AND"/>
    </div>
</div>
Choice from a list of channels
<div class="emui-row">
    <div class="emui-title">Channel</div>
    <div class="emui-content">
        <select data-xvalue="channel" class="form-control" data-operator="OR">
            <option value="">All channels</options>
            <option value="Globe-Print">Globe-Print</options>
            <option value="Globe-Web">Globe-Web</options>
        </select>
    </div>
</div>
Preload user channels (ONLY for userchannel keyword)
<div class="emui-row">
    <div class="emui-title">Channel</div>
    <div class="emui-content">
        <select data-xvalue="userchannel" class="form-control" data-preload="true" data-operator="OR">
        </select>
    </div>
</div>
Warning
In case of userchannel keyword, it is possible to use data-preload="true". In that case, only the current user’s channels are available.

content

Search a specific text in the content of an object.

Syntax
content:"CONTENT"
Values
Table 175. Supported values
Keyword Example Description

CONTENT

content:Obama

Any string value (with quotes if there is a space).

Suggested HTML implementations
<div class="emui-row">
    <div class="emui-title">Content</div>
    <div class="emui-content">
        <input type="text" class="form-control" data-xvalue="content" placeholder="Content"data-identifier="contentField1"/>
    </div>
</div>

contentmetadata

Search for a text in both content and metadata.

Syntax
contentmetadata:"CONTENT"
Values
Table 176. Supported values
Keyword Example Description

CONTENT

contentmetadata:Obama

Any string value (with quotes if there is a space).

Suggested HTML implementations

See content for a suggested implementation: please remember to replace data-xvalue="content" with data-xvalue="contentmetadata".

created_lastdays

Allow to obtain the documents created in the last N days

Syntax
created_lastdays:(VALUE)
Values
Table 177. Supported values
Keyword Example Description

VALUE

created_lastdays:10

Any numeric value.

creator

freexml

Allow to insert a specific xml in the query. Please use it with moderation.

Syntax
freexml:"CONTENT"
Values
Table 178. Supported values
Keyword Example Description

CONTENT

freexml:"<SysAttributes><props><productInfo><issueDate q:op='EXIST'/></productInfo></props></SysAttributes>"

Any string value (with quotes if there is a space). Note: please use single quotes when a double quote is used inside the value.

Tip

In case of freexml, double quotes need to be replaced by @@. Alternatively, CDATA can be used to wrap "content".

<filter>
<name>EDT_Sport</name>
<condition>freexml:<![CDATA[<ObjectInfo><oteam>EDT_Sport</oteam></ObjectInfo>]]></condition>
</filter>
Suggested HTML implementations

If checked, only items with an issue date are searched.

<div class="emui-row">
    <div class="emui-content">
        <div class="checkbox">
          <label>
            <input type="checkbox" data-xvalue="freexml" value="<SysAttributes><props><productInfo><issueDate q:op='EXIST'/></productInfo></props></SysAttributes>"/>
            Only items with issue date
          </label>
        </div>
    </div>
</div>
Advanced HTML Sample

Here follows a complex example that makes use of freexml to search into Virtual Attributes according to the user input.

<div class="emui-row">
    <div class="emui-title">Owner Team</div>
    <div class="emui-content">
        <input type="text" class="form-control" data-xvalue="oteamVA" />
    </div>
</div>

<div class="emui-row">
    <div class="emui-title">C Team</div>
    <div class="emui-content">
        <input type="text" class="form-control" data-xvalue="cteamVA" />
    </div>
</div>

<!-- hidden field for virtual-attributes existence -->
<input type="hidden" data-identifier="vaexist" data-xvalue="freexml" />

The javascript part must be included within the Filter definition.

    getSearchValue: function( ctx, params ) {
        // Example to manage the virtual attributes
        if (params.dataId === 'oteamVA') {
            // Saves for later reuse
            this.oTeam = params.getSearchValue();
            return null;
        } else if (params.dataId === 'cteamVA') {
            // Saves for later reuse
            this.cTeam = params.getSearchValue();
            return null;
        } else if (params.dataIdentifier === 'vaexist') {
            var xml = "<va xmlns:eom='http://www.eidosmedia.com/eom'>" +
            '<parent_uuid>fbed282e-35e2-11e2-9e81-0545e1a77e80</parent_uuid>' +
            (this.oTeam ? '<oteam>' + this.oTeam + '</oteam>' : '') +
            (this.cTeam ? '<cteam>' + this.cTeam + '</cteam>' : '') +
            '<vid>3</vid>' +
            '<vt>1511298626</vt>' +
            '<vm>eidosmedia_support</vm>'
            '</va>';
            return xml;
        }

        return params.getSearchValue();
     }

lastmodifier

Returns the objects last modified by a specific user.

Syntax
lastmodifier:(USER|myself)
Values
Table 179. Supported values
Keyword Example Description

USER

lastmodifier:johndoe

Any string value (with quotes if there is a space). Return the objects modified by the specified user.

myself

lastmodifier:myself

Return the objects modified by the current user

Suggested HTML implementations

See user, creator, owner. The supported value and the HTML implementations are the same. Please remember to replace "owner", "user" or "creator" with "lastmodifier".

limit

Limits the results to a specific number.

Syntax
limit:(VALUE)
Values
Table 180. Supported values
Keyword Example Description

VALUE

Any numeric value

limit:100

Suggested HTML implementations
<div class="emui-row">
    <div class="emui-title">Limit results</div>
    <div class="emui-content">
        <input type="number" class="form-control" data-xvalue="limit" min="0" max="5000"/>
    </div>
</div>

locker, lockedby

Search for objects locked by a given user

Syntax
locker:(USER|myself)
Values
Table 181. Supported values
Keyword Example Description

USER

locker:joe.bolton

Any string value (with quotes if there is a space). Return the objects locked by the specified user.

myself

locker:myself

Return the objects locked by the current user

Tip

locker, lockedby keywords are totally equivalent.

Suggested HTML implementations

See user, creator, owner. The supported value and the HTML implementations are the same. Please remember to replace "owner", "user" or "creator" with "locker".

metadata

Search a specific value in a given xpath.

Syntax
metadata:"CONTENT"
Values
Table 182. Supported values
Keyword Example Description

CONTENT

metadata:"{{SETTINGS}}/Metadata/Editorial/ContentType=my value here"

Any string value (with quotes if there is a space).

Suggested HTML implementations
<div class="emui-row">
    <div class="emui-title">Metadata</div>
    <div class="emui-content">
        <input type="text" class="form-control" data-xvalue="metadata" placeholder="Metadata" data-identifier="metadataField1"/>
    </div>
</div>

If you want the user to put only the value, because the x-path is already defined ( and should not be changed ), use the data-xprefix attribute, as in the following example:

<div class="emui-row">
    <div class="emui-title">Editorial/ContentType</div>
    <div class="emui-content">
        <input type="text" class="form-control" data-xvalue="metadata" data-xprefix="/Editorial/ContentType=" placeholder="ContentType"/>
    </div>
</div>

In this second case, the user will only need to write the value of the /Editorial/ContentType/ xpath.

Important

It is possible to specify additional properties within the metadata keyword. At the moment, the only supported setting is the search operator. To configure it, add {{op=MATCH}} in the data-prefix or to the value of the metadata. The content inside the {{ …​ }} will be processed and all the settings inside applied to the search. Currently supported settings are:

  • Search operator : op=OPERATOR (e.g. op=MATCH )

A sample with settings:

<div class="emui-row">
    <div class="emui-title">Editorial/ContentType</div>
    <div class="emui-content">
        <input type="text" class="form-control" data-xvalue="metadata" data-xprefix="{{op=MATCH}}/Editorial/ContentType=" placeholder="ContentType"/>
    </div>
</div>

metadatarange

Search a specific value in a given xpath, with the "range" operator ( inside the se:attributes tag )

Syntax
metadatarange:"{X-PATH}={VALUE}"
Values
Table 183. Supported values
Keyword Example Description

"{X-PATH}={VALUE}"

metadatarange:"/Metadata/Editorial/ContentType=RANGE"

See previous example. Note: Quotes are mandatory. If the value contains double quotes, use single quotes instead.

Important

The RANGE value must be in the following format: YYYYMMDDhhmmss;YYYYMMDDhhmmss.

Suggested HTML implementations

See Modified: Interval of dates for a sample implementation.

In this example, we are creating a "Created range" filter, allowing the user to specify both date and time. Please notice that:

Tip
  • data-xvalue attributes are respectively "field-from", "field-to", and "range" and are placed in the DIV element with data-emui-type="datetimepicker". This allows the user to obtain the Javascript Date Object as an elaboration.

  • The element with data-xvalue="range" also has a data-xprefix="/ObjectInfo/Created=" attribute.

  • the only difference between metadatarange and range is that the generated xml is wrapped in a <se:attributes></se:attributes> tag in case of metadatarange.

Javascript

See Modified: Interval of dates for a sample implementation. Please refer only to the first part of the getSearchValue function.

Modified: Interval of dates

With this filter implementation, it is possible to play a little bit with the fields to allow the use of an interval of dates.

Let’s see a complete example:

HTML
<!-- MODIFIED -->
<div class="emui-row">
    <div class="emui-title">Modified</div>
    <div>
        <div class="emui-content" style="width: 40%;float: left;">
            <div class="emui-title">From:</div>
            <div class="input-append date" data-emui-type="datepicker" data-xvalue="modified-date-from">
                <input id="modified-date-from" class="form-control" placeholder="From" type="text" data-identifier="fromField1"></input>
                <span class="add-on"><i data-date-icon="icon-calendar"></i></span>
            </div>
        </div>
        <div class="emui-content" style="width: 40%;float: left; margin-left:30px">
            <div class="emui-title">To:</div>
            <div class="input-append date" data-emui-type="datepicker" data-xvalue="modified-date-to">
                <input id="modified-date-to" class="form-control" placeholder="To" type="text" data-identifier="toField1"></input>
                <span class="add-on"><i data-date-icon="icon-calendar"></i></span>
            </div>
        </div>
        <div class="emui-content" style="display: none; visibility: hidden;">
                <div class="input-append date" data-emui-type="datepicker" data-xvalue="modified">
                <input id="date-to" class="form-control" type="text" data-identifier="modifiedField1"></input>
            </div>
        </div>
    </div>
</div>
Warning

It is extremely important to decide where to put the data-xvalue attribute in the case of datepicker or datetimepicker. If, as in the example, it is places in the input field, the value returned is the Date converted in the format specified by the data-format attribute. If, instead, it is placed directly in the div with the data-emui-type attribute, the value returned is a Javascript Date Object.

Tip
In this case, the data-xvalue is placed in the DIV element of the datepicker.
Javascript
// NOTE: We are including ONLY the "getSearchValue" method of the Javascript file. The rest looks the same as documented below.

getSearchValue: function(ctx, params) {
    /*
     *  ctx object, in this case, contains only info about the current view and tab.
     *  Use this method ONLY if you need to perform further elaborations ( e.g. in case
     *  you don't want to pass some values, or in case this element is hidden but
     *  you still want to pass it, or in case of multiple connected inputs to produce
     *  a single value ).
     */

    /* EXAMPLE WITH DATA-XVALUE IN THE DATEPICKER DIV. A DATE OBJECT IS RETURNED. */

    // Does nothing.
    if (params.dataId === 'modified-date-from') {
        // First, save the date-from value for later
        this.dateFrom = null;
        if(params.getSearchValue() !== null){
             this.dateFrom = params.getSearchValue()[0];
        }
        // We return null because we don't want it to be processed by the filter engine.
        return null;
    }
    else if (params.dataId === 'modified-date-to') {
        // Then, save the date-to value for later
        this.dateTo = null;
        if(params.getSearchValue() !== null){
            this.dateTo = params.getSearchValue()[0];
        }
        // We return null because we don't want it to be processed by the filter engine.
        return null;
    } else if (params.dataId === 'modified') {
        // At last, I have the hidden "modified" field, which I can build as desired.

        if (this.dateFrom === null && this.dateTo === null) {
            // User did not specify anything. We don't specify the "modified" field
            return null;
        } else if (this.dateFrom !== null && this.dateTo !== null) {
            // User specified both the "from" date and the "to" one.
            // We build the modified value as "DATEFROM;DATETO";

            /* NOTE: IN CASE OF RANGE / METADATARANGE FILTER, the format MUST BE YYYYMMDDHHmmss instead of YYYYMMDD */
            return moment(this.dateFrom).format('YYYYMMDD') + ';' + moment(this.dateTo).format('YYYYMMDD');
        } else if (this.dateFrom === null) {
            // User specified ONLY the "to" date.
            // We can decide that, in this case, the from date is a year before.
            var today = new Date();
            var yyyy = today.getFullYear() - 1;
            this.dateFrom = moment(today).year(yyyy).toDate();

            /* NOTE: IN CASE OF RANGE / METADATARANGE FILTER, the format MUST BE YYYYMMDDHHmmss instead of YYYYMMDD */
            return moment(this.dateFrom).format('YYYYMMDD') + ';' + moment(this.dateTo).format('YYYYMMDD');
        } else {
            // User specified ONLY the "from" date.
            // We can decide that, in this case, the to date is today.
            var today = new Date();
            this.dateTo = moment(today).toDate();

            /* NOTE: IN CASE OF RANGE / METADATARANGE FILTER, the format MUST BE YYYYMMDDHHmmss instead of YYYYMMDD */
            return moment(this.dateFrom).format('YYYYMMDD') + ';' + moment(this.dateTo).format('YYYYMMDD');
        }
    }
    else {
        // In any other case, for any other field, we return the value inserted by the user.
        return params.getSearchValue();
    }


    /* ALTERNATIVE EXAMPLE WITH DATA-XVALUE IN THE INPUT DATEPICKER. A STRING IS RETURNED. */

    if (params.dataId === 'modified-date-from') {
        // First, save the date-from value for later
        this.dateFrom = params.getSearchValue();
        // We return null because we don't want it to be processed by the filter engine.
        return null;
    }
    else if (params.dataId === 'modified-date-to') {
        // Then, save the date-to value for later
        this.dateTo = params.getSearchValue();
        // We return null because we don't want it to be processed by the filter engine.
        return null;
    }
    else if (params.dataId === 'modified') {
        // At last, I have the hidden "modified" field, which I can build as desired.

        if (this.dateFrom === null && this.dateTo === null) {
            // User did not specify anything. We don't specify the "modified" field
            return null;
        } else if (this.dateFrom !== null && this.dateTo !== null) {
            // User specified both the "from" date and the "to" one.
            // We build the modified value as "DATEFROM;DATETO";
            return this.dateFrom + ';' + this.dateTo;
        } else if (this.dateFrom === null) {
            // User specified ONLY the "to" date.
            // We can decide that, in this case, the from date is a year before.

            var today = new Date();
            var yyyy = today.getFullYear() - 1;
            var newDateFrom = yyyy + '' + '0101';

            // We build the new interval.
            return newDateFrom + ';' + this.dateTo;
        } else {
            // User specified ONLY the "from" date.
            // We can decide that, in this case, the from date is 15 days after today.

            var today = new Date();
            today.setDate(today.getDate() + 15);

            var dd = today.getDate();
            var mm = today.getMonth() + 1;

            if (dd < 10) dd = '0'+ dd;
            if (mm < 10) mm = '0'+ mm;

            var newDateTo = today.getFullYear() + '' + mm + dd;

            return dateFrom + ';' + newDateTo;
        }
    } else {
        // In any other case, for any other field, we return the value inserted by the user.
        return params.getSearchValue();
    }
}
Explanation
Tip

We are exploiting the fact that the filter engine processes fields in the order they appear. So, at first we include two fields, whose data-xvalue attribute is modified-date-from and modified-date-to. Then, we include a hidden field named modified, which is the supported keyword. By hiding it, we prevent the user from filling it. By including it, the modified field will be processed exactly like any other, so we can process it in the Javascript file, as presented.

modified_lastdays

Allow to obtain the documents modified in the last N days

Syntax
modified_lastdays:(VALUE)
Values
Table 184. Supported values
Keyword Example Description

VALUE

modified_lastdays:10

Any numeric value.

range

restrictto

Returns the objects inside a path.

Syntax
restrictto:(VALUE)
Values
Table 185. Supported values
Keyword Example Description

VALUE

Any string value (with quotes if there is a space).

restrictto:"/Globe/Images"

Suggested HTML implementations
Free input
<div class="emui-row">
    <div class="emui-title">Restrict to path (and subfolders)</div>
    <div class="emui-content">
        <input type="text" class="form-control" data-xvalue="restrictto" placeholder="Path" />
    </div>
</div>
Choice from a list
<div class="emui-row">
    <div class="emui-title">Restrict to path (and subfolders)</div>
    <div class="emui-content">
        <select data-xvalue="restrictto" class="form-control">
            <option value="">All paths</options>
            <option value="/Globe/Stories/Politics">/Globe/Stories/Politics</options>
            <option value="/Globe/Stories/Sport">/Globe/Stories/Sport</options>
        </select>
    </div>
</div>

sort

Complete sorting mechanism.

Syntax
sort:"{X-PATH};{VALUE}"
Values
Table 186. Supported values
Keyword Example Description

"{X-PATH};{VALUE}"

sort:"ObjectInfo/modified;ND"

See previous example. Note: Quotes are mandatory. If the value contains double quotes, use single quotes instead.

Tip

In {x-path};{Value}, value can be:

Table 187. Values
Value Description

A

Ascending

D

Descending

NA

Numeric Ascending

ND

Ascending

Suggested HTML implementations
Free input
<div class="emui-row">
    <div class="emui-title">Sort</div>
    <div class="emui-content">
        <input type="text" class="form-control" data-xvalue="sort" placeholder="Sort" />
    </div>
</div>
Choice from a list of sorting mechanisms
<div class="emui-row">
    <div class="emui-title">Sort</div>
    <div class="emui-content">
        <select data-xvalue="sort" class="form-control">
            <option value="">Default sort</options>
            <option value="ObjectInfo/modified;ND">Modified, DESC</options>
            <option value="ObjectInfo/modified;NA">Modified, ASC</options>
            <option value="ObjectInfo/created;ND">Created, DESC</options>
            <option value="ObjectInfo/created;NA">Created, ASC</options>
        </select>
    </div>
</div>

sortby

Simple descending sort according to a parameter in the ObjectInfo.

Syntax
sortby:(VALUE)
Values
Table 188. Supported values
Keyword Example Description

created

sortby:created

Return the objects sorted by creation date, descending.

modified

sortby:modified

Return the objects sorted by modified date, descending.

Suggested HTML implementations
<div class="emui-row">
    <div class="emui-title">Sort by:</div>
    <div class="emui-content">
        <select class="form-control" data-xvalue="sortby">
            <option value="">Default sort</option>
            <option value="Created">Created</option>
            <option value="Modified">Modified</option>
        </select>
    </div>
</div>

status, workflow

Search objects with a given status ( workflow ).

Syntax
status:(VALUE)
Values
Table 189. Supported values
Keyword Example Description

VALUE

status:NewsFlow/Editing

Any string value (with quotes if there is a space).

Suggested HTML implementations
Tip

By adding the data-preload="true" attribute, the select element will be preloaded with all the workflow steps available.

<div class="emui-row">
    <div class="emui-title">Workflow</div>
    <div class="emui-content">
        <select class="form-control" data-xvalue="workflow" data-preload="true"></select>
    </div>
</div>

It is also possible to specify the values manually. Be careful in putting a value="" in case no filter should be applied.

<div class="emui-row">
    <div class="emui-title">Workflow</div>
    <div class="emui-content">
        <select class="form-control" data-xvalue="workflow">
            <option value="">Any workflow</option>
            <option value="NewsFlow/Editing">NewsFlow/Editing</option>
            <option value="NewsFlow/For Approval"></option>
        </select>
    </div>
</div>

type

Returns only the objects of a given type.

Syntax
type:(TYPE)
Values
Table 190. Supported values
Keyword Example Description

TYPE

type:EOM::Story

Any string value (with quotes if there is a space). Return the objects of specified type.

Suggested HTML implementations
Tip

By adding the data-preload="true" attribute, the select element will be preloaded with all the types available.

<div class="emui-row">
    <div class="emui-title">Type</div>
    <div class="emui-content">
        <select class="form-control" data-xvalue="type" data-preload="true"></select>
    </div>
</div>

It is also possible to specify the values manually. Be careful in putting a value="" in case no filter should be applied.

<div class="emui-row">
    <div class="emui-title">Type</div>
    <div class="emui-content">
        <select class="form-control" data-xvalue="type">
            <option value="">Any type</option>
            <option value="EOM::Story">EOM::Story</option>
            <option value="EOM::MediaGallery">EOM::MediaGallery</option>
        </select>
    </div>
</div>

It is also possible to have a multiple selection of types. REMEMBER to change the data-operator attribute to OR to make it work. data-block-operator should be omitted or "AND".

<div class="emui-row">
    <div class="emui-title">Type</div>
    <div class="emui-content">
        <select class="form-control" data-xvalue="type" data-operator="OR" data-preload="true" multiple data-block-operator="AND"></select>
    </div>
</div>

usageticket

Allow to search within the usage tickets.

Syntax
usageticket:"tp:{type};;c:{creator};;rng:{range}"
Values
Table 191. Supported values
Keyword Example Description

CONTENT

tp:{type};;c:{creator};;rng:{range}

usageticket:"tp:WebPub;c:alessandropiana;rng:20160420220000__20160421215900"

Tip
  • Type (tp) is the only mandatory field for the usageticket filter. creator (c) and range (rng) are optional.

  • Range (rng) is in the format YYYYMMDDhhmmss__YYYYMMDDhhmmss

  • Separate the fields with a double ; ( ;; ).

  • If the field values have spaces in it, use a double underscore instead of spaces ( __ )

Suggested HTML implementations

There is no a real suggested HTML implementation. It could be useful to create three different choices for the different fields ( types, creator and range ), and combine them in the filter JS.

user, creator, owner

Search for objects created by a given user

Syntax
user:(USER|myself)
Values
Table 192. Supported values
Keyword Example Description

USER

user:johndoe

Any string value (with quotes if there is a space). Return the objects created by the specified user.

myself

user:myself

Return the objects created by the current user

Tip

user, creator, owner keywords are totally equivalent.

Suggested HTML implementations
Tip

By adding the data-preload="true" attribute, the select element will be preloaded with all the users available.

<div class="emui-row">
    <div class="emui-title">Owner</div>
    <div class="emui-content">
        <select class="form-control" data-xvalue="owner" data-preload="true"></select>
    </div>
</div>

It is also possible to specify the values manually. Be careful in putting a value="" in case no filter should be applied.

<div class="emui-row">
    <div class="emui-title">Owner</div>
    <div class="emui-content">
        <select class="form-control" data-xvalue="owner">
            <option value="">Any user</option>
            <option value="johndoe">johndoe</option>
            <option value="Kurt">Kurt Cobain</option>
        </select>
    </div>
</div>

userchannel

See channel.

workflow

workfolder

Returns the objects inside a workfolder.

Syntax
workfolder:(VALUE)
Values
Table 193. Supported values
Keyword Example Description

VALUE

Any string value (with quotes if there is a space).

workfolder:"/Globe/Images"

Suggested HTML implementations
Free path input
<div class="emui-row">
    <div class="emui-title">Search in workfolder</div>
    <div class="emui-content">
        <input type="text" class="form-control" data-xvalue="workfolder" placeholder="Path" />
    </div>
</div>
Choice from a list of paths
<div class="emui-row">
    <div class="emui-title">Search in workfolder</div>
    <div class="emui-content">
        <select data-xvalue="workfolder" class="form-control">
            <option value="">All paths</options>
            <option value="/Globe/Stories/Politics">/Globe/Stories/Politics</options>
            <option value="/Globe/Stories/Sport">/Globe/Stories/Sport</options>
        </select>
    </div>
</div>

How to configure search filters in external folder

Additional search filters may be made available to Swing application by defining one or more nested components in Swing web context in server.xml. (for further details on Tomcat 9.x Resources configuration, please refer to Resources configuration).

This is an example of the external filters configuration.

<Context docBase="com.eidosmedia.webclient.web-app"
    path="/swing" reloadable="false">
    <Resources
        className="org.apache.catalina.webresources.StandardRoot">
        <PreResources
            className="org.apache.catalina.webresources.DirResourceSet"
            base="/methode/meth01/extension/searchfilters" readOnly="true"
            webAppMount="/config/templates/search/filters" />
    </Resources>
</Context>

Explorer: filter on queries

Queries created in Swing

Queries generated from Swing will work like they do inside the search. Please see Search custom filter for reference on how to create and register a filter for the Swing searches.

Queries created in Prime, with filter.

Queries created in Prime can have a filter specified in their System Attributes. An example is the following:

<?xml version="1.0" encoding="utf-8"?>
<props>
  <!-- ... -->
  <filter>myFilter</filter>
  <!-- ... -->
</props>

In Prime, this opens up a specific panel myFilter.html. To have the same functionality in Swing, it is necessary to register the filter with the following namespace

eidosmedia.webclient.extensions.queryFilters.register( filterName, options);

As the following example shows, the configuration is equal to the Swing query filters. Please see Search custom filter for reference on how to create and register a filter for the Swing searches.

The variables specified in the query correspond to the name of the data-xvalue attribute of the input. See example below:

Important

An additional defaultValues property can be defined. This means that the filter is executed with those values when the query is launched for the first time. The defaultValues property can also be a function that must returns a JSON object.+ See example at the end of the page.

Important

Operators are ignored in this kind of filter. The filter is used to retrieve a value for all the variables specified with the data-xvalue attribute.

Query XML

<?xml version="1.0" encoding="UTF-8"?>
<EOMSearch
    xmlns="http://EidosMedia.com/EOM/SearchEngine"
    xmlns:se="http://EidosMedia.com/EOM/SearchEngine"
    xmlns:q="http://EidosMedia.com/EOM/SearchEngine/query"
    xmlns:qm="http://EidosMedia.com/EOM/SearchEngine/query/macro"
    xmlns:qa="http://EidosMedia.com/EOM/SearchEngine/query/alias"
    xmlns:qui="http://EidosMedia.com/EOM/SearchEngine/query/UI"
    xmlns:i="http://EidosMedia.com/query/interpolate">
    <q:Query type="INDEX">
        <q:Properties>
            <q:MaxResultItems value="200" />
            <q:Index name="@meth01_eomjse1" />
        </q:Properties>
        <q:Boolean>
            <ObjectInfo>
                <q:OR>
                    <type>EOM::Story</type>
                    <type>EOM::CompoundStory</type>
                </q:OR>
            </ObjectInfo>
            <se:SysAttributes>
                <props>
                    <productInfo>
                        <q:OR>
                            <name>
                                <i:metadata select="production.channel" />
                            </name>
                        </q:OR>
                    </productInfo>
                    <workfolder>
                        <i:variable name="production.workfolder.path" />
                    </workfolder>
                </props>
            </se:SysAttributes>
        </q:Boolean>
        <q:Where />
        <qui:Query_UI version="1.1" domain="methode">
            <qui:selItem list="repositories" />
        </qui:Query_UI>
    </q:Query>
</EOMSearch>

Filter HTML

<div class="emui-row">
    <div class="emui-title">Channel</div>
    <div class="emui-content">
        <select class="form-control" data-xvalue="production.channel">
            <option>Globe-Web</option>
            <option>Globe-Print</option>
            <option>Globe-Tablet</option>
        </select>
    </div>
</div>
<div class="emui-row">
    <div class="emui-title">Workfolder</div>
    <div class="emui-content">
        <input type="text" class="form-control" data-xvalue="production.workfolder.path" />
    </div>
</div>

Filter Javascript

eidosmedia.webclient.extensions.queryFilters.register('myFilter', {
    // template is placed under /config/search/filters
    template: 'explorer-filters/swing-filter-explorer-query.html',

    defaultValues: {
        "production.workfolder.path": "/Globe/Art"
    },
    /**
    * Default values as function
    * @param {Object} options - options to be used create default filter values, available properties: currentUser
    *
    * defaultValues: function(options) {
    *     return {
    *   "production.workfolder.path": "/Globe/Art"
    * };
    * }
    */

    /**
     * Function called after loading the template, but BEFORE loading the query
     * use it to add listeners.
     * @param {ContextObject}
     * @param {Object} params - the params of the search element
     * @param {Node} params.el - the current DOM node analized
     */
    onLoad: function( ctx, params ) {
        console.log('ON onLoad')
    },

    /**
     * Function called after loading the query
     * use it to fix the custom elements.
     * @param {ContextObject}
     * @param {Object} params - the params of the search element
     * @param {Node} params.el - the current DOM node analized
     */
    onQueryLoaded: function( ctx, params ) {
        console.log('ON QUERY LOADED')
    },

    /**
     * This function must return the value in the form <key>:<value> for each of the
     * elements configured.
     * @method getSearchValue
     * @param {Object} params - the params of the search element
     * @param {Node} params.el - the current DOM node analized
     * @param {String} params.dataId - the value of the data-xvalue attribute
     * @param {Function} getSearchValue() - the method that returns the search value calculated by default.
     */
    getSearchValue: function( ctx, params ) {
        console.log('GET SEARCH VALUE');
        return params.getSearchValue();
    }
});