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:

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
ISOstringproperty.
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 component | Contexts | |
|---|---|---|
| Content Activity | LIST | CONTENT-ACTIVITY |
| Content Workflow | LIST | CONTENT-WORKFLOW |
| Search Dropdown | LIST | SEARCH-DROPDOWN |
| Full Search | CARD | SEARCH-VIEW |
| Recent Content | LIST | RECENT-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
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
}
}
};
}


