UNPKG

ng2-right-click-menu

Version:
823 lines (809 loc) 29.5 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/core'), require('@angular/common'), require('@angular/cdk/overlay'), require('@angular/cdk/portal'), require('rxjs')) : typeof define === 'function' && define.amd ? define('ng2-right-click-menu', ['exports', '@angular/core', '@angular/common', '@angular/cdk/overlay', '@angular/cdk/portal', 'rxjs'], factory) : (global = global || self, factory(global['ng2-right-click-menu'] = {}, global.ng.core, global.ng.common, global.ng.cdk.overlay, global.ng.cdk.portal, global.rxjs)); }(this, function (exports, core, common, overlay, portal, rxjs) { 'use strict'; /*! ***************************************************************************** Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. See the Apache Version 2.0 License for specific language governing permissions and limitations under the License. ***************************************************************************** */ function __read(o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; } function __spread() { for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i])); return ar; } /** * @fileoverview added by tsickle * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ var MenuItemContext = /** @class */ (function () { function MenuItemContext() { this.$implicit = {}; } return MenuItemContext; }()); var ShContextMenuItemDirective = /** @class */ (function () { function ShContextMenuItemDirective(template) { this.template = template; this.closeOnClick = true; this.click = new core.EventEmitter(); this.context = new MenuItemContext(); } /** * @return {?} */ ShContextMenuItemDirective.prototype.setNotActive = /** * @return {?} */ function () { this._active = false; if (this.subMenu) { this.subMenu.setNotActive(); } }; /** * @return {?} */ ShContextMenuItemDirective.prototype.setActive = /** * @return {?} */ function () { this._active = true; }; ShContextMenuItemDirective.decorators = [ { type: core.Directive, args: [{ selector: '[shContextMenuItem]' },] } ]; /** @nocollapse */ ShContextMenuItemDirective.ctorParameters = function () { return [ { type: core.TemplateRef, decorators: [{ type: core.Optional }] } ]; }; ShContextMenuItemDirective.propDecorators = { subMenu: [{ type: core.Input }], divider: [{ type: core.Input }], visible: [{ type: core.Input }], disabled: [{ type: core.Input }], closeOnClick: [{ type: core.Input }], click: [{ type: core.Output }] }; return ShContextMenuItemDirective; }()); /** * @fileoverview added by tsickle * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ var ShContextMenuService = /** @class */ (function () { function ShContextMenuService(overlay) { this.overlay = overlay; this.activeOverlays = []; } /** * @param {?} ctxEvent * @return {?} */ ShContextMenuService.prototype.openMenu = /** * @param {?} ctxEvent * @return {?} */ function (ctxEvent) { this.closeCurrentOverlays(); var menu = ctxEvent.menu, mouseEvent = ctxEvent.mouseEvent, data = ctxEvent.data; this.activeMenu = menu; this.anchorElement = this.createAnchorElement(); /** @type {?} */ var scrollStrategy = this.buildScrollStrategy(); /** @type {?} */ var positionStrategy = this.buildPositionStrategy(this.anchorElement, mouseEvent); this.attachContextToItems(menu, data); /** @type {?} */ var overlayRef = this.createAndAttachOverlay(positionStrategy, scrollStrategy, menu, true); this.attachOverlayRef(menu, overlayRef); this.registerDetachEvents(overlayRef); }; /** * @param {?} ctxEvent * @return {?} */ ShContextMenuService.prototype.openSubMenu = /** * @param {?} ctxEvent * @return {?} */ function (ctxEvent) { var menu = ctxEvent.menu, mouseEvent = ctxEvent.mouseEvent, targetElement = ctxEvent.targetElement, data = ctxEvent.data, parentMenu = ctxEvent.parentMenu; mouseEvent.preventDefault(); mouseEvent.stopPropagation(); /** @type {?} */ var scrollStrategy = this.buildScrollStrategy(); /** @type {?} */ var positionStrategy = this.buildPositionStrategyForSubMenu(targetElement); /** @type {?} */ var overlayRef = this.createAndAttachOverlay(positionStrategy, scrollStrategy, menu, false); this.attachContextToItems(menu, data); this.attachThisContext(menu, parentMenu); this.attachOverlayRef(menu, overlayRef); }; /** * @return {?} */ ShContextMenuService.prototype.destroy = /** * @return {?} */ function () { this.closeCurrentOverlays(); this.subs.unsubscribe(); }; /** * @return {?} */ ShContextMenuService.prototype.ngOnDestroy = /** * @return {?} */ function () { this.destroy(); }; /** * @param {?} menu * @return {?} */ ShContextMenuService.prototype.closeSubMenus = /** * @param {?} menu * @return {?} */ function (menu) { var _this = this; /** @type {?} */ var itemsWithSubMenus = menu.menuItems.filter((/** * @param {?} i * @return {?} */ function (i) { return !!i.subMenu && !!i.subMenu.overlayRef; })); if (itemsWithSubMenus.length) { itemsWithSubMenus.forEach((/** * @param {?} sm * @return {?} */ function (sm) { return _this.closeSubMenus(sm.subMenu); })); /** @type {?} */ var overlayRefs = itemsWithSubMenus.map((/** * @param {?} i * @return {?} */ function (i) { return i.subMenu.overlayRef; })); overlayRefs.forEach((/** * @param {?} r * @return {?} */ function (r) { return r.dispose(); })); } }; /** * @private * @param {?} overlayRef * @return {?} */ ShContextMenuService.prototype.registerDetachEvents = /** * @private * @param {?} overlayRef * @return {?} */ function (overlayRef) { this.subs = overlayRef .backdropClick() .subscribe(this.closeCurrentOverlays.bind(this)); this.subs.add(overlayRef.detachments().subscribe(this.closeCurrentOverlays.bind(this))); }; /** * @private * @param {?} positionStrategy * @param {?} scrollStrategy * @param {?} menu * @param {?=} hasBackdrop * @return {?} */ ShContextMenuService.prototype.createAndAttachOverlay = /** * @private * @param {?} positionStrategy * @param {?} scrollStrategy * @param {?} menu * @param {?=} hasBackdrop * @return {?} */ function (positionStrategy, scrollStrategy, menu, hasBackdrop) { if (hasBackdrop === void 0) { hasBackdrop = true; } /** @type {?} */ var overlayRef = this.overlay.create({ positionStrategy: positionStrategy, scrollStrategy: scrollStrategy, hasBackdrop: hasBackdrop, backdropClass: 'sh-backdrop' }); /* TODO: try passing the TemplatePortal context (data) and then injecting it to the *ngTemplateOutlet in the component template */ /** @type {?} */ var menuPortal = new portal.TemplatePortal(menu.menuTemplate, menu.menuContainer); overlayRef.attach(menuPortal); this.activeOverlays.push(overlayRef); return overlayRef; }; /** * @private * @return {?} */ ShContextMenuService.prototype.buildScrollStrategy = /** * @private * @return {?} */ function () { return this.overlay.scrollStrategies.reposition({ autoClose: true }); }; /** * @private * @param {?} ele * @param {?} event * @return {?} */ ShContextMenuService.prototype.buildPositionStrategy = /** * @private * @param {?} ele * @param {?} event * @return {?} */ function (ele, event) { var x = event.x, y = event.y; return this.overlay .position() .flexibleConnectedTo(ele) .withDefaultOffsetX(x) .withDefaultOffsetY(y) .withPositions(this.buildPositions()) .withFlexibleDimensions(false) .withPush(true); }; /** * @private * @param {?} elm * @return {?} */ ShContextMenuService.prototype.buildPositionStrategyForSubMenu = /** * @private * @param {?} elm * @return {?} */ function (elm) { return this.overlay .position() .flexibleConnectedTo(elm) .withPositions(this.buildSubMenuPositions()) .withFlexibleDimensions(false) .withPush(true); }; /** * @private * @return {?} */ ShContextMenuService.prototype.closeCurrentOverlays = /** * @private * @return {?} */ function () { if (this.anchorElement) { this.anchorElement.remove(); } this.activeOverlays.forEach((/** * @param {?} o * @return {?} */ function (o) { o.detach(); o.dispose(); })); this.activeOverlays = []; // TODO: create close subject and emit. // subscribe in component if (this.activeMenu) { this.activeMenu.close(); } }; /** * @private * @param {?} menu * @param {?} data * @return {?} */ ShContextMenuService.prototype.attachContextToItems = /** * @private * @param {?} menu * @param {?} data * @return {?} */ function (menu, data) { menu.menuItems.forEach((/** * @param {?} i * @return {?} */ function (i) { return (i.context.$implicit = data); })); }; /** * @private * @param {?} menu * @param {?} parentMenu * @return {?} */ ShContextMenuService.prototype.attachThisContext = /** * @private * @param {?} menu * @param {?} parentMenu * @return {?} */ function (menu, parentMenu) { menu.thisContext = parentMenu.thisContext; }; /** * @private * @param {?} menu * @param {?} overlayRef * @return {?} */ ShContextMenuService.prototype.attachOverlayRef = /** * @private * @param {?} menu * @param {?} overlayRef * @return {?} */ function (menu, overlayRef) { menu.overlayRef = overlayRef; }; /** * @private * @return {?} */ ShContextMenuService.prototype.createAnchorElement = /** * @private * @return {?} */ function () { /** @type {?} */ var div = document.createElement('div'); div.style.position = 'absolute'; div.style.top = '0'; div.style.bottom = '0'; div.style.left = '0'; div.style.right = '0'; document.body.appendChild(div); return div; }; /** * @private * @return {?} */ ShContextMenuService.prototype.buildSubMenuPositions = /** * @private * @return {?} */ function () { return [ { originX: 'end', originY: 'top', overlayX: 'start', overlayY: 'top' }, { originX: 'start', originY: 'top', overlayX: 'end', overlayY: 'top' }, { originX: 'end', originY: 'bottom', overlayX: 'start', overlayY: 'bottom' }, { originX: 'start', originY: 'bottom', overlayX: 'end', overlayY: 'bottom' } ]; }; /** * @private * @return {?} */ ShContextMenuService.prototype.buildPositions = /** * @private * @return {?} */ function () { return [ { originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'top' }, { originX: 'start', originY: 'top', overlayX: 'end', overlayY: 'top' }, { originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom' }, { originX: 'start', originY: 'top', overlayX: 'end', overlayY: 'bottom' } ]; }; ShContextMenuService.decorators = [ { type: core.Injectable } ]; /** @nocollapse */ ShContextMenuService.ctorParameters = function () { return [ { type: overlay.Overlay } ]; }; return ShContextMenuService; }()); /** * @fileoverview added by tsickle * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ var ShContextMenuComponent = /** @class */ (function () { function ShContextMenuComponent(ctxService) { this.ctxService = ctxService; this.contentChildrenItems = new core.QueryList(); this.viewChildrenItems = new core.QueryList(); } Object.defineProperty(ShContextMenuComponent.prototype, "menuItems", { get: /** * @return {?} */ function () { // when using the ShContextMenuComponent as menu, the ContentChildren is the source if (this.contentChildrenItems.length) { return this.contentChildrenItems; } // when using a custom component as menu the ViewChildren is the source return this.viewChildrenItems; }, enumerable: true, configurable: true }); /** * @param {?} $event * @param {?} item * @param {?} elm * @return {?} */ ShContextMenuComponent.prototype.onEnter = /** * @param {?} $event * @param {?} item * @param {?} elm * @return {?} */ function ($event, item, elm) { this.ctxService.closeSubMenus(this); this.setNotActive(); if (!item.subMenu) { return; } this.setActive(item); this.ctxService.openSubMenu({ data: item.context.$implicit, targetElement: new core.ElementRef(elm), menu: item.subMenu, mouseEvent: $event, parentMenu: this }); }; /** * @private * @param {?} item * @return {?} */ ShContextMenuComponent.prototype.setActive = /** * @private * @param {?} item * @return {?} */ function (item) { item.setActive(); this.subActive = true; }; /** * @param {?} event * @param {?} item * @return {?} */ ShContextMenuComponent.prototype.onClick = /** * @param {?} event * @param {?} item * @return {?} */ function (event, item) { // TODO: move click handling to service if (item.divider) { return; } if (!item.subMenu && item.closeOnClick) { this.ctxService.destroy(); item.click.emit({ data: item.context.$implicit, event: event }); } }; /** * @private * @param {?} fn * @param {?} fallbackContext * @param {?} data * @param {?} event * @return {?} */ ShContextMenuComponent.prototype.callWithContext = /** * @private * @param {?} fn * @param {?} fallbackContext * @param {?} data * @param {?} event * @return {?} */ function (fn, fallbackContext, data, event) { return fn.call(this.thisContext ? this.thisContext : fallbackContext, { data: data, event: event }); }; /** * @return {?} */ ShContextMenuComponent.prototype.close = /** * @return {?} */ function () { this.setNotActive(); this.menuContainer.detach(); if (this.overlayRef) { this.overlayRef.detach(); } }; /** * @return {?} */ ShContextMenuComponent.prototype.ngOnDestroy = /** * @return {?} */ function () { this.close(); }; /** * @return {?} */ ShContextMenuComponent.prototype.setNotActive = /** * @return {?} */ function () { this.subActive = false; this.menuItems.forEach((/** * @param {?} i * @return {?} */ function (i) { return i.setNotActive(); })); }; /** * @param {?} item * @return {?} */ ShContextMenuComponent.prototype.isVisible = /** * @param {?} item * @return {?} */ function (item) { if (!item.visible) { return true; } return this.callWithContext(item.visible, this, item.context.$implicit, null); }; ShContextMenuComponent.decorators = [ { type: core.Component, args: [{ selector: 'sh-context-menu', encapsulation: core.ViewEncapsulation.None, template: "\n\t\t<ng-container #menuContainer></ng-container>\n\t\t<ng-template #menuTemplate>\n\t\t\t<div class=\"sh-context-menu\">\n\t\t\t\t<div\n\t\t\t\t\t*ngFor=\"let menuItem of menuItems\"\n\t\t\t\t\t#itemElement\n\t\t\t\t\t[ngClass]=\"{\n\t\t\t\t\t\t'sh-sub-anchor': menuItem.subMenu,\n\t\t\t\t\t\t'sh-context-menu--item__divider': menuItem.divider,\n\t\t\t\t\t\t'sh-context-menu--item__sub-active': subActive && menuItem.active\n\t\t\t\t\t}\"\n\t\t\t\t\tclass=\"sh-context-menu--item\"\n\t\t\t\t\t(mouseenter)=\"onEnter($event, menuItem, itemElement)\"\n\t\t\t\t\t(click)=\"onClick($event, menuItem)\"\n\t\t\t\t>\n\t\t\t\t\t<ng-container *ngIf=\"!menuItem.divider || !isVisible(menuItem)\">\n\t\t\t\t\t\t<ng-content\n\t\t\t\t\t\t\t*ngTemplateOutlet=\"menuItem.template; context: menuItem.context\"\n\t\t\t\t\t\t></ng-content>\n\t\t\t\t\t</ng-container>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</ng-template>\n\t", styles: [".sh-backdrop{background-color:transparent}.sh-context-menu{background:#ececec;min-width:150px;border:1px solid rgba(0,0,0,.2);border-radius:3px;box-shadow:0 0 10px 2px rgba(0,0,0,.1);color:#000;padding:5px 0;margin:0}.sh-context-menu--item{padding:5px 10px 5px 15px;-webkit-transition:.15s;transition:.15s}.sh-context-menu--item:hover,.sh-context-menu--item__sub-active{background-color:#4b8bec;color:#fff;cursor:pointer}.sh-context-menu--item.sh-context-menu--item__divider:hover{background-color:#ececec;color:#000;cursor:default}.sh-context-menu--item__divider{height:1px;margin:1px 1px 8px;overflow:hidden;border-bottom:1px solid #d0d0d0}.sh-context-menu--item.sh-sub-anchor{position:relative;min-width:160px}.sh-sub-anchor:after{content:'';top:50%;right:6px;-webkit-transform:translateY(-50%);transform:translateY(-50%);position:absolute;border-top:6px solid transparent;border-bottom:6px solid transparent;border-left:8px solid #000}"] }] } ]; /** @nocollapse */ ShContextMenuComponent.ctorParameters = function () { return [ { type: ShContextMenuService } ]; }; ShContextMenuComponent.propDecorators = { thisContext: [{ type: core.Input, args: ['this',] }], contentChildrenItems: [{ type: core.ContentChildren, args: [ShContextMenuItemDirective, { read: ShContextMenuItemDirective },] }], viewChildrenItems: [{ type: core.ViewChildren, args: [ShContextMenuItemDirective, { read: ShContextMenuItemDirective },] }], menuTemplate: [{ type: core.ViewChild, args: ['menuTemplate', { read: core.TemplateRef, static: true },] }], menuContainer: [{ type: core.ViewChild, args: ['menuContainer', { read: core.ViewContainerRef, static: true },] }] }; return ShContextMenuComponent; }()); /** * @fileoverview added by tsickle * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ var ShAttachMenuDirective = /** @class */ (function () { function ShAttachMenuDirective(ctxService, elm) { this.ctxService = ctxService; this.elm = elm; this.open = new core.EventEmitter(); } /** * @return {?} */ ShAttachMenuDirective.prototype.ngOnInit = /** * @return {?} */ function () { this.setupEvents(); }; /** * @private * @return {?} */ ShAttachMenuDirective.prototype.setupEvents = /** * @private * @return {?} */ function () { var _this = this; /** @type {?} */ var observables = []; if (!this.triggers) { observables.push(rxjs.fromEvent(this.elm.nativeElement, 'contextmenu')); } else { this.triggers.forEach((/** * @param {?} t * @return {?} */ function (t) { observables.push(rxjs.fromEvent(_this.elm.nativeElement, t)); })); } this.sub = rxjs.merge.apply(void 0, __spread(observables)).subscribe(this.openMenu.bind(this)); }; /** * @param {?} event * @return {?} */ ShAttachMenuDirective.prototype.openMenu = /** * @param {?} event * @return {?} */ function (event) { event.preventDefault(); event.stopPropagation(); /** @type {?} */ var preventOpen = false; this.open.emit({ data: this.data, mouseEvent: event, preventOpen: (/** * @return {?} */ function () { preventOpen = true; }) }); if (preventOpen) return; this.ctxService.openMenu({ menu: this.menu, mouseEvent: event, targetElement: this.elm, data: this.data }); }; /** * @return {?} */ ShAttachMenuDirective.prototype.ngOnDestroy = /** * @return {?} */ function () { if (this.sub) { this.sub.unsubscribe(); } }; ShAttachMenuDirective.decorators = [ { type: core.Directive, args: [{ selector: '[shAttachMenu]' },] } ]; /** @nocollapse */ ShAttachMenuDirective.ctorParameters = function () { return [ { type: ShContextMenuService }, { type: core.ElementRef } ]; }; ShAttachMenuDirective.propDecorators = { menu: [{ type: core.Input, args: ['shAttachMenu',] }], triggers: [{ type: core.Input, args: ['shMenuTriggers',] }], data: [{ type: core.Input, args: ['shMenuData',] }], open: [{ type: core.Output }] }; return ShAttachMenuDirective; }()); /** * @fileoverview added by tsickle * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ var ShContextMenuModule = /** @class */ (function () { function ShContextMenuModule() { } ShContextMenuModule.decorators = [ { type: core.NgModule, args: [{ declarations: [ ShAttachMenuDirective, ShContextMenuComponent, ShContextMenuItemDirective ], exports: [ ShAttachMenuDirective, ShContextMenuComponent, ShContextMenuItemDirective ], providers: [ShContextMenuService], imports: [common.CommonModule, overlay.OverlayModule], entryComponents: [ShContextMenuComponent] },] } ]; return ShContextMenuModule; }()); exports.ShAttachMenuDirective = ShAttachMenuDirective; exports.ShContextMenuComponent = ShContextMenuComponent; exports.ShContextMenuItemDirective = ShContextMenuItemDirective; exports.ShContextMenuModule = ShContextMenuModule; exports.ShContextMenuService = ShContextMenuService; exports.ɵa = MenuItemContext; Object.defineProperty(exports, '__esModule', { value: true }); })); //# sourceMappingURL=ng2-right-click-menu.umd.js.map