Last active
February 4, 2021 19:19
-
-
Save dannyconnolly/be1795cfd9054b97d299424d3661b7f4 to your computer and use it in GitHub Desktop.
Vanilla JS Modal
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function() { | |
// Define constructor | |
this.Modal = function() { | |
// Create global element references | |
this.closeButton = null; | |
this.modal = null; | |
this.overlay = null; | |
// Determine proper prefix | |
this.transitionEnd = transitionSelect(); | |
// Define option defaults | |
var defaults = { | |
className: 'fade-and-drop', | |
closeButton: true, | |
content: "", | |
maxWidth: 600, | |
minWidth: 280, | |
overlay: true, | |
overlayClose: true | |
}; | |
// Create options by extending defaults with the passed in arugments | |
if (arguments[0] && typeof arguments[0] === "object") { | |
this.options = extendDefaults(defaults, arguments[0]); | |
} | |
} | |
// Public Methods | |
Modal.prototype.open = function () { | |
// Build out our Modal | |
buildOut.call(this); | |
// Initialize event listeners | |
initializeEvents.call(this); | |
/* | |
* After adding elements to the DOM, use getComputedStyle | |
* to force the browser to recalc and recognize the elements | |
* that we just added. This is so that CSS animation has a start point | |
*/ | |
window.getComputedStyle(this.modal).height; | |
/* | |
* Add our open class and check if the modal is taller than the window | |
* If so, our anchored class is also applied | |
*/ | |
this.modal.className = this.modal.className + (this.modal.offsetHeight > window.innerHeight ? ' scotch-open scotch-anchored' : ' scotch-open'); | |
this.overlay.className = this.overlay.className + ' scotch-open'; | |
} | |
Modal.prototype.close = function () { | |
// store the value of this | |
var _ = this; | |
// Remove the open class name | |
this.modal.className = this.modal.className.replace(' scotch-open', ''); | |
this.overlay.className = this.overlay.className.replace(' scotch-open', ''); | |
/* | |
* Listen for CSS transitionend event and then | |
* Remove the nodes from the DOM | |
*/ | |
this.modal.addEventListener(this.transitionEnd, function(){ | |
_.modal.parentNode.removeChild(_.modal); | |
}); | |
this.modal.addEventListener(this.transitionEnd, function() { | |
if(_.overlay.parentNode) _.overlay.parentNode.removeChild(_.overlay); | |
}); | |
} | |
// Private Methods | |
function buildOut() { | |
var content, contentHolder, docFrag; | |
/* | |
* If content is an HTML string, append the HTML string. | |
* If content is a domNode, append its content. | |
*/ | |
if (typeof this.options.content === 'string') { | |
content = this.options.content; | |
} | |
else { | |
content = this.options.content.innerHTML; | |
} | |
// Create a document fragment to build with | |
// Document Fragment is used to construct collections of DOM elements outside of the DOM, | |
// and is used to cumulatively add what we have built to the DOM. | |
docFrag = document.createDocumentFragment(); | |
this.modal = document.createElement('div'); | |
this.modal.className = "scotch-modal " + this.options.className; | |
this.modal.style.minWidth = this.options.minWidth + 'px'; | |
this.modal.style.maxWidth = this.options.maxWidth + 'px'; | |
if (this.options.closeButton === true) { | |
this.closeButton = document.createElement('button'); | |
this.closeButton.className = 'scotch-close close-button'; | |
this.closeButton.innerHTML = 'x'; | |
this.modal.appendChild(this.closeButton); | |
} | |
if (this.options.overlay === true) { | |
this.overlay = document.createElement('div'); | |
this.overlay.className = 'scotch-overlay ' + this.options.className; | |
docFrag.appendChild(this.overlay); | |
} | |
// Create content holder and append to the modal | |
contentHolder = document.createElement('div'); | |
contentHolder.className = 'scotch-content'; | |
contentHolder.innerHTML = content; | |
this.modal.appendChild(contentHolder); | |
// Append modal to document fragment | |
docFrag.appendChild(this.modal); | |
// Append document fragment to body | |
document.body.appendChild(docFrag); | |
} | |
function initializeEvents() { | |
if (this.closeButton) { | |
this.closeButton.addEventListener('click', this.close.bind(this)); | |
} | |
if (this.overlay && this.overlayClose) { | |
this.overlay.addEventListener('click', this.close.bind(this)); | |
} | |
} | |
// Utility method to extend defaults with user options | |
function extendDefaults(source, properties) { | |
var property; | |
for (property in properties) { | |
if (properties.hasOwnProperty(property)) { | |
source[property] = properties[property]; | |
} | |
} | |
return source; | |
} | |
// Utility method to determine which transistionend event is supported | |
function transitionSelect() { | |
var el = document.createElement('div'); | |
if (el.style.WebkitTransition) return 'webkitTransitionEnd'; | |
if (el.style.OTransition) return 'oTransitionEnd'; | |
return 'transitionend'; | |
} | |
}()); | |
/* | |
| | |
| Usage | |
| var modal = new Modal({ | |
| closeButton: false, | |
| content: '<div>HTML content can go here!</div>', | |
| maxWidth: 600, | |
| overlayClose: false | |
| }); | |
| | |
| modal.open(); | |
| | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment