/** * The mask class is used to lock the interface for long asynchronous operations. * In order to put a mask on the container, you need to call the show method and pass the configuration object * in which the selector property specifies the selector on which the DOM element will be found. * If the selector is not specified, the mask will be applied to the Viewport. * For example, to display a mask in a container with id = "maskContainer", run the following code: * * var maskId = Terrasoft.Mask.show({ * selector: "#maskContainer" * }); * * To hide the mask, call: * Terrasoft.Mask.hide(maskId); * * The remaining parameters are optional and assume the default values. */ Ext.define("Terrasoft.controls.Mask", { alternateClassName: "Terrasoft.Mask", extend: "Terrasoft.BaseObject", singleton: true, /** * Mask delay time * @type {Number} * @private */ defaultTimeout: 500, /** * Transparency of the mask in the range from 0 to 1 * @type {Float} * @private */ defaultOpacity: 0.4, /** * The background color of the mask * @type {String} * @private */ defaultBackgroundColor: "#ffffff", /** * The name of the mask container class * @type {String} * @private */ maskOpacityClass: "ts-mask-opacity", /** * Object for storing masks by identifier. * @type {Object} * @private */ storage: {}, /** * The string displayed at startup. * @type {String} * @private */ defaultCaption: Terrasoft.Resources.Controls.Mask.Caption, /** * Adds the stylized display of the container where the spinner and header are located. * @type {Boolean} * @private */ defaultFrameVisible: true, /** * @private */ _defaultShowSpinner: true, /** * Template for the mask element. * Specifies the frame of the control, to which the content is displayed afterwards. * @type {Array} * @private */ tpl: [ /*jshint white:false */ "<div class=\"ts-mask-container\"", "<tpl if=\"position\">", "style=\"{position}\"", "</tpl> >", "<div class=\"{maskOpacityClass}\" style=\"{opacityStyle}\"></div>", "<tpl if=\"showSpinnerEl\">", "<div class=\"{maskSpinnerClass}\">", "<div class=\"ts-mask-frame\">", "<div class=\"ts-mask-spinner\">", "{progressSpinnerHtml}", "</div>", "<div class=\"ts-mask-spinner-caption\">", "<tpl>{caption}</tpl>", "</div>", "</div>", "</div>", "</tpl>", "</div>" /*jshint white:true */ ], /** * The method displays a mask and returns the mask identifier. * @param {Object} [config] Mask options. * @param {String} config.selector Selector to find the DOM element on which the mask will be applied. * If the selector is not specified, the mask is superimposed on the Viewport. * @param {Number} config.timeout Delay before displaying the mask. * @param {Number} config.showHidden Show a transparent mask before the timeout occurs. * @param {Number} config.opacity The degree of transparency of the mask in the range from 0 to 1. * @param {String} config.backgroundColor The background color of the mask fill. * @param {String} config.clearMasks Clear old masks if exist. * @param {String} config.showSpinner Show spinner. * @param {String} config.showSpinnerEl Show spinner element. * @return {String} The mask identifier. */ show: function (config) { var self = this; config = config || {}; var selector = config.selector; if (!selector) { selector = config.selector = "body"; } if (config.clearMasks) { this.clearMasks(selector); } else if (this.isMaskExist(selector)) { return null; } var mask = this.createMask(config); mask.containerEl.set({ "maskState": "visible" }); if (config.showHidden) { var showOpacity = mask.opacity; mask.opacity = 0; this.renderMask(mask.id); var maskOpacityEl = mask.el.child("div." + this.maskOpacityClass); mask.timeoutId = setTimeout(function () { maskOpacityEl.setOpacity(showOpacity); }, mask.timeout); } else { if (mask.timeout) { mask.timeoutId = setTimeout(function () { self.renderMask(mask.id); }, mask.timeout); } else { self.renderMask(mask.id); } } return mask.id; }, /** * The method deletes the mask by its identifier. * @param {String} maskId */ hide: function (maskId) { var mask = this.storage[maskId]; if (mask == null) { return; } var containerEl = mask.containerEl; containerEl.set({ "maskState": "none" }); if (!mask.rendered || mask.showHidden) { clearTimeout(mask.timeoutId); } if (mask.progressSpinner && !mask.progressSpinner.destroyed) { mask.progressSpinner.destroy(); } if (mask.rendered) { mask.el.destroy(); var parentStylePosition = mask.parentStylePosition; if (parentStylePosition !== "absolute" && parentStylePosition !== "relative" && parentStylePosition !== "fixed") { containerEl.setStyle("position", ""); } } delete this.storage[maskId]; }, /** * Clear old masks if exist. * @param {String} selector Selector container element. */ clearMasks: function (selector) { Terrasoft.each(this.storage, function (mask) { if (mask.containerEl.is(selector)) { this.hide(mask.id); } }, this); }, /** * Clears all masks. */ clearAllMasks: function () { Terrasoft.each(this.storage, function (mask) { this.hide(mask.id); }, this); }, /** * The method creates a mask and returns its configuration. * @throws {Terrasoft.UnknownException} * Throws an exception if more than one container is found. * @throws {Terrasoft.NullOrEmptyException} * throws an exception if no containers are found. * @param {Object} config is passed from the show method {Terrasoft.controls.Mask.show} * @return {Object} the configuration of the created mask. * @private */ createMask: function (config) { var defaultMaskConfig = { timeout: this.defaultTimeout, opacity: this.defaultOpacity, backgroundColor: this.defaultBackgroundColor, caption: this.defaultCaption, frameVisible: this.defaultFrameVisible, showSpinner: this._defaultShowSpinner }; var maskConfig = Ext.applyIf(config, defaultMaskConfig); var maskId = Ext.id(); var elements = Ext.select(maskConfig.selector); if (elements.getCount() > 1) { throw new Terrasoft.UnknownException({ message: Terrasoft.Resources.Controls.Mask.DuplicateContainerException }); } var containerEl = elements.item(0); if (!containerEl) { throw new Terrasoft.NullOrEmptyException({ message: Terrasoft.Resources.Exception.NullOrEmptyException }); } var mask = Ext.apply({ containerEl: containerEl, id: maskId }, maskConfig); if (config.showSpinner) { mask.progressSpinner = mask.progressSpinner || Ext.create("Terrasoft.ProgressSpinner", { extraComponentClasses: "ts-mask-spinner" }); } else { this._destroyProgressSpinner(mask); } this.storage[maskId] = mask; return mask; }, /** * @private */ _destroyProgressSpinner: function (mask) { if (mask.progressSpinner) { mask.progressSpinner.destroy(); } }, /** * The method checks whether the mask is superimposed on the element by the selector being passed. * @param {String} selector * @return {Boolean} * @private */ isMaskExist: function (selector) { var isMaskExist = false; Terrasoft.each(this.storage, function (mask) { if (mask.containerEl.is(selector)) { isMaskExist = true; return false; } }); return isMaskExist; }, /** * The method displays the mask by the transmitted identifier. * @param {String} maskId mask identifier. * @private */ renderMask: function (maskId) { var mask = this.storage[maskId]; var containerEl = mask.containerEl; var parentStylePosition = mask.parentStylePosition = containerEl.getStyle("position"); if (parentStylePosition !== "absolute" && parentStylePosition !== "relative" && parentStylePosition !== "fixed") { containerEl.setStyle("position", "relative"); } var tpl = mask.tpl = new Ext.XTemplate(this.tpl.join(""), {}); var opacity = mask.opacity; var styleConfig = { "opacity": opacity, "backgroundColor": mask.backgroundColor }; if (Ext.isIE9m) { styleConfig.filter = "alpha(opacity=" + opacity * 100 + ")"; } var maskSpinnerClass = "ts-mask-spinner-wrap"; if (mask.frameVisible) { maskSpinnerClass += " ts-mask-spinner-frame-visible"; } var opacityStyle = Ext.DomHelper.generateStyles(styleConfig); var position = containerEl.dom.nodeName === "BODY" ? "position: fixed" : ""; var progressSpinnerHtml = mask.progressSpinner && mask.progressSpinner.generateHtml(); var showSpinnerEl = mask.showSpinnerEl === false ? false : true; var maskEl = mask.el = tpl.append(containerEl, { opacityStyle: opacityStyle, progressSpinnerHtml: progressSpinnerHtml, caption: mask.caption, position: position, showSpinnerEl: showSpinnerEl, maskSpinnerClass: maskSpinnerClass, maskOpacityClass: this.maskOpacityClass }, true); maskEl.on("click", this.onMaskElClick); mask.rendered = true; }, /** * The method intercepts the click handler by mask and stops the event propagation. * @param {Object} e Event * @private */ onMaskElClick: function (e) { e.stopPropagation(); } });