Content presentation

There are several places in the gui, besides the main content editor, where content is presented and it is possible to control how the content is displayed at those places. For example:

examples content presentation

To construct the data model for the presentation, the content developer components first fetches the content in the aceUISearch variant and look for the property contentCard in the result which contains configuration for one or more contexts. For example the Content Activity component constructs its data model from the contexts 'LIST' and 'CONTENT-ACTIVITY' resulting in a contextual data model that is used to display the content.

It is possible to customize the appearance of content of a specific type in the aceUISearch variant composer, gui components will look for the property contentCard in the resulting data and use it as the foundation when constructing its data model.

Example:

function compose (content) {

  // This is a composer for a content representing an image
  var image = content.aspects.image;

  var contentCard = {

    // 'label' is a context property, it is typically placed
    // in a prime position in the view. Since it is here defined
    // in the root level of the object it is considered to
    // belong to the root context and will always be present.
    label: image.title,

    // 'thumbnail' is a context property that references an
    // image that can be used to make a thumbnail image of
    // content.
    thumbnail: {
      alias: content.system.id
    },

    // 'configurations' can only be defined in the root of
    // this object and contains a list of contextual configurations.
    // The contexts CARD and LIST will add the 'abstract' field to
    // the result data.
    configurations: [{
      contexts: ['CARD', 'LIST'],
      fields: {
        // 'abstract' is a context property that implies some
        // sort of summary of the content.
        abstract: {
          value: image.description,
          // Fields may have properties, the 'rows' property
          // of 'abstract' suggests that no more than two rows
          // of text is sufficient to display this field.
          rows: 2
        }
      }
    }, {
      // Contexts may target specific components of the gui.
      // The Content Activity component of Content Developer
      // will always get data from the context CONTENT-ACTIVITY.
      contexts: ['CONTENT-ACTIVITY'],
      fields: {
        datetime: content.system.modificationTime
      }
    }]
  };

  return {
    cacheControl: CacheControl,
    aspects: {
      aceUISearchEntry: {
        contentCard: contentCard
      }
    }
  };
}

The contextual data model

UI components can fetch data and extract a contextual data model from it using zero or more contexts. The context configurations are merged together into a compiled contextual data model, consisting of some predefined fields. If a field is not set it wont be displayed in the gui, however, gui components have the ability to override and add to the resulting contextual data model if they please.

Example of a complete contextual data model result where all fields has been set:

{
  alias: '<string:alias>',
  contentType: {
    value: '<string:contentType>',
    label: '<string>'
  },
  thumbnail: {
    alias: '<string:alias>',
    url: '<string:url>'
  },
  label: {
    value: '<string>'
  },
  abstract: {
    value: '<string>'
  },
  datetime: {
    ISOstring: '<string>',
    value: '<Date>'
  },
  classifiers: [
    {
      className: '<string>',
      value: ['<string>']
    }
  ],
  tags: {
    value: ['<string>']
  }
}

Most fields follow the pattern { <key>: { value: 'grit value' } }, see below, but it is often possible to use a short-hand syntax like { <key>: 'grit value' } when configuring contexts:

{
  alias: '<string:alias>',
  contentType: '<string>',     // ! -> contentType: { label: '<string>' }
  thumbnail: '<string:alias>', // ! -> thumbnail: { alias: '<string>' }
  label: '<string>',
  abstract: '<string>',
  datetime: '<string | Date>',
  classifiers: '<Array>',     // ! no short-hand for classifiers
  tags: '<Array>'
}

Field by field reference

Most fields follow the pattern of an object with a 'value' property that is the displayed value in the gui.

alias: string

The alias field exists in the compiled end context, it is an alias as a string for the content represented. Specifying this field in any other context has no effect.

abstract: { value: string, rows: number }

Comprises some essential parts of the content in a brief manner. The rows property suggests it is ok to display a truncated part of the value.

classifiers: [ { className: string, value: [ string... ], showClassName: boolean } ]

Create named groups of data to be displayed in the gui. This is the way to inject custom fields to the view, each class is treated as a cohesive unit of information, and each item in value is considered to belong to its class. If the showClassName is true (defaults to false) the className is to be displayed in the GUI.

contentType: { value: string, label: string }

Conveys the contentType of the content represented, setting the value wont have any effect in the end context. The label property represents the display value of the contentType, setting the label suggests that it should be displayed in the gui.

datetime: { value: Date, label: string, ISOstring: string, shortDateFormat: boolean }

Associate an important date and time to the entry. The emphasis of this field is highly context dependent. Only one of the value / ISOstring properties needs to be set. If both are specified, the value will be overwritten by the date that ISOstring represents. Setting the shortDateFormat to true communicates that the datetime may displayed in a shorter format. If the label property is present, its value will be used as a label for the date when displayed as a card.

If the configuration is going to be serialized, e.g. written in an ACE variant composer run server side, it is serialized into json which has no support for the javascript Date object and therefore it is recommended to always use the ISOstring property.

label: { value: string, rows: number }

The display name of the content. It is the significant field of an entry and will be displayed in a highlighted position of the entry in the gui. The rows property suggests that the value can be truncated to a certain degree before displaying it.

tags: [ string... ]

A list of tags to be displayed in conjunction with the content.

