Vanilla JS Modal with good iFrame support

2.1k views Asked by At

Hi Im trying to trying to track down a good modern Vanilla Javascript modal/lytebox with iFrame support, essentially I have I number of links like below:

<a class="edit-html" href="/iframe.html?para=123"></a>

That I want to trigger the modal with iframe content, without having to embed anything other than JS/CSS in the page (i.e. no modal markup)

HighslideJS (http://highslide.com/examples/iframe.html) meets the main requirements(although it doesn't have a modern look and isn't open source) does anyone know of any alternatives?

I've had a look at this link http://planetozh.com/projects/lightbox-clones/ although the list looks quite old and only HighSlideJS meets my requirements on that list

So my main requirements are:

  1. Vanilla JS (No dependencies)
  2. Iframe Content determined by href tag
  3. Actively Maintained, ideally on Github
  4. Modal markup does not need to be manually embedded on page
1

There are 1 answers

0
cage rattler On

Interesting to try to see how we could accomplish your iframe manipulation in a way that would degrade gracefully without script. The anchor tag attributes can do most of the heavy lifting.

<a href="https://jsfiddle.net/rtoal/wvp4scLL/" target="iframe1" onclick="modal.show()">Link</a>
<a href="https://jsfiddle.net/exdev/sxGN3/" target="iframe1" onclick="modal.show()">Link</a>

<iframe name="iframe1" src="about:blank""></iframe>

Personally I think the best lightweight approach to dialogs is to use something sparse like the code below. They aren't often required to do much and therefore don't really require much in the way of being "maintained".

Fiddle here.

var Dialog = function(content, config){
  /*
  content: selector, element, or text to wrap into dialog body
  config object parameters:
    modal: boolean,
    dialogClass: text,
    createCallBack, renderCallBack, showCallBack, hideCallBack, toggleCallBack: functions
  */

  var self = this;

  this.config = config || {};

  this.init = function(){
    //check for an element passed as content or a selector corresponding to an element
    self.content = content.tagName ? content : document.querySelector(content);
    if( ! self.content){
      //otherwise content is text to be appended to the dialog body
      self.content = document.createElement("div");
      self.content.innerText = content;
    }
    self.container = self.create();
    self.body.appendChild(self.content);
    if(document.body){
      self.render();
    }else{
      document.body.addEventListener("load", self.render);
    }

    window.addEventListener("resize", function(){
      self.size();
    })

    return self;
  }

  this.create=function create(){
    self.container = document.createElement("div");
    self.dialog = document.createElement("div");
    self.head = document.createElement("h2");
    self.closeButton = document.createElement("button");
    self.body = document.createElement("div");
    self.head.innerText = self.config.headerText || "";
    self.dialog.appendChild(self.head);
    self.dialog.appendChild(self.closeButton);
    self.container.appendChild(self.dialog);
    self.dialog.appendChild(self.body);
    self.body.appendChild(self.content);
    self.container.className = "dialog-container" + (self.config.modal ? " modal" : "");
    self.dialog.className = "dialog " + self.config.dialogClass || "";
    self.head.className = "dialog-head";
    self.body.className = "dialog-body";
    self.closeButton.className = "dialog-close";
    self.closeButton.innerText = self.config.closeButtonText || "close";
   self.closeButton.title = self.config.closeButtonText || "close"; self.closeButton.addEventListener("click", self.hide);
    self.closeButton.setAttribute("type","button");
    self.checkCallBack();
    return self.container;
  }

  this.render = function render(){
    document.body.appendChild(self.container);
    self.checkCallBack(arguments);
    return self.dialog;
  }

  this.show = function(){
    setTimeout(function(){
      self.container.classList.add("visible");
      self.closeButton.focus();
      self.checkCallBack(arguments); 
      return self.container;
    },0);
  }

  this.hide = function hide(){
    var iframe = self.dialog.querySelector("iframe");
    if(iframe){
      iframe.setAttribute("src","about:blank");
    }
    self.container.classList.remove("visible");
    self.checkCallBack(arguments);
    return self.container;
  }

  this.toggle = function(){
    if(self.dialog.classList.contains("visible")){
      self.hide();
    }else{
      self.show();
    }
    self.checkCallBack(arguments);
    return self.container;
  }

  this.size = function(){
    var padding = 80;
    self.body.style.maxHeight = window.innerHeight - self.head.offsetHeight - padding + "px";
    console.log(self.body.style.maxHeight);
    return self.body.style.maxHeight;
  }

  this.checkCallBack = function(args){
    var action = arguments.callee.caller.name,
        callBackName = action + "CallBack",
      args = Array.prototype.slice.call(args || []),
      fn = self.config[callBackName];

    if(fn){
      args.unshift(action);
      fn.apply(self, args);
    }

    return !!fn;
  }

  this.init();
}

//sample usage
var.modal = new Dialog("iframe", {modal: true});