NAV
Javascript

Templates Documentation

Nudge Engagement Templates enables AB Tasty’s users to enrich their testing or personalisation campaigns with your service.

From chats to social media tools, through to newsletter forms or anything else you come up with!

What is a Template?

A Template is a small package (NPM) that runs on any website to quickly and easily add features with non-technical knowledge requirements. Templates can be created by a wide range of users: agencies partnering with AB Tasty, the open-source community, Saas companies, AB Tasty CSMs, AB Tasty clients… and you!

Quick Start

First of all, install the CLI package to be able to build your template by typing into your terminal:

npm install -g @abtasty/widget-cli
widget new

GUIDE

- Create a Template

Javascript file

1. Overview

An AB Tasty template requires a unique JavaScript file that will be injected into the client’s website. The JavaScript file’s location must be specified explicitly in the package.json, in the main field, as shown below:

"main": "main.js"

You can easily code directly into a single file. To get the latest JavaScript features, we recommend using a bundler like rollup.js or webpack in combination with a transpiler like bublé or babel. Please note that the template generated by the AB Tasty Widget CLI uses rollup.js and babel out of the box. In this case, the bundled file will probably be generated in a folder such as /dist or /build.

You will then need to modify the location of your main file in your package.json as follows:

"main": "dist/main.js"

2. Ressources

Globals variables

The following variables are global and can be used anywhere in your javascript file:

Name Description
PACKAGE The name of your package
DATA All the options from the configuration form of the template
TEST_ID The id of the test the template is currently running. Works only in production, in developpment the value is always 1.

Tracking events

Below how the javasScript function will looks like:

ABTastyEvent('Name of your event', null, TEST_ID)

You can track events with the ABTastyEvent function.

Here an example of how it will be displayed in our reporting:

Widget Utils

Widgets Utils is a library containing a package of useful functions, applicable to the Templates.

You find it here: https://www.npmjs.com/package/@abtasty/widget-utils

Configuration form

1. Overview

The configuration form allows the end user of your template to customize it easily, even without any technical knowledge. The form file’s location must be specified explicitly in the package.json in the form field, as follows:

"form": "dist/form.js"

2. How to use it

Templates forms are an array of components. A component is a simple plain object that represents an input or an option for your Template. If you have created your Template with the Widget CLI, you can edit the form.js directly in the src folder (otherwise you will have to create one). To get the data from your form to your javascript file, add/edit the propName property in your form components.

Below an example of a text input:

export default [
  {
    type: 'text',
    category: 'content',
    label: 'Message :',
    propName: 'message',
    placeholder: 'Enter a message'
  },
]

You will find the DATA.message variable in your Javascript. You can view all the available components in the Components Summary.

3. Component categories

Below an example of the radioImage component in the Layout category and the inputText component in the Content category:

export default [
  {
    type: 'radioImage',
    category: 'layout',
    label: 'Select a layout',
    value: 'center',
    propName: 'layout',
    options: [
        { label: 'Center', value: 'center', src: 'http://img.com/center.jpg' },
        { label: 'Left', value: 'left', src: 'http://img.com/left.jpg' },
        { label: 'Right', value: 'right', src: 'http://img.com/right.jpg' }
    ],
  },
  {
    type: 'text',
    category: 'content',
    label: 'Message :',
    propName: 'message',
    placeholder: 'Enter a message'
  },
]

Each component has to be in a category, each category representing a tab within the configuration form. The configuration component will then be displayed within each of these tabs. 4 categories are currently available: * Layout: The component will modify the inner/outer disposal of the Template * Content: The component will modify the text of the Template (the title or text or a button for example) or add/edit some content related elements (a button for example). * Styles: The component will impact the design of the Template. * Conditions: The component will affect the trigger events or tracking options of the Template.

4. Condition management

In the configuration form, you can show or hide a component (if a component is present or a value is active) by adding a conditions property.

Below an example of the Select component. Components are shown only if there is another component with an "animals" propName AND another component with a "videogames" propName:

export default [
  {
    type: "select",
    label: "Which one ?",
    placeholder: "Panda",
    propName: "animal",
    conditions: [
      { field: "animals" },
      { field: "videogames" },
    ],
    options: [{ label: "Cat", value: 1 }, { label: "Dog", value: 2 }]
  },
]

Below an example of the Select component. Components are shown only if there is another component with a "videogames" propName that has "cod" value:

