All pages
Powered by GitBook
1 of 17

Overview of Extension API

Symphony extension applications are standalone web applications that are embedded within the Symphony user interface as iframes that interact with the Symphony container using the Client Extension API.

Extension API Capabilities

The Client Extension API is a JavaScript library that consists of services containing methods that allow developers to build apps that extend and interact with Symphony's user interface. Using these services, developers can:

  • Add modules, or windows, containing your app content to the Symphony client

  • Add entry points for your app, such as navigation items in Symphony's left sidebar or links on #hashtag and $cashtag hovercards

  • Add interactive buttons to chat and user profile module headers

  • Enable users to share content from your app into Symphony chats

  • Register custom renderers to richly display messages containing structured objects

Some of Symphony’s services will require you to implement your own services with methods to handle events. For example:

  • Handling a user click on your app’s left sidebar menu item by opening your default app module

  • Handling a user click on your app’s #hashtag or $cashtag hovercard link by opening an app module with a contextual search

Many of these event handlers are provided out of the box by the BDK 1.0's App Template. To learn more about the out-of-the-box implementations provided by the BDK 1.0 continue to the Planning Your App or Tutorials sections.

App Controller and Views

Applications created with the Client Extension API run in iframes inside the Symphony client.

Symphony apps consists of:

  • The main application controller, a hidden iframe that uses the Client Extension API services to bootstrap your app, extending the Symphony user interface

  • In most cases, one or more application views, separate iframes that are rendered within Symphony modules

Applications can be built using any web development technology of your choice.

Extension API Services

Services are used for communication between your app and the Symphony client. There are two types of services: remote and local.

Remote Services

Remote services are services that are shared:

  • The services of the Client Extension API are remote services whose methods can be invoked by your application controller and views

  • You can also implement remote services that can be shared between your application controllers and views

Local Services

Local services are services are specific to either your controller or one of your views.

To learn more about the services and capabilities provided by the Extension API continue here:

Extension API Services

Initialization

Including the Client Extension API Javascript Library

To use the Client Extension API services, you must include the symphony-api.js JavaScript file in your application controller and views.

<script type="text/javascript" src="https://cdn.symphony.com/resources/api/v1.0/symphony-api.js" charset="utf-8"></script>

Including Symphony's Style Sheet

To style your app, you must include the symphony-style.css CSS file in your application views and add the class "symphony-external-app" to the <body> tag of your app views.

<link rel="stylesheet" type="text/css" href="https://cdn.symphony.com/resources/api/v1.1/symphony-style.css">

Icons guidelines

Icons must be square, with a recommended size of 32x32.

The supported formats are SVG (recommended), PNG and JPG.

Transparency is supported, but please take into account that your icon should work both in the light theme and the dark theme.

In the legacy Symphony Client, it was possible to use a rectangular sprite icon (32x16), where the first 16 pixels were used for the light theme and the last 16 pixels for the dark theme. This is not supported on Client 2.0.

SYMPHONY.remote.hello()

The SYMPHONY.remote.hello() method should be used to initialize the connection to the Client Extension API from your application controller and views.

Returns a promise that will be fulfilled when the introduction is complete. If there is a problem, the promise will be rejected. The promise returns an object containing the user's Symphony client theme name, font size, and any associated classes, including those for theme name or size, as well for condensed and contrast modes.

hello: function()

Returns

Type

Description

themeV2

Object

An object containing the user's Symphony client theme settings

locale

String

The language selected by the user in his settings. Possible values are "en-US" | "fr-FR" | "ja-JP".

{
  "themeV2" : {
    "name": "dark",
    "size": "normal",
    // This will include a list of all theme and font classes available.
    "classes": [],
  },
  "locale" : "en-US"
}

You should style your application according to the user's theme by applying the theme and font size classes to the <body> tag of any application modules.


  SYMPHONY.remote.hello().then(function(data) {
  // Set the theme of the app module
  var themeColor = data.themeV2.name;
  var themeSize = data.themeV2.size;
  // You must add the symphony-external-app class to the body element
  document.body.className = "symphony-external-app " + themeColor + " " + themeSize;
});

If a user changes his theme, a themeChangeV2 event is fired from the ui service, which will pass a themeV2 object with the new values. You should use a service to listen to this event and update the classes on the application module <body>.

Register and Connect

You must register your application controller with Symphony and connect your application views using the SYMPHONY.application methods. During this time, the Services that will be used by your application must be specified.

SYMPHONY.application.register()

Register an application controller with the Symphony client. Additionally, subscribe the application to remote services and register local services that can be used remotely. Returns a promise that will be fulfilled when registration is complete.

This method must be called before the application can register or subscribe to any services.

register : function(id, servicesWanted, servicesSent)

Parameter

Type

Description

id

String

The id of your application. For partner apps, this is an alphanumeric string chosen by the partner. For custom enterprise apps, this is generated when creating the app in the Admin Portal.

servicesWanted

Array of Strings

A list of names of remote services that your application wants to subscribe to

servicesSent

Array of Strings

A list of names of local services your application wants to make available remotely (any implemented methods on this service will be made available remotely)

Returns

Type

Description

userReferenceId

String

A unique anonymized identifier for the user in context that will perpetuate until the user uninstalls the application

// Register the "hello" application with the Symphony client
// Subscribe our application to Symphony's services
// Register the "hello" app's controller service (this service must be registered using SYMPHONY.services.register())
SYMPHONY.application.register(
  "hello",
  ["modules", "applications-nav", "ui", "share", "commerce"],
  ["hello:controller"]
).then(function(response) {
  var userId = response.userReferenceId;
}));

SYMPHONY.application.connect()

Connect an application view to an existing application that has been registered with Symphony. Additionally, subscribe the application to remote services and register local services that can be used remotely. Returns a promise that will be fulfilled when connection is complete.

connect : function(id, servicesWanted, servicesSent)

Parameter

Type

Description

id

String

The id of your application. For partner apps, this is an alphanumeric string chosen by the partner. For custom enterprise apps, this is generated when creating the app in the Admin Portal.

servicesWanted

Array of Strings

A list of names of remote services that your application wants to subscribe to

servicesSent

Array of Strings

