Jump to content
  • JavaScript Popup for Spotfire


    A small floating draggable window that appears when clicking on a trigger that can hold Spotfire controls and other html elements.

    Introduction

    A popup is a small window that it is display on top of other windows. The JavaScript Popup for Spotfire can hold Spotfire controls such as Action Controls, Filters, Property Controls and Dynamic Items. Examples of these can be buttons, dropdowns, input boxes, filters, calculated values, Sparklines, etc. It can also hold or any other HTML element supported by the Text Area. 

    Popups are great way to save on valuable dashboard space and help make a better experience for the analyst. 
     

    jspopup.thumb.gif.e0781eed112d6de747fc5deb2f53cfd8.gif

    How it works

    The popup consists in html code and some JavaScript code. The html must follow a specific structure that defines the popup elements so the script can render the popup. To have multiple triggers and multiple popups, you need multiple html and javascript sets for each popup.

    Popup elements

    These parts are the popup container, popup trigger, the popup title and the popup contents. The popup container is an html tag element that enclose these element in sequence.
    image.png.5d59b5395614b0313e7c89893a02c13a.png

    Popup container

    The main container has 3 children, one for each popup component (trigger, title and contents). It should have a unique id attribute to identify the popup. This id is passed as a parameter for the popup script.

    Popup trigger

    The first popup container child is the trigger. The trigger is responsible to show or hide the popup. This can be an image, text or icon. It can hold Spotfire controls but it is not recommended, unless you use a label or calculated value without any click event handlers.  

    Popup title

    This is the title of the popup, and can only take text. The second child of the popup container is defined as the popup title. If the popup title ends with *** the default popup visibility will be opened by default.


    Popup contents

    The third child of the popup container holds the contents of the popup and can include any Spotfire control or html tag. 

    Example with one popup

    html

    <div id="myPopup" class="JSPopup">
    	<div>Open popup A</div>
    	<div>This is popup A</div>
    	<div>
            Popup contents goes <b>here</b>
        </div>
    </div>
     

    script

    The script takes the id as the input parameter. To test without this parameter, uncomment the second that reads id="popup2";

     

    JavaScript

    /*
    place this in the html code
    <div class="JSPopup" id="myPopup">
        <div>click to open popup (trigger)</div> 
        <div>Popup title (pullable)</div>
        <div>Popup contents</div>
    </div>
    
    add this JavaScript to a text area. ***Only one per page*** and reload browser (or page by switching tabs) after editing
    */
    (() => {
      let highestZIndex = 1000; // Start with a high z-index value
    
      class PopupManager {
        constructor(popupId, index) {
          this.popupId = popupId;
          this.index = index;
          this.draggingLibraryUrl = 'https://unpkg.com/draggabilly@3/dist/draggabilly.pkgd.min.js';
          this.init();
        }
    
        init() {
          this.loadDraggingLibrary().then(() => {
            this.createPopout(document.getElementById(this.popupId), this.index);
          });
        }
    
        loadDraggingLibrary() {
          return new Promise((resolve) => {
            if (!document.querySelector(`script[src="${this.draggingLibraryUrl}"]`)) {
              const script = document.createElement("script");
              script.src = this.draggingLibraryUrl;
              script.onload = resolve;
              document.body.appendChild(script);
            } else {
              resolve();
            }
          });
        }
    
        createPopout(popup, index) {
          let id = "JSPopup_" + index;
          let popupElements = popup.children;
          let popupTrigger = popupElements[0];
          let popupTitle = popupElements[1].innerText;
          let popupContents = popupElements[2];
          let isOpened = false;
    
          popupTrigger.style.cursor = "default";
    
          let template = `
            <div id="${id}" class="pullable ${isOpened ? "" : "hidden"}" style="z-index: ${highestZIndex};">
              <span class="close"></span>
              <div class="contents"></div>
            </div>
            <style>
              .hidden { left: -1000px !important; }
              #${id} {
                border: 1px solid darkgray;
                position: fixed;
                padding: 5px;
                background: ${popup.style.background || "whitesmoke"};
                box-shadow: 0 3px 11px 0 rgba(0,0,0,.16), 0 3px 6px 0 rgba(0,0,0,.16);
                border-radius: 6px;
                cursor: default;
                width: 300px;
                overflow-y: auto;
                max-height: 700px;
              }
              #${id} .close::after {
                content: "✖";
                color: darkgray;
                float: right;
                margin-top: -15px;
                cursor: default;
                font-size: 20px;
              }
              #${id} .close {
                padding: 5px;
              }
              #${id} .close:hover::after {
                color: gray;
                font-size: 22px;
              }
              #${id} .contents {
                border: 0px solid darkgray;
                background: ${popupContents.style.background || "#FFF"};
                margin-top: 3px;
                padding: 5px;
                min-height: 100px;
              }
              .DropdownListContainer.sf-element-styled-dialog.sfc-style-root.prevent-flyout-close {
                z-index: 99999999;
              }
            </style>
          `;
          popup.innerHTML = template;
          let popupBody = document.getElementById(id);
    
          popup.appendChild(popupTrigger);
    
          if (popupTitle.endsWith("***")) {
            popupTitle = popupTitle.slice(0, popupTitle.length - 3);
            popupBody.classList.remove("hidden");
          }
          let handle = document.createElement("div");
          handle.className = "handle";
          let textNode = document.createTextNode(popupTitle);
          handle.prepend(textNode);
          popupBody.prepend(handle);
    
          let templateContents = document.querySelector(`#${id} .contents`);
          templateContents.style = popupContents.style.cssText;
          popupBody.style = popup.style.cssText;
          popup.removeAttribute("style");
    
          templateContents.append(...popupContents.childNodes);
    
          popupTrigger.onclick = () => {
            let pp = document.getElementById(id);
            pp.classList.remove("hidden");
            this.bringToFront(pp);
          };
    
          handle.onclick = () => {
            let pp = document.getElementById(id);
            this.bringToFront(pp);
          };
    
          popupBody.addEventListener('mousedown', () => {
            this.bringToFront(popupBody);
          });
    
          document.querySelectorAll("#" + id + " .close").forEach((x) => {
            x.onclick = () => {
              x.parentNode.classList.add("hidden");
            };
          });
    
          document.querySelectorAll(".pullable").forEach((aPopup) => {
            const draggie = new Draggabilly(aPopup, { handle: ".handle", containment: 'body' });
            draggie.on('dragStart', () => {
              this.bringToFront(aPopup);
            });
          });
        }
    
        bringToFront(element) {
          highestZIndex++;
          element.style.zIndex = highestZIndex;
        }
      }
    
      // Usage
      const popups = document.querySelectorAll('.JSPopup');
      popups.forEach((popup, index) => {
        new PopupManager(popup.id, index);
      });
    })();

     

    Making the Popups draggable when Internet is unreliable

    You need to install this library in case there are internet restrictions to go fetch draggabilly, a third party JavaScript library that allows the popups to be draggable. From https://unpkg.com/draggabilly@3/dist/draggabilly.pkgd.min.js, just copy the code from the last link from this sentence into your JavaScript and you are done. Remember, this an optional step if we cannot assure connection to the draggabilly.min.js file.

    Changing the look and feel of the popup

    The style of the popup is embedded in the script. The best way is to override the styles with a separate script. To change the default look and feel for all the popups, then change the main script. Here is an example of that

    popup_blueberry.css

    //requires: popup.js
    
    //script params
    //id="myPopup"
    
    const popupColors={
     c1:"lightgray",//background
     c2:"#003C84",  //border
     c3:"navy",     //title background
     c4:"#0E0E0E",  //text 
     c5:"#FFF"      //title
    } 
    
    //default style. Override with popup_yourtheme.css
    css =`<style>
    
    #${id} .popup-jsc {
        width: min-content !important;
        background-color: #eaeaea !important;
        border-radius: 0.5em;
        border: 1px solid whitesmoke;
        box-shadow: rgb(187 187 187) 5px 4px 9px 1px;
    }
    
    #${id} .flt.drag {
        border: none;
        margin: 0;
        padding: 5px;
    	color:${popupColors.c5};
        background: ${popupColors.c3};
    }
    
    #${id} .popupContents {
      display: inline-block;
      padding: 6px 10px;
      font: 1em arial, helvetica, sans-serif;
      color: ${popupColors.c4};;
      background-color: ${popupColors.c1};
      border:1px outset ${popupColors.c2};
      border-radius:.5em;
      border-top: none;
      border-top-left-radius: 0;
      border-top-right-radius: 0;
    }
    
    </style>`
    
    document.getElementById(id).insertAdjacentHTML("beforeend", css);
     


    Popup_greendish.js

    //requires: popup.js
    
    //script params
    //id="myPopup"
    
    const popupColors={
     c1:"green",      //contents
     c2:"darkGreen",  //border contents
     c3:"lightgray",  //title background
     c4:"whitesmoke", //contents color
     c5:"navy"        //title color
    } 
    
    
    //default style. Override with popup_yourtheme.css
    css =`<style>
    
    #${id} .popup-jsc {
        width: min-content !important;
        background-color: #eaeaea !important;
        border-radius: 0.5em;
        border: 1px solid whitesmoke;
        box-shadow: rgb(187 187 187) 5px 4px 9px 1px;
    }
    
    #${id} .flt.drag {
        border: none;
        margin: 0;
        padding: 5px;
    	color:${popupColors.c5};
        background: ${popupColors.c3};
    }
    
    #${id} .popupContents {
      display: inline-block;
      padding: 6px 10px;
      font: 1em arial, helvetica, sans-serif;
      color: ${popupColors.c4};;
      background-color: ${popupColors.c1};
      border:1px outset ${popupColors.c2};
      border-radius:.5em;
      border-top: none;
      border-top-left-radius: 0;
      border-top-right-radius: 0;}
    
    </style>`
    
    document.getElementById(id).insertAdjacentHTML("beforeend", css);
     

    Back to the JavaScript Component Hub for Spotfire

    Disclaimer

    This method makes assumptions about the inner workings of Spotfire version 12.0.0 LTS Any analyses created using this hack may cause instability and performance issues and are likely to break when Spotfire is upgraded or hotfixed in the future.  Any issues resulting from applying this hack are not covered by Spotfire maintenance agreements and Support will not assist in troubleshooting problems with analysis files where this approach is used.

     

    • Thanks 2

    User Feedback

    Recommended Comments

    There are no comments to display.


×
×
  • Create New...