/**
|
* @fileoverview This module has some methods for handling popup-window
|
* @author NHN.
|
* FE Development Lab <dl_javascript@nhn.com>
|
*/
|
|
'use strict';
|
|
var collection = require('./collection');
|
var type = require('./type');
|
var func = require('./func');
|
var browser = require('./browser');
|
var object = require('./object');
|
|
var popupId = 0;
|
|
/**
|
* Popup management class
|
* @constructor
|
* @memberof tui.util
|
* @example
|
* // node, commonjs
|
* var popup = require('tui-code-snippet').popup;
|
* @example
|
* // distribution file, script
|
* <script src='path-to/tui-code-snippt.js'></script>
|
* <script>
|
* var popup = tui.util.popup;
|
* <script>
|
*/
|
function Popup() {
|
/**
|
* Caching the window-contexts of opened popups
|
* @type {Object}
|
*/
|
this.openedPopup = {};
|
|
/**
|
* In IE7, an error occurs when the closeWithParent property attaches to window object.<br>
|
* So, It is for saving the value of closeWithParent instead of attaching to window object.
|
* @type {Object}
|
*/
|
this.closeWithParentPopup = {};
|
|
/**
|
* Post data bridge for IE11 popup
|
* @type {string}
|
*/
|
this.postBridgeUrl = '';
|
}
|
|
/**********
|
* public methods
|
**********/
|
|
/**
|
* Returns a popup-list administered by current window.
|
* @param {string} [key] The key of popup.
|
* @returns {Object} popup window list object
|
*/
|
Popup.prototype.getPopupList = function(key) {
|
var target;
|
if (type.isExisty(key)) {
|
target = this.openedPopup[key];
|
} else {
|
target = this.openedPopup;
|
}
|
|
return target;
|
};
|
|
/**
|
* Open popup
|
* Caution:
|
* In IE11, when transfer data to popup by POST, must set the postBridgeUrl.
|
*
|
* @param {string} url - popup url
|
* @param {Object} options - popup options
|
* @param {string} [options.popupName] - Key of popup window.<br>
|
* If the key is set, when you try to open by this key, the popup of this key is focused.<br>
|
* Or else a new popup window having this key is opened.
|
*
|
* @param {string} [options.popupOptionStr=""] - Option string of popup window<br>
|
* It is same with the third parameter of window.open() method.<br>
|
* See {@link http://www.w3schools.com/jsref/met_win_open.asp}
|
*
|
* @param {boolean} [options.closeWithParent=true] - Is closed when parent window closed?
|
*
|
* @param {boolean} [options.useReload=false] - This property indicates whether reload the popup or not.<br>
|
* If true, the popup will be reloaded when you try to re-open the popup that has been opened.<br>
|
* When transmit the POST-data, some browsers alert a message for confirming whether retransmit or not.
|
*
|
* @param {string} [options.postBridgeUrl='']
|
* Use this url to avoid a certain bug occuring when transmitting POST data to the popup in IE11.<br>
|
* This specific buggy situation is known to happen because IE11 tries to open the requested url<br>
|
* not in a new popup window as intended, but in a new tab.<br>
|
* See {@link http://wiki.nhnent.com/pages/viewpage.action?pageId=240562844}
|
*
|
* @param {string} [options.method=get]
|
* The method of transmission when the form-data is transmitted to popup-window.
|
*
|
* @param {Object} [options.param=null]
|
* Using as parameters for transmission when the form-data is transmitted to popup-window.
|
*/
|
Popup.prototype.openPopup = function(url, options) { // eslint-disable-line complexity
|
var popup, formElement, useIEPostBridge;
|
|
options = object.extend({
|
popupName: 'popup_' + popupId + '_' + Number(new Date()),
|
popupOptionStr: '',
|
useReload: true,
|
closeWithParent: true,
|
method: 'get',
|
param: {}
|
}, options || {});
|
|
options.method = options.method.toUpperCase();
|
|
this.postBridgeUrl = options.postBridgeUrl || this.postBridgeUrl;
|
|
useIEPostBridge = options.method === 'POST' && options.param &&
|
browser.msie && browser.version === 11;
|
|
if (!type.isExisty(url)) {
|
throw new Error('Popup#open() need popup url.');
|
}
|
|
popupId += 1;
|
|
/*
|
* In form-data transmission
|
* 1. Create a form before opening a popup.
|
* 2. Transmit the form-data.
|
* 3. Remove the form after transmission.
|
*/
|
if (options.param) {
|
if (options.method === 'GET') {
|
url = url + (/\?/.test(url) ? '&' : '?') + this._parameterize(options.param);
|
} else if (options.method === 'POST') {
|
if (!useIEPostBridge) {
|
formElement = this.createForm(url, options.param, options.method, options.popupName);
|
url = 'about:blank';
|
}
|
}
|
}
|
|
popup = this.openedPopup[options.popupName];
|
|
if (!type.isExisty(popup)) {
|
this.openedPopup[options.popupName] = popup = this._open(useIEPostBridge, options.param,
|
url, options.popupName, options.popupOptionStr);
|
} else if (popup.closed) {
|
this.openedPopup[options.popupName] = popup = this._open(useIEPostBridge, options.param,
|
url, options.popupName, options.popupOptionStr);
|
} else {
|
if (options.useReload) {
|
popup.location.replace(url);
|
}
|
popup.focus();
|
}
|
|
this.closeWithParentPopup[options.popupName] = options.closeWithParent;
|
|
if (!popup || popup.closed || type.isUndefined(popup.closed)) {
|
alert('please enable popup windows for this website');
|
}
|
|
if (options.param && options.method === 'POST' && !useIEPostBridge) {
|
if (popup) {
|
formElement.submit();
|
}
|
if (formElement.parentNode) {
|
formElement.parentNode.removeChild(formElement);
|
}
|
}
|
|
window.onunload = func.bind(this.closeAllPopup, this);
|
};
|
|
/**
|
* Close the popup
|
* @param {boolean} [skipBeforeUnload] - If true, the 'window.onunload' will be null and skip unload event.
|
* @param {Window} [popup] - Window-context of popup for closing. If omit this, current window-context will be closed.
|
*/
|
Popup.prototype.close = function(skipBeforeUnload, popup) {
|
var target = popup || window;
|
skipBeforeUnload = type.isExisty(skipBeforeUnload) ? skipBeforeUnload : false;
|
|
if (skipBeforeUnload) {
|
window.onunload = null;
|
}
|
|
if (!target.closed) {
|
target.opener = window.location.href;
|
target.close();
|
}
|
};
|
|
/**
|
* Close all the popups in current window.
|
* @param {boolean} closeWithParent - If true, popups having the closeWithParentPopup property as true will be closed.
|
*/
|
Popup.prototype.closeAllPopup = function(closeWithParent) {
|
var hasArg = type.isExisty(closeWithParent);
|
|
collection.forEachOwnProperties(this.openedPopup, function(popup, key) {
|
if ((hasArg && this.closeWithParentPopup[key]) || !hasArg) {
|
this.close(false, popup);
|
}
|
}, this);
|
};
|
|
/**
|
* Activate(or focus) the popup of the given name.
|
* @param {string} popupName - Name of popup for activation
|
*/
|
Popup.prototype.focus = function(popupName) {
|
this.getPopupList(popupName).focus();
|
};
|
|
/**
|
* Return an object made of parsing the query string.
|
* @returns {Object} An object having some information of the query string.
|
* @private
|
*/
|
Popup.prototype.parseQuery = function() {
|
var param = {};
|
var search, pair;
|
|
search = window.location.search.substr(1);
|
collection.forEachArray(search.split('&'), function(part) {
|
pair = part.split('=');
|
param[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);
|
});
|
|
return param;
|
};
|
|
/**
|
* Create a hidden form from the given arguments and return this form.
|
* @param {string} action - URL for form transmission
|
* @param {Object} [data] - Data for form transmission
|
* @param {string} [method] - Method of transmission
|
* @param {string} [target] - Target of transmission
|
* @param {HTMLElement} [container] - Container element of form.
|
* @returns {HTMLElement} Form element
|
*/
|
Popup.prototype.createForm = function(action, data, method, target, container) {
|
var form = document.createElement('form'),
|
input;
|
|
container = container || document.body;
|
|
form.method = method || 'POST';
|
form.action = action || '';
|
form.target = target || '';
|
form.style.display = 'none';
|
|
collection.forEachOwnProperties(data, function(value, key) {
|
input = document.createElement('input');
|
input.name = key;
|
input.type = 'hidden';
|
input.value = value;
|
form.appendChild(input);
|
});
|
|
container.appendChild(form);
|
|
return form;
|
};
|
|
/**********
|
* private methods
|
**********/
|
|
/**
|
* Return an query string made by parsing the given object
|
* @param {Object} obj - An object that has information for query string
|
* @returns {string} - Query string
|
* @private
|
*/
|
Popup.prototype._parameterize = function(obj) {
|
var query = [];
|
|
collection.forEachOwnProperties(obj, function(value, key) {
|
query.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
|
});
|
|
return query.join('&');
|
};
|
|
/**
|
* Open popup
|
* @param {boolean} useIEPostBridge - A switch option whether to use alternative
|
* of tossing POST data to the popup window in IE11
|
* @param {Object} param - A data for tossing to popup
|
* @param {string} url - Popup url
|
* @param {string} popupName - Popup name
|
* @param {string} optionStr - Setting for popup, ex) 'width=640,height=320,scrollbars=yes'
|
* @returns {Window} Window context of popup
|
* @private
|
*/
|
Popup.prototype._open = function(useIEPostBridge, param, url, popupName, optionStr) {
|
var popup;
|
|
if (useIEPostBridge) {
|
popup = window.open(this.postBridgeUrl, popupName, optionStr);
|
setTimeout(function() {
|
popup.redirect(url, param);
|
}, 100);
|
} else {
|
popup = window.open(url, popupName, optionStr);
|
}
|
|
return popup;
|
};
|
|
module.exports = new Popup();
|