A list of names of local services your application wants to make available remotely (any implemented methods on this service will be made available remotely)

Returns

Type

Description

userReferenceId

String

A unique anonymized identifier for the user in context that will perpetuate until the user uninstalls the application

// Connect an application view to the "hello" application
// Subscribe our application to Symphony's services
// Register the "hello" app's view service (this service must be registered using SYMPHONY.services.register())
SYMPHONY.application.connect(
  "hello",
  ["modules", "applications-nav", "ui", "share", "commerce"],
  ["hello:app"]
).then(function(response) {
  var userId = response.userReferenceId;
}));

Extension API Services

The Client Extension API uses services for communication between your application and the Symphony client. The Client Extension API provides a set of services that your application can leverage to extend the Symphony Client and to create custom workflows and experiences.

Client Extension API Services:

The Client Extensions API provides the following remote services:

Modules Service

Use the modules service to create application-specific modules:

Modules Service

Applications-Nav Service

The Applications navigation section is found at the bottom of the left-hand sidebar of the Symphony client workspace. Use the applications-nav service to create a navigation item for your application:

Applications-Nav Service

UI Service

Use the ui service to extend various parts of the Symphony client user interface. For example, add buttons on 1 to 1 chats and chatroom modules or add links to the #hashtag and $cashtag hovercards:

UI Service

Share Service

Use the share service to allow users to share content from your application into Symphony conversations:

Share Service

Entity Service

Use the entity service to allow your app to render a Structured Object within a within a message sent by the REST API:

Entity Service

Commerce Service

Apps can offer premium functionality through licensed subscriptions. Use the commerce service to identify the products (premium versions) to which a user is subscribed:

Commerce Service

Dialogs Service

Use the dialogs service to create modal windows (e.g. to open a modal window from a button registered at a room level):

Dialogs Service

Service Interface

Both the Client Extensions API services and your application services use the same interface. Continue here to learn how to implement the Service interface methods:

Service Interface

Service Interface

Both the Client Extensions API services and your application services use the same interface. The service interface consists of the following methods:

  • implement

  • invoke

  • fire

  • listen

  • remove

implement()

Create a method on a service and specify the implementation.

function implement(methodName, implementation)

Parameter

Type

Description

methodName

String

The name of the method to create on your service

implementation

Function

The implementation of the method

var helloAppService = SYMPHONY.services.register("hello:app");

helloAppService.implement("helloWorld", function() {
    console.log("Hello World!");
});

Alternately, create several methods on a service at once by specifying an object consisting of multiple functions:

function implement(implementations)

Parameters

Type

Description

implementations

Object

An object containing one or more functions to create on this service, where the keys are the names of the functions and the values are the implementations

var helloAppService = SYMPHONY.services.register("hello:app");

helloAppService.implement({
    helloWorld: function() {
      console.log("Hello World!");
  }
});

invoke()

Call a method on a service. Any extra parameters passed to this method will be sent as arguments to the service method:

function invoke(methodName, ...)

Parameters

Type

Description

methodName

String

The name of the method to call on the service

var helloAppService = SYMPHONY.services.register("hello:app");

helloAppService.implement("helloWorld", function() {
    console.log("Hello World!");
});

helloAppService.invoke("helloWorld");

fire()

Fire an event from a service. Any extra parameters passed to this method will be passed to the callbacks defined by services that listen to this event:

function fire(eventName, ...)

Parameters

Type

Description

eventName

String

The name of the event to fire

var helloAppService = SYMPHONY.services.register("hello:app");
helloAppService.fire('myEvent');

listen()

Subscribe a service to an event that is fired by another service (or itself). This method returns a handle that can later be used to remove the listener:

function listen(eventName, callback)

Parameters

Type

Description

eventName

String

The name of the event to listen for

callback

Function

The function that will be called when the event is fired

The listen namespace is the same as the namespace for methods, thus names must be unique across both service methods and events.

var uiService = SYMPHONY.services.subscribe("ui");

// themeChangeV2 is an event fired by the UI service when the user changes his theme or font. The themeV2 object which contains the theme name and font size is also passed along with the event.
uiService.listen("themeChangeV2", function() {
  themeColor = data.themeV2.name;
  themeSize = data.themeV2.size;
  console.log("The user changed his theme color to " + themeColor " and font size to " + themeSize ".");
});

remove()

Unsubscribe a service from an event:

function remove(eventName, handle)

Parameters

Type

Description

eventName

String

The name of the event to unsubscribe from

handle

String

The handle returned by the call to listen

var uiService = SYMPHONY.services.subscribe("ui");

// themeChangeV2 is an event fired by the UI service when the user changes his theme or font. The themeV2 object which contains the theme name and font size is also passed along with the event.
var handle = uiService.listen("themeChangeV2", function() {
  themeColor = data.themeV2.name;
  themeSize = data.themeV2.size;
  // Styling is achieved by specifying the appropriate classes on the app module's body element.
  document.body.className = "symphony-external-app " + themeColor + " " + themeSize;
  console.log("The user changed his theme color to " + themeColor " and font size to " + themeSize ".");
});

uiService.remove("themeChangeV2", handle);

Register and Subscribe

In order to leverage the services provided by the Client Extension API, you must first subscribe to them. To use your applications own services, you must register them via the Client Extension API. Extension apps can register and subscribe to local and remote services in the following ways:

SYMPHONY.services.make()

Creates a new local service and register it using existing classes:

If you are developing an Object-Oriented Application, SYMPHONY.services.make() allows you to use a class as a prototype for implementing service methods, allowing you to choose which methods of the class will be available in the service by specifying them in the implements list.

This cannot be and this cannot be achieved by the SYMPHONY.services.register() function, which is only recommended when creating small services since it does not require any class, and it only requires the serviceName. If you use SYMPHONY.services.register() for large services, you will have to call service.implement() passing an object to it. As a result, all the methods will be public and the code might look unorganized.

SYMPHONY.services.make(name, context, methods, makeEventHandlers)

Parameter

Description

name

The name of the service being created

context

The object instance, usually this

methods

The names of the methods of this object that will be available on the created service

makeEventHandlers

If true, the methods listen and fire will be added to this instance. Calling the listen or fire objects will do so on the service.

