UNPKG

sprotty

Version:

A next-gen framework for graphical views

308 lines 14.4 kB
"use strict"; /******************************************************************************** * Copyright (c) 2017-2018 TypeFox and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at * http://www.eclipse.org/legal/epl-2.0. * * This Source Code may also be made available under the following Secondary * Licenses when the conditions for such availability set forth in the Eclipse * Public License v. 2.0 are satisfied: GNU General Public License, version 2 * with the GNU Classpath Exception which is available at * https://www.gnu.org/software/classpath/license.html. * * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ 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); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ClosePopupActionHandler = exports.HoverKeyListener = exports.PopupHoverMouseListener = exports.HoverMouseListener = exports.AbstractHoverMouseListener = exports.SetPopupModelCommand = exports.HoverFeedbackCommand = void 0; const inversify_1 = require("inversify"); const actions_1 = require("sprotty-protocol/lib/actions"); const geometry_1 = require("sprotty-protocol/lib/utils/geometry"); const keyboard_1 = require("../../utils/keyboard"); const types_1 = require("../../base/types"); const smodel_1 = require("../../base/model/smodel"); const mouse_tool_1 = require("../../base/views/mouse-tool"); const command_1 = require("../../base/commands/command"); const smodel_factory_1 = require("../../base/model/smodel-factory"); const key_tool_1 = require("../../base/views/key-tool"); const smodel_utils_1 = require("../../base/model/smodel-utils"); const model_1 = require("../bounds/model"); const model_2 = require("./model"); let HoverFeedbackCommand = class HoverFeedbackCommand extends command_1.SystemCommand { constructor(action) { super(); this.action = action; } execute(context) { const model = context.root; const modelElement = model.index.getById(this.action.mouseoverElement); if (modelElement) { if ((0, model_2.isHoverable)(modelElement)) { modelElement.hoverFeedback = this.action.mouseIsOver; } } return this.redo(context); } undo(context) { return context.root; } redo(context) { return context.root; } }; exports.HoverFeedbackCommand = HoverFeedbackCommand; HoverFeedbackCommand.KIND = actions_1.HoverFeedbackAction.KIND; exports.HoverFeedbackCommand = HoverFeedbackCommand = __decorate([ (0, inversify_1.injectable)(), __param(0, (0, inversify_1.inject)(types_1.TYPES.Action)), __metadata("design:paramtypes", [Object]) ], HoverFeedbackCommand); let SetPopupModelCommand = class SetPopupModelCommand extends command_1.PopupCommand { constructor(action) { super(); this.action = action; } execute(context) { this.oldRoot = context.root; this.newRoot = context.modelFactory.createRoot(this.action.newRoot); return this.newRoot; } undo(context) { return this.oldRoot; } redo(context) { return this.newRoot; } }; exports.SetPopupModelCommand = SetPopupModelCommand; SetPopupModelCommand.KIND = actions_1.SetPopupModelAction.KIND; exports.SetPopupModelCommand = SetPopupModelCommand = __decorate([ (0, inversify_1.injectable)(), __param(0, (0, inversify_1.inject)(types_1.TYPES.Action)), __metadata("design:paramtypes", [Object]) ], SetPopupModelCommand); class AbstractHoverMouseListener extends mouse_tool_1.MouseListener { mouseDown(target, event) { this.mouseIsDown = true; return []; } mouseUp(target, event) { this.mouseIsDown = false; return []; } stopMouseOutTimer() { if (this.state.mouseOutTimer !== undefined) { window.clearTimeout(this.state.mouseOutTimer); this.state.mouseOutTimer = undefined; } } startMouseOutTimer() { this.stopMouseOutTimer(); return new Promise((resolve) => { this.state.mouseOutTimer = window.setTimeout(() => { this.state.popupOpen = false; this.state.previousPopupElement = undefined; resolve(actions_1.SetPopupModelAction.create({ type: smodel_factory_1.EMPTY_ROOT.type, id: smodel_factory_1.EMPTY_ROOT.id })); }, this.options.popupCloseDelay); }); } stopMouseOverTimer() { if (this.state.mouseOverTimer !== undefined) { window.clearTimeout(this.state.mouseOverTimer); this.state.mouseOverTimer = undefined; } } } exports.AbstractHoverMouseListener = AbstractHoverMouseListener; __decorate([ (0, inversify_1.inject)(types_1.TYPES.ViewerOptions), __metadata("design:type", Object) ], AbstractHoverMouseListener.prototype, "options", void 0); __decorate([ (0, inversify_1.inject)(types_1.TYPES.HoverState), __metadata("design:type", Object) ], AbstractHoverMouseListener.prototype, "state", void 0); let HoverMouseListener = class HoverMouseListener extends AbstractHoverMouseListener { computePopupBounds(target, mousePosition) { // Default position: below the mouse cursor let offset = { x: -5, y: 20 }; const targetBounds = (0, model_1.getAbsoluteBounds)(target); const canvasBounds = target.root.canvasBounds; const boundsInWindow = geometry_1.Bounds.translate(targetBounds, canvasBounds); const distRight = boundsInWindow.x + boundsInWindow.width - mousePosition.x; const distBottom = boundsInWindow.y + boundsInWindow.height - mousePosition.y; if (distBottom <= distRight && this.allowSidePosition(target, 'below', distBottom)) { // Put the popup below the target element offset = { x: -5, y: Math.round(distBottom + 5) }; } else if (distRight <= distBottom && this.allowSidePosition(target, 'right', distRight)) { // Put the popup right of the target element offset = { x: Math.round(distRight + 5), y: -5 }; } let leftPopupPosition = mousePosition.x + offset.x; const canvasRightBorderPosition = canvasBounds.x + canvasBounds.width; if (leftPopupPosition > canvasRightBorderPosition) { leftPopupPosition = canvasRightBorderPosition; } let topPopupPosition = mousePosition.y + offset.y; const canvasBottomBorderPosition = canvasBounds.y + canvasBounds.height; if (topPopupPosition > canvasBottomBorderPosition) { topPopupPosition = canvasBottomBorderPosition; } return { x: leftPopupPosition, y: topPopupPosition, width: -1, height: -1 }; } allowSidePosition(target, side, distance) { return !(target instanceof smodel_1.SModelRootImpl) && distance <= 150; } startMouseOverTimer(target, event) { this.stopMouseOverTimer(); return new Promise((resolve) => { this.state.mouseOverTimer = window.setTimeout(() => { const popupBounds = this.computePopupBounds(target, { x: event.pageX, y: event.pageY }); resolve(actions_1.RequestPopupModelAction.create({ elementId: target.id, bounds: popupBounds })); this.state.popupOpen = true; this.state.previousPopupElement = target; }, this.options.popupOpenDelay); }); } mouseOver(target, event) { const result = []; if (!this.mouseIsDown) { const popupTarget = (0, smodel_utils_1.findParent)(target, model_2.hasPopupFeature); if (this.state.popupOpen && (popupTarget === undefined || this.state.previousPopupElement !== undefined && this.state.previousPopupElement.id !== popupTarget.id)) { result.push(this.startMouseOutTimer()); } else { this.stopMouseOverTimer(); this.stopMouseOutTimer(); } if (popupTarget !== undefined && (this.state.previousPopupElement === undefined || this.state.previousPopupElement.id !== popupTarget.id)) { result.push(this.startMouseOverTimer(popupTarget, event)); } if (this.lastHoverFeedbackElementId) { result.push(actions_1.HoverFeedbackAction.create({ mouseoverElement: this.lastHoverFeedbackElementId, mouseIsOver: false })); this.lastHoverFeedbackElementId = undefined; } const hoverTarget = (0, smodel_utils_1.findParentByFeature)(target, model_2.isHoverable); if (hoverTarget !== undefined) { result.push(actions_1.HoverFeedbackAction.create({ mouseoverElement: hoverTarget.id, mouseIsOver: true })); this.lastHoverFeedbackElementId = hoverTarget.id; } } return result; } mouseOut(target, event) { const result = []; if (!this.mouseIsDown) { const elementUnderMouse = this.getElementFromEventPosition(event); if (!this.isSprottyPopup(elementUnderMouse)) { if (this.state.popupOpen) { const popupTarget = (0, smodel_utils_1.findParent)(target, model_2.hasPopupFeature); if (this.state.previousPopupElement !== undefined && popupTarget !== undefined && this.state.previousPopupElement.id === popupTarget.id) result.push(this.startMouseOutTimer()); } this.stopMouseOverTimer(); const hoverTarget = (0, smodel_utils_1.findParentByFeature)(target, model_2.isHoverable); if (hoverTarget !== undefined) { result.push(actions_1.HoverFeedbackAction.create({ mouseoverElement: hoverTarget.id, mouseIsOver: false })); if (this.lastHoverFeedbackElementId && this.lastHoverFeedbackElementId !== hoverTarget.id) { result.push(actions_1.HoverFeedbackAction.create({ mouseoverElement: this.lastHoverFeedbackElementId, mouseIsOver: false })); } this.lastHoverFeedbackElementId = undefined; } } } return result; } getElementFromEventPosition(event) { return document.elementFromPoint(event.x, event.y); } isSprottyPopup(element) { return element ? (element.id === this.options.popupDiv || (!!element.parentElement && this.isSprottyPopup(element.parentElement))) : false; } mouseMove(target, event) { const result = []; if (!this.mouseIsDown) { if (this.state.previousPopupElement !== undefined && this.closeOnMouseMove(this.state.previousPopupElement, event)) { result.push(this.startMouseOutTimer()); } const popupTarget = (0, smodel_utils_1.findParent)(target, model_2.hasPopupFeature); if (popupTarget !== undefined && (this.state.previousPopupElement === undefined || this.state.previousPopupElement.id !== popupTarget.id)) { result.push(this.startMouseOverTimer(popupTarget, event)); } } return result; } closeOnMouseMove(target, event) { return target instanceof smodel_1.SModelRootImpl; } }; exports.HoverMouseListener = HoverMouseListener; __decorate([ (0, inversify_1.inject)(types_1.TYPES.ViewerOptions), __metadata("design:type", Object) ], HoverMouseListener.prototype, "options", void 0); exports.HoverMouseListener = HoverMouseListener = __decorate([ (0, inversify_1.injectable)() ], HoverMouseListener); let PopupHoverMouseListener = class PopupHoverMouseListener extends AbstractHoverMouseListener { mouseOut(target, event) { return [this.startMouseOutTimer()]; } mouseOver(target, event) { this.stopMouseOutTimer(); this.stopMouseOverTimer(); return []; } }; exports.PopupHoverMouseListener = PopupHoverMouseListener; exports.PopupHoverMouseListener = PopupHoverMouseListener = __decorate([ (0, inversify_1.injectable)() ], PopupHoverMouseListener); class HoverKeyListener extends key_tool_1.KeyListener { keyDown(element, event) { if ((0, keyboard_1.matchesKeystroke)(event, 'Escape')) { return [actions_1.SetPopupModelAction.create({ type: smodel_factory_1.EMPTY_ROOT.type, id: smodel_factory_1.EMPTY_ROOT.id })]; } return []; } } exports.HoverKeyListener = HoverKeyListener; let ClosePopupActionHandler = class ClosePopupActionHandler { constructor() { this.popupOpen = false; } handle(action) { if (action.kind === SetPopupModelCommand.KIND) { this.popupOpen = action.newRoot.type !== smodel_factory_1.EMPTY_ROOT.type; } else if (this.popupOpen) { return actions_1.SetPopupModelAction.create({ id: smodel_factory_1.EMPTY_ROOT.id, type: smodel_factory_1.EMPTY_ROOT.type }); } } }; exports.ClosePopupActionHandler = ClosePopupActionHandler; exports.ClosePopupActionHandler = ClosePopupActionHandler = __decorate([ (0, inversify_1.injectable)() ], ClosePopupActionHandler); //# sourceMappingURL=hover.js.map