Content Picker

Oracle Content and Experience Cloud (OCE) supports two mechanisms for integration so users can browse and select content and assets to bring into OCE.

The content picker for a content connector can be either the common content picker or a custom one:

  • The common content picker is provided by OCE.

    With the generic common picker, OCE provides a basic framework and capabilities to build content browsing and selection. This works seamlessly in conjunction with the Connector Framework SDK and the APIs defined.

  • The custom picker needs to be built by the content connector and can be built using any JS technology.

    The custom picker is typically used in cases where the content connector builds its own experience for accessing content in the remote store. Some stores have their own native pickers, which the content connector could reuse for integrating with the asset repository; for example, Google Drive, Microsoft OneDrive, and Dropbox. Additionally, the content connector can develop its own picker UI following the predefined interfaces and callback mechanisms prescribed by OCE.

Use the Common UI

If the content connector uses the common picker, then it needs to define pickerType in the eserver implementation:

intradoc.connectorcommon.server.ServerResource implementation

serverInfo.pickerType = PickerType.COMMON;

The content connector also needs to implement the intradoc.connectorcommon.server.FilesystemResource interface. The implementation needs to adhere to following guidelines in its filesystem REST implementation:

  1. The content connector must append "fFolderGUID:" in uri, parentUri for each folder in the response of fileSystem.

  2. A few fields are mandatory for every folder and file to be set in FileSystemResource for the common UI to work without any issues: uri, parentUri, and name. If parentUri is not applicable, then it can be set to fFolderGUID:null.

  3. You must know the size of the result set being returned up front; that is, totalItemsCount needs to be set.

Use a Custom UI

A content connector can implement a custom UI for its picker. This can be built using any JS technology. However, it needs to invoke some predefined methods in OCE to obtain connector configuration and to pass back selections. The custom picker can be built to expose its own OK and Cancel buttons, in which case it needs to invoke the appropriate handlers. If the picker doesn't expose its own OK and Cancel buttons, OCE will provide this.

The pickerType needs to be defined as CUSTOM in the server implementation:

intradoc.connectorcommon.server.ServerResource implementation

serverInfo.pickerType = PickerType.CUSTOM;

The custom implementation needs to include the following JS file in its library:

oracle-oce-custompicker.js

/*global window:true*/
(function() {
  'use strict';
 
  var name = window.name; // name set on iframe element to uniquely identify the instance
  var receiver = window.opener || window.parent;
  var origin = "*";
  function _postMessage(msg) {
    msg.name = name;
    receiver.postMessage(msg, origin);
  }
 
  var namespace = "OCE"; //todo: allow passing in data attribute
  if (!window[namespace]) {
    window[namespace] = {};
  }
  var OCE = window[namespace];
 
  if (!OCE.CustomPicker) {
 
    OCE.CustomPicker = {
 
      selection: [],
 
      addItem: function(id, name, type, size) {
        var item = {id: id, name: name, type: type, size: size};
        this.selection.push(item);
        this.onChange();
      },
 
      removeItem: function(id) {
        this.selection = this.selection.filter(function(item) {
          return item.id !== id;
        });
        this.onChange();
      },
 
      onInit: function(cbInit) {
        var msg = {
          message: 'init',
          needAuthToken: true
        };
        _postMessage(msg);
        this.messageListener = this.onPostMessage.bind(this);
        window.addEventListener('message', this.messageListener, false);
        this.cbInit = cbInit;
      },
 
      onClose: function() {
        window.removeEventListener('message', this.messageListener, false);
      },
 
      onPostMessage: function(event) {
        if (event.data && event.data.message === "init") {
          if (this.cbInit) {
            this.cbInit(event.data);
          }
        }
      },
 
      onChange: function() {
        var msg = {
          message: 'change',
          selection: this.selection
        };
        _postMessage(msg);
      },
 
      onOk: function(selection) {
        selection = selection || this.selection;
        var msg = {
          message: 'ok',
          selection: this.selection
        };
        _postMessage(msg);
      },
 
      onCancel: function() {
        var msg = {
          message: 'cancel'
        };
        _postMessage(msg);
      }
    };
  }
 
})();

This JS file needs to be packaged in a content connector.

This library follows the JS postMessaging paradigm to pass information. The following methods are of interest.

onInit

The custom picker needs to invoke this method during its initialization. This is where the custom picker can get connector configuration information, like client ID and access token. The attributes defined in the connector configuration (/rest/api/v1/server) are passed via this method.

OCE.CustomPicker.onInit(function(data) {
    {
        if (data != null) {
            self.clientId = data.ClientID;
 
            //If connector uses OAuth
            self.AccessToken = data.AccessToken;
             
            //If connector uses BASIC auth
            self.user = data.UserName;
            self.password = Base64.decode(data.UserPwd);
    }
 
        //Use client id and access token to fetch data from back end.
    }
})

onOk

If the custom picker exposes its own OK button, then it needs to invoke this method to pass back the event to OCE.

function pickerCallback(data) {
  if (data[google.picker.Response.ACTION] === google.picker.Action.PICKED) {
    data[google.picker.Response.DOCUMENTS].forEach(function(doc) {
      OCE.CustomPicker.addItem(doc.id, doc.name, "file", doc.sizeBytes);
    });
    OCE.CustomPicker.onOk();
  }
  else if (data[google.picker.Response.ACTION] === google.picker.Action.CANCEL) {
    OCE.CustomPicker.onCancel();
  }
}

onCancel

If the custom picker exposes its own Cancel button, then it needs to invoke this method to pass back the event to OCE, like the onOk method does for the OK button in the preceding snippet.

addItem

This method needs to be invoked to pass back selections from the custom picker to OCE so that it displays the list of selected items in the Add to repository dialog. The IDs passed here are then used to fetch content with /rest/api/v1/content while adding an item to the asset repository.

addImage(selectedImages: Image[]) {
    selectedImages.forEach(o => {
        var name = "PexelsImages_" + o.uri;
        OCE.CustomPicker.addItem(o.uri, name, o.thumbnail, o.size);
    });
}

removeItem

This method needs to be invoked when an item is unselected from a custom picker so that the list maintained by OCE is up to date. The final list is shown in the Add to repository dialog. The ID passed here is the same as the ID passed in the addItem call.
removeImage(image: Image) {
    OCE.CustomPicker.removeItem(image);
}

Package the custom picker in the connector. While registering the content connector, specify the following values:

  1. Custom Picker URL: Such as http://host:port/pexels-picker/web (This is the custom picker packaged in the content connector.)

  2. Custom Picker uses its own OK/Cancel buttons: Leave it unchecked. (This indicates that you want OCE to embed your picker in their dialog.)

    If the custom picker implements its own OK and Cancel buttons, then check this.