// 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); } } }