Using JavaScript Modules for Beacon Plugins

In this topic, you will learn how JavaScript modules can be used in the code implementation of Beacon Plugins.

Introduction

OTT Plugins are implemented with JavaScript and CSS. Anytime you are using code you want to consider code organization. In the Learning Guide: OTT Plugins document, you learned plugins are implemented by loading one JavaScript file into your Beacon web app. That single file, named index.js, could hold all your OTT plugin JavaScript code, but this would lead to poor coding practices. Also, there are a myriad of other JavaScript frameworks from which you could choose. For a balance between poor practices and complexity, the documents around OTT Plugins use JavaScript modules for code organization.

Basically, the index.js acts as a "controller" and the actual implementation details for each plugin element are in a JavaScript module file. Like a "traffic police officer" directs where cars should go, the controller directs program execution. In the case of JavaScript modules, the "traffic cop" is basically importing modules and directing which modules should be called when and what data should be passed to the modules. The idea of a controller very common in programming practice and, of course, you may choose your favorite JavaScript framework.

Example code samples can be download from the ott-plugins-example-code GitHub repo.

The modules

It is consider good coding practices to:

  • Not duplicate code
  • Make your code as reusable as possible

Using modules help accomplish both of these tasks. First, let's take a look at the basic syntax of how modules are structured in the examples shown in these docs:

const function1 = () => { 
  code;
  code;
  code;
  code;
};
  
const function2 = () => {
  code;
  code;
  code;
  code;
};

const function3 = () => {
  code;
  code;
  code;
  code;
};
  
export { function1, function2, functions3 };

You see three functions defined as constants using arrow notation. These functions performs tasks like:

  • Add a button
  • Open the side panel
  • Place content in a custom div
  • Contain the code for a button click handler

The functions are imported into the controller, which is the file index.js for OTT Plugins , then used as necessary.

Here is a simple module that contains a function that creates a button.

const addCustomButtonDetails = () => {
    
  window.postMessage({
    event: 'detailsPageAddCustomButton',
    data: {
      title: 'Test Button',
      font_awesome_icon: 'fa fa-info-circle',
      element_id: 'TEST_BTN_ID'
    }
  }, window.location.origin);
  
};
  
export { addCustomButtonDetails };

This functions properly, but is not reusable. You need a different function for every button you wish to create. To make the function reusable parameters are used:

const addCustomButtonDetails = (pTitle, pIcon, pID) => {
  
  window.postMessage({
    event: 'detailsPageAddCustomButton',
    data: {
      title: pTitle,
      font_awesome_icon: pIcon,
      element_id: pID
    }
  }, window.location.origin);

};

export { addCustomButtonDetails };

If there are buttons, there should be click handlers. A function is added to the module that is called on a button click, and simply pops up an alert with the name of the button in it. Actually handling the event is left to the controller

const addCustomButtonDetails = (pTitle, pIcon, pID) => {
      
  window.postMessage({
    event: 'detailsPageAddCustomButton',
    data: {
      title: pTitle,
      font_awesome_icon: pIcon,
      element_id: pID
    }
  }, window.location.origin);

};

const handleButtonClick = (buttonString) => {

  alert('Button clicked: ' + buttonString);

};

export { addCustomButtonDetails, handleButtonClick };

Now it is time to move on to see how the functions can be used.

The index.js controller

The index.js file is setup to be the centralized event handler and "direct traffic" from there. In this example the following happens:

  • Line 1: The functions from the module are imported
  • Lines 3-8: Standard OTT plugin event handler syntax
  • Line 9: A switch-case statement directs execution to the correct code
  • Lines 10-13: Adds two buttons to the web app when the onBeaconPageLoad event is handled
  • Lines 15-22: On the detailsPageExternalButtonWasClicked event, the handleButtonClick() function is called; the if statements are used to pass the correct parameter value to the function
import { addCustomButtonDetails, handleButtonClick } from './button-demo-module.js';
    
window.addEventListener("message", (event) => {
  const originsAllowed = [
    'https://yourapplocation.com',
    'https://yourapplocation.com'
  ];
  if (originsAllowed.includes(event.origin)) {
    switch (event.data.event) {
      case 'onBeaconPageLoad':
        addCustomButtonDetails('Download', 'fa fa-info-circle', 'download-button');
        addCustomButtonDetails('Location', 'fa fa-info-circle', 'location-button');
        break;

      case 'detailsPageExternalButtonWasClicked':
        if (event.data.data.element_id == 'download-button') {
         handleButtonClick('Download');
        };
        if (event.data.data.element_id == 'location-button') {
          handleButtonClick('Location');
        };
        break;
    }

  }
},
false
);

Here is the plugin in action:

Summary

You have seen one simple example of a module used to implement a feature of OTT Plugins, buttons. Please consider the following when you implement OTT Plugins:

  • Using modules is one way to implement plugin code, but it is not the only way. Although Brightcove does not recommend this approach, you may find that it works for your use cases.
  • There are degrees of code reuse and levels of abstraction. You may wish to use more or less than what you find in the Brightcove plugin examples.
  • The example modules do NOT cover every possible need for every plugin implementor. The examples provide a basis on which you can develop code for your use cases.