class Navigation {
    implements = ['ready', 'select'];
    serviceName = 'sample-navigation';

    register() {
        SYMPHONY.services.make(this.serviceName, this, this.implements, true);
    }

    ready() {
        this.nav = SYMPHONY.services.subscribe('applications-nav');
        this.nav.add('sample', 'My App', this.serviceName)
    }

    select() {
    // do something here
    }
}

var service = new Navigation();
service.register()

SYMPHONY.services.register()

Creates a new local service and register it to be used by a specific application view or your application controller:

SYMPHONY.services.register() is an alternative method for creating a new local service and it is recommended only when creating small services. For Object-Oriented Applications, the use of the SYMPHONY.services.make() is recommended since it uses the class as a prototype for implementing the service methods.

register: function(serviceName)

Parameter

Type

Description

serviceName

String

The name of the service to register

Local services should be namespaced using a string representing the application followed by a colon. For example: hello:controller.

// hello:controller is a service implemented by my application
var helloControllerService = SYMPHONY.services.register("hello:controller");

SYMPHONY.services.subscribe()

Finds a service - either local or remote - that has been registered and returns it. Returns false if the service does not exist.

In order to use a service, it must have been requested by your application during application.register() or application.connect() .

subscribe : function(serviceName)

Parameter

Type

Description

serviceName

String

The name of the service to subscribe to

// modules is a service provided by the Client Extensions API
var modulesService = SYMPHONY.services.subscribe("modules");

SYMPHONY.remote.register()

Takes an existing local service and makes it available remotely. Use this to make services available between multiple application views or between your application view and controller:

register : function(serviceName)

Parameter

Type

Description

serviceName

String

The name of the existing local service to make available remotely

SYMPHONY.remote.subscribe()

Imports a remote service and makes it available locally. Returns a promise which resolves to a reference to a service. This service would now be available in your registry using SYMPHONY.services.subscribe:

subscribe : function(serviceName)

Parameter

Type

Description

serviceName

String

The name of the remote service that you would like to access locally.

Modules Service

A module is a new window inside the Symphony client workspace, such as a chatroom or an instant message. Use the modules service to create application-specific modules.

// To use the modules service, you must subscribe to it from your application
var modulesService = SYMPHONY.services.subscribe("modules");

The following methods are available on the modules service:

  • show

  • hide

  • setTitle

  • focus

  • setHandler

  • openLink

  • redirect

show()

Show a new application module:

function show(id, title, serviceName, iframe, options)

Parameter

Type

Description

id

String

A unique id for this module (must be unique across all modules of a given application)

Either title or {title, icon}

String or Object

Either the title of the module as a string or an object with the keys title and icon

  • The value of title is a string

  • The value of icon is the url of a square SVG image (recommended), or the url of a square png/jpg image. Recommended size is 32x32.

serviceName

String

The name of a local service implemented by your application that will be invoked when a user action is performed relating to this module

iframe

String

The URL for the content of the module (must be an HTTPS URL)

options

Object

An object, which can contain:

  • canFloat: if set to true, a menu item will be added to the More menu (found under the (…) on the module frame) that, when clicked, will pop the module out into its own browser window

  • parentModuleId: if set to the ID of a module opened by an application, the specified module will not be closed when this module is shown

modulesService.show(
  "hello", 
  {title: "Hello World App"}, 
  "hello:controller", 
  "https://localhost:4000/app.html", 
  {
    "canFloat": true
  }
);

hide()

Hide an existing application module:

function hide(id)

Parameter

Type

Description

id

String

The id of the module that should be hidden.

modulesService.hide("hello");

setTitle()

Change the title of an existing application module:

Note that this only changes the title of a specific module, not all titles of all modules created by the application.

function setTitle(id, title)

Parameters

Type

Description

id

String

The id of the module for which the title should be changed

Either title or {title, icon}

String or Object

Either the title of the module as a string or an object with the keys title and icon

  • The value of title is a string

  • The value of icon is the url of a square SVG image (recommended), or the url of a square png/jpg image. Recommended size is 32x32.

modulesService.setTitle("hello", "New Module Title");

focus()

Focus an existing application module:

function focus(id)

Parameter

Type

Description

id

String

The id of the module to focus

modulesService.focus("hello");

openLink()

Opens a link from your application in a new tab in the user's default browser. This method should be used to open links, rather than <a href="..." target="_blank">...</a>.

function openLink(url)

Parameter

Type

Description

url

String

The URL to be opened

// This code will live in your application view.

// Assume there is a button element with id "link" on the application module
// If that button is clicked, open a Google link.

var linkButton = document.getElementById("link");

linkButton.addEventListener("click", function(){
  modulesService.openLink("https://www.google.com");
});

redirect()

Reloads the content of the module at the new URL.

The Client Extensions API is designed for single-page applications. Use this method with multi-page applications to load new content when users navigate to another page:

function redirect(id, url)

Parameter

Type

Description

id

String

The unique identifier for the module. A module with this id must already exist.

url

String

The URL of the new iframe to load in the module.

onSelect : function(symbol) {
        this.modulesService.redirect(this.moduleId, MODULE.baseUrl + 'details?symbol=' + encodeURIComponent(symbol));
    },

Entity Service

Use the entity service to allow your app to render a Structured Object created by the REST API within a message:

var entityService = SYMPHONY.services.subscribe("entity");

The following methods are available on the entity service:

  • registerRenderer

  • render

  • update

  • pause and resume

registerRenderer()

Register a renderer for a type of entity:

function registerRenderer(type, options, serviceName)

Parameter

Type

Description

type

String

The type of entity that will be rendered by your application. Entities are namespaced using reverse domain name notation, e.g. com.symphony.address.

options

Array

Reserved for future use.

serviceName

String

The name of the application service that will be used to render this entity.

You must implement the render() method on the specified application service. This method will be invoked when the associated entity is rendered in the Symphony client.

render()

Renders an entity given its type and data values:

render: function(type, data) {}

Parameter

Type

Description

type

String

The type of entity to be rendered.

data

Object

The data for the specific entity being rendered. This data is specified when the message is created.

The render method returns an object with the following fields:

Parameter

Type

Description