export default [
  {
   type: "select",
   label: "Which one?",
   placeholder: "Panda",
   propName: "animal",
   conditions: [
     { field: "videogames", value: "cod" },
   ],
   options: [{ label: "Cat", value: 1 }, { label: "Dog", value: 2 }],
 },
]

5. Translation

Below an example of the component with the label translated into french and english:

export default [
  {
   category: "conditions",
   propName: "wysiwyg",
   type: "wysiwyg",
   value: "<strong>BOLD</strong> <i>italic</i>",
   label: {
     fr: "FR wysiwyg",
     en: "EN wysiwyg",
   },
 }
]

You can add translation to label, value and placeholder. To add a translation, create an object with at least 2 properties. Please use these keys:

Best practices

While developing your new and awesome Template, make sure to follow these guidelines to streamline your code:

How to avoid CSS conflicts between the website and your Template?

Bad practice:

<div class='tooltip'>
    <div class='content'>
        <ul class='list'>
            <li class='list-item'></li>
            <li class='list-item'></li>
        </ul>
    </div>
</div>

Good practice, prefix your class with a namespace

<div class='abtasty-tooltip'>
    <div class='abtasty-tooltip__content'>
        <ul class='abtasty-tooltip__list'>
            <li class='abtasty-tooltip__list-item'></li>
            <li class='abtasty-tooltip__list-item'></li>
        </ul>
    </div>
</div>

Best practice, use custom tags:

<tooltip>
    <tooltip-content>
        <ul class='abtasty-tooltip__list'>
            <li class='abtasty-tooltip__list-item'></li>
            <li class='abtasty-tooltip__list-item'></li>
        </ul>
    </tooltip-content>
</tooltip>

Since your Template could be injected into any type of website, your Template will inherit from the CSS of this website, which can break the styling of your Template. To prevent this from happening, we recommend following these rules:

Keep your Template size small

Your Template can be added on any webpage on any website. A heavy Template may slow the loading of the webpage down. To do that, please try to: Use as few as dependencies as possible, especially the heavy ones like jQuery: http://youmightnotneedjquery.com/. Instead install the Widget utils package (https://www.npmjs.com/package/@abtasty/widget-utils) that contains small utility functions for your Template. Make the libraries that support the module field your first choice, then use ES6 modules and import the functions you use (instead of the entire library). The module bundler Rollup.js will take the module field by default to take advantage of this (https://rollupjs.org/#tree-shaking).

Avoid adding events on window

When a user adds a widget on his website through the AB Tasty Editor, the configuration form has a built-in live reload that automatically resets the body of the page and re-injects the widget. The body is reset, but the window is still the same, so your events linked to window will be piled up each time the user changes an option in your Template form. One way of preventing this from happening is to check if a given event is already linked to window before adding it. If so, simply remove it. You can do this by storing your event names and listeners in a global array.

Use automated unit testing to test your Template

In order for your new Template to be stable and secure, we recommend implementing unit tests as soon as it is bootstrapped. We recommend using Jest.

- Widget Workflow

2 branches by default: master and prerelease.

Branch master is always protected.

master is where you can publish releases version like npm version patch.

prerelease is where you can publish prereleases like npm version prerelease.

Your working branch name must start by ticket ID like this BD-5633-Problem-CSS or SQ4-636-Improve-countdown.

- QA your Template

With widget CLI

The Widget CLI allows you to test your Template before rolling it out in production. Install it by entering npm install -g @abtasty/widget-cli.

Then, to test your Template, simply use this command from the root of your Template folder: widget serve

An interface will then pop up on your screen, allowing you to test your Template with different configurations. Here are some examples of configuration options: * Url (indicate which website you want to test your Template on). * User-agent/resolution (responsive mode). * Configure the form on the left hand side to check the wysiwyg configuration options.

What it looks like:

Insert image

Configuration form preview

Enables you to preview the rendering of the configuration form you have built. This configuration form is a simple JavaScript object.

Please check out the configuration form documentation for more details about its creation.

A “Dev tools” button enables you to track errors within your configuration form to help with debugging. Clicking it will open a separate console related exclusively to the configuration form.

The “webpage” view

Finally, the webpage view on the right-hand side loads the URL of your choice (AB Tasty’s corporate website by default) and injects your Template onto the page. It takes into account the fields of the configuration form that are visible on the left-hand side.

The “Live reload” option is enabled by default, meaning that the view will be re-loaded automatically each time a change is made to the configuration form.

Similarly to the configuration form view, you can access a “Dev tools” button, which opens a separate console to debug interactions between the Template and the website once your Template is injected. This enables you to debug the code of your Template in a production-like environment.

