System Admin


Application Manager App

Table of Contents


The Application Manager App was designed to reduce the number of calls to the server to load apps on a page. By listing all apps used on the page in the Application Manager App, multiple calls can be reduced to a single call.

The Application Manager App includes a list of all apps running on the page (usually a Fund Page template). The script for the Application Manager app is embedded on the page, and then looks for embeds or divs on that page that reference the listed apps, thus reducing request calls back and forth for configuration, and improving speed and performance. This also means easier maintenance of apps when a new version of a particular app is released, as it can be updated globally by updating the version number referenced by the Application Manager app.

Add a new App

Click on the Studio tab, then click + to add a new application.

Studio Wizard

  1. Click Next to start the Studio Wizard.
  2. Provide a name and description for your app. Once these items have been filled, the Next button will become active. Click Next.
  1. Use the dropdown arrow to select a template to base your application on. Enter a few letters of the application name to make the search easier.
  2. Select Kurtosys App Manager (latest version), then click Next.
  1. A Parent Client Configuration is not required for the Application Manager App, click Next.
  2. The token (each client instance has a unique identifier) will be added automatically, click Next.
  1. On the Summary page, click Finish.


The Application Manager app will need some additional configuration. It is easiest to start with a JSON structure already added. 

Click the Configuration tab in your newly created app to begin.

There is no preset configuration for the Application Manager app which means that all configuration must be done manually. 

Either using the UI, or by copying and pasting a js file into the configuration JS <> tab.

Adding a JSON file:

Copy and paste the file below into the Configuration | JSON <> tab

  "appVersions": {
    "ksys-app-attestation": "v2.2.0",
    "ksys-app-commentary": "v1.5.0",
    "ksys-app-page-header": "v1.4.0"
  "appsExternalScriptOptions": {
    "defer": false
  "appsRenderOptons": {
    "groups": [
        "apps": [
            "templateId": "ksys-app-page-header"
        "key": "aboveFold"
  "appsRequestOptons": {
    "culture": "default"
  "core": {
    "skeletonLoaders": {
      "loaders": [] //this will not set up an actual loader but indicates the position where loader details will be placed

Using the UI:

  1. If you have skipped the Wizard, add in your client instance token to replace “USE YOUR OWN TOKEN HERE”.
  2. Click Save.

  1. Click Add Element +.

  1. Check the checkboxes for the elements to include.
    • App Versions: this allows you to select the apps to be referenced by the Application Manager. This is a mandatory selection.
    • Apps External Script Options: how the apps should load; one at a time or wait for all to be available
    • Apps Render Options: if any apps should load before others
    • Apps Request Options: whether or not to combine the returned json
    • Core: this section can be used to set up skeleton loaders or loading icons to display while waiting for a page to render
    • Culture: option to set a default culture to use in case one is not available
    • Data: how the data is fetched


  1. Click Save.

  1. Click App Versions.
  1. Click Add Element+.
  2. Check the checkboxes next to the Apps for the Application Manager to list.
  3. Click Save.
  1. Add version numbers to each of the apps you have selected.
Note: There is no dropdown list available for the app version numbers. These must be typed in manually with a lowercase v as a prefix.
  1. Click Save.
  2. Add a comment, then click Confirm.
  1. Click Apps External Script Options.
  2. Click Add Element+.
  1. Check the checkbox next to Defer.
  2. Click Save.
  3. Check defer to set it to true or leave it unchecked for false. If set to true then the apps will wait to load all at once.
  4. Click Save.
  5. Add a comment, then click Confirm.


Above Fold Grouping

  1. Click Apps Render Options.
  2. Click + Create Groups*.
  1. Click Add Row+.
  2. Click 1. No label.
  1. Type in a Key* – this will be aboveFold for the group of apps to load first.
  2. Click + Create Apps*.
  3. Click Apps*.
  1. Click 1. No Label. Type in the template name of an app to be included in the primary group of apps to display on the web page (up to the point where you would begin scrolling to see more of the page).
Note: You can click Configuration in the navigation pane, then the JSON <> icon to see the app template names.
  1. Type in the Template Id*.
  2. Click Add Element+ to add additional apps to the group.
  3. Click Save.
  4. Type in a comment, then click Confirm.
Note: There is no dropdown list of app names available, so make sure you type the app template ID names correctly.

Skeleton Loaders

Note: Each listed app needs its own loader icon added. It is therefore easiest to add a json file for the loaders which can then be copied and pasted as many times as necessary and adapted for the particular app. Adding via the UI is a much slower process.
  1. Click Core.
  2. Click Add Element+.
  1. Check the checkbox for Skeleton Loaders.
  2. Click Skeleton Loaders.
  3. Click Save.
  1. Click Add Element+.
  2. Check the checkbox next to Loaders.
  3. Click Save.
  1. Click Loaders.
  2. Click Add Row+.
  1. Click 1.No Label.
  2. Type in an app template id next to Id*.
  3. Click Add Element+.
  1. Check the checkbox next to Breakpoints.
  2. Click Save.
  3. Click Breakpoints.
  1. Click Add Row+.
  2. Click 1. No Label.
  1. Click Add Element+.
  2. Check the checkbox for Children.
  3. Click Save.
  1. Click Children.
  2. Click Add Row+.
  1. Click 1. No Label.
  2. Click Add Element+.
  1. Click Select All.
  2. Click Save.
  3. Complete details for all fields.
  4. Click Save.
Note: The Label should match the Commentary Type in the Data table.
  1. Type a comment, then click Confirm.
  2. Repeat this process for each app.


  1. Locate your Fund page template in WordPress.
  2. Click Edit with Elementor.

Adding a widget for the Application Manager App

  1. Drag a JS Html Widget into the appropriate section on the page.

The first JS widget will be used for the Application Manager app script, and for defining the variables related to the different parts of the URL indicating location, country, language, investor type (more or less parts depending on the site).

In the Kurtosys App | Studio | Application Manager app:

  1. Click the embed icon <> in the right pane to view the script and div information for the app.

  1. Copy just the https information inside the script src.

  1. Paste this into the JS Files section of the JS Html widget.

  1. In the Raw Javascript section of the widget you will need to add your java to define the URL sections, this will be something along the lines of the example below, dependent on how the site’s sub-sites and posts are set up according to domains, country, country code, language, investor type, etc.
var domain = null;
var country = null;
var language = null;
var investor = null; 

var locationMatch = window.location.pathname.match(/\/(countryA|countryB|countryC)\/([a-z]{2,6})\/([a-z]{2})\/(investortypeA|investortypeB|investortypeC)/);

//prod url
if(locationMatch !== null) {
    domain = locationMatch[1];
    country = locationMatch[2];
    language = locationMatch[3];
    investor = locationMatch[4]; 
	var domainMapping = {
      'countryA': 'com',
      'countryB': '2LetterCountrycodeB',
      'countryC': '2LetterCountrycodeC'
	domain = domainMapping[domain];
//live url
else {
	var liveMatch = window.location.pathname.match(/\/([a-z]{2,6})\/([a-z]{2})\/(investortypeA|investortypeB|investortypeC)/);
	if(liveMatch !== null) {
		country = liveMatch[1];
		language = liveMatch[2];
		investor = liveMatch[3];
		domain =\.(com|2LetterCountrycodeB|2LetterCountrycodeC)/)[1];

var cultureCountry = 'GB'; //for example Great Britain 2 letter code and 2 letter language code below - en 
switch (language) {
 case 'en': 
  cultureCountry = 'GB'; 
  cultureCountry = language.toUpperCase();
window['__ksysGlobalVariables__'] = {
 culture: language + "-" + cultureCountry,
 entity: {
  fundCode: window['data_fundcode'],
  fundList: window['data_fundlist'],
  isin: window['data_isin'],
  seoFriendlyShareClassName: window['data_seofriendlyshareclassname']
 investorType: investor,
 locale: {
  country: country,
  language: language,
 siteLocale: window['data_sitelocale']

function checkSections() {
    // Skip if we are in the admin side of things
    if ('elementor') > -1) {
    function canSkipNoDataCheck(app) {
        const templateId = app.getAttribute("data-ksys-app-template-id");
        const styleKey = app.getAttribute("data-style-key");
        const skips = [
                templateId: ["ksys-app-commentary"],
                styleKey: ["sectionTitle"]
        for (let i = 0; i  -1 && skip.styleKey.indexOf(styleKey) > -1) {
                return true;
        return false;
    const mappings = [
            "key": "performance",
            "key": "risk-statistics",
            "key": "portfolio"
            "key": "fees"
            "key": "documents"
    for (let i = 0; i < mappings.length; i++) {
        const mapping = mappings[i];
        const selector = ".section-" + mapping.key;
        const sections = document.querySelectorAll(selector);
        if (sections) {
            for (let sectionIndex = 0; sectionIndex < sections.length; sectionIndex++) {
                const section = sections[sectionIndex];
                const checkSectionHidden = section.getAttribute('data-check-complete');
                if (checkSectionHidden !== "true" || true) {
                    const appSelector = "[data-ksys-app-template-id]";
                    const apps = section.querySelectorAll(appSelector);
                    let totalApps = 0;
                    let appsWithNoData = 0;
                    for (let appIndex = 0; appIndex < apps.length; appIndex++) {
                        const app = apps[appIndex];
                        const skipNoDataCheck = canSkipNoDataCheck(app);
                        if (skipNoDataCheck) {
                        const initializedAttr = app.getAttribute("data-initialized");
                        const isInitialized = initializedAttr === "true";
                        if (isInitialized) {
                            const hasChildren = app.hasChildNodes();
                            if (!hasChildren) {
                            else {
                                const appStyle = window.getComputedStyle(app, null);
                                if (appStyle && appStyle.height === "0px") {
                    if (!mapping.hide) {
                        mapping.hide = [];
                    mapping.hide.push(totalApps === appsWithNoData);
            let shouldHide = false;
            if (mapping.hide) {
                shouldHide = true;
                for (let hideIndex = 0; hideIndex < mapping.hide.length; hideIndex++) {
                    shouldHide = mapping.hide[hideIndex] && shouldHide;
                    if (!shouldHide) {
                if (shouldHide) {
                    for (let sectionIndex = 0; sectionIndex < sections.length; sectionIndex++) {
                        const section = sections[sectionIndex];
                        const parentNavSection = jQuery(section).closest('.js-sub-nav-section');
                        if (parentNavSection) {
                            const grandParent = parentNavSection.context.parentElement;
                        const links = document.querySelectorAll('a[href="#' + mapping.key + '"');
                        for (let linkIndex = 0; linkIndex < links.length; linkIndex++) {
                            const link = links[linkIndex];
                            const linkParent = link.parentElement;
                            const bar = linkParent.parentElement;

jQuery(document).ready(function () {
    document.removeEventListener("ksys-apps-loaded", checkSections);
    document.addEventListener("ksys-apps-loaded", checkSections);
  1. In the Disable deferring execution section of the widget, add the data for the apps that will be used on this page. For example, a culture and an ISIN will need to be defined, the data that is defined here is based on the name of the variables in the Raw Javascript section above. This will look something along the lines of the example below.
< div >
< div data-ksys-app-template-id="ksys-app-manager"
>< /div >
   < div
                >< /div >
< /div >
//note: spaces have been added for readability
  1. After adding the above for the Application Manager app, add additional JS Html widgets for the apps to be used on the page.

Adding a widget for a Commentary App


  1. Drag a JS Html widget into the applicable section of the page.

In Kurtosys App | Studio | Commentary app (as an example)

  1. Open the applicable app and click the embed <> icon in the right pane.

  1. Copy the entire div section including the start and end brackets, then paste this into the Disable deferring execution section in the widget.

Note: The data-theme-key, data-input-culture and data-input-isin will all have been defined in the Application Manager widget Disable deferring execution section so they can be deleted for the additional apps added to the page.

Continue adding additional widgets as needed for the page, and copying and pasting the div sections for those widgets.