template

String

An ExtensionML string that specifies the object's presentation.

In addition to ExtensionML tags, iframe tags are also supported.

data

Object

An object containing the data referenced by the template. Described in entity advanced templating.

entityInstanceId

String

A unique identifier used to reference a specific entity.

update()

Effectively re-renders an entity with new template and data objects given its entityInstanceId:

update: function(entityInstanceId, template, data) {}

Parameter

Type

Description

entityInstanceId

String

The instance id of the entity to be updated

template

String

The updated ExtensionML string that specifies the object presentation.

data

Object

The data for the entity being updated

Sample Renderer Application

// The application service that will be used to handle entity renderering
const helloControllerService = SYMPHONY.services.register("hello:controller");

const entityService = SYMPHONY.services.subscribe("entity");
entityService.registerRenderer(
  "com.symphony.address",
  {},
  "hello:controller"
);

// Implement the trigger method on your application service
helloControllerService.implement({
  render: (type, data) => {
    const template = "<entity><span>Street Address: <text id='address'/></span><br/><span>City: Palo Alto</span><br/><span>State: California</span><br/><span>Zip Code: 94304</span></entity>"
    entityInstanceId = "0";

    if (type == "com.symphony.address") {
      const newTemplate = "<entity><span>The message is updated</span></entity>";
      // Update the entity after 5 seconds with a new template
      setTimeout(() => {
        entityService.update(entityInstanceId, newTemplate, {});
      }, 5000);

      return {
        template,
        data,
        entityInstanceId
      };
    }
  }
});

pause() and resume()

The 'pause' and 'resume' methods are optional. If you choose to use the methods, implement them on the renderer service. These methods will be invoked when the associated entity is rendered in the Symphony client.

Entities are checked periodically (every two seconds) if they are visible on the screen. If an entity is completely visible, a resume event is triggered to the renderer service of this entity. If an entity is partially visible or completely hidden, a pause event is triggered instead.

Example: • Pause event: responsible for stopping/pausing a video transmission (video iframe). • Resume event: responsible for playing the video.

Note: An entity is considered not visible when scrolling the screen down/up or when changing the module (conversation) to a new chat room or screen.

If the entity has an iframeId, it will be passed in the invocation of the methods, otherwise the entityInstanceId will be used instead.

iFrame Tag Support

In addition to ExtensionML tags, iframe tags are also supported in the template parameter:

helloControllerService.implement({
  render: function(type, data) {
    if (type == "com.symphony.address") {
      return {
        template: '<entity><iframe src="http://your-site.com/iframe-url.html" /></entity>',
        data: {}
      };
    }
  }
});

Entity Advanced Templating

The templateparameter in the render() function of the entity Service is an ExtensionML string used to render entities. To render a static object or an iFrame, you can use advanced templating.

For a full ExtensionML reference, continue here:

Message Format - ExtensionML

Template and Data

You can create a reusable template that leverages the values in the data object for the specific object. When using the data for these attributes, the template uses the id attribute on the tag to specify which member of the data object holds these attributes.

For example, the template and data below could be used to display a link within a Symphony message:

<!-- A <text> primitive must be used to inject 
     text objects from the JSON data into the template -->
<messageml>
  <a id="url"><text id="text"></a>
</messageml>
{
  url: "https://www.symphony.com",
  text: "Symphony website"
}

Flow Control Tags

Use the following flow control tags to support entities that have conditional logic or recursive data:

Tag

Description

<if>

Use this tag to conditionally use the enclosing template. This tag must include an id attribute. If there is data at the key specified by the id, then the enclosing template will be used, otherwise it will be skipped.

<if:last>

Use this tag within an iteration to conditionally use the enclosing template. If the current iteration is the last item in the iterated list, the enclosing template will be used.

<if:not-last>

Use this tag within an iteration to conditionally use the enclosing template. If the current iteration is not last item in the iterated list, the enclosing template will be used. This is useful to add commas between items in a list, without adding one to the last item.

<iterate>

Use this tag to loop through the items in an array. The template between the opening and closing <iterate> tag will be used for each item in the array. The data for the template will reference the data in current the list item. This tag must include an id attribute. This must be the key to an array in the data object.

Interactivity Tags

Use the following tags to have interactivity on messages by implementing methods that are called to execute business logic:

Tag

Description

<action>

Use this tag to enable clicks on entities. For more information on how to use the action tag, refer to Using Actions.

Using Actions

The following steps show examples on how to use actions.

  1. Add the <action> tag to an entity template.

<entity id="survey-voting-template" class="template">
    <card id="card">
        <h3>How did you like today's <text id="type"/> from <text id="venue"/>?</h3>
        <p>
            Please provide feedback by clicking one of the stars below to rate the meal.
        </p>
        <p>
            <action id="onestar"/>
            <action id="twostars"/>
            <action id="threestars"/>
            <action id="fourstars"/>
            <action id="fivestars"/>
        </p>
        <p>
            Voting ends at <text id="end"/>
        </p>
    </card>
</entity>
  1. The data field of the entity must have objects that match the actions ids. For these objects, we can provide an icon, a label and a service name for the action.

 onestar: {
                icon: 'icon_url',
                label: '',
                service: serviceName,
                data: {}
              }
  1. Implement an action method for the service of the entity renderer. This method will be called once the <action> tag is clicked.

action: function(data){
    console.log(data);
        }

Message Format - ExtensionML

ExtensionML is a special form of markup that a front end app can use to perform custom rendering of an entity, instead of relying on Symphony to perform the default presentation.

ExtensionML is generated from a given entity and emitted by a built-in or third-party renderer. It is similar to PresentationML but is used for interactive presentation.

While similar to PresentationML, ExtensionML consists of a template and corresponding data. Each tag in the template can have an ID that references a value stored in the data, binding the data to whatever is being rendered. For example, multiple paragraphs in the template can reference a sentence stored in the data by ID, allowing for reuse of that sentence in multiple places within the template being rendered.

Symphony Elements

Note: ExtensionML does not support Symphony Elements. For more information, refer to Symphony Elements.

Standard HTML Tags

A number of standard HTML tags are supported within templates: b, u, i, strong, br, ul, ol, li, span, div, table, th, tr, and td.