With local framework

In your machine:

1. Create vhosts

  <VirtualHost *:80>
    DocumentRoot "/Applications/XAMPP/htdocs/web/abtasty/widgets/"
    ServerName local.widgets.abtasty.com
    ErrorLog "/Applications/XAMPP/logs/widgets.abtasty.com-error.log"
    CustomLog "/Applications/XAMPP/logs/widgets.abtasty.com-access.log" combined
    <Directory "/Applications/XAMPP/htdocs/web/abtasty/widgets/">
        Options Indexes FollowSymLinks Includes execCGI
        AllowOverride All
        Require all granted
    </Directory>
  </VirtualHost>

cd /Applications/XAMMP/etc/extra

nano httpd-vhosts.conf

code httpd-vhosts.conf

2. Add hosts

sudo nano /etc/hosts

sudo code /etc/hosts

127.0.0.1 local.widgets.abtasty.com

In your local framework:

// Replace this snippet code
const path = {
  prod: `https://widgets.abtasty.com/${pack}@${version}?main=main`,
  local: 'https://localhost:1212/dist/main.js',
};

const url = pack !== 'test' ? path.prod : path.local;
// by this snippet code
const localPack = pack.replace('@abtasty/', '');
const path = {
  prod: `https://widgets.abtasty.com/${pack}@${version}?main=main`,
  local: `http://local.widgets.abtasty.com/${localPack}/dist/main.js`,
};

const url = path.local;

npm run build:watch -- --env.identifier=YOUR_IDENTIFIER

In your browser:

IMPORTANT:

Folder name must be same as NPM project name

Example: stress-test folder name for @abtasty/social-proof NPM project name will not good

With Preprod

To test a widget on Preprod, merge your branch into the branch prerelease, then do a ‘prerelease’ version:

npm version prerelease

Then, npm publish.

- Publishing your Template

To submit your Template to AB Tasty and make it available to the AB Tasty customer base, please follow the steps below:

  1. First, you’ll need to have your Template on NPM:
    • Create a minified bundle with npm run build
    • Bump the version of your Template (using semver) with npm version [patch|minor|major]
    • Publish it to NPM: npm publish (you will need an account on npmjs.com)
  2. Once your Template is on NPM, you can send us the name of your package at product@abtasty.com .

FORM COMPONENTS

Each component is generated from a plain Javascript object. The Template form is an array of objects (components).

Common properties

Each object should have these following properties:

Property Description Type Required
category Be rendered. Possible values: “conditions”, “content”, “styles, layouts”. Will be set to “content” if not provided. String No
label Label of the radio group. String No
type The type of your field (the component name) String Yes
propName Name of the input String No
conditions Manage conditions to show or hide components string No

Group

Properties

Example of group properties

{
  type: 'group',
  label: {
    en: 'Date & Time',
    fr: 'Date et heure de fin',
  },
  children: [
    {
      propName: 'dateStart',
      type: 'datepicker',
      value: new Date(),
    },
    {
      propName: 'timeStart',
      type: 'timepicker',
      value: new Date(),
    },
  ],
}
Property Description Type Required
children An array of objects representing the components Object  Yes

And all the common properties for all components.

Checkbox

Properties

Examples of checkbox

// One checkbox
{
    category: 'style',
    propName: 'foreground',
    type: 'checkbox',
    label: 'Put on foreground (z-index)',
    checked: true,
},

// Group of checkboxes
{
    category: 'conditions',
    type: 'group',
    label: 'Interests',
    children: [
        { type: 'checkbox', label: 'Animals', propName: 'animals', checked: true},
        { type: 'checkbox', label: 'Cooking', propName: 'cooking' },
        { type: 'checkbox', label: 'Video games', propName: 'videogames' }
    ],
},
Property Description Type Required
checked The state of the checkbox Boolean No

And all the common properties for all components.

Color picker

Properties

Example

{
    category: 'styles',
    type: 'colorpicker',
    propName: 'backgroundColor',
    label: 'Background Color',
    value: 'rgba(247, 12, 53, 1)',
}
Property Description Type Required
value rgba value of the input (ex: “rgba(0, 0, 0, 1)”) String No

And all the common properties for all components.

Content separator

Example

{
  category: 'layout',
  type: 'separator',
}

A simple horizontal rule to organize your form.

Properties

See common properties for all components.

Date picker

Properties

Example