thumbnail: { alias: string, url: string, aspectRatio: string, height: Number, width: Number, alt: string }

A thumbnail is a small image representation of the content. 'alias' is used to fetch the image from the Ace Image Service and 'url' uses the url value to get the image. The 'url' property takes precedence over the 'alias' property. The properties 'aspectRatio', 'width' and 'height' can be provided to suggest the appearance of the thumbnail in the gui. The value of 'alt' is the alternative text displayed if the image cannot be displayed for some reason.

Contexts used by Content Developer components

List of components and the contexts they use to get the view model.

Contexts are merged from right to left with the most specific context to the right.

GUI componentContexts
Content ActivityLISTCONTENT-ACTIVITY
Content WorkflowLISTCONTENT-WORKFLOW
Search DropdownLISTSEARCH-DROPDOWN
Full SearchCARDSEARCH-VIEW
Recent ContentLISTRECENT-CONTENT

Customize the appearance of context fields in Content Developer

Although the gui components are in full control of the placement of different fields when displaying them in the gui, it is possible to control the appearance of the individual fields by context.

data addition html structured custom field with styles
Add to the data

Add to the data

The most basic form of customization is to add information to the data model. For example to display the content type as a tag in the Content Activity component:

// This example is utilizing the article content type of Ace Starter Kit

// Example of adding a 'tag'
function compose (content) {
  var typeLabel = 'articleContent';
  var label = content.aspects.article.title;
  var thumbnail = content.aspects.article.imageRef;
  var abstract = content.aspects.article.lead;
  var datetime = content.system.modificationTime;
  var contentCard = {
    label: {
      value: label
    },
    thumbnail: {
      alias: thumbnail
    },
    configurations: [{
      contexts: ['CONTENT-ACTIVITY'],
      fields: {
        abstract: {
          value: abstract,
          rows: 1
        },
        datetime: {
          ISOstring: datetime
        },
        // Here we add the content type as a tag
        tags: [typeLabel]
      }
    }]
  };

  return {
    cacheControl: CacheControl,
    aspects: {
      aceUISearchEntry: {
        contentCard: contentCard
      }
    }
  };
}

Customizing existing field appearance

Almost all fields allows for basic html formatting in its values, making it possible to customize the appearance of fields being displayed in the gui. For example:

// This example is utilizing the article content type of Ace Starter Kit

// Example of adding a 'type badge' in front of the label.  The Content
// Developer comes with bootstrap styles by default so we take advantage
// of that
function compose (content) {
  var typeLabel = 'Article';
  var label = content.aspects.article.title;
  var thumbnail = content.aspects.article.imageRef;
  var abstract = content.aspects.article.lead;
  var datetime = content.system.modificationTime;
  var contentCard = {
    label: {
      value: label
    },
    thumbnail: {
      alias: thumbnail
    },
    configurations: [{
      contexts: ['CONTENT-ACTIVITY'],
      fields: {
        // This label overwrites the label in the root context...
        label: {
          value: '<span class="badge badge-primary">' + typeLabel + '</span> ' + label,
          rows: 1
        },
        abstract: {
          value: abstract,
          rows: 1
        },
        datetime: {
          ISOstring: datetime
        }
      }
    }]
  };

  return {
    cacheControl: CacheControl,
    aspects: {
      aceUISearchEntry: {
        contentCard: contentCard
      }
    }
  };
}

Adding custom fields with styles

It is even possible to provide css to further control the display of the context in the gui:

// This example is utilizing the article content type of Ace Starter Kit

var categorizationUtil = require ('categorization');

function compose (content) {
  var typeLabel = 'Article',
   label = content.aspects.article.title,
   thumbnail = content.aspects.article.imageRef,
   abstract = content.aspects.article.lead,
   datetime = content.system.modificationTime,
   categories = categorizationUtil.getEntityNames (content.aspects.aceCategorization || { categorization: {} });
   articleTypes = categories.filter (function (category) {
    return (category === 'news report' || category === 'editorial' || category === 'column');
  });

  var contentCard = {
    label: {
      value: label
    },
    thumbnail: {
      alias: thumbnail
    }
    configurations: [{
      contexts: ['CONTENT-ACTIVITY'],
      fields: {
        // Note that css is added 'globally' so care must be taken
        // not to overwrite existing rules
        style: {
          '.article-type': {
            'background-color': 'green',
            'color': 'white',
            'font-weight': 'bolder'
          },
          '.favorite-tag': {
            'background-color': 'lightblue',
            'border': '1px dotted black',
            'border-radius': '5px'
          },
          '.favorite-tag .heart': {
            'color': 'red',
            'font-size': '18px'
          }
        },
        classifiers: [{
          // the field will have the className automagically added as a class
          // attribute to the outputted html element for this field
          className: 'article-type',
          value: articleTypes
        }, {
          className: 'favorite-tag',
          value: ['I <i class="material-icons heart">favorite</i> Ace']
        }],
        label: {
          rows: 1
        },
        abstract: {
          value: abstract,
          rows: 1
        },
        datetime: {
          ISOstring: datetime
        }
      }
    }]
  };

  return {
    cacheControl: CacheControl,
    aspects: {
      aceUISearchEntry: {
        contentCard: contentCard
      }
    }
  };
}