These behave like their HTML counterparts but must be properly-formatted XML. So, for example, rather than <br> you must use <br/>.

Text Tags

The following tags present text in different ways. Most of these require data to specify their content, but some can also use the content between the opening and closing tags.

Tag

Description

Attributes

<formatted>

Adds text formatted with HTML markup. This must be properly formatted XML See here for information on converting HTML to XHTML.

• id (Required): The key of a string within the template data.

<text>

Specifies regular text to be inserted into the entity. This text is inserted as is, without processing any HTML markup.

• id (Optional): The key of a string within the template data. If no id is specified, it uses the contents between the opening and closing tags.

<label>

Inserts a label. Labels are like text tags but are styled differently.

• id (Optional): The key of a string within the template data. If no id is specified, it uses the contents between the opening and closing tags.

<color-text>

Inserts a colored text. Supported colors: red, purple, green, darkGreen, blue, darkBlue, orange, grey, and yellow.

id (Optional): The key of an object with two members: • text specifies the text to be used • color is one of the listed colors.

<pill>

Inserts text with a colored background and rounded corners. Supported colors: red, purple, green, darkGreen, blue, darkBlue, orange, grey, and yellow.

id (Optional): The key of an object with two members: • text specifies the text to be used • color is one of the listed colors.

Extended HTML Tags

The following HTML tags are handled in a slightly modified way:

Tag

Description

Attributes

<a>

Inserts a link.

• id (Optional): The tag must include either an id attribute or an href attribute. If id is specified, it must be a key to a string specifying the URL of the link. If no id attribute is specified, the href attribute is used.

<hr>

Inserts a horizontal line.

​

<icon>

Displays a 16x16 pixel icon.

• id (Required): The key to a text string specifying the URL to the image to display.

<small-icon>

Displays a 13x13 pixel icon.

• id (Required): The key to a text string specifying the URL to the image to display.

<img>

Displays a 128x128 pixel image.

• id (Optional): The tag must include either an id attribute or an src attribute. If id is specified, it must be a key to a string specifying the URL of the link. If no id attribute is specified, the src attribute is used.

<iframe>

Inserts an iframe.

• src (Required): The URL to the iframe. • height (Optional): If not specified, the default height of the iframe will be 50px. The maximum height is 1000px. • width (Optional): If not specified, the default width of the iframe will be 100%. The maximum width is 300px.

Special Entity Tags

Tag

Description

Attributes

<mention>

Insert a mention.

• id (required): The key to an object with the following members: - id: The unique ID of the user being mentioned. - name: The pretty name that is displayed for the mentioned user.

<hashtag>

Inserts a hashtag.

• id (required): The key to a string specifying the hashtag. The string must be prefixed with '#'.

<cashtag>

Inserts a cashtag.

• id (required): The key to a string specifying the cashtag. The string must be prefixed with '$'.

Flow Control Tags

The following flow control tags are used for entities that have conditional logic or data that can be iterated upon:

Tag

Description

Attributes

<if>

Conditionally uses the enclosing template.

• id (required): The key to the data. If there is data at the specified key, the enclosing template is used; otherwise it is skipped.

<if:not-last>

Conditionally uses the enclosing template within an iteration. If the current iteration is not the last item in the iterated list, the enclosing template is used. This is convenient when you want to add commas between list items without adding one after the last item.

​

<if:last>

Conditionally uses the enclosing template within an iteration. If the current iteration is the last item in the iterated list, the enclosing template will be used.

​

<iterate>

Loops through the items in an array. The template between the opening and closing iterate tag is used for each array item. The data for the template references the data in the current list item.

• id (Required): The key to an array in the data object.

The following example shows the XML template for an entity with flow control logic and corresponding data:

<entity>
    <label>Guild: </label><text id="guildName"/>
    <if id="webpageLink">
        <label>Web page: </label>
        <a id="webpageLink"><text id="webpageName"/></a>
    </if>
    <if id="people">
        <iterate id="people">
            <label>Name: </label><text id="name">
            <label>Notes:</label><br/>
            <formatted id="notes"/>
            <if:not-last><hr/></if:not-last>
        </iterate>
    </if>
</entity>
var data = {
    "content" = {
        "guildName": "Loyal Order of Water Buffalo",
        "webpageLink": "https://www.waterbuffalo.net/bedrock",
        "webpageName": "The Loyal Order of Water Buffalo, Bedrock Chapter",
        "people": [{
            "name": "Fred Flintstone",
            "notes": "Yabba Dabba Dooooo!"
        },
        {
            "name": "Barney Rubble",
            "notes": "Fred's sidekick"
        },
        {
            "name": "Dino",
            "notes": "He's kind of like a dog, but also a small sauropod. Yaps a lot.<br/> Really odd, he spoke in his first appearance."
        }]
    }
}

Generating Properly Formatted XML

The following function can be used to turn HTML into properly formatted XML:

function xmlize(html) {
    return new XMLSerializer().serializeToString($('<span>').html(html)[0])
}

Applications-Nav Service

The Applications navigation section is found at the bottom of the left-hand sidebar of the Symphony client workspace. Use the applications-nav service to create a navigation item for your application:

// To use the applications-nav service, you must subscribe to it from your application
var navService = SYMPHONY.services.subscribe("applications-nav");

The following methods are available on the applications-nav service:

  • add

  • remove

  • count

  • rename

  • focus

add()

Add a new navigation item to the Applications section of the left-hand sidebar:

function add(id, title, serviceName)

Parameter

Type

Description

id

String

A unique id for this navigation item (must be unique across all navigation items of a given application)

Either title or {title, icon}

String or Object

Either the title of the left navigation item as a string or an object with the keys title and icon where the value of title is a string and the value of icon is the url of a square SVG (recommended), or the url of a square png/jpg image. Recommended size is 32x32.

serviceName

String

The name of a local service implemented by your application that will be invoked when a user action is performed relating to the application navigation

Note: You must implement the select method on your application service in order to handle clicks on the created left navigation item.

// The application service that will be used to handle left navigation item clicks
var helloControllerService = SYMPHONY.services.register("hello:controller");

navService.add("hello-nav", "Hello World App", "hello:controller");

