UNPKG

ag-grid

Version:

Advanced Data Grid / Data Table supporting Javascript / React / AngularJS / Web Components

326 lines (325 loc) 14 kB
/** * ag-grid - Advanced Data Grid / Data Table supporting Javascript / React / AngularJS / Web Components * @version v18.1.2 * @link http://www.ag-grid.com/ * @license MIT */ "use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; Object.defineProperty(exports, "__esModule", { value: true }); var utils_1 = require("../utils"); var constants_1 = require("../constants"); var context_1 = require("../context/context"); var gridCore_1 = require("../gridCore"); var gridOptionsWrapper_1 = require("../gridOptionsWrapper"); var environment_1 = require("../environment"); var PopupService = (function () { function PopupService() { this.activePopupElements = []; } PopupService.prototype.getPopupParent = function () { var ePopupParent = this.gridOptionsWrapper.getPopupParent(); if (ePopupParent) { // user provided popup parent, may not have the right theme applied return ePopupParent; } else { return this.gridCore.getRootGui(); } }; PopupService.prototype.positionPopupForMenu = function (params) { var sourceRect = params.eventSource.getBoundingClientRect(); var parentRect = this.getPopupParent().getBoundingClientRect(); var y = sourceRect.top - parentRect.top; y = this.keepYWithinBounds(params, y); var minWidth = (params.ePopup.clientWidth > 0) ? params.ePopup.clientWidth : 200; var widthOfParent = parentRect.right - parentRect.left; var maxX = widthOfParent - minWidth; // the x position of the popup depends on RTL or LTR. for normal cases, LTR, we put the child popup // to the right, unless it doesn't fit and we then put it to the left. for RTL it's the other way around, // we try place it first to the left, and then if not to the right. var x; if (this.gridOptionsWrapper.isEnableRtl()) { // for RTL, try left first x = xLeftPosition(); if (x < 0) { x = xRightPosition(); } if (x > maxX) { x = 0; } } else { // for LTR, try right first x = xRightPosition(); if (x > maxX) { x = xLeftPosition(); } if (x < 0) { x = 0; } } params.ePopup.style.left = x + "px"; params.ePopup.style.top = y + "px"; function xRightPosition() { return sourceRect.right - parentRect.left - 2; } function xLeftPosition() { return sourceRect.left - parentRect.left - minWidth; } }; PopupService.prototype.positionPopupUnderMouseEvent = function (params) { var parentRect = this.getPopupParent().getBoundingClientRect(); this.positionPopup({ ePopup: params.ePopup, x: params.mouseEvent.clientX - parentRect.left, y: params.mouseEvent.clientY - parentRect.top, keepWithinBounds: true }); this.callPostProcessPopup(params.ePopup, null, params.mouseEvent, params.type, params.column, params.rowNode); }; PopupService.prototype.positionPopupUnderComponent = function (params) { var sourceRect = params.eventSource.getBoundingClientRect(); var parentRect = this.getPopupParent().getBoundingClientRect(); this.positionPopup({ ePopup: params.ePopup, minWidth: params.minWidth, nudgeX: params.nudgeX, nudgeY: params.nudgeY, x: sourceRect.left - parentRect.left, y: sourceRect.top - parentRect.top + sourceRect.height, keepWithinBounds: params.keepWithinBounds }); this.callPostProcessPopup(params.ePopup, params.eventSource, null, params.type, params.column, params.rowNode); }; PopupService.prototype.callPostProcessPopup = function (ePopup, eventSource, mouseEvent, type, column, rowNode) { var callback = this.gridOptionsWrapper.getPostProcessPopupFunc(); if (callback) { var params = { column: column, rowNode: rowNode, ePopup: ePopup, type: type, eventSource: eventSource, mouseEvent: mouseEvent }; callback(params); } }; PopupService.prototype.positionPopupOverComponent = function (params) { var sourceRect = params.eventSource.getBoundingClientRect(); var parentRect = this.getPopupParent().getBoundingClientRect(); this.positionPopup({ ePopup: params.ePopup, minWidth: params.minWidth, nudgeX: params.nudgeX, nudgeY: params.nudgeY, x: sourceRect.left - parentRect.left, y: sourceRect.top - parentRect.top, keepWithinBounds: params.keepWithinBounds }); this.callPostProcessPopup(params.ePopup, params.eventSource, null, params.type, params.column, params.rowNode); }; PopupService.prototype.positionPopup = function (params) { var x = params.x; var y = params.y; if (params.nudgeX) { x += params.nudgeX; } if (params.nudgeY) { y += params.nudgeY; } // if popup is overflowing to the bottom, move it up if (params.keepWithinBounds) { x = this.keepXWithinBounds(params, x); y = this.keepYWithinBounds(params, y); } params.ePopup.style.left = x + "px"; params.ePopup.style.top = y + "px"; }; PopupService.prototype.keepYWithinBounds = function (params, y) { var parentRect = this.getPopupParent().getBoundingClientRect(); var minHeight; if (params.ePopup.clientHeight > 0) { minHeight = params.ePopup.clientHeight; } else { minHeight = 200; } var heightOfParent = parentRect.bottom - parentRect.top; var maxY = heightOfParent - minHeight - 5; if (y > maxY) { return maxY; } else if (y < 0) { return 0; } else { return y; } }; PopupService.prototype.keepXWithinBounds = function (params, x) { var parentRect = this.getPopupParent().getBoundingClientRect(); var minWidth; if (params.minWidth > 0) { minWidth = params.minWidth; } else if (params.ePopup.clientWidth > 0) { minWidth = params.ePopup.clientWidth; } else { minWidth = 200; } var widthOfParent = parentRect.right - parentRect.left; var maxX = widthOfParent - minWidth - 5; if (x > maxX) { return maxX; } else if (x < 0) { return 0; } else { return x; } }; //adds an element to a div, but also listens to background checking for clicks, //so that when the background is clicked, the child is removed again, giving //a model look to popups. PopupService.prototype.addAsModalPopup = function (eChild, closeOnEsc, closedCallback, click) { var _this = this; var eBody = this.gridOptionsWrapper.getDocument(); if (!eBody) { console.warn('ag-grid: could not find the body of the document, document.body is empty'); return; } eChild.style.top = '0px'; eChild.style.left = '0px'; var popupAlreadyShown = utils_1.Utils.isVisible(eChild); if (popupAlreadyShown) { return; } var ePopupParent = this.getPopupParent(); // add env CSS class to child, in case user provided a popup parent, which means // theme class may be missing var eWrapper = document.createElement('div'); utils_1.Utils.addCssClass(eWrapper, this.environment.getTheme()); eWrapper.appendChild(eChild); ePopupParent.appendChild(eWrapper); this.activePopupElements.push(eChild); var popupHidden = false; var hidePopupOnKeyboardEvent = function (event) { var key = event.which || event.keyCode; if (key === constants_1.Constants.KEY_ESCAPE) { hidePopup(null); } }; var hidePopupOnMouseEvent = function (event) { hidePopup(event); }; var hidePopupOnTouchEvent = function (event) { hidePopup(null, event); }; var hidePopup = function (mouseEvent, touchEvent) { // we don't hide popup if the event was on the child, or any // children of this child if (_this.isEventFromCurrentPopup(mouseEvent, touchEvent, eChild)) { return; } // if the event to close is actually the open event, then ignore it if (_this.isEventSameChainAsOriginalEvent(click, mouseEvent, touchEvent)) { return; } // this method should only be called once. the client can have different // paths, each one wanting to close, so this method may be called multiple times. if (popupHidden) { return; } popupHidden = true; ePopupParent.removeChild(eWrapper); utils_1.Utils.removeFromArray(_this.activePopupElements, eChild); eBody.removeEventListener('keydown', hidePopupOnKeyboardEvent); eBody.removeEventListener('click', hidePopupOnMouseEvent); eBody.removeEventListener('touchstart', hidePopupOnTouchEvent); eBody.removeEventListener('contextmenu', hidePopupOnMouseEvent); if (closedCallback) { closedCallback(); } }; // if we add these listeners now, then the current mouse // click will be included, which we don't want setTimeout(function () { if (closeOnEsc) { eBody.addEventListener('keydown', hidePopupOnKeyboardEvent); } eBody.addEventListener('click', hidePopupOnMouseEvent); eBody.addEventListener('touchstart', hidePopupOnTouchEvent); eBody.addEventListener('contextmenu', hidePopupOnMouseEvent); }, 0); return hidePopup; }; PopupService.prototype.isEventFromCurrentPopup = function (mouseEvent, touchEvent, eChild) { var event = mouseEvent ? mouseEvent : touchEvent; if (event) { var indexOfThisChild = this.activePopupElements.indexOf(eChild); for (var i = indexOfThisChild; i < this.activePopupElements.length; i++) { var element = this.activePopupElements[i]; if (utils_1.Utils.isElementInEventPath(element, event)) { return true; } } } return false; }; // in some browsers, the context menu event can be fired before the click event, which means // the context menu event could open the popup, but then the click event closes it straight away. PopupService.prototype.isEventSameChainAsOriginalEvent = function (originalClick, mouseEvent, touchEvent) { // we check the coordinates of the event, to see if it's the same event. there is a 1 / 1000 chance that // the event is a different event, however that is an edge case that is not very relevant (the user clicking // twice on the same location isn't a normal path). // event could be mouse event or touch event. var mouseEventOrTouch; if (mouseEvent) { // mouse event can be used direction, it has coordinates mouseEventOrTouch = mouseEvent; } else if (touchEvent) { // touch event doesn't have coordinates, need it's touch object mouseEventOrTouch = touchEvent.touches[0]; } if (mouseEventOrTouch && originalClick) { // for x, allow 4px margin, to cover iPads, where touch (which opens menu) is followed // by browser click (when you life finger up, touch is interrupted as click in browser) var xMatch = Math.abs(originalClick.screenX - mouseEvent.screenX) < 5; var yMatch = Math.abs(originalClick.screenY - mouseEvent.screenY) < 5; if (xMatch && yMatch) { return true; } } return false; }; __decorate([ context_1.Autowired('gridCore'), __metadata("design:type", gridCore_1.GridCore) ], PopupService.prototype, "gridCore", void 0); __decorate([ context_1.Autowired('gridOptionsWrapper'), __metadata("design:type", gridOptionsWrapper_1.GridOptionsWrapper) ], PopupService.prototype, "gridOptionsWrapper", void 0); __decorate([ context_1.Autowired('environment'), __metadata("design:type", environment_1.Environment) ], PopupService.prototype, "environment", void 0); PopupService = __decorate([ context_1.Bean('popupService') ], PopupService); return PopupService; }()); exports.PopupService = PopupService;