-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
shane
committed
Jan 24, 2019
0 parents
commit 15ba98d
Showing
12 changed files
with
7,713 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
module.exports = { | ||
globals: { | ||
Promise: true | ||
} | ||
}; |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
node_modules |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
# @zaneray/modal-extras | ||
|
||
|
||
## Getting Started | ||
|
||
Modal Extras can be used in an project that implements Bootstrap modal | ||
|
||
``` | ||
yarn add @zaneray/modal-extras | ||
``` | ||
|
||
and then import the functions you wish to use through ES6 imports: | ||
|
||
``` | ||
import * as modalextras from '@zaneray/modal-extras`; | ||
``` | ||
|
||
If you prefer not to use a package manager, you can download the latest version of Modal Extras and include it in your project manually from the following links: | ||
|
||
- [modal-extras.js](http://unpkg.com/@zaneray/modal-extras@latest/dist/modal-extras.js) | ||
- [theme-cart.min.js](http://unpkg.com/@zaneray/modal-extras@latest/dist/modal-extras.min.js) | ||
|
||
These files make Modal Extras accessible via the `Zaneray.bootstrap.modal` global variable. | ||
|
||
## Browser Support | ||
|
||
Modal Extras uses two APIs not available to legacy browsers, Fetch and Promise. If you wish to support legacy browsers, make sure you add the following dependencies to your project: | ||
|
||
``` | ||
yarn add unfetch es6-promise | ||
``` | ||
|
||
and then import them before you import Modal Extras: | ||
|
||
```js | ||
// Only need to import these once | ||
import 'unfetch/polyfill'; | ||
import 'es6-promise/auto'; | ||
|
||
// Import @zaneray/modal-extras anywhere you need it | ||
import * as modalextras from '@zaneray/modal-extras'; | ||
``` | ||
|
||
## Methods | ||
|
||
### onLoad() | ||
|
||
Finds all data-toggle elements on the page and binds them to the proper methods based on their value | ||
|
||
```js | ||
modalextras.onLoad(); | ||
``` | ||
|
||
### generateModalTemplate(html, clazz) | ||
|
||
Injects the dynamic-modal HTML wrapper to the begining of the body and binds a modal.bs.hide method to remove it from the DOM | ||
|
||
```js | ||
modalextras.generateModalTemplate('<div>content</div>', ''); | ||
``` | ||
|
||
## Binding Usage | ||
|
||
### Inline Html | ||
|
||
Auto bind a link on the page to load content on the page to a modal. To avoid duplicate DOM id's on the page | ||
when the content is copied in to the modal, the parent element ID is changed to [id]-modal. If you're relying | ||
on this id for styling, ensure you also include this selector in your css. | ||
|
||
```html | ||
<a href="#" data-toggle="modal-html" data-id="id-1234">Open HTML modal by ID</a> | ||
<div id="id-1234">Content to load in a modal</div> | ||
``` | ||
|
||
### AJAX Content | ||
By default you can specify a URL and all of that URL will be loaded to the page. Specify data-toggle of modal-ajax | ||
and the script will grab the URL in the href. This works fine for snippets of HTML but in demo you can see that it | ||
loads all of the image from /includes/ajax.html including the header and footer. | ||
|
||
```html | ||
<a href="includes/ajax.html" data-toggle="modal-ajax">Open Ajax Modal</a> | ||
``` | ||
|
||
#### Load a page with an optional selector | ||
|
||
Optionally you can specify an id and the script will load the whole page and display the results specified in the data-id selector. | ||
|
||
```html | ||
<a href="includes/ajax.html" data-toggle="modal-ajax" data-id="wrapper">Open Ajax Modal and inject with Element id="wrapper" from response</a> | ||
``` | ||
|
||
### Modal Images | ||
|
||
Specify a data-toggle attribute of modal-image to load the image in the href of an anchor link in a modal window. | ||
|
||
```html | ||
<a href="http://www.zaneray.com/proto/images/flatheadsunset.jpg" data-toggle="modal-image">Open horizontal Image Modal </a> | ||
``` | ||
|
||
### Modal Videos | ||
|
||
Specify a data-toggle of modal-video to dynamically load the video. It is required to specify a data-key as well as a data-source which at the moment only includes Youtube and Vimeo. It is recommended to make the href a link to the URL of the video for Accessbility reasons. | ||
|
||
```html | ||
<a href="https://vimeo.com/74980365" data-key="74980365" data-source="Vimeo" data-toggle="modal-video">Open Vimeo Video</a> | ||
``` | ||
|
||
### Additional Classes | ||
|
||
If you need to override the styling of a modal window you can always specify a custom class with data-class attribute. | ||
|
||
```html | ||
<a href="http://www.zaneray.com/proto/images/flatheadsunset.jpg" data-toggle="modal-image" data-class="my-additional-class">Open Image with Custom Class </a> | ||
``` | ||
|
||
### Closing the modal window | ||
|
||
Pressing escape will close the Modal window for all dynamically created modal windows not including standard inline Bootstrap Modals. Click outside the modal | ||
window will also close the modal. | ||
|
||
The hidden.bs.modal event is bound to remove the modal from the DOM upon close |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,252 @@ | ||
'use strict'; | ||
|
||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
|
||
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } | ||
|
||
var $ = _interopDefault(require('jquery')); | ||
|
||
/** | ||
* | ||
* @export | ||
*/ | ||
function onLoad(){ | ||
bindActions(); | ||
closeModalOnEscape(); | ||
} | ||
|
||
const BASE_MODAL = '<div id="dynamic-modal" class="modal fade"><div class="modal-dialog"><div class="modal-btn-close btn-close" data-dismiss="modal"></div><div id="modal-content" class="modal-content"></div></div></div>'; | ||
|
||
/** | ||
* Checks to see if the modal by ID is already in the dom. If so, uses it | ||
* If not, inserts after the opening body tag | ||
* | ||
* @export | ||
* @param {*} html the HTML to inject in to the modal content area | ||
* @param {*} classname a classname to add to the modal element | ||
*/ | ||
function generateModalTemplate(html, className){ | ||
let modal = getModal(); | ||
|
||
if (!modal){ | ||
document.body.insertAdjacentHTML('afterbegin', BASE_MODAL); | ||
modal = getModal(); | ||
} | ||
|
||
if (html) { | ||
modal.querySelector('.modal-content').innerHTML = html.outerHTML; | ||
} | ||
|
||
if (className) { | ||
className.split(' ').forEach(element => { | ||
if ( element && element.length){ | ||
modal.classList.add(element); | ||
} | ||
}); | ||
} | ||
|
||
// addEventlistener will not fire the hidden.bs.modal event due to how | ||
// bootstrap binds the events with .trigger instead of fireEvent | ||
$(modal).modal().on('hidden.bs.modal', function() { | ||
getModal().remove(); | ||
}); | ||
} | ||
|
||
function getModal(){ | ||
return document.getElementById('dynamic-modal'); | ||
} | ||
|
||
function getModalContent(){ | ||
return getModal().querySelector('.modal-content'); | ||
} | ||
|
||
/** | ||
* Finds all DOM elements with data-toggle and hooks their | ||
* click even to trigger the appropriate method | ||
* based on the data-toggle value. | ||
* | ||
* The data-toggle value is lowercased, and has hyphens | ||
* removed, and then the Element is passed to that function | ||
* | ||
* Because there could be other data-toggle's on the page | ||
* for accordions, etc, we make sure that we only preventDefault | ||
* and stopPropagation when we know we have a link that | ||
* we want to handle. | ||
*/ | ||
function bindActions() { | ||
document.body.addEventListener('click', (evt) => { | ||
evt = evt || window.event; | ||
if (evt.target !== evt.currentTarget){ | ||
if (!evt.target.hasAttribute('data-toggle')) return; | ||
const modalType = String(evt.target.dataset.toggle.replace(/-/g,'')).toLowerCase(); | ||
console.log(modalType); | ||
switch (modalType){ | ||
case 'modalhtml': { | ||
evt.preventDefault(); | ||
modalhtml(evt.target); | ||
evt.stopPropagation(); | ||
break; | ||
} | ||
case 'modalajax': { | ||
evt.preventDefault(); | ||
modalajax(evt.target); | ||
evt.stopPropagation(); | ||
break; | ||
} | ||
case 'modalvideo': { | ||
evt.preventDefault(); | ||
modalvideo(evt.target); | ||
evt.stopPropagation(); | ||
break; | ||
} | ||
case 'modalimage': { | ||
evt.preventDefault(); | ||
modalimage(evt.target); | ||
evt.stopPropagation(); | ||
break; | ||
} | ||
default: | ||
console.log(`${modalType} not a valid modal-extras data-toggle, skipping`); | ||
break; | ||
} | ||
} | ||
}); | ||
} | ||
|
||
/** | ||
* Adds an event listener to the document to check to see | ||
* that the key pressed is the escape key. If so, and if | ||
* the modal element is visible, it triggers a click | ||
* on the modals btn-close link | ||
*/ | ||
function closeModalOnEscape() { | ||
document.addEventListener('keyup', (evt) => { | ||
evt = evt || window.event; | ||
var isEscape = false; | ||
if ("key" in evt) { | ||
isEscape = (evt.key == "Escape" || evt.key == "Esc"); | ||
} else { | ||
isEscape = (evt.keyCode == 27); | ||
} | ||
const modal = getModal(); | ||
if (isEscape && modal && !modal.hidden) { | ||
modal.querySelector('.modal-btn-close').click(); | ||
} | ||
}); | ||
} | ||
|
||
/** | ||
* Bind all links that open a modal from an | ||
* HTML element that lives in the current page | ||
* | ||
* @param {*} el the HTML object that was clicked | ||
*/ | ||
function modalhtml(el){ | ||
let html = ''; | ||
const id = el.dataset.id; | ||
const clazz = el.dataset.class || ''; | ||
const targetElement = document.getElementById(id); | ||
|
||
if(targetElement){ | ||
html = targetElement.cloneNode(true); | ||
html.id = html.id + '-modal'; | ||
} | ||
|
||
generateModalTemplate(html, clazz); | ||
} | ||
|
||
/** | ||
* Content is loaded from an ajax call | ||
* | ||
* @param {*} el the HTML object that was clicked | ||
*/ | ||
function modalajax(el){ | ||
let pageURL = el.href; | ||
const clazz = el.dataset.class || ''; | ||
const contentId = el.dataset.id; | ||
const unwrap = el.dataset.unwrap || false; | ||
|
||
generateModalTemplate('', 'modal-ajax modal-loading ' + clazz); | ||
|
||
fetch(pageURL).then(response =>{ | ||
if (!response.ok) { | ||
throw Error(response.statusText); | ||
} | ||
return response.text(); | ||
}).then(html => { | ||
let inject = html; | ||
if(typeof contentId !== 'undefined') { | ||
const parser = new DOMParser(); | ||
const doc = parser.parseFromString(html, "text/html"); | ||
try { | ||
inject = unwrap ? doc.querySelector(contentId).innerHTML : doc.querySelector(contentId).outerHTML; | ||
} | ||
catch(e){ | ||
inject = `id='${contentId}' was not found in the response from ${pageURL}`; | ||
} | ||
} | ||
getModalContent().innerHTML = inject; | ||
getModal().classList.remove('modal-loading'); | ||
}) | ||
.catch(err => { | ||
console.log(err); | ||
alert('there was an error loading the URL'); | ||
getModal().remove(); | ||
}); | ||
|
||
} | ||
|
||
/** | ||
* Content is a video coming either from YouTube or Vimeo. | ||
* | ||
* @param {*} el the HTML object that was clicked | ||
*/ | ||
function modalvideo(el) { | ||
const clazz = el.dataset.class || ''; | ||
const videoSource = el.dataset.source; | ||
const videoKey = el.dataset.key; | ||
let videoHTML, embedURL; | ||
|
||
switch (videoSource.toLowerCase()) { | ||
case 'vimeo': | ||
embedURL = `https://player.vimeo.com/video/${videoKey}?autoplay=1&title=0&byline=0&portrait=0`; | ||
break; | ||
case 'youtube': | ||
embedURL = `https://www.youtube.com/embed/${videoKey}?rel=0&showinfo=0&autoplay=1`; | ||
break; | ||
default: | ||
alert(`The video source '${videoKey}' is not valid (must be vimeo or youtube)`); | ||
} | ||
|
||
videoHTML = `<div class="modal-video-wrapper"><iframe src="${embedURL}" class="modal-video-iframe" width="720" height="405" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></div>`; | ||
const videoElement = document.createElement('div'); | ||
videoElement.innerHTML = videoHTML; | ||
generateModalTemplate(videoElement.firstChild, 'modal-video ' + clazz); | ||
} | ||
|
||
/** | ||
* Content is image(s) on the page or | ||
* coming from Instagram | ||
* | ||
* @param {*} el the HTML object that was clicked | ||
*/ | ||
function modalimage(el) { | ||
const $this = $(el); | ||
const clazz = el.dataset.class || ''; | ||
const img = new Image(); | ||
img.title = el.title || ''; | ||
img.id = 'modal-image'; | ||
img.classList.add('modal-image'); | ||
img.addEventListener('load', function() { | ||
getModal().classList.remove('modal-loading'); | ||
}, false); | ||
img.src = el.href; | ||
|
||
generateModalTemplate(img, 'modal-image-wrapper modal-loading ' + clazz); | ||
|
||
/* TODO add more functionality */ | ||
|
||
} | ||
|
||
exports.onLoad = onLoad; | ||
exports.generateModalTemplate = generateModalTemplate; |
Empty file.
Oops, something went wrong.