// Implement the select method on your application service
helloControllerService.implement({
  select: function(id) {
    if (id == "hello-nav") {
      console.log("hello-nav was selected.");
    }
  }
});

remove()

Remove an existing application navigation item:

function remove(id)

Parameter

Type

Description

id

String

The id of the navigation item that should be removed

navService.remove('hello-nav');

count()

Set the badge (notification) count on an application navigation item:

function count(id, count)

Parameter

Type

Description

id

String

The id of the navigation item that should have its count updated

count

Integer

The new badge count number. Specifying 0 will hide the badge count.

navService.count("hello-nav", count);

rename()

Change the title of an existing application navigation item.

Note that this only changes the title of a specific navigation item -- not to all navigation items created by the application:

function rename(id, title)

Parameter

Type

Description

id

String

The id of the navigation item that should be renamed

Either title or {title, icon}

String or Object

Either the title of the left navigation item as a string or an object with the keys title and icon where the value of title is a string and the value of icon is the url of a square SVG (recommended), or the url of a square png/jpg image. Recommended size is 32x32.

navService.rename('hello-nav', 'New Left Nav Title');

focus()

Focus an existing application navigation item:

function focus(id)

Parameter

Type

Description

id

String

The id of the application navigation item to focus

navService.focus("hello-nav");

Share Service

Use the share service to allow users to share content from your application into Symphony conversation:

// To use the share service, you must subscribe to it from your application
var shareService = SYMPHONY.services.subscribe("share");

When the share function is invoked, a modal dialog is launched and populated with the shared object content (for example, the article options). The end user can then select conversations (IMs or chatrooms) into which to share the article.

Once the article is shared, it appears in the conversation view in a card format. The article will be linked either to a webpage (if the href option is provided) or deep linked into the app (if the id option is provided).

In order to view article contents in an application (for example, if the article id is provided), the user must have the application installed.

