import { VTapeLayout, RightVerticalAdaptLayout, HTapeLayout, AbsoluteLayout, VerticalLayout, Widget, shortcut, clamp, isPlainObject, extend, isNotNull, MouseMoveTracker, i18nText, SIZE_CONSANTS } from "@/core"; import { Label, IconButton, Button } from "../single"; import { Resizers } from "../0.base"; import { getOuterBody } from "@/core/utils/dom"; /** * Popover弹出层, * @class Popover * @extends Widget */ @shortcut() export class Popover extends Widget { _constant = { SIZE: { SMALL: "small", NORMAL: "normal", BIG: "big", }, MAX_HEIGHT: 600, }; props() { return { baseCls: "bi-popover bi-card bi-border-radius", size: "normal", // small, normal, big logic: { dynamic: false, }, header: null, headerHeight: 40, body: null, footer: null, footerHeight: 44, footerButtonHeight: 28, closable: true, // BI-40839 是否显示右上角的关闭按钮 bodyHgap: SIZE_CONSANTS.H_GAP_SIZE, bodyTgap: SIZE_CONSANTS.V_GAP_SIZE, }; } static xtype = "bi.popover"; static EVENT_CLOSE = "EVENT_CLOSE"; static EVENT_OPEN = "EVENT_OPEN"; static EVENT_CANCEL = "EVENT_CANCEL"; static EVENT_CONFIRM = "EVENT_CONFIRM"; render() { // var self = this; const { header, headerHeight, closable, logic, footer, footerHeight, body, bodyTgap, bodyHgap } = this.options; const c = this._constant; const size = this._calculateSize(); const items = [ { el: { type: HTapeLayout.xtype, cls: "bi-message-title bi-header-background", items: [ { el: { type: AbsoluteLayout.xtype, ref: _ref => { this.dragger = _ref; }, items: [ { el: isPlainObject(header) ? extend({}, header, { extraCls: "bi-font-bold", }) : { type: Label.xtype, cls: "bi-font-bold", height: headerHeight, text: header, title: header, textAlign: "left", }, top: 0, bottom: 0, left: SIZE_CONSANTS.H_GAP_SIZE, right: closable ? 0 : SIZE_CONSANTS.H_GAP_SIZE, } ], }, }, closable ? { el: { type: IconButton.xtype, cls: "bi-message-close close-font", height: headerHeight, handler: () => { this.close(); }, }, width: 56, } : null ], height: headerHeight, }, height: headerHeight, }, logic.dynamic ? { el: { type: VerticalLayout.xtype, scrolly: true, cls: "popover-body", ref: _ref => { this.body = _ref; }, css: { "max-height": this._getSuitableBodyHeight( c.MAX_HEIGHT - headerHeight - (footer ? footerHeight : 0) - bodyTgap ), "min-height": this._getSuitableBodyHeight( size.height - headerHeight - (footer ? footerHeight : 0) - bodyTgap ), }, items: [ { el: body, } ], hgap: bodyHgap, tgap: bodyTgap, }, } : { el: { type: AbsoluteLayout.xtype, items: [ { el: body, left: bodyHgap, top: bodyTgap, right: bodyHgap, bottom: 0, } ], }, } ]; if (footer) { items.push({ el: { type: AbsoluteLayout.xtype, items: [ { el: footer, left: SIZE_CONSANTS.H_GAP_SIZE, top: 0, right: SIZE_CONSANTS.H_GAP_SIZE, bottom: 0, } ], height: footerHeight, }, height: footerHeight, }); } return extend( { items, width: this._getSuitableWidth(size.width), }, logic.dynamic ? { type: VerticalLayout.xtype, scrolly: false, } : { type: VTapeLayout.xtype, height: this._getSuitableHeight(size.height), } ); } // mounted之后绑定事件 mounted() { this.startX = 0; this.startY = 0; this.tracker = new MouseMoveTracker( (deltaX, deltaY) => { const el = Widget._renderEngine.createElement(getOuterBody())[0]; const W = el.clientWidth; const H = el.clientHeight; this.startX += deltaX; this.startY += deltaY; this.element.css({ left: `${clamp(this.startX, 0, W - this.element.width())}px`, top: `${clamp(this.startY, 0, H - this.element.height())}px`, }); // BI-12134 没有什么特别好的方法 Resizers._resize({ target: this.element[0], }); }, () => { this.tracker.releaseMouseMoves(); }, _global ); this.dragger?.element.mousedown(e => { if (this.options.draggable !== false) { this.startX = this.element[0].offsetLeft; this.startY = this.element[0].offsetTop; this.tracker.captureMouseMoves(e); } }); } _getSuitableBodyHeight(height) { const { headerHeight, footer, footerHeight, bodyTgap } = this.options; const bodyDom = getOuterBody(); return clamp( height, 0, Widget._renderEngine.createElement(bodyDom)[0].clientHeight - headerHeight - (footer ? footerHeight : 0) - bodyTgap ); } _getSuitableHeight(height) { return clamp(height, 0, Widget._renderEngine.createElement(getOuterBody())[0].clientHeight); } _getSuitableWidth(width) { return clamp(width, 0, Widget._renderEngine.createElement(getOuterBody())[0].clientWidth); } _calculateSize() { const { size, width, height } = this.options; const sizeValue = {}; if (isNotNull(size)) { switch (size) { case this._constant.SIZE.SMALL: sizeValue.width = 450; sizeValue.height = 200; sizeValue.type = "small"; break; case this._constant.SIZE.BIG: sizeValue.width = 900; sizeValue.height = 500; sizeValue.type = "big"; break; default: sizeValue.width = 550; sizeValue.height = 500; sizeValue.type = "default"; } } return { width: width || sizeValue.width, height: height || sizeValue.height, type: sizeValue.type || "default", }; } setDraggable(b) { this.options.draggable = b; } hide() { } open() { this.show(); this.fireEvent(Popover.EVENT_OPEN, arguments); } close() { this.hide(); this.fireEvent(Popover.EVENT_CLOSE, arguments); } setZindex(zindex) { this.element.css({ "z-index": zindex }); } } @shortcut() export class BarPopover extends Popover { static xtype = "bi.bar_popover"; _defaultConfig() { return extend(super._defaultConfig(...arguments), { btns: [i18nText("BI-Basic_OK"), i18nText("BI-Basic_Cancel")], }); } beforeCreate() { const { footer, warningTitle, footerButtonHeight } = this.options; footer || (this.options.footer = { type: RightVerticalAdaptLayout.xtype, lgap: 10, items: [ { type: Button.xtype, height: footerButtonHeight, text: this.options.btns[1], value: 1, light: true, handler: v => { this.fireEvent(Popover.EVENT_CANCEL, v); this.close(v); }, }, { type: Button.xtype, height: footerButtonHeight, text: this.options.btns[0], warningTitle, value: 0, handler: v => { this.fireEvent(Popover.EVENT_CONFIRM, v); this.close(v); }, } ], }); } }