Tutorial 2: Lightbox

Difficulty: Intermediate

In the Hello World! tutorial a very basic plugin was created. This tutorial aims to create a more complex plugin: a custom lightbox. In creating the plugin we will touch on typical subjects that arise when developing custom plugins.

 


Introduction

In this tutorial we will create an Interaction Type plugin that will allow a marketer to create a Dialogue for a lightbox on a page in the BlueConic Client (the backend). The contents of the lightbox can be edited.

The Dialogue will show the visitor of the website (the frontend) a lightbox with the configured content.


File structure

This plugin requires a number of files that are structured like in the schematic directory overview below:

mylightbox/
  +-- jquery/
  |     +-- jquery-1.7.2.min.js
  +-- fancybox/
  |     +-- blank.gif
  |     +-- [...]
  |     +-- jquery.fancybox.pack.js
  +-- mylightbox.js
  +-- mylightbox.xml

Although this directory structure looks much more complex than the "Hello World!" example, it builds on the exact same structure:

  • "mylightbox.xml" is the XML definition file
  • "mylightbox.js" is the main JavaScript file

Additionally:

  • To display our lightbox we use jQuery and its plugin Fancybox. The "jquery" and "fancybox" directories contain the third party library files that we need to make our lightbox work.

The files can be downloaded here: mylightbox-1.0.0.zip

Relevant files are explained in more detail in the following sections.


XML definition file

<?xml version="1.0" encoding="UTF-8"?>
<plugin>
  <id>mylightbox</id>
  <version>1.0.0</version>
  <type>action</type>
  <name>
    <label locale="en_US">My Lightbox</label>
    <label locale="nl_NL">Mijn Lightbox</label>
  </name>
  <description>
    <label locale="en_US">A 'My Lightbox' interaction allows you to display entered content or external content in a lightbox on a web-based channel.</label>
  </description>

  <!-- frontend specific properties -->
  <frontend>
    <script>mylightbox.js</script>
    <positiontype>overlay</positiontype>
    <libraries>
      <library>/jquery/jquery-1.7.2.min.js</library>
      <library>/fancybox/jquery.fancybox.pack.js</library>
    </libraries>
  </frontend>

  <!-- backend specific properties -->
  <backend>
    <view>channel</view>
  </backend>
</plugin>

This XML definition file contains the following instructions:

  • The <id> is the unique identifier string that allows BlueConic to distinguish this plugin from other plugins.
  • The <version> contains a version number. Once you have installed a plugin in BlueConic, you can only update to higher version numbers. So, if you install version "1.0.0" of this plugin, you can update to version "1.0.1" or version "2.27.0". But you cannot install version "1.0.0" again - unless you delete the existing plugin first. However, remember that deleting a plugin will also delete all dialogues based on that plugin!
  • The <type> tells BlueConic that this plugin contains an interaction that performs some visual action.
  • The <label> is a friendly name for the plugin. The locale indicates for which of the editing languages the friendly name is. Currently only "en_US" and "nl_NL" are supported.
  • The <description> provides a description of what the plugin does.

Above are the general instructions. There are also instructions specifically for the <frontend>:

  • The <script> tag defines the JavaScript file that will be executed to implement the inner workings of the plugin, in this case "mylightbox.js".
  • The <positiontype> tag defines what kind of positioning the plugin uses. Since our lightbox does not require a position, but is shown in a layer hovering above the page, we use the value "overlay".
  • The <libraries> tag contains the paths to external JavaScript libraries that need to be loaded for this plugin to work. In our case we want jQuery and Fancybox to be loaded, so we specify the paths to them, using "/" to refer to the root directory of the plugin. So the <library> paths become: "/jquery/jquery-1.7.2.min.js" and "/fancybox/jquery.fancybox.pack.js". If you want to learn more about dependencies, see BCGD001 - Use declared dependencies to load the required JavaScript libraries (JQuery, for example).

There are also instructions specifically for the <backend>:

  • The <view> tag tells BlueConic that the backend should use the "channel" view (i.e. display the website inline) when editing the interaction.

JavaScript file

mylightbox.js

var InteractionTypeImpl = InteractionType.extend( {

  // Called every time a new interaction of this type is created.
  init: function(blueConicClient, context) {
    this.blueConicClient = blueConicClient;
    this.context = context;

    // Url for this interactiontype
    var interactionTypeId = context.getInteractionTypeId();
    var baseUrl = blueConicClient.getBaseURL(interactionTypeId);

    // Load the CSS for the fancybox jQuery plugin
    var fancyboxCSS = baseUrl + 'fancybox/jquery.fancybox.css';
    blueConicClient.util.loadCSS(fancyboxCSS);

    // Retrieve the content
    var params = this.context.getParameters();
    var html = params.content ? params.content[0] : params.content;

    if (typeof html === 'undefined') {
      // Make sure the variable is defined
      html = ' ';
    }

    // Create a HTML fragment for the HTML we need to add to the DOM
    this.htmlFragment = this.createElement(html);
  },

  // Called when an interaction based on this type is executed.
  onLoad: function() {
    this.showLightbox();
  },

  // The work horse of our plugin
  showLightbox: function() {
    var content = ' ';
    var effect = 'elastic';
    var width = 200;
    var height = 150;

    if (this.htmlFragment) {
      content = this.htmlFragment.innerHTML;
    }

    var settings = {
      'autoDimensions': false,
      'type': 'inline',
      'content': content,
      'width': width,
      'height': height,
      'transitionIn': effect,
      'transitionOut': effect
    };

    // Create the lightbox
    this.jQuery.fancybox(settings);

    if (this.blueConicClient.isInEditMode()) {
      // The inside of the lightbox is editable
      this.blueConicClient.setEditableNode('.fancybox-inner', {
          colorScheme: 'light',
          positionName: 'My Lightbox'
      });
    }
  },

  // Utility function to create an element inside a div
  createElement: function(html) {
    var fragment;

    if (!html) {
      return null;
    }

    try {
      fragment = document.createElement('div');
      fragment.innerHTML = html;
    } catch(error) {
      return null;
    }

    return fragment;
  }
});

