Configuration in WebApps
Page content
config/
WebApp configuration files are stored in the config folder. To set up a global configuration for your WebApp, add a folder named global and include the files you need.
- src/
- config/
- index.html
- index.js (since 5.0)
- config.js
- config.css
- global/ (since 5.2)
- index.html
- index.js
- config.js
- config.css
- config/
Configuration is retrieved in a WebApp server side context through the appData-object. Global configuration is retrieved through the globalAppData-object.
index.js [@since 5.0]
index.js enables route configuration and template rendering with a context. The concept is very similar to the app's regular index.js. Given that, Sitevision's Public API can be accessed, while browser objects cannot. A requester is available in the config's client context to fetch data client side.
Rendering index.html with a context
App configuration is rendered from the root route ('/'). Data passed to the render function on the response
object will be available as context when index.html is rendered. It will be evaluated, just like any other WebApp template, as an underscore template. Note that index.html is the only template that will be rendered, regular WebApp components are not available in the configuration view.
If no index.js is present it will be rendered as is.
Below is an example of how one might get data from Sitevision's Public API and expose it to index.html.
// index.js
(function() {
const router = require('router');
const portletContextUtil = require('PortletContextUtil');
const properties = require('Properties');
const appInfo = require('appInfo');
router.get('/', (req, res) => {
const currentUserEmail = properties.get(portletContextUtil.getCurrentUser(), 'mail');
const appName = appInfo.appName;
res.render({
currentUserEmail: currentUserEmail,
appName: appName
});
});
})();
// index.html
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Configure <%- appName %></h3>
</div>
<div class="panel-body">
<div class="form-group">
<label>Send reports to</label>
<input class="form-control" type="email" value="<%- currentUserEmail %>">
</div>
</div>
</div>
Below is another example of how to utilize Requester to fetch data from an external API and make it available in the configuration.
// config/index.js
(function() {
const router = require('router');
const requester = require('Requester');
router.get('/', (req, res) => {
requester
.get('https://jsonplaceholder.typicode.com/posts')
.done(data => res.render({ posts: data }));
});
})();
// config/index.html
<div class="form-group">
<label>Font</label>
<select>
<% _.each(posts, function(post) { %>
<option value="<%- post.id %>">
<%- post.title %>
</option>
<% }) %>
</select>
</div>
Response object (res)
The response object provides the following methods in the configuration view.
res.render(data)
Renders the index.html of the configuration. The data will be the context when the template is rendered.
res.send(data)
Default data type is json. For other cases dataType must be explicitly set in the request.
Request object (req)
The request object is identical to the request object in the app's regular index.js.
Require
Objects available server-side via the require function. Note that only server modules are available.
// Server context, e.g. config/index.js
var
_ = require('underscore'), // [example](https://underscorejs.org/)
router = require('router'), // [example](/docs/webapps/webapps-1/index.js#h-Routing)
i18n = require('i18n'), // [example](/docs/webapps/webapps-1/i18n)
appInfo = require('appInfo'), // since 4.5.3 [example](/docs/webapps/webapps-1/require/appinfo)
storage = require('storage'), // since 5.0
appData = require('appData'), // since 5.2 [example](/docs/webapps/webapps-1/configuration/appdata)
globalAppData = require('globalAppData'), // since 5.2 [example](/docs/webapps/webapps-1/configuration/appdata)
appResource = require('appResource'), // since 5.2 [example](/docs/webapps/webapps-1/resource)
privileged = require('privileged'), // since 7.0 [example](/docs/webapps/webapps-1/require/privileged)
myServerModule = require('/module/server/nameOfServerModule'); // [example](/docs/webapps/module)
index.html
WebApp configuration is defined in index.html.
If an index.js file is present, index.html will be rendered server side as an underscore template. If there is no index.js, it will be rendered as is.
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">WebApp Configuration</h3>
</div>
<div class="panel-body">
<div class="form-group">
<input class="form-control" data-component="page-selector" name="page">
</div>
<div class="form-group">
<label>Text</label>
<input class="form-control" type="text" name="text">
</div>
</div>
</div>
Toggle content [@since 6.1]
Content can be toggled based on checkbox/radio button state by using data-enables="<selector>"
.
// Radio
<div class="form-group">
<input type="radio" id="color1" name="color" value="red">
<label for="color1">Red</label>
<input type="radio" data-enables=".container-radio" id="color2" name="color" value="green">
<label for="color2">Green</label>
</div>
<div class="container-radio">
Show me if "Green" is selected
</div>
// Checkbox
<div class="form-group">
<input type="checkbox" data-enables=".container-check" id="check" name="useCaptions" data-value-type="boolean">
<label for="check">Use captions</label>
</div>
<div class="container-check">
Show me if "Use captions" is checked
</div>
Checkbox boolean
For checkboxes you can use the data attribute data-value-type="boolean"
to make it return true
or false
.
Sitevision components
Sitevision offers "native" components to select values from the Sitevision model. Values are retrieved using the appData-object in a server side script context.
In order to utilize Sitevision components, simply add data-component="<type>"
to an input/select element. The following types are supported.
// page-selector
<input class="form-control" data-component="page-selector" name="page">
// file-selector
<input class="form-control" data-component="file-selector" name="file">
// image-selector
<input class="form-control" data-component="image-selector" name="image">
// user-selector [@since 4.5.3]
<input class="form-control" data-component="user-selector" name="user">
// content-node-selector [@since 4.5.3]
<input class="form-control" data-component="content-node-selector" name="content">
// tags-selector [@since 6.2]
<input class="form-control" data-component="tags-selector" name="tags">
// link-selector [@since 9.1]
<input class="form-control" data-component="link-selector" name="link">
// number spinner [@since 6.2]
<input class="form-control" data-component="number-spinner" data-min="0" data-max="10" data-step="2" name="count">
// metadata-selector
<select data-component="metadata-selector" name="metadata"></select>
// template-selector
<select data-component="template-selector" name="template"></select>
// oauth2-configuration-selector [@since 7.0]
<select data-component="oauth2-configuration-selector" name="oauth2-configuration"></select>
// virtual-group-selector [@since 5.0]
<select data-component="virtual-group-selector" name="virtual-group"></select>
// search-index-selector [@since 5.0]
<select data-component="search-index-selector" name="search-index"></select>
// font-selector [@since 5.1]
<select data-component="font-selector" name="font"></select>
// color-selector [@since 5.1]
<select data-component="color-selector" name="color"></select>
// custom-selector [@since 9.1]
<select data-component="custom-selector" name="custom"></select>
Options
Options are passed to node selectors as data-attributes.
Attribute | Description | Since |
---|---|---|
data-removable | Makes it possible to clear a selected value | 4.5.3 |
<input class="form-control" data-removable data-component="page-selector" name="page">
<select data-removable data-component="template-selector" name="template"></select>
Types
Apply data-types
to filter what types should be selectable. The following components accept data-types
.
metadata selector [@since 7.0]
// Apply comma separated if multiple
<select
data-types="sv:metadataUserDefinition,sv:metadataMultipleDefinition"
data-component="metadata-selector"
name="meta"></select>
Available types
sv:metadataDateDefinition
sv:metadataUserDefinition
sv:metadataDirectoryDefinition
sv:metadataTextDefinition
sv:metadataSingleDefinition
sv:metadataMultipleDefinition
sv:metadataSystemLinkDefinition
sv:metadataSystemIntegerDefinition
sv:metadataSystemTextDefinition
sv:metadataSystemDefinition
sv:metadataLinkDefinition
sv:metadataTextPortletDefinition
sv:metadataImagePortletDefinition
sv:metadataKeywordDefinition
sv:metadataRelatedInformationDefinition
sv:metadataMediaPortletDefinition
sv:metadataSingleTagDefinition
sv:metadataMultipleTagDefinition
page selector [@since 7.0]
// Apply comma separated if multiple
<input
data-types="sv:page,sv:sitePage"
data-component="page-selector"
name="page">
Available types
sv:sitePage
sv:page
sv:article
sv:archive
sv:folder
sv:link
sv:structurePage
sv:structureFolder
sv:structureLink
sv:collaborationGroupPage
sv:collaborationGroupFolder
template selector [@since 10.1]
// Only single value allowed
<select
data-types="page"
data-component="template-selector"
name="template"></select>
Available types
page
group
template
List components
In order to utilize Sitevision list components, simply add data-component="<type>-list"
to a hidden input element.
List component values are retrieved in a server side script context using the appData.getArray-
method.
The following types are supported.
// page-list [@since 4.5.3]
<input type="hidden" data-component="page-list" name="pages">
// file-list [@since 4.5.3]
<input type="hidden" data-component="file-list" name="files">
// image-list [@since 4.5.3]
<input type="hidden" data-component="image-list" name="images">
// user-list [@since 4.5.3]
<input type="hidden" data-component="user-list" name="users">
// userfield-list [@since 9.0.1]
<input type="hidden" data-component="userfield-list" name="userfields">
// template-list [@since 10.1]
<input type="hidden" data-component="template-list" name="templates">
Sorting [@since 9.1]
Apply data-sortable
to allow custom sorting of a list component.
<input type="hidden" data-component="page-list" name="pages" data-sortable>
Types
Apply data-types
to filter what types should be selectable. The following components accept data-types
.
page-list selector [@since 7.0]
// Apply comma separated if multiple
<input
type="hidden"
data-types="sv:page,sv:sitePage"
data-component="page-list"
name="pages">
Available types
sv:sitePage
sv:page
sv:article
sv:archive
sv:folder
sv:link
sv:structurePage
sv:structureFolder
sv:structureLink
sv:collaborationGroupPage
sv:collaborationGroupFolder
file-list selector [@since 7.0]
// Apply comma separated if multiple
<input
type="hidden"
data-types="sv:file"
data-component="file-list"
name="files">
Available types
sv:file
sv:folder
image-list selector [@since 7.0]
// Apply comma separated if multiple
<input
type="hidden"
data-types="sv:image"
data-component="image-list"
name="images">
Available types
sv:image
sv:folder
template-list selector [@since 10.1]
// Only single value allowed
<input
type="hidden"
data-types="page"
data-component="template-list"
name="templates">
Available types
page
group
template
Custom selector [@since 9.1]
Select replacement for custom options.
// Add data-searchable to allow searching in options
<select
name="custom"
data-component="custom-selector"
data-searchable></select>
Events
Adding Sitevision components dynamically
Sitevision components may be initialized dynamically by triggering 'setup-component' on the body
with a selector targeting the component to initialize. See the following example:
//config.js
$(function() {
$('#addComponentButton').on('click', function() {
var el =
'<div class="form-group">' +
'<label>Page</label>' +
'<input id="myCustomId" class="form-control" data-component="page-selector" name="myCustomName">' +
'</div>';
$('.panel-body').append($(el));
$('body').trigger('setup-component', '#myCustomId');
});
});
Configuration initialization [@since 6.2]
When the configuration is loaded (values are set and components are initialized) an 'initialized'
event will be triggered on the <html>
element.
// config.js
(function() {
document.documentElement.addEventListener('initialized', () => console.log('ready!'));
}());
A 'sv:loaded'
jQuery-event will also be triggered for <select>
-based Sitevision components when the component has fetched its data.
HTML Components
Regular HTML elements may also be used to accept data from the user.
AppData
Configuration is accessed server side using appData.
Global AppData [@since 5.2]
Configuration that is shared among all instances of a WebApp is accessed server side using globalAppData.
i18n
The i18n function is available when rendering if the index.html file is evaluated as an underscore template, i.e. when an index.js file is present.
The app's default language bundles will be used.
// config/index.html
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title"><%= i18n('settings') %></h3>
</div>
<div class="panel-body">
<div class="form-group">
<label><%= i18n('pickStartPage') %></label>
<input class="form-control" data-component="page-selector" name="page">
</div>
</div>
</div>
// i18n/en.json
{
"settings": "Settings",
"pickStartPage": "Select a start page"
}
The i18n function is also available server side in index.js (and server modules).
var
i18n = require('i18n'),
localizedName,
...
localizedName = i18n.get('name');
...
config.js
In config.js, custom client JavaScript may be added, that will be executed in the configuration panel. It is also possible to overwrite default functions (validate
, setValues
and getValues
).
Validate
By default, elements with the required
attribute are validated. To add custom validation, overwrite the default validation function.
(function() {
// overwrite default validate function
window.validate = function() {
var emailInput = document.querySelector('input[name=email]');
return isValidEmail(emailInput.value);
};
}());
setValues
setValues
populates elements with data when configuration is loaded. To handle custom components this function should be overridden.
(function($) {
// populate inputs when configuration is loaded
window.setValues = function(values) {
var inputs = document.querySelectorAll('input');
inputs.forEach(function(input) {
var name = input.name;
if (name) {
var value = values && values[name],
$input = $(input);
$input.val(value);
$input.trigger('change');
}
});
};
}(jQuery));
getValues
getValues
retrieves values from elements that will be sent to the server. To handle custom components this function should be overridden.
(function($) {
// retrieve values that will be sent to the server
window.getValues = function() {
var values = {},
inputs = document.querySelectorAll('input');
inputs.forEach(function(input) {
var name = input.name;
if (name) {
var inputValue = input.value;
values[name] = inputValue;
}
});
return values;
};
}(jQuery));
Client requester [@since 5.0]
A client requester is available on the window object in the config's client context (i.e. config/config.js). Utilize the requester to perform requests to routes specified in config/index.js.
The requester is similar to the client requester available in the WebApp SDK. What differs is that instead of specifying a url, a route is specified.
Default response data type is json. For other cases dataType must be explicitly set in the request.
Below is an example of how to call a route ('/test') defined in config/index.js from the config's client context.
// config/index.js
router.get('/test', (req, res) => {
res.json({
value: 'Hello from /test'
});
});
// config/config.js
$(function () {
$('button').on('click', function () {
requester.doGet({
route: '/test',
data: {
value: $('[data-value]').val()
}
}).done(function (res) {
$('#fetched-data').text(res.value);
});
});
});
config.css
Add custom CSS for the configuration panel.
// index.html
<div class="form-group">
<label>Text</label>
<input class="form-control amazing-class" name="text">
</div>
// config.css
.amazing-class {
color: blue;
}
Config Example App
A WebApp demonstrating configuration is available in Sitevision's GitHub repository.