Simple Modal Popup
Upload a file in the Ghost editor and display the file contents in a popup modal window...
... to upload the file I used the File Upload Card in the post editor ...
Now I want to display the contents of that file in a Modal Window when a link in my post is clicked...
PDF in a Modal...
Uploading a file into your Ghost post displays the file in the post like so...
HOW-TO
- This goes in the Header Code Injection...
<style>
.sp-wrapper {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgb(0, 0, 0, 0.5);
height: 100%;
width: 100%;
overflow-y: auto;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
z-index: 1000;
}
.sp-wrapper .content {
border-radius: 4px;
min-height: 100px;
max-width: 800px;
width: 90%;
background-color: #fff;
position: absolute;
margin: 1em 0;
overflow: hidden;
}
.sp-wrapper .content.into-view {
top: 0;
}
.center-all {
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.sp-source {
display: none;
}
.sp-wrapper .sp-close-button {
height: 30px;
width: 30px;
position: absolute;
top: 0;
right: 0;
background-color: #eee;
cursor: pointer;
}
.sp-wrapper .sp-close-button::before {
content: 'x';
height: auto;
width: auto;
position: absolute;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%, -50%);
-ms-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
}
.sp-wrapper.fadeIn {
-webkit-animation: fadeIn .25s both;
animation: fadeIn .25s both
}
@-webkit-keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.sp-wrapper.fadeOut {
-webkit-animation: fadeOut .25s both;
animation: fadeOut .25s both
}
@-webkit-keyframes fadeOut {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
@keyframes fadeOut {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
.sp-wrapper .fadeInDown {
-webkit-animation: fadeInDown .35s both;
animation: fadeInDown .35s both
}
@-webkit-keyframes fadeInDown {
0% {
opacity: 0;
margin-top: -20px
}
100% {
opacity: 1;
}
}
@keyframes fadeInDown {
0% {
opacity: 0;
margin-top: -20px
}
100% {
opacity: 1;
}
}
.sp-wrapper .fadeOutUp {
-webkit-animation: fadeOutUp .35s both;
animation: fadeOutUp .35s both
}
@-webkit-keyframes fadeOutUp {
0% {
opacity: 1;
}
100% {
opacity: 0;
margin-top: -20px
}
}
@keyframes fadeOutUp {
0% {
opacity: 1;
}
100% {
opacity: 0;
margin-top: -20px
}
}
.sp-wrapper .zoomIn {
-webkit-animation: zoomIn .15s both;
animation: zoomIn .15s both;
}
@-webkit-keyframes zoomIn {
0% {
opacity: 0;
-webkit-transform: scale(.95);
transform: scale(.95);
}
100% {
opacity: 1;
-webkit-transform: scale(1);
transform: scale(1);
}
}
@keyframes zoomIn {
0% {
opacity: 0;
-webkit-transform: scale(.95);
transform: scale(.95);
}
100% {
opacity: 1;
-webkit-transform: scale(1);
transform: scale(1);
}
}
.sp-wrapper .zoomOut {
-webkit-animation: zoomOut .15s both;
animation: zoomOut .15s both;
}
@-webkit-keyframes zoomOut {
0% {
opacity: 1;
-webkit-transform: scale(1);
transform: scale(1);
}
100% {
opacity: 0;
-webkit-transform: scale(.85);
transform: scale(.85);
}
}
@keyframes zoomOut {
0% {
opacity: 1;
-webkit-transform: scale(1);
transform: scale(1);
}
100% {
opacity: 0;
-webkit-transform: scale(.85);
transform: scale(.85);
}
}
</style>
2. This goes in an HTML Card in the post editor...
<a href="#" class="sp-trigger" data-target="source1">PDF in a Modal...</a>
<div class="sp-source" id="source1">
<iframe src="https://ghost-o-matic.com/content/files/2022/06/JENS-DAD-HAROLD-WALLACE.pdf" frameborder="0" style="width:100%; height:90vh; margin:0"></iframe>
</div>
3. This goes in the Footer Code Injection...
<script>
const SimplePopup = (function() {
let wrapper, instance, closeButton, content, _params, t, isAnimating = false,
animationType;
const defineProperty = (obj, prop) => {
obj = obj || {}
obj[prop] = obj[prop] || '';
return obj;
};
const centerize = () => {
// center the content's height is greater window's height
if (content.scrollHeight >= window.innerHeight) {
content.classList.add('into-view');
} else {
content.classList.remove('into-view');
}
};
function SimplePopup() {}
SimplePopup.prototype.openModal = (params, cb) => {
// set params
_params = params;
// set flag when animation in progress
isAnimating = true;
// set animation type
_params.styles = defineProperty(_params.styles, 'position');
if (_params.styles.animation) {
animationType = _params.styles.position === 'center' ? 'zoomIn' : 'fadeInDown';
}
wrapper = document.createElement('div');
wrapper.setAttribute('class', `sp-wrapper ${_params.styles.animation && 'fadeIn'} ${_params.styles.position === 'center' ? 'center-all' : ''}`);
// populate the content
content = document.createElement('div');
content.setAttribute('class', `content ${animationType}`);
const tempDiv = document.createElement('div');
tempDiv.innerHTML = params.content;
content.appendChild(tempDiv);
//apply inline style
const maxWidth = params.styles.maxWidth ? `max-width: ${params.styles.maxWidth}` : '';
const duration = params.styles.duration ? `; animation-duration:${params.styles.duration/1000}s` : '';
content.setAttribute('style', `${maxWidth}${_params.styles.animation && duration}`);
// add close button
if (_params.styles.closeButton) {
const closeButton = document.createElement('div');
closeButton.setAttribute('class', 'sp-close-button');
content.prepend(closeButton);
}
// add content to wrapper
wrapper.appendChild(content);
// add to body
document.body.prepend(wrapper);
t && clearTimeout(t);
t = setTimeout(() => {
isAnimating = false;
}, params.styles.duration);
cb && cb();
};
SimplePopup.prototype.closeModal = (e) => {
if (isAnimating) return;
const classes = e.srcElement.getAttribute('class');
if (classes && (classes.indexOf('sp-wrapper') > -1 || classes.indexOf('sp-close-button') > -1)) {
if (_params.styles.animation) {
wrapper.classList.remove('fadeIn');
wrapper.classList.add('fadeOut');
if (_params.styles.position !== 'center') {
content.classList.remove('fadeInDown');
content.classList.add('fadeOutUp');
} else {
content.classList.remove('zoomIn');
content.classList.add('zoomOut');
}
setTimeout(() => {
wrapper && wrapper.parentNode.removeChild(wrapper);
}, _params.styles.duration || 350)
} else {
wrapper.parentNode.removeChild(wrapper);
}
}
};
SimplePopup.prototype.init = (params) => {
let triggers = document.querySelectorAll('.sp-trigger');
triggers.forEach((item) => {
item.addEventListener('click', (e) => {
const target = e.target;
const id = target.getAttribute('data-target');
const source = document.querySelector(`#${id}`);
if (!source) {
alert('Error: Source unknown.')
return;
}
instance.openModal({ content: source.innerHTML, styles: params }, function() {
//load close wrapper
wrapper && wrapper.removeEventListener('click', instance.closeModal);
wrapper && wrapper.addEventListener('click', instance.closeModal);
//load close button
closeButton && closeButton.removeEventListener('click', instance.closeModal);
closeButton && closeButton.addEventListener('add', instance.closeModal);
centerize();
});
});
});
window.addEventListener('resize', () => centerize);
};
if (!instance) {
instance = new SimplePopup();
}
return instance;
})();
</script>
<script>
SimplePopup.init({
maxWidth: '500px',
duration: '200',
closeButton: true,
animation: true
});
</script>