{
    category: 'content',
    type: 'datepicker',
    propName: 'startdate',
    label: 'Start date',
    placeholder: 'Pick a date',
    value: new Date(),
}
Property Description Type Required
value Will be used as default value Date No
placeholder Placeholder when there is no value String No

And all the common properties for all components.

Date range picker

Properties

Example

{
    category: 'content',
    type: 'dateRangePicker',
    propName: 'rangedate',
    label: 'Range date',
    placeholder: 'Pick a range of date',
    value: [],
}
Property Description Type Required
value Will be used as default value. It’s an array with 2 date values. Array Yes
placeholder Placeholder if both values and placeholder are provided, value will be used String No

And all the common properties for all components.

Select (dropdown)

Properties

Example

{
    type: 'select',
    category: 'conditions',
    label: 'Job',
    propName: 'job',
    value: 1,
    options: [
        { label: 'Dev', value: 1 },
        { label: 'Sysadmin', value: 2 },
        { label: 'Commercial', value: 3 },
    ],
}
Property Description Type Required
value Will be used as default value. String Yes
options An array of objects representing each possible value. Each should have a (String) label and a value. Value can be one of the following types : Array, Object, Number or String. Array Yes

And all the common properties for all components.

Collapsed

Expanded

Media upload

The value will be the URL of the uploaded image.

Properties

Example

{
    category: 'layout',
    type: 'mediaupload',
    propName: 'backgroundImage',
    label: 'Background Image',
}

And all the common properties for all components.

Number

Properties

Example

{
  type: 'number',
  category: 'content',
  propName: 'age',
  label: 'Your age',
  value: 1,
}
Property Description Type Required
value Will be used as default value. Number No
min Minimum value, default is 0 Number No
max Maximum value, default is 9999 Number No
step Step, default is 1 Number No

And all the common properties for all components.

Radio button

Properties

Example

{
  category: 'conditions',
  propName: 'content',
  label: 'Happy?',
  type: 'radio',
  value: 'yes',
  options: [
    { label: 'Yes', 'value': 'yes' },
    { label: 'No', 'value': 'no' },
    { label: 'Maybe', 'value': 'maybe' },
  ],
}
Property Description Type Required
value Will be used as default value. String Yes
options An array of objects representing each radio input. Each should have a (String) label and a (String) value Array Yes

And all the common properties for all components.

Radio image

Properties

Example

{
  category: 'layout',
  type: 'radioImage',
  propName: 'layout',
  label: 'Select a layout',
  value: 'center',
  options: [
    { label: 'Center', value: 'center', src: 'http://img.com/center.jpg' },
    { label: 'Left', value: 'left', src: 'http://img.com/left.jpg' },
    { label: 'Right', value: 'right', src: 'http://img.com/right.jpg' },
  ],
}
Property Description Type Required
value Will be used as default value. String Yes
options An array of objects representing each radio input. Each should have a (String) label, a (String) value and a (String) src Array Yes

And all the common properties for all components.

Slider

Properties

Example

{
    category: 'conditions',
    type: 'slider',
    propName: 'slider',
    label: 'Slider',
    unit: 'px',
    min: 5,
    max: 79,
    value: 10,
}
Property Description Type Required
value Will be used as default value. Number Yes
unit The unit of the value String Yes
min The minimum value Number No
max The maximum value Number No

And all the common properties for all components.

Switch (toggle)

Properties

Example

{
    category: 'conditions',
    type: 'switch',
    propName: 'okay',
    label: 'Ok?',
    value: true,
}
Property Description Type Required
value The default value, false if not provided boolean No

And all the common properties for all components.

Text field

Properties

Example

{
    category: 'content',
    type: 'text',
    propName: 'firstName',
    label: 'First name',
    placeholder: 'John',
}
Property Description Type Required
value Will be used as default value String No
placeholder Placeholder. If both value and placeholder are provided, value will be used. String No

And all the common properties for all components.

Textarea field

Properties

Example

{
    category: 'content',
    type: 'textarea',
    propName: 'description',
    label: 'Description',
    value: 'Lorem ipsum...',
}
Property Description Type Required
value Will be used as default value String No
placeholder Placeholder. If both value and placeholder are provided, value will be used. String No

And all the common properties for all components.

Time picker

Properties

Example

{
    category: 'content',
    type: 'timepicker',
    propName: 'startTime',
    label: 'Start time',
    placeholder: 'Select a time',
    value: new Date(),
}
Property Description Type Required
value Will be used as default value Date No
placeholder Placeholder. If both value and placeholder are provided, value will be used. String No

And all the common properties for all components.