Configuration in RESTApps

Page content

config/

RESTApp configuration files are stored in the config folder.

  • src/
    • config/
      • index.html
      • index.js (since 5.0)
      • config.js
      • config.css

Configuration is retrieved in a RESTApp server side context through the appData-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
(() => {
   const 
      router               = require('router'),
      portletContextUtil   = require('PortletContextUtil'),
      properties           = require('Properties'),
      appInfo              = require('appInfo');

   router.get('/', (req, res) => {
      const 
         currentUserEmail = properties.get(portletContextUtil.getCurrentUser(), 'mail'),
         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
(() => {
   const 
      router    = require('router'),
      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 id="fontSelection" name="font" class="form-control">
		<% _.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.

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/index.js#h-Routing)
  i18n           = require('i18n'), // [example](/docs/webapps/i18n)

  appInfo        = require('appInfo'), // since 4.5.3 [example](/docs/webapps/require/appinfo)
  storage        = require('storage'), // since 5.0 
  
  myServerModule = require('/module/server/nameOfServerModule'); // [example](/docs/webapps/module)

index.html

index.html defines your RESTApp configuration. index.html is stored in the /config folder.

If an index.js (available since 5.0) file is present index.html will be rendered as an underscore template.
If there is no index.js file index.html will be rendered as plain html.

Below is an example of a basic index.html.

<div class="panel panel-default">
   <div class="panel-heading">
      <h3 class="panel-title">RESTApp Configuration</h3>
   </div>

   <div class="panel-body">
      <div class="form-group">
         <input class="form-control" placeholder="Select Page" 
         data-component="page-selector" name="page">
      </div>

      <div class="form-group">
         <label>Text</label>
         <input class="form-control" name="text">
      </div>
   </div>
</div>

Checkbox boolean

For checkboxes, use the data attribute data-value-type="boolean" to make it return a true or false value.

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.

Node selectors

In order to utilize SiteVision node selectors, 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">

// metadata-selector
<select data-component="metadata-selector" name="metadata"></select>

// template-selector
<select data-component="template-selector" name="template"></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>

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>

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">

Adding SiteVision components dynamically [@since 4.5.2]

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');
   });
});

A sv:loaded jQuery-event will be triggered for <select>-based components (template/metadata-selector) when the component has fetched its data (since 4.5.3).

HTML Components

Regular HTML elements may also be used to accept data from the user.

AppData

Configuration is accessed server side using appData.

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.

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;
}   

SiteVision node types

Refer to the node types documentation to see what properties are available for different node types. Values retrieved from appData.get() are JavaScript compatible.

  • PropertyType.DATE returns a timestamp
  • PropertyType.WEAKREFERENCE returns an ID

Config Example App

A WebApp demonstrating configuration is available in SiteVision's GitHub repository.