If the recipient of a shared article does not have the application installed, the user will be prompted to install the application (provided that the user's enterprise has that application enabled).

If the recipient of a shared article does not have the application installed, and the application is not enabled for the user's enterprise, the user can view the content via the link (if href is provided). If a link is not provided, the user will be notified that the article cannot be viewed because the application is disabled for the enterprise.

The following methods are available on the share service:

share()

Launches the "Share on Symphony" modal from your application, allowing the user to share content from your application into a Symphony conversation (IM or chatroom):

function share(type, content, options)

Parameter

Type

Required

Description

type

String

Yes

The type of content that is being shared.

content

Object

Yes

An object that describes the content being shared. For a list of objects see standard entities.

options

Object

No

An object that describes options that can be used to enhance the share service

The following JavaScript shows an example of an article being shared:

// This code will live in your application view.

// Assume there is a button element with id "share" on the application module
// If that button is clicked, launch the Share modal.

var shareButton = document.getElementById("share");

var articleContent = {
  title: "Symphony Launches Mobile App",
  subTitle: "Application is mobile device management (MDM) compatible.",
  blurb: "Symphony Communication Services, a Palo Alto, Calif.-based messaging startup, announced its enterprise-ready mobile app for Apple iPhone is now available for download.",
  date : new Date("07 June 2016").getTime() / 1000,
  publisher: "Waters Technology",
  author: "Dan DeFrancesco",
  id: "symphony-article",
  thumbnail: 'https://symphony.com/example/image.png',
  href: 'https://symphony.com'
};

var shareOptions = {
  prepopulateUsers: ['71811853190920', '71811853190903']
};

// Launch Symphony's share modal when the Share button is clicked
shareButton.addEventListener("click", function(){
  shareService.share(
    "article",
    articleContent,
    shareOptions
  );
});

The following table shows the article content:

Field

Required

Format

Description

title

Yes

String

The headline of the article

subTitle

No

String

The subtitle of the article

blurb

No

String

A summary of the article to display

date

No

Unix Epoch Timestamp

Date of publication

publisher

No

String

Name of the publisher

author

No

String

Name of the author

thumbnail

No

URL (could be a data url)

Image to be displayed - 106px-106px

id

Must provide either id or href, or both

String

An identifier used by the application to deeplink to the article

href

Must provide either id or href, or both

URL

URL to the article (opened in a new browser window)

The following table shows the share options:

Field

Required

Format

Description

prepopulateUsers

No

Array of strings

The users (UserIds) who will be listed initially as recipients in the share modal.

Available only for authenticated apps, and only for Client 2.0.

It is recommended to limit the number of pre-populated users so the Symphony end user can easily review the list of recipients before sharing.

Sharing Third Party Content

The share function can also be used to share custom, third-party entity types. In this case, the data parameter must be populated with the following fields:

Field

Description

inputAutofill

Use this to fill the comment field in the share dialog to provide initial text. Cash tags and hash tags that are specified in the text will be converted to the correct entity.

plaintext

The markdown representation of the entity, supporting a limited set of markdown features. The value of this field will be displayed on mobile devices and other older clients.

presentationML

The default presentation of the entity using presentationML. This will be seen by everybody who does not have an app with a custom renderer for the given type.

entityJSON

The object being shared.

format

The format of the message being sent. This must be set to "com.symphony.messageml.v2".

The following JavaScript shows an example of a custom third party entity being shared:

share : function(gameNbr, time)
{
    var fullTime = time;
    var hours = Math.floor(time / 60 / 60 / 1000);
    time -= hours * 60 * 60 * 1000;
    var minutes = Math.floor(time / 60 / 1000);
    time -= minutes * 60 * 1000;
    var seconds = Math.floor(time / 1000);
    var duration = hours.toString() + ':' + minutes.toString().pad(2, '0', 'left') + ':' + seconds.toString().pad(2, '0', 'left');

    var title = 'Somebody you know won at Mah Jongg Solitaire';
    var blurb = 'try to beat their time of ' + duration;
    var date = new Date().getTime() / 1000;
    var thumbnail = this.thumb;
    var id = JSON.stringify({gameNbr: gameNbr, time: fullTime});

    var presentationML =`
        <entity>
            <table><tr>
                <td><img src="${thumbnail}" /></td>
                <td>
                    <h1>${title}</h1>
                    ${blurb}
                </td>
            </tr></table>
        </entity>`;

    var entityJSON = {
        date: date,
        thumbnail: thumbnail,
        results: id,
        time : time,
        gameNbr : gameNbr,
    };

    var data = {
        plaintext: `*${title}*\n${blurb}\n`,
        presentationML : presentationML,
        entityJSON: entityJSON,
        entity: {},
        format: 'com.symphony.messageml.v2',
        inputAutofill : 'I ROCK!',
    }
    this.shareService.share('com.symfuny.invite.won', data);
}

In this example, the following modal dialog is launched and populated with the shared object content:

handleLink()

You must specify your own application service for handling clicks on shared articles using handleLink if you use the id field for deep linking articles into your application.

You must implement the link method on your application service in order to handle clicks on shared articles in conversations.

// This code will live in your application controller.

// The application service that will be used to handle clicks on shared articles
var helloControllerService = SYMPHONY.services.register("hello:controller");

// Assume you have registered your application with the Symphony client and subscribed to the Share service.

shareService.handleLink("article", "hello:controller");

helloControllerService.implement({
    // You only need to implement this function if you intend to deeplink articles into your app by specifying an id for the article. If you use href, then article links will open in a new browser window.
  link: function(type, articleId) {
    if(type == "article") {
      // Implement this
      // For example, you might launch a new application module with a url that includes the articleId in the query parameters
      console.log("Article with id: " + articleId + " was clicked.");
    }    
  }
});

Commerce Service

Apps can offer premium functionality through licensed subscriptions. Use the commerce service to identify the products (premium versions) to which a user is subscribed:

// To use the commerce service, you must subscribe to it from your application
var commerceService = SYMPHONY.services.subscribe("commerce");

getProducts()

Returns the list of products to which the user is subscribed for your app:

function getProducts(serviceName)

Parameters

Type

Description

serviceName (optional)

String

The name of a local application-implemented service. If passed, the productUpdate event will be fired on that service if the user's product subscriptions change.

This method returns a promise that will be fulfilled with the array of products the user is subscribed to for your app. For each product, the following is returned:

{ 
  name: "<name>", 
  type: "premium", 
  sku: "<sku>", 
  subscribed: true/false
}

"Premium" is the term used for paid subscription products, while "Standard" represents a freemium app. The name and SKU will be values specified by the application developer when implementing a premium version of their app.

commerceService.getProducts('hello:controller').then(function(products) {
  console.log(products);
});

productUpdate

This event is fired when the user's product subscriptions are changed.

Use the listen method on the service specified in getProducts() to subscribe to this event and specify a callback that will be executed when the event is fired. The callback should change the contents/features of your application to match the user's updated product subscriptions.

Dialogs Service

Use the dialogs service to create modal windows (e.g. to open a modal window from a button registered at a room level).

The following methods are available on the dialogs service:

  • show

  • rerender

  • hide

The following picture is an example of what you will be able to create with this service - this module will overlay onto the entire Symphony client window:

show()

Presents a modal dialog to the user:

function show(id, serviceName, template, data, options)

Parameter

Type

Description

id

String

A unique id for the dialog.

serviceName

String

The name of a local application-implemented service implemented.

template

String

The extensionML for the dialog content.

data

String

The data for the extensionML.

options

Object

The data for the extensionML

    const dialogsService = SYMPHONY.services.subscribe("dialogs");
    dialogsService.show(
        "my-dialog",
        "hello:controller",
        `<dialog>
            <div class="container">
                <div class="header">
                    <h1>Configuration</h1>
                    <br/>
                    <div class="headerError">                              
                        <text id="title"/>
                    </div>
                    <p class="value">Please check if the public and private
                    key files match and if they are correctly configured in 
                    Jira's application link section.</p>
                </div>
            </div>
        </dialog>`,
        "undefined",
        {
            title: "Application Configuration"
        }
    );

rerender()

Changes the contents of the dialog. This is usually invoked when the user has performed some action:

function rerender(id, template, data)

Parameter

Type

Description

id

String

The id of the dialog that should be updated.

template

String

The new extensionML content to display.

data

String

The data for the extensionML.

close()

function close(id)

Parameters

Type

Description

id

String

The id of the dialog to close.

UI Service

Use the ui service to extend various parts of the Symphony client user interface. For example, add buttons on IM (1-1 chat) and chatroom modules or add links to the #hashtag and $cashtag hovercards:

// To use the ui service, you must subscribe to it from your application
var uiService = SYMPHONY.services.subscribe("ui");

Extension apps can receive stream participant information when an end user clicks on a button added by the app. For more information, refer to Receiving Conversation and User Data.

The following methods are available on the ui service:

  • openIMbyStreamID

  • openIMbyUserIDs

  • registerExtension

  • unregisterExtension

The following events are fired by the ui service:

  • themeChangeV2

openIMbyStreamID()

Open an existing conversation in a new module.

Released in version 20.10.

function openIMbyStreamID(streamID, messageId)

Parameter

Type

Possible Values

Description

streamID

String

The stream ID or conversation ID to be opened.

messageID

String

Either a messageID, or the null value

The messageId can be used in addition to the streamId to focus on a specific message of the conversation. Use "null" as parameter value to jump to the latest message of the conversation.

openIMbyUserIDs()

Open a conversation with one or more users in a new module.

Released in version 20.10.

function openIMbyUserIDs(userIds)

Parameter

Type

Possible Values

Description

userIds

String[]

Array of userIds.

registerExtension()

Add an action button to the Symphony user interface.

Action buttons are added to various places in the UI, such as in the header of chat modules, in #hashtag or $cashtag hovercards, on the profile of users and more.

function registerExtension(uiClass, id, serviceName, options)

Parameter

Type

Description

uiClass

String

The location within the Symphony application where the action button should be placed. Possible values: - single-user-im : Button added to the header of 1-1 chats - multi-user-im : Button added to the header of group chats - room : Button added to the header of chatrooms - hashtag : Link added to the hovercard that appears when hovering over a hashtag (e.g. #symphony) - cashtag : Link added to the hovercard that appears when hovering over a cashtag (e.g. $GOOG) - settings : Link added to detail card of the application in the Marketplace - profile : Link added to the user profile page and profile hovercard

id

String

A unique identifier for this extension (can be used to unregister).

serviceName

String

The name of a local service implemented by your application that will be invoked when a user clicks on your action button.

options

Object

An object, containing:

  • icon: the url of an image that will be displayed on the action button. Recommended format is a square SVG.

  • label: a label associated with the action button.

  • data: an opaque block of data that will be passed along with the trigger event

trigger()

You must implement the trigger method on your application service in order to handle clicks on the registered action buttons:

// The application service that will be used to handle clicks on UI extensions
var helloControllerService = SYMPHONY.services.register("hello:controller");
// The application service that will handle the filter on UI extensions
var helloFilterService = SYMPHONY.services.register("hello:filter");

// Displays a button in the header of 1-1 chats
uiService.registerExtension(
  "single-user-im", 
  "hello-im", 
  "hello:controller", 
  {
    label: "IM Button", 
    data: {"datetime": Date()}
  }
);

// Implement the trigger method on your application service
helloControllerService.implement({
  trigger: function(uiClass, id, payload, data) {
    if (uiClass == "single-user-im") {
      console.log('IM button was clicked on ' + data.datetime + '.');
    }

unregisterExtension()

Remove a previously registered action button.

This will remove all instances of a particular extension - for example, from all single chat modules or all #hashtag and $cashtag hovercards.

function unregisterExtension(uiClass, id)

Parameter

Type

Possible Values

Description

uiClass

String

  • single-user-im

  • multi-user-im

  • room

  • hashtag

  • cashtag

  • settings

The location within the Symphony application where the action button was registered.

id

String

The id of the UI extension that should be removed.

uiService.unregisterExtension('single-user-im', 'hello-im');

themeChangeV2 event

This event is fired when the user's font size or theme is changed.

Use the listen method on this service to subscribe to this event and specify a callback that will be executed when the event is fired. The callback should change the styling of your application to match the user's new theme.

var uiService = SYMPHONY.services.subscribe("ui");

uiService.listen("themeChangeV2", function() {
  themeColor = data.themeV2.name;
  themeSize = data.themeV2.size;
  // Styling is achieved by specifying the appropriate classes on the app module's body element.
  document.body.className = "symphony-external-app " + themeColor + " " + themeSize;
});

Receiving Conversation and User Information

Symphony’s Extension API allows apps to extend the Symphony client user interface by adding buttons on the IM, MIM, profile, and chatroom modules. This capability can be used to build apps that act upon the room and user identity details, such as a click-to-call integration.

Prerequisites

  • Your app must be an authenticated Extension App.

How this works

Extension apps can receive stream participant information when an end user clicks on a button added by the app.

Your button will receive information from the user object in a MIM, IM and a room of up to 20 users.

Please note that the current user’s information isn’t returned, only the information of the other user(s) in the profile of a user, an IM, MIM or room.

Sample Objects

This is the information that you will receive if your button is pressed inside of an IM or on a users Profile:

{
   threadId,         //id of the conversation. Also known as streamId or conversationId
   userCount,        //number of users returned
   isCrossPod,       //if cross pod, returns true
   user :  {         //user information
        id,             //user identifier
        emailAddress,   //user email
        username,       //user name
          displayName,    //user display name
          firstName,      //user first name
          lastName,       //user last name
        phone,          //user phone number
        mobile,         //user mobile phone number
    }
}

You must implement the trigger() method on your application service in order to handle clicks on the registered extensions. This is a sample trigger method that will allow you to receive a user's phone number and email address as an authenticated extension app:

// The application service that willbe used to handle clicks on UI extensions
var helloControllerService = SYMPHONY.services.register("hello:controller");

// Displays a button on 1-1 instant messages
uiService.registerExtension(
  "single-user-im", 
  "hello-im", 
  "hello:controller", 
  {
    label: "IM Button", 
    data: {"datetime": Date()}
  }
);

// Implement the trigger method on your application service
helloControllerService.implement({
  trigger: function(uiClass, id, payload, data) {
    if (uiClass == "single-user-im") {
      console.log('IM button was clicked on ' + data.datetime + '.');
      // This acquires the user's phone number from the payload
      var userPhone = payload.user.phone; 
      // You can do this for any field in the prior section, such as emailAddress 
      var userEmail = payload.user.emailAddress;
      // You can now pass the user's phone number and email to your system. 
    }
  }
});

This is the information that you will receive if your button is pressed inside of a MIM or a room:

This is the information that you will receive if your button is pressed inside of a MIM or a room with less than 20 users. If there are more than 20 users, the users list will be returned empty.

{
   isCopyDisabled,   //if copy is disabled in the room returns true
   isWriteAllowed,   //if the user can send a message in the room, returns true
   isCrossPod,       //if it is a cross pod room, returns true
   roomName,         //room name
   threadId,         //id of the conversation. Also known as streamId or conversationId
   userCount,        //number of users returned
   users : [ {       //users information
       id,              //user id
       isCrossPodUser,  //if this is a cross pod user, returns true
       isOwner,         //if the user is owner of the room, returns true
       emailAddress,    //user email
       username,        //user name
       displayName,     //user display name
       firstName,       //user first name
       lastName,        //user last name
       phone,           //user phone number
       mobile,          //user mobile phone number
    }]
}
{
    isCopyDisabled,
    isWriteAllowed,
    isCrossPod,
    roomName, 
    threadId, 
    userCount
}

Filter Function

You can add a new method to the service that is handling button clicks, called filter(), on any UI extension that you are implementing. Before a button is shown, that method is passed the uiClass, the id, and the payload. If filter() returns false, the button is not shown. If the method is unimplemented or it returns any value other than false, the button is shown.

The filter function returns the same data returned by the ui Service here. All data except for the the user's phone number is returned in cases where you are using an authenticated app. The user phone number is only returned for 1x1 IMs and User Profiles.

Based on the information returned, you can choose to selectively display the button. For example, you can display the button only if a user's phone number is present, or if a user is not a cross-pod user.

// Implement the filter function on your application service
helloFilterService.implement(
   filter: function (type, id, data) {
        return !!(data.user && data.user.phone);
    }
  }
});