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 for creating an interaction Dialogue for a lightbox on a page in the BlueConic Client (the backend). The content displayed in the lightbox can be edited to suit your needs.
The Dialogue will show visitors to the website (the frontend) a lightbox with the configured content.
File structure
This plugin requires a number of files that are structured as in the schematic directory overview below:
mylightbox/ +-- jquery/ | +-- jquery-1.11.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' dialogue
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.11.2.min.js</library> <library>/fancybox/jquery.fancybox.pack.js</library> </libraries> </frontend> <!-- backend specific properties --> <backend> <view>channel</view> <parameters> <parameter> <id>content</id> <type>html</type> </parameter> </parameters> </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 a dialogue 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.11.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 dialogue.
- The <parameters> tag contains the definitions of parameters that the user can configure in the UI. In this case we define a <parameter> with the <id> "content" of the <type> "html", because we want to enable the user to type in the lightbox editor and store the edits.
JavaScript file
mylightbox.js
var InteractionTypeImpl = InteractionType.extend( { // Called every time a new interaction dialogue 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 dialogue 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:
- init() and onLoad() override JavaScript Back-end API or JavaScript Front-end API functions to tap into BlueConic plugin events.
- showLightbox() and createElement() are our own functions to display a lightbox.
The JavaScript is discussed in more detail below.
- var InteractionTypeImpl = InteractionType.extend({
- Like every interaction dialogue 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 dialogue 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 initialization, 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 (just 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.