mailymaily/src/mailymaily.js

1074 lines
33 KiB
JavaScript
Raw Normal View History

2020-08-29 14:38:25 +00:00
// Let's not step on anybody else's toes.
2020-08-29 11:59:02 +00:00
var mailymailyApp = mailymailyApp || {};
2020-08-29 11:55:43 +00:00
(function(app) {
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* The html element.
* @type {Element}
*/
2020-08-29 14:38:25 +00:00
var html = document.getElementsByTagName('html')[0];
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* The body element.
* @type {Element}
*/
2020-08-29 14:38:25 +00:00
var body = document.getElementsByTagName('body')[0];
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:59:02 +00:00
* The active mailymaily modal.
2020-08-29 11:55:43 +00:00
* @type {Element}
*/
2020-08-29 14:38:25 +00:00
var modal = null;
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* List of focusable elements within modal.
* @type {String}
*/
2020-08-29 14:38:25 +00:00
var focusable = 'a[href], button:not([disabled]), [tabindex]:not([tabindex="-1"])';
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* The last document element to have focus before the modal was opened.
* Focus is to be set back on this element after the modal is closed.
* @type {Element}
*/
2020-08-29 14:38:25 +00:00
var lastDocElementFocused = null;
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* The default svg icon for email client buttons.
* @type {String}
*/
2020-08-29 14:38:25 +00:00
var worldSvg = `<svg viewBox="0 0 24 24"><g class="nc-icon-wrapper" stroke-linecap="square" stroke-linejoin="miter" stroke-width="2" fill="currentColor" stroke="currentColor"><path data-cap="butt" data-color="color-2" fill="none" stroke-miterlimit="10" d="M5.704,2.979 c0.694,0.513,1.257,1.164,1.767,2.02C7.917,5.746,8.908,7.826,8,9c-1.027,1.328-4,1.776-4,3c0,0.921,1.304,1.972,2,3 c1.047,1.546,0.571,3.044,0,4c-0.296,0.496-0.769,0.92-1.293,1.234" stroke-linecap="butt"/> <path data-cap="butt" data-color="color-2" fill="none" stroke-miterlimit="10" d="M20.668,5.227 C18.509,6.262,15.542,6.961,15,7c-1.045,0.075-1.2-0.784-2-2c-0.6-0.912-2-2.053-2-3c0-0.371,0.036-0.672,0.131-0.966" stroke-linecap="butt"/> <circle fill="none" stroke="currentColor" stroke-miterlimit="10" cx="12" cy="12" r="11"/> <path data-cap="butt" data-color="color-2" fill="none" stroke-miterlimit="10" d="M19.014,12.903 C19.056,15.987,15.042,19.833,13,19c-1.79-0.73-0.527-2.138-0.986-6.097c-0.191-1.646,1.567-3,3.5-3S18.992,11.247,19.014,12.903z" stroke-linecap="butt"/></g></svg>`;
2020-08-29 11:55:43 +00:00
2020-08-29 15:16:31 +00:00
/**
* The svg icon for outlook web.
* @type {String}
*/
var outlookSvg = `<svg viewBox="0 0 48 48" width="48px" height="48px" style="vertical-align:middle"><path fill="#03A9F4" d="M21,31c0,1.104,0.896,2,2,2h17c1.104,0,2-0.896,2-2V16c0-1.104-0.896-2-2-2H23c-1.104,0-2,0.896-2,2V31z"/><path fill="#B3E5FC" d="M42,16.975V16c0-0.428-0.137-0.823-0.367-1.148l-11.264,6.932l-7.542-4.656L22.125,19l8.459,5L42,16.975z"/><path fill="#0277BD" d="M27 41.46L6 37.46 6 9.46 27 5.46z"/><path fill="#FFF" d="M21.216,18.311c-1.098-1.275-2.546-1.913-4.328-1.913c-1.892,0-3.408,0.669-4.554,2.003c-1.144,1.337-1.719,3.088-1.719,5.246c0,2.045,0.564,3.714,1.69,4.986c1.126,1.273,2.592,1.91,4.378,1.91c1.84,0,3.331-0.652,4.474-1.975c1.143-1.313,1.712-3.043,1.712-5.199C22.869,21.281,22.318,19.595,21.216,18.311z M19.049,26.735c-0.568,0.769-1.339,1.152-2.313,1.152c-0.939,0-1.699-0.394-2.285-1.187c-0.581-0.785-0.87-1.861-0.87-3.211c0-1.336,0.289-2.414,0.87-3.225c0.586-0.81,1.368-1.211,2.355-1.211c0.962,0,1.718,0.393,2.267,1.178c0.555,0.795,0.833,1.895,0.833,3.31C19.907,24.906,19.618,25.968,19.049,26.735z"/></svg>`;
2020-08-29 15:16:31 +00:00
/**
* The svg icon for gmail.
* @type {String}
*/
var gmailSvg = `<svg viewBox="0 0 48 48" width="48px" height="48px" style="vertical-align:middle"><path fill="#e0e0e0" d="M5.5,40.5h37c1.933,0,3.5-1.567,3.5-3.5V11c0-1.933-1.567-3.5-3.5-3.5h-37C3.567,7.5,2,9.067,2,11v26C2,38.933,3.567,40.5,5.5,40.5z"/><path fill="#d9d9d9" d="M26,40.5h16.5c1.933,0,3.5-1.567,3.5-3.5V11c0-1.933-1.567-3.5-3.5-3.5h-37C3.567,7.5,2,9.067,2,11L26,40.5z"/><path fill="#eee" d="M6.745,40.5H42.5c1.933,0,3.5-1.567,3.5-3.5V11.5L6.745,40.5z"/><path fill="#e0e0e0" d="M25.745,40.5H42.5c1.933,0,3.5-1.567,3.5-3.5V11.5L18.771,31.616L25.745,40.5z"/><path fill="#ca3737" d="M42.5,9.5h-37C3.567,9.5,2,9.067,2,11v26c0,1.933,1.567,3.5,3.5,3.5H7V12h34v28.5h1.5c1.933,0,3.5-1.567,3.5-3.5V11C46,9.067,44.433,9.5,42.5,9.5z"/><path fill="#f5f5f5" d="M42.5,7.5H24H5.5C3.567,7.5,2,9.036,2,11c0,1.206,1.518,2.258,1.518,2.258L24,27.756l20.482-14.497c0,0,1.518-1.053,1.518-2.258C46,9.036,44.433,7.5,42.5,7.5z"/><path fill="#e84f4b" d="M43.246,7.582L24,21L4.754,7.582C3.18,7.919,2,9.297,2,11c0,1.206,1.518,2.258,1.518,2.258L24,27.756l20.482-14.497c0,0,1.518-1.053,1.518-2.258C46,9.297,44.82,7.919,43.246,7.582z"/></svg>`;
2020-08-29 15:16:31 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* The default svg icon for default email app button.
* @type {String}
*/
var uiSvg = `<svg viewBox="0 0 32 32" style="vertical-align:middle"><path d="M 3 8 L 3 26 L 29 26 L 29 8 Z M 7.3125 10 L 24.6875 10 L 16 15.78125 Z M 5 10.875 L 15.4375 17.84375 L 16 18.1875 L 16.5625 17.84375 L 27 10.875 L 27 24 L 5 24 Z"/></svg>`;
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* The default svg icon for copy button.
* @type {String}
*/
var clipboardSvg = `<svg viewBox="0 0 32 32" style="vertical-align:middle"><path d="M 16 3 C 14.742188 3 13.847656 3.890625 13.40625 5 L 6 5 L 6 28 L 26 28 L 26 5 L 18.59375 5 C 18.152344 3.890625 17.257813 3 16 3 Z M 16 5 C 16.554688 5 17 5.445313 17 6 L 17 7 L 20 7 L 20 9 L 12 9 L 12 7 L 15 7 L 15 6 C 15 5.445313 15.445313 5 16 5 Z M 8 7 L 10 7 L 10 11 L 22 11 L 22 7 L 24 7 L 24 26 L 8 26 Z"/></svg>`;
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:59:02 +00:00
* User options to change mailymaily's behavior and/or appearance.
2020-08-29 11:55:43 +00:00
* @type {Object}
*/
2020-08-29 14:38:25 +00:00
var options = new Object();
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Allows for a custom class to namespace css classes.
* @type {String}
*/
2020-08-29 14:38:25 +00:00
options.linkClass = 'mailymaily';
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* When set to true, the modal is closed automatically when email client is clicked.
* @type {Boolean}
*/
2020-08-29 14:38:25 +00:00
options.autoClose = true;
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* When set to true, the modal is not displayed on mobile devices, and the local email app is used automatically.
* @type {Boolean}
*/
2020-08-29 14:38:25 +00:00
options.disableOnMobile = true;
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* The modal title.
* @type {String}
*/
2020-08-29 15:16:31 +00:00
options.title = 'Neue E-Mail schreiben mit';
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Text for button 1.
* @type {String}
*/
2020-08-29 15:16:31 +00:00
options.buttonText1 = 'Gmail';
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Text for button 2.
* @type {String}
*/
2020-08-29 15:16:31 +00:00
options.buttonText2 = 'Outlook Web';
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Text for button 4.
* @type {String}
*/
2020-08-29 15:16:31 +00:00
options.buttonText4 = 'Standardanwendung';
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* URL of svg file used as icon for button 1.
* @type {String}
*/
2020-08-29 15:16:31 +00:00
options.buttonIcon1 = gmailSvg;
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* URL of svg file used as icon for button 2.
* @type {String}
*/
2020-08-29 15:16:31 +00:00
options.buttonIcon2 = outlookSvg;
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* URL of svg file used as icon for button 3.
* @type {String}
*/
2020-08-29 14:38:25 +00:00
options.buttonIcon3 = worldSvg;
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* URL of svg file used as icon for button 4.
* @type {String}
*/
2020-08-29 14:38:25 +00:00
options.buttonIcon4 = uiSvg;
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* URL of svg file used as icon for Copy button.
* @type {String}
*/
2020-08-29 14:38:25 +00:00
options.buttonIconCopy = clipboardSvg;
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Text for Copy button.
* @type {String}
*/
2020-08-29 15:16:31 +00:00
options.buttonTextCopy = 'Kopieren';
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Text for Copy button when clicked.
* @type {String}
*/
2020-08-29 15:16:31 +00:00
options.buttonTextCopyAction = 'Kopiert!';
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Keep track of the page's scroll position.
* @type {Number}
*/
2020-08-29 14:38:25 +00:00
var scrollPosition = 0;
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Keep track of the page's original scroll behavior.
* @type {String}
*/
2020-08-29 14:38:25 +00:00
var scrollBehavior = 'auto';
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Build a style tag with default styling to be embedded on the page.
*
* @return {String} The style tag markup.
*/
2020-08-29 14:38:25 +00:00
app.buildStyleTag = function() {
var styleTag = document.createElement('style');
var css = `___css_inserter___`;
2020-08-29 14:38:25 +00:00
css = css.replace(/mailymaily/g, app.prefix());
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
styleTag.setAttribute('id', app.prefix('-styles'));
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
if (styleTag.styleSheet) {
// Required for IE8 and below.
styleTag.styleSheet.cssText = css;
} else {
styleTag.appendChild(document.createTextNode(css));
}
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
return styleTag;
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Embed style tag on the page.
*/
2020-08-29 14:38:25 +00:00
app.embedStyleTag = function() {
if (app.styleTagExists()) {
return;
}
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
var firstHeadChild = document.head.firstChild;
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
document.head.insertBefore(app.buildStyleTag(), firstHeadChild);
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Check if style tag has already been embedded on the page.
*
* @return {Boolean} True if style tag is already embedded.
*/
2020-08-29 14:38:25 +00:00
app.styleTagExists = function() {
if (document.getElementById(app.prefix('-styles'))) {
return true;
}
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
return false;
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Build the modal markup.
*
* @return {String} The modal markup.
*/
2020-08-29 14:38:25 +00:00
app.buildModal = function() {
var modal = document.createElement('div');
var markup = `___html_inserter___`;
2020-08-29 14:38:25 +00:00
markup = markup.replace(/mailymaily/g, app.prefix());
modal.setAttribute('id', app.prefix('-modal'));
modal.setAttribute('class', app.prefix('-modal'));
modal.setAttribute('style', 'display: none;');
modal.setAttribute('aria-hidden', true);
modal.innerHTML = markup;
return modal;
};
/**
2020-08-29 11:55:43 +00:00
* Embed modal on the page.
*/
2020-08-29 14:38:25 +00:00
app.embedModal = function() {
if (app.modalExists()) {
return;
}
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
var modal = app.buildModal();
var firstBodyChild = document.body.firstChild;
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
document.body.insertBefore(modal, firstBodyChild);
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Check if modal markup has already been embedded on page.
*
* @return {Boolean} True if modal markup ia already embedded.
*/
2020-08-29 14:38:25 +00:00
app.modalExists = function() {
if (document.getElementById(app.prefix('-modal'))) {
return true;
}
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
return false;
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Get modal populated with data from the given link.
*
* @param {Element} link The link that was clicked.
* @return {Element} The modal associated with the given link.
*/
2020-08-29 14:38:25 +00:00
app.getModal = function(link) {
app.hydrateModal(link);
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
return document.getElementById(app.prefix('-modal'));
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Populate current modal with data from the link that was clicked.
*
* @param {Element} link The link that was clicked.
*/
2020-08-29 14:38:25 +00:00
app.hydrateModal = function(link) {
var email = app.getEmail(link);
var subject = app.getLinkField(link, 'subject');
var cc = app.getLinkField(link, 'cc');
var bcc = app.getLinkField(link, 'bcc');
var body = app.getLinkField(link, 'body');
var gmail = document.getElementById(app.prefix('-button-1'));
gmail.href = `https://mail.google.com/mail/?view=cm&fs=1&to=${email}&su=${subject}&cc=${cc}&bcc=${bcc}&body=${body}`;
2020-08-29 14:38:25 +00:00
var outlook = document.getElementById(app.prefix('-button-2'));
outlook.href = `https://outlook.office.com/owa/?path=/mail/action/compose&to=${email}&subject=${subject}&body=${body}`;
var defaultApp = document.getElementById(app.prefix('-button-4'));
defaultApp.href = `mailto:${email}?subject=${subject}&cc=${cc}&bcc=${bcc}&body=${body}`;
var emailField = document.getElementById(app.prefix('-email-address'));
emailField.innerHTML = email;
var buttonIcon1 = document.getElementById(app.prefix('-button-icon-1'));
buttonIcon1.innerHTML = options.buttonIcon1;
var buttonIcon2 = document.getElementById(app.prefix('-button-icon-2'));
buttonIcon2.innerHTML = options.buttonIcon2;
var buttonIcon4 = document.getElementById(app.prefix('-button-icon-4'));
buttonIcon4.innerHTML = options.buttonIcon4;
var buttonIconCopy = document.getElementById(app.prefix('-button-icon-copy'));
buttonIconCopy.innerHTML = options.buttonIconCopy;
app.toggleHideCopyUi(email);
};
/**
2020-08-29 11:55:43 +00:00
* When the modal is displayed, the "no-scroll" class sets the body's position to fixed. This has the
* side effect of the page getting scrolled to the top. To counter that, we need to save the scroll
* position when the modal is displayed, so it can be restored later on when the modal is closed.
*/
2020-08-29 14:38:25 +00:00
app.savePageScrollPosition = function() {
scrollPosition = window.pageYOffset;
body.style.top = -scrollPosition + 'px';
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* When the modal is closed, we need to reset the page scroll position. Needed due to
* the position:fixed being set by the "no-scroll" class on the body element when
* the modal is open. Refer to savePageScrollPosition() method for details.
*/
2020-08-29 14:38:25 +00:00
app.restorePageScrollPosition = function() {
window.scrollTo(0, scrollPosition);
body.style.top = 0;
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Save the page's current scroll behavior AND set it to auto, in case the current
* scroll behavior is set to smooth. This prevents smooth scrolling from showing
* when scrollPosition is restored via restorePageScrollPosition() method.
*/
2020-08-29 14:38:25 +00:00
app.saveScrollBehavior = function() {
scrollBehavior = html.style.scrollBehavior;
html.style.scrollBehavior = 'auto';
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Restore the original page scroll behavior saved by saveScrollBehavior().
*/
2020-08-29 14:38:25 +00:00
app.restoreScrollBehavior = function() {
html.style.scrollBehavior = scrollBehavior;
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Save the last doc element to have focus before displaying modal,
* so that we can reset focus to it when the modal is closed.
*/
2020-08-29 14:38:25 +00:00
app.saveLastDocElementFocused = function() {
lastDocElementFocused = document.activeElement;
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Open modal.
*
* @param {Object} event The object created by the event.
*/
2020-08-29 14:38:25 +00:00
app.openModal = function(event) {
if (options.disableOnMobile && app.isMobileDevice()) {
return;
}
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
event.preventDefault();
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
app.saveLastDocElementFocused();
app.savePageScrollPosition();
app.saveScrollBehavior();
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
app.displayModal(event);
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
app.hideModalFromScreenReader(false);
app.enablePageScrolling(false);
app.modalFocus();
app.triggerEvent(modal, 'open');
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Display modal and carry out other tasks needed when modal is open.
*
* @param {Object} event The object created by the event.
*/
2020-08-29 14:38:25 +00:00
app.displayModal = function(event) {
var link = app.getParentElement(event.target, 'a');
modal = app.getModal(link);
modal.style.display = 'block';
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Set focus on the first button in the modal.
*/
2020-08-29 14:38:25 +00:00
app.modalFocus = function() {
modal.focusableChildren = Array.from(modal.querySelectorAll(focusable));
modal.focusableChildren[1].focus();
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Close modal.
*
* @param {Object} event The object created by the event.
*/
2020-08-29 14:38:25 +00:00
app.closeModal = function(event) {
event.preventDefault();
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
app.hideModal();
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
app.enablePageScrolling(true);
app.restorePageScrollPosition();
app.restoreScrollBehavior();
app.docRefocus();
app.triggerEvent(modal, 'close');
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Hide modal.
*/
2020-08-29 14:38:25 +00:00
app.hideModal = function() {
app.hideModalFromScreenReader(true);
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
if (app.isDefined(modal)) {
modal.style.display = 'none';
}
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Set aria attributes to hide modal from screen readers.
*
* @param {Boolean} hidden True to hide modal from screen reader. False otherwise.
*/
2020-08-29 14:38:25 +00:00
app.hideModalFromScreenReader = function(hidden) {
if (app.isDefined(modal)) {
modal.setAttribute('aria-hidden', hidden);
}
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Toggle a css class to enable/disable page scrolling.
*
* @param {Boolean} enabled True to enable page scrolling. False to disable it.
*/
2020-08-29 14:38:25 +00:00
app.enablePageScrolling = function(enabled) {
if (enabled) {
body.classList.remove(app.prefix('-no-scroll'));
html.classList.remove(app.prefix('-no-scroll'));
} else {
body.classList.add(app.prefix('-no-scroll'));
html.classList.add(app.prefix('-no-scroll'));
}
};
/**
2020-08-29 11:55:43 +00:00
* Set focus back on the last element focused on the page.
*/
2020-08-29 14:38:25 +00:00
app.docRefocus = function() {
lastDocElementFocused.focus();
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Open the given client link element.
*
* @param {Element} element The client link that was clicked.
* @param {Object} event The object created by the event.
*/
2020-08-29 14:38:25 +00:00
app.openClient = function(element, event) {
var target = '_blank';
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
if (app.isDefaultEmailAppButton(element)) {
target = '_self';
}
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
window.open(element.href, target);
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
app.triggerEvent(element, 'compose');
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
if (options.autoClose) {
app.closeModal(event);
}
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Determine if the given element is the Default Email App button.
*
* @param {Element} element The element to be checked.
* @return {Boolean} True if the given element's id corresponds to button 4.
*/
2020-08-29 14:38:25 +00:00
app.isDefaultEmailAppButton = function(element) {
return element.id == app.prefix('-button-4');
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* When an anchor tag (<a>) contains other elements, the element returned can vary
* depending on where you click. We need to search up the DOM tree until we find
* the parent anchor tag, which is the element that was intended to be clicked.
*
* @param {Element} element The element that was clicked.
* @return {Element} The parent anchor tag of the element that was clicked.
*/
2020-08-29 14:38:25 +00:00
app.getParentElement = function(element, parentTag) {
while (element !== null) {
if (element.tagName.toUpperCase() == parentTag.toUpperCase()) {
return element;
}
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
element = element.parentNode;
}
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
return null;
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Fire up an event for the given element.
*
* @param {Element} element Trigger event for this element.
* @param {String} eventName The name of the event to be triggered.
*/
2020-08-29 14:38:25 +00:00
app.triggerEvent = function(element, eventName) {
var event = new Event(eventName);
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
element.dispatchEvent(event);
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Check if device is a mobile phone or tablet.
*/
2020-08-29 14:38:25 +00:00
app.isMobileDevice = function() {
var check = false;
(function(a) {
if (
/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(
a
) ||
/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(
a.substr(0, 4)
)
) {
check = true;
}
})(navigator.userAgent || navigator.vendor || window.opera);
return check;
};
/**
2020-08-29 11:55:43 +00:00
* Listen for events.
*/
2020-08-29 14:38:25 +00:00
app.listenForEvents = function() {
app.listenForClickOnLink();
app.listenForClickOnClient();
app.listenForClickOnCopy();
app.listenForClickOnClose();
app.listenForClickOnWindow();
app.listenForKeys();
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Listen for click event on mailto links.
*/
2020-08-29 14:38:25 +00:00
app.listenForClickOnLink = function() {
var links = document.getElementsByClassName(app.prefix());
for (var i = 0; i < links.length; i++) {
links[i].addEventListener(
'click',
function(event) {
app.openModal(event);
},
false
);
}
};
/**
2020-08-29 11:55:43 +00:00
* Listen for click event on client links.
*/
2020-08-29 14:38:25 +00:00
app.listenForClickOnClient = function() {
var clients = document.getElementsByClassName(app.prefix('-button'));
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
for (var i = 0; i < clients.length; i++) {
clients[i].addEventListener(
'click',
function(event) {
event.preventDefault();
event.stopPropagation();
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
var client = app.getParentElement(event.target, 'a');
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
app.openClient(client, event);
},
false
);
}
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Listen for click event on Copy button.
*/
2020-08-29 14:38:25 +00:00
app.listenForClickOnCopy = function() {
var copyButton = document.getElementById(app.prefix('-button-copy'));
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
copyButton.addEventListener(
'click',
function(event) {
app.copy(event);
},
false
);
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Listen for click event on Close button.
*/
2020-08-29 14:38:25 +00:00
app.listenForClickOnClose = function() {
var closeButton = document.getElementById(app.prefix('-modal-close'));
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
closeButton.addEventListener(
'click',
function(event) {
app.closeModal(event);
},
false
);
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Listen for click event on window (to close modal).
*/
2020-08-29 14:38:25 +00:00
app.listenForClickOnWindow = function() {
window.addEventListener(
'click',
function(event) {
var element = event.target;
if (element !== null && element.classList.contains(app.prefix('-modal'))) {
app.closeModal(event);
}
},
false
);
};
/**
2020-08-29 11:55:43 +00:00
* Listen for keydown events to escape modal or tab within it.
*/
2020-08-29 14:38:25 +00:00
app.listenForKeys = function() {
document.addEventListener(
'keydown',
function(event) {
app.escapeModal(event);
app.trapTabWithinModal(event);
},
false
);
};
/**
2020-08-29 11:55:43 +00:00
* Close modal when Esc key is pressed.
*
* @param {KeyboardEvent} event The event generated by pressing a key.
*/
2020-08-29 14:38:25 +00:00
app.escapeModal = function(event) {
if (event.keyCode === 27) {
app.closeModal(event);
}
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Should not be able to tab outside the modal. Pressing the tab
* key moves focus to the next focusable element within modal.
*
* @param {KeyboardEvent} event The event generated by pressing a key.
*/
2020-08-29 14:38:25 +00:00
app.trapTabWithinModal = function(event) {
if (event.keyCode === 9 && modal !== null) {
var currentFocus = document.activeElement;
var totalFocusable = modal.focusableChildren.length;
var focusedIndex = modal.focusableChildren.indexOf(currentFocus);
if (event.shiftKey) {
if (focusedIndex === 0) {
event.preventDefault();
modal.focusableChildren[totalFocusable - 1].focus();
}
} else {
if (focusedIndex == totalFocusable - 1) {
event.preventDefault();
modal.focusableChildren[0].focus();
}
}
}
};
/**
2020-08-29 11:59:02 +00:00
* Get all "mailymaily" links on the page.
2020-08-29 11:55:43 +00:00
*
2020-08-29 11:59:02 +00:00
* @return {HTMLCollection} All links with the class "mailymaily" (default).
2020-08-29 11:55:43 +00:00
*/
2020-08-29 14:38:25 +00:00
app.getLinks = function() {
return document.getElementsByClassName(app.prefix());
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Split the URL scheme of given link in two strings: the email address, and the
* key-value query string. Also remove 'mailto:' to get nice clean values.
*
* @param {Element} link The link element clicked.
* @return {Array} The two parts of the link scheme separated at '?'.
*/
2020-08-29 14:38:25 +00:00
app.splitLink = function(link) {
var scheme = link.href.replace('mailto:', '').trim();
var parts = scheme.split('?', 1);
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
if (parts !== null && parts.length > 0) {
parts[1] = scheme.replace(parts[0] + '?', '').trim();
}
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
return parts;
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Extract the value of the given field from the link.
*
* @param {Element} link The link element clicked.
* @param {String} field The name of the field we want to get.
* @return {String} The value corresponding to the given field.
*/
2020-08-29 14:38:25 +00:00
app.getLinkField = function(link, field) {
var parts = app.splitLink(link);
var query = '';
var terms = [];
var keyValues = [];
var value = '';
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
if (parts !== null && parts.length > 0) {
query = parts[1];
}
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
if (query !== null && query.length > 0) {
// Encode any instance of ' & ' inside field values to prevent spliting at the wrong place.
query = query.replace('%20&%20', '%20%26%20');
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
terms = query.split('&');
}
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
for (var i = 0; i < terms.length; i++) {
// Encode any instance of ' = ' inside field values to prevent spliting at the wrong place.
terms[i] = terms[i].replace('%20=%20', '%20%3D%20');
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
keyValues = terms[i].split('=');
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
for (var n = 0; n < keyValues.length; n++) {
if (keyValues[0] == field) {
return keyValues[1];
}
}
}
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
return value;
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Extract email address from mailto string.
*
* @param {Element} link The link element clicked.
* @return {String} The email address.
*/
2020-08-29 14:38:25 +00:00
app.getEmail = function(link) {
var parts = app.splitLink(link);
var email = '';
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
if (parts !== null && parts.length > 0) {
email = parts[0];
}
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
return decodeURIComponent(email);
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Build and return the class name used to hide the Copy UI.
*
* @return {String} The CSS class name needed to hide the Copy UI.
*/
2020-08-29 14:38:25 +00:00
app.getClassHideCopyUi = function() {
return app.prefix('-is-hidden');
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Show or hide the Copy UI based on email address presence.
*
* @param {String} email The email address to be checked.
*/
2020-08-29 14:38:25 +00:00
app.toggleHideCopyUi = function(email) {
var copyUi = document.getElementById(app.prefix('-copy'));
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
if (email.length == 0) {
copyUi.classList.add(app.getClassHideCopyUi());
} else {
copyUi.classList.remove(app.getClassHideCopyUi());
}
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Set copy button text to indicate the email address has been copied.
*/
2020-08-29 14:38:25 +00:00
app.toggleCopyButton = function() {
button = document.getElementById(app.prefix('-button-copy'));
buttonText = document.getElementById(app.prefix('-button-text-copy'));
buttonText.innerHTML = options.buttonTextCopyAction;
button.classList.add(app.prefix('-button-copy-clicked'));
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
setTimeout(function() {
buttonText.innerHTML = options.buttonTextCopy;
button.classList.remove(app.prefix('-button-copy-clicked'));
}, 600);
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Copy email address to the clipboard.
*
* @param {String} event The event generated by clicking on Copy button.
*/
2020-08-29 14:38:25 +00:00
app.copy = function(event) {
event.preventDefault();
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
var targetId = app.getParentElement(event.target, 'button').getAttribute('data-copytargetid');
var email = document.getElementById(targetId);
var range = document.createRange();
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
range.selectNodeContents(email);
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
var selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
document.execCommand('copy');
app.triggerEvent(email, 'copy');
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
app.toggleCopyButton();
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Check if device is running iOS.
*
* @return {Boolean} True if device runs iOS.
*/
2020-08-29 14:38:25 +00:00
app.isiOSDevice = function() {
return navigator.userAgent.match(/ipad|iphone/i);
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Get user options provided as an object parameter in the run
* method, or as a JSON string provided in a data attribute
* of the script tag. Save all in the options object.
*
* @param {Object} optionsObj An object containing user options.
*/
2020-08-29 14:38:25 +00:00
app.setOptions = function(optionsObj) {
if (optionsObj) {
var userOptions = JSON.stringify(optionsObj);
} else {
var userOptions = app.getOptionsFromScriptTag();
}
if (userOptions && userOptions.trim().length > 0) {
userOptions = JSON.parse(userOptions);
for (var name in options) {
if (userOptions.hasOwnProperty(name)) {
options[name] = app.sanitizeUserOption(name, userOptions[name]);
}
}
}
};
/**
2020-08-29 11:55:43 +00:00
* Clean up given user options.
*
* @param {String} name The name of the user option to be sanitized.
* @param {mixed} value The value of the user option.
* @return {mixed} The sanitized value when applicable, or the original value.
*/
2020-08-29 14:38:25 +00:00
app.sanitizeUserOption = function(name, value) {
if (app.stringContains(name, 'icon')) {
return app.validateSvg(name, value);
}
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
if (app.isString(value)) {
return app.stripHtml(value);
}
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
return value;
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Check svg file for possible problems or tampering.
*
* @param {String} name The name of an 'icon' user option (must exist in options array).
* @param {String} url The url to an svg file.
*/
2020-08-29 14:38:25 +00:00
app.validateSvg = function(name, url) {
app
.getSvg(name, url)
.then(function(promise) {
if (!app.stringIsSvg(promise.responseText)) {
throw new Error(name + ': ' + url + ' is not an SVG file.');
}
if (app.stringHasScript(promise.responseText)) {
throw new Error(name + ': ' + url + ' is an invalid SVG file.');
} else {
options[name] = promise.responseText;
}
})
.catch(function(error) {
if (name == 'buttonIconCopy') {
options[name] = clipboardSvg;
} else {
options[name] = worldSvg;
}
console.log(error);
});
};
/**
2020-08-29 11:55:43 +00:00
* Load an svg file from the given url.
*
* @param {String} name The name of an 'icon' user option (must exist in options array).
* @param {String} url The url to an svg file.
* @return {Promise} The resolved or rejected promise after ajax call to load svg file.
*/
2020-08-29 14:38:25 +00:00
app.loadSvg = function(name, url) {
return new Promise((resolve, reject) => {
var ajax = new XMLHttpRequest();
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
ajax.open('GET', url, true);
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
ajax.onload = function(event) {
if (ajax.status == 200) {
resolve(ajax);
} else {
reject(ajax);
}
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
ajax.send();
});
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Async method to load svg file from given url.
*
* @param {String} name The name of an 'icon' user option (must exist in options array).
* @param {String} url The url to an svg file.
* @return {Promise} The Promise with the result returned by loadSvg().
*/
2020-08-29 14:38:25 +00:00
app.getSvg = async function(name, url) {
return await app.loadSvg(name, url);
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Check if given value is a string.
*
* @param {mixed} value The value to be checked.
* @return {Boolean} True if value is a string. False otherwise.
*/
2020-08-29 14:38:25 +00:00
app.isString = function(value) {
return typeof value === 'string';
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Remove html tags from given string.
*
* @param {String} text The string to be stripped.
* @return {String} The given string stripped off markup tags.
*/
2020-08-29 14:38:25 +00:00
app.stripHtml = function(text) {
return text.replace(/(<([^>]+)>)/g, '');
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Check if a string contains another string ("needle in a haystack").
*
* @param {String} haystack The string where to search.
* @param {String} needle The string to search for.
* @return {Boolean} True if needle is found in haystack. False otherwise.
*/
2020-08-29 14:38:25 +00:00
app.stringContains = function(haystack, needle) {
return haystack.toLowerCase().indexOf(needle.toLowerCase()) !== -1;
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Check if given string is an svg file.
*
* @param {String} text The string to be checked.
* @return {Boolean} True if string starts with '<svg'. False otherwise.
*/
2020-08-29 14:38:25 +00:00
app.stringIsSvg = function(text) {
return text.startsWith('<svg');
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Check if given string contains an embedded <script> tag.
*
* @param {String} text The string to be checked.
* @return {Boolean} True if given string contains <script>. False otherwise.
*/
2020-08-29 14:38:25 +00:00
app.stringHasScript = function(text) {
return app.stringContains(text, '<script');
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Check if the given item is defined.
*
* @param {mixed} item The item to be checked.
* @return {Boolean} True if the given item is defined. False otherwise.
*/
2020-08-29 14:38:25 +00:00
app.isDefined = function(item) {
return typeof item !== 'undefined';
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Read options passed in the data-options attribute of the script tag.
*
* @return {String} Options string provided in JSON format.
*/
2020-08-29 14:38:25 +00:00
app.getOptionsFromScriptTag = function() {
var scripts = document.getElementsByTagName('script');
var scriptName = scripts[scripts.length - 1];
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
return scriptName.getAttribute('data-options');
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Append the linkClass user option to the given string.
*
* @param {String} text The string to which the linkClass will be appended.
* @return {String} The linkClass user option appended to the given string.
*/
2020-08-29 14:38:25 +00:00
app.prefix = function(text = '') {
return options.linkClass + text;
};
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
/**
2020-08-29 11:55:43 +00:00
* Let's kick things off.
* @param {Object} optionsObj An object containing user options.
*/
2020-08-29 14:38:25 +00:00
app.run = function(optionsObj = null) {
app.setOptions(optionsObj);
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
app.embedModal();
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
app.embedStyleTag();
2020-08-29 11:55:43 +00:00
2020-08-29 14:38:25 +00:00
app.listenForEvents();
};
2020-08-29 11:59:02 +00:00
})(mailymailyApp);
2020-08-29 11:55:43 +00:00
/**
2020-08-29 11:59:02 +00:00
* Are we loaded in the browser? If so, run mailymaily automatically.
* Otherwise, make mailymaily available to the outside world so
2020-08-29 11:55:43 +00:00
* it can be triggered (run) manually when appropriate.
*/
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
2020-08-29 14:38:25 +00:00
// We're not in the browser.
module.exports = {
run: mailymailyApp.run
};
2020-08-29 11:55:43 +00:00
} else {
2020-08-29 14:38:25 +00:00
// We're in the browser.
mailymailyApp.run();
2020-08-29 11:55:43 +00:00
}