This JavaScript defines four functions:

The JavaScript is discussed in more detail below.

var InteractionTypeImpl = InteractionType.extend({
Like every interaction plugin, our plugin extends the default BlueConic InteractionType. The function extend() takes an object with function definitions as argument. The defined functions will overrule the standard functions of the InteractionType. For our lightbox example we overrule two API functions (init(), onLoad()) and add our own functions function showLightbox() andcreateElement(). We will go into more details for each of these functions below.
init: function(blueConicClient, context) {

This line overrules the API function init(blueConicClient, interactionContext). The function is called every time a new interaction of this type is created. We start by storing the two parametersblueConicClient and interactionContext, because we will need them to retrieve parameter values when showing the actual lightbox:

    this.blueConicClient = blueConicClient;
    this.context = context;

The lightbox is based on the jQuery plugin Fancybox, which needs its own style sheet information to be loaded on the web page. This information is stored in the directory structure of our plugin, in the file "jquery.fancybox.css". To load the CSS information we first obtain the id for our interactionType using getInteractionTypeId(). With this id, we can get the base URL for our deployed plugin usinggetBaseURL(interactionTypeId).

We then append the path of the Fancybox CSS file to the base URL to get the full URL from which we can load the CSS using util.loadCSS(stylesheet):

    // Url for this interactiontype
    var interactionTypeId = context.getInteractionTypeId();
    var baseUrl = blueConicClient.getBaseURL(interactionTypeId);

    // Load the CSS for the fancybox jQuery plugin
    var fancyboxCSS = baseUrl + 'fancybox/jquery.fancybox.css';
    blueConicClient.util.loadCSS(fancyboxCSS);

Note: Fancybox also needs a javascript library, which is why we defined it as <library> in the XML definition file. This will make BlueConic load the library automatically.

To finish the initialisation we make sure that we have a HTML fragment to display. We retrieve the content using the function getParameters(). In a new Dialogue the content will be undefined, so we check for this and make sure the variable html is defined. Finally we create a HTML fragment based on the content for later use when we actually want to display the lightbox. The this.htmlFragment will hold onto the content for us.

    // Retrieve the content
    var params = this.context.getParameters();
    var html = params.content ? params.content[0] : params.content;

    if (typeof html === 'undefined') {
      // Make sure the variable is defined
    	html = ' ';
    }

    // Create a HTML fragment for the HTML we need to add to the DOM
    this.htmlFragment = this.createElement(html);
onLoad: function() {
Nothing exciting about this function; we overrule the API function onLoad(), which is called when the plugin is executed for an interaction of a dialogue. The only thing we do here is make a function call to show the lightbox.
  onLoad: function() {
    this.showLightbox();
  },
showLightbox: function() {

This function is in charge of displaying the lightbox. To do so, it must first gather the settings and then it can create the lightbox.

First, we define some static values:

  showLightbox: function() {
    var content = ' ';
    var effect = 'elastic';
    var width = 200;
    var height = 150;

We then apply some checks, because the lightbox will not display if the content is empty. More importantly, we prefer to use our private HTML fragment storage for the content value. As a final sanity check, the content cannot be empty or fancybox will not show a lightbox at all:

    if (this.htmlFragment) {
      content = this.htmlFragment.innerHTML;
    }

    if (typeof content === 'undefined' || content === null || content === '') {
      content = ' ';
    }

What follows is fancybox specific code; a function beforeLoad() to force the lightbox to listen to resizes (simply setting the width and height does not seem to be enough) and settings to initialize the lightbox. With everything in place, we create the lightbox:

    // Function to adjust the width and height of the fancybox
    var beforeLoad = function() {
      this.width = width;
      this.height = height;
      this.minWidth = width;
      this.minHeight = height;
      this.maxWidth = width;
      this.maxHeight = height;
    };

    var settings = {
      'autoDimensions': false,
      'type': 'inline',
      'content': content,
      'width': width,
      'height': height,
      'transitionIn': effect,
      'transitionOut': effect,
      'beforeShow': beforeLoad,
      'beforeLoad': beforeLoad
    };

    // Create the lightbox
    this.jQuery.fancybox(settings);

Now that the lightbox is drawn, we can point out which HTML node can be edited using the function setEditableNode(domElement, options). This is only relevant if the Dialogue is being edited, so we use the function isInEditMode() to verify if this is the case:

    if (this.blueConicClient.isInEditMode()) {
      // The inside of the lightbox is editable
      this.blueConicClient.setEditableNode('.fancybox-inner', {
          colorScheme: 'light',
          positionName: 'My Lightbox'
      });
    }

Packaging the plugin

Package the plugin by creating a ZIP file with the file structure laid out above. Make sure the files "mylightbox.xml" and "mylightbox.js" are in the root of the ZIP file.

You can install the packaged plugin in BlueConic and create a new dialogue that uses the "My Lightbox" plugin. See the Hello World tutorial for the details on how to do this. If all went as planned, this should look as the screenshot in the introduction.


Summary

In this tutorial you learned how to create a custom BlueConic plugin for an editable lightbox.

In the next tutorial we will expand our plugin by adding parameters to it.

If you want to learn more about BlueConic Plugins, check the Getting Started page for an overview of available tutorials.