// Dialogs replacing native browser dialogs.
/*
*/
"use strict";
var IsaDialog = (function() {
var ID_DIALOG = 'isa-dialog';
var ID_OVERLAY = 'isa-dialog-overlay';
var ID_MESSAGE = 'isa-dialog-message';
var ID_INPUT = 'isa-dialog-input';
var ID_BUTTON = 'isa-dialog-button';
var STYLES = {
PLAIN: 'header-body',
INFO: 'info',
WARNING: 'warn',
ERROR: 'error'
}
/**
* Default button click handler, only logs button press.
*/
var DEFAULT_HANDLER = function(button) {
console.log('Button pressed: ' + button);
}
var ButtonTexts = {
OK: 'OK',
Cancel: 'Cancel'
}
/**
* Create the dialog element.
*/
function createDialog() {
var dialog = this.byId(ID_DIALOG);
if (!dialog) {
var dialog = this.createElement('div');
dialog.id = ID_DIALOG;
//Dialog box
dialog.classList.add('popup');
dialog.classList.add('header-body'); //For white brackground
dialog.style['z-index'] = 101;
//Position into top center
dialog.style.position = 'absolute';
dialog.style.top = 0;
dialog.style.left = '50%';
dialog.style.transform = "translate(-50%, 0)";
dialog.style.margin = 'auto';
dialog.style['padding-left'] = '1em';
dialog.style['padding-right'] = '1em';
//Contents
var message = this.createElement('div');
message.id = ID_MESSAGE;
message.classList.add('content');
dialog.appendChild(message);
var input = this.createElement('input');
input.id = ID_INPUT;
input.classList.add('input-values');
dialog.appendChild(input);
var buttonsContainer = this.createElement('div');
buttonsContainer.classList.add('messages-buttons');
var buttons = this.createElement('ul');
buttons.id = ID_BUTTON;
buttons.classList.add('buttons-3');
buttonsContainer.appendChild(buttons);
dialog.appendChild(buttonsContainer);
for (var button in IsaDialog.Buttons) {
var buttonWrapper = this.createElement('li');
var buttonElement = this.createElement('a');
buttonElement.id = getButtonId(IsaDialog.Buttons[button]);
buttonElement.classList.add('button');
buttonElement.innerHTML = ButtonTexts[button];
buttonElement.href = '#';
buttonWrapper.appendChild(buttonElement);
buttons.appendChild(buttonWrapper);
}
}
}
/**
* Calculate the button ID for a button.
* @param button The key of the button.
* @return The calculated ID for the button.
*/
function getButtonId(button) {
return ID_BUTTON + '-' + button;
}
function updateText() {
var messageElement = this.byId(ID_MESSAGE);
//Remove old text
while (messageElement.firstChild) {
messageElement.removeChild(messageElement.firstChild);
}
var lines = this.message.split("\n");
for (var index = 0; index < lines.length; index++) {
var message = this.targetWindow.document.createTextNode(lines[index]);
messageElement.appendChild(message);
var newline = this.targetWindow.document.createElement('br');
messageElement.appendChild(newline);
}
}
/**
* Set the dialog element visible.
* @param visible true
to show the dialog, false
to hide the dialog.
*/
function showDialog(visible) {
var dialog = this.byId(ID_DIALOG);
if (!dialog) {
console.warn("Dialog shown but not created yet");
return;
}
//Update content
if (visible) {
//Update message text
updateText.call(this);
//Show/hide input field
this.byId(ID_INPUT).style.display = this.showInputField ? 'block' : 'none';
this.byId(ID_INPUT).value = ""; //Clear previous input
this.byId(ID_INPUT).placeholder = this.inputDefaultValue;
//Show/hide buttons
for (var button in IsaDialog.Buttons) {
this.byId(getButtonId(IsaDialog.Buttons[button])).style.display = 'none';
}
for (var buttonIndex = 0; buttonIndex < this.buttons.length; buttonIndex++) {
this.byId(getButtonId(this.buttons[buttonIndex])).style.display = 'inline';
}
//Update styles
for (var style in STYLES) {
dialog.classList.remove(style);
}
dialog.classList.add(STYLES[this.dialogType || IsaDialog.Types.Plain]);
}
//Display overlay
showOverlayInFrames(window.top, visible);
//Display dialog
dialog.style.display = visible ? 'block' : 'none';
}
/**
* Show the overlay in all frames of the target window. Only targets frame where the ISA dialogs module
* is available.
*
* @param targetWindow The target window.
* @param visible true
to make the overlay visible, false
to hide the overlay.
*/
function showOverlayInFrames(targetWindow, visible) {
if (typeof targetWindow.isaDialogs === 'function') {
targetWindow.isaDialogs().overlay(visible);
}
for (var index = 0; index < targetWindow.frames.length; index++) {
showOverlayInFrames(targetWindow.frames[index], visible);
}
}
/**
* Create the overlay element if it does not yet exist. The overlay is initially hidden.
*/
function createOverlay(targetWindow) {
var overlay = this.byId(ID_OVERLAY);
if (!overlay) {
overlay = this.createElement('div');
overlay.id = ID_OVERLAY;
overlay.style.display = 'none';
overlay.style.position = 'fixed';
overlay.style.top = 0;
overlay.style.left = 0;
overlay.style.width = '100%';
overlay.style.bottom = '0px';
overlay.style.opacity = '0.4';
overlay.style['background-color'] = '#000000';
overlay.style['z-index'] = 100;
}
}
/**
* Show the overlay in the target window.
*
* @param visible true
to make the overlay visible, false
to hide the overlay.
*/
function showOverlay(visible) {
var overlay = this.byId(ID_OVERLAY);
overlay.style.display = visible ? 'block' : 'none';
}
/**
* Register callback function for the current instance. Method must be called for each opened
* dialog in case the dialog object changed.
* @param callback Callback function. Called with the ID of the button the user pressed.
*/
function registerCallback() {
for (var button in IsaDialog.Buttons) {
var buttonElement = this.byId(getButtonId(IsaDialog.Buttons[button]));
buttonElement.onclick = (function(buttonID) {
return function() {
this.onPressButton(buttonID);
}
})(IsaDialog.Buttons[button]).bind(this);
}
}
/**
* Create and configure a new dialog.
* @param options Configuration of the dialog.
* @param options.targetWindow Window or frame in which the dialog is opened. Defaults to the window in which this script is loaded.
* @param options.message A string of text to display to the user.
* @param options.buttons Array of buttons to show in the dialog.
* @param options.showInputField Set to true
to show an input field in the dialog.
* @param options.inputDefaultValue Default value for the input field.
* @param options.dialogType Type of the dialog. Use constants defined in IsaDialog.Type
.
* @returns
*/
function IsaDialog(options) {
this.message = options.message || "";
this.buttons = options.buttons || [IsaDialog.Buttons.OK];
this.showInputField = options.showInputField ? true : false;
this.inputDefaultValue = options.inputDefaultValue !== undefined ? (options.inputDefaultValue + "") : "";
this.targetWindow = options.targetWindow;
this.callback = DEFAULT_HANDLER;
this.dialogType = options.dialogType || IsaDialog.Types.None
}
/**
* Constants for dialog buttons.
*/
IsaDialog.Buttons = {
/**
* OK button.
*/
OK: 1,
/**
* Cancel button.
*/
Cancel: 2
};
/**
* Constants for dialog types.
*/
IsaDialog.Types = {
/**
* Plain dialog.
*/
None: 'PLAIN',
/**
* Information dialog.
*/
Information: 'INFO',
/**
* Warning dialog.
*/
Warning: 'WARNING',
/**
* Error dialog.
*/
Error: 'ERROR'
};
/**
* Show the dialog.
* @param callback Function called when the user closes the dialog. The callback receives two parameters: The button
* that was pressed by the user, and the value that was entered in the input field (undefined if no input field was
* displayed).
*/
IsaDialog.prototype.open = function(callback) {
createDialog.call(this);
this.callback = callback;
registerCallback.call(this);
showDialog.call(this, true);
}
/**
* Show or hide the overlay.
* @param visible true
to make the overlay visible, false
to hide the overlay.
*/
IsaDialog.prototype.overlay = function(visible) {
createOverlay.call(this);
showOverlay.call(this, visible);
}
/**
* Lookup a document by its ID from the target document.
* @param id The element ID.
* @returns The element, or null
if no element with the given ID was found.
*/
IsaDialog.prototype.byId = function(id) {
return this.targetWindow.document.getElementById(id);
}
/**
* Create and append a new element in the target document.
* @param tagName HTML tag of the new element to be created
* @returns The new element instance.
*/
IsaDialog.prototype.createElement = function(tagName) {
var newElement = this.targetWindow.document.createElement(tagName);
this.targetWindow.document.body.appendChild(newElement);
return newElement;
}
/**
* Handler for button click. Calls the registered callback.
* @param button Button ID.
*/
IsaDialog.prototype.onPressButton = function(button) {
showDialog.call(this, false);
if (typeof this.callback === 'function') {
var userInput = this.byId(ID_INPUT).value.trim();
if (!userInput) {
userInput = this.inputDefaultValue;
}
this.callback(button, userInput || null);
}
}
return IsaDialog;
})();
/**
* Create ISA dialogs.
*
* @param targetWindow (optional) Window or frame in which the dialog is opened. Defaults to the window in which this script is loaded.
* must be set when the dialog is used from a frame.
*/
function isaDialogs(targetWindow) {
var targetWindow = targetWindow || window;
return {
/**
* Display a dialog with an optional message and a single OK button.
*
* Replaces window.alert().
*
* @param message A string of text to display to the user. Can be omitted if there is nothing to show in the prompt window.
* @param callback Method called without arguments when the user closes the dialog.
*/
alert: function(message, callback) {
var dialog = new IsaDialog({
targetWindow: targetWindow,
message: message
});
var alertCallback = function () {
if (typeof callback === 'function') {
callback();
}
}
dialog.open(alertCallback);
},
/**
* Display a dialog with an optional message and OK and Cancel buttons.
*
* Replaces window.confirm().
*
* @param message A string of text to display to the user. Can be omitted if there is nothing to show in the prompt window.
* @param callback Method called with a boolean argument, true
if the user confirmed the dialog (OK button) or
* false
if the user canceled the dialog (Cancel button).
*/
confirm: function(message, callback) {
var dialog = new IsaDialog({
targetWindow: targetWindow,
message: message,
buttons: [IsaDialog.Buttons.OK, IsaDialog.Buttons.Cancel]
});
var alertCallback = function (button) {
if (typeof callback === 'function') {
callback(button === IsaDialog.Buttons.OK);
}
}
dialog.open(alertCallback);
},
/**
* Display a dialog with an optional message prompting the user to input some text.
*
* Replaces window.prompt().
*
* @param message A string of text to display to the user. Can be omitted if there is nothing to show in the prompt window.
* @param defaultValue A string containing the default value displayed in the text input field.
* @param callback Function called after the user closed the dialog. Will be called with the text the user entered, or
* null
if the user entered no text or canceled the dialog.
*/
prompt: function(message, defaultValue, callback) {
var dialog = new IsaDialog({
targetWindow: targetWindow,
message: message,
buttons: [IsaDialog.Buttons.OK, IsaDialog.Buttons.Cancel],
showInputField: true,
inputDefaultValue: defaultValue
});
var alertCallback = function (button, input) {
if (typeof callback === 'function') {
if (button === IsaDialog.Buttons.OK && input) {
callback(input);
} else {
callback(null);
}
}
}
dialog.open(alertCallback);
},
/**
* Show the ISA dialogs overlay.
*
* Internal function.
*
* @param visible true
to make the overlay visible, false
to hide the overlay.
*/
overlay: function(visible) {
var dialog = new IsaDialog({
targetWindow: targetWindow
});
dialog.overlay(visible);
}
}
}