dockview-core
Version:
Zero dependency layout manager supporting tabs, grids and splitviews
477 lines (476 loc) • 21.5 kB
JavaScript
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __read = (this && this.__read) || function (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;
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Overlay = void 0;
var dom_1 = require("../dom");
var events_1 = require("../events");
var lifecycle_1 = require("../lifecycle");
var math_1 = require("../math");
var AriaLevelTracker = /** @class */ (function () {
function AriaLevelTracker() {
this._orderedList = [];
}
AriaLevelTracker.prototype.push = function (element) {
this._orderedList = __spreadArray(__spreadArray([], __read(this._orderedList.filter(function (item) { return item !== element; })), false), [
element,
], false);
this.update();
};
AriaLevelTracker.prototype.destroy = function (element) {
this._orderedList = this._orderedList.filter(function (item) { return item !== element; });
this.update();
};
AriaLevelTracker.prototype.update = function () {
for (var i = 0; i < this._orderedList.length; i++) {
this._orderedList[i].setAttribute('aria-level', "".concat(i));
this._orderedList[i].style.zIndex = "calc(var(--dv-overlay-z-index, 999) + ".concat(i * 2, ")");
}
};
return AriaLevelTracker;
}());
var arialLevelTracker = new AriaLevelTracker();
var Overlay = /** @class */ (function (_super) {
__extends(Overlay, _super);
function Overlay(options) {
var _this = _super.call(this) || this;
_this.options = options;
_this._element = document.createElement('div');
_this._onDidChange = new events_1.Emitter();
_this.onDidChange = _this._onDidChange.event;
_this._onDidChangeEnd = new events_1.Emitter();
_this.onDidChangeEnd = _this._onDidChangeEnd.event;
_this.addDisposables(_this._onDidChange, _this._onDidChangeEnd);
_this._element.className = 'dv-resize-container';
_this._isVisible = true;
_this.setupResize('top');
_this.setupResize('bottom');
_this.setupResize('left');
_this.setupResize('right');
_this.setupResize('topleft');
_this.setupResize('topright');
_this.setupResize('bottomleft');
_this.setupResize('bottomright');
_this._element.appendChild(_this.options.content);
_this.options.container.appendChild(_this._element);
// if input bad resize within acceptable boundaries
_this.setBounds(__assign(__assign(__assign(__assign({ height: _this.options.height, width: _this.options.width }, ('top' in _this.options && { top: _this.options.top })), ('bottom' in _this.options && { bottom: _this.options.bottom })), ('left' in _this.options && { left: _this.options.left })), ('right' in _this.options && { right: _this.options.right })));
arialLevelTracker.push(_this._element);
return _this;
}
Object.defineProperty(Overlay.prototype, "minimumInViewportWidth", {
set: function (value) {
this.options.minimumInViewportWidth = value;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Overlay.prototype, "minimumInViewportHeight", {
set: function (value) {
this.options.minimumInViewportHeight = value;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Overlay.prototype, "element", {
get: function () {
return this._element;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Overlay.prototype, "isVisible", {
get: function () {
return this._isVisible;
},
enumerable: false,
configurable: true
});
Overlay.prototype.setVisible = function (isVisible) {
if (isVisible === this.isVisible) {
return;
}
this._isVisible = isVisible;
(0, dom_1.toggleClass)(this.element, 'dv-hidden', !this.isVisible);
};
Overlay.prototype.bringToFront = function () {
arialLevelTracker.push(this._element);
};
Overlay.prototype.setBounds = function (bounds) {
if (bounds === void 0) { bounds = {}; }
if (typeof bounds.height === 'number') {
this._element.style.height = "".concat(bounds.height, "px");
}
if (typeof bounds.width === 'number') {
this._element.style.width = "".concat(bounds.width, "px");
}
if ('top' in bounds && typeof bounds.top === 'number') {
this._element.style.top = "".concat(bounds.top, "px");
this._element.style.bottom = 'auto';
this.verticalAlignment = 'top';
}
if ('bottom' in bounds && typeof bounds.bottom === 'number') {
this._element.style.bottom = "".concat(bounds.bottom, "px");
this._element.style.top = 'auto';
this.verticalAlignment = 'bottom';
}
if ('left' in bounds && typeof bounds.left === 'number') {
this._element.style.left = "".concat(bounds.left, "px");
this._element.style.right = 'auto';
this.horiziontalAlignment = 'left';
}
if ('right' in bounds && typeof bounds.right === 'number') {
this._element.style.right = "".concat(bounds.right, "px");
this._element.style.left = 'auto';
this.horiziontalAlignment = 'right';
}
var containerRect = this.options.container.getBoundingClientRect();
var overlayRect = this._element.getBoundingClientRect();
// region: ensure bounds within allowable limits
// a minimum width of minimumViewportWidth must be inside the viewport
var xOffset = Math.max(0, this.getMinimumWidth(overlayRect.width));
// a minimum height of minimumViewportHeight must be inside the viewport
var yOffset = Math.max(0, this.getMinimumHeight(overlayRect.height));
if (this.verticalAlignment === 'top') {
var top_1 = (0, math_1.clamp)(overlayRect.top - containerRect.top, -yOffset, Math.max(0, containerRect.height - overlayRect.height + yOffset));
this._element.style.top = "".concat(top_1, "px");
this._element.style.bottom = 'auto';
}
if (this.verticalAlignment === 'bottom') {
var bottom = (0, math_1.clamp)(containerRect.bottom - overlayRect.bottom, -yOffset, Math.max(0, containerRect.height - overlayRect.height + yOffset));
this._element.style.bottom = "".concat(bottom, "px");
this._element.style.top = 'auto';
}
if (this.horiziontalAlignment === 'left') {
var left = (0, math_1.clamp)(overlayRect.left - containerRect.left, -xOffset, Math.max(0, containerRect.width - overlayRect.width + xOffset));
this._element.style.left = "".concat(left, "px");
this._element.style.right = 'auto';
}
if (this.horiziontalAlignment === 'right') {
var right = (0, math_1.clamp)(containerRect.right - overlayRect.right, -xOffset, Math.max(0, containerRect.width - overlayRect.width + xOffset));
this._element.style.right = "".concat(right, "px");
this._element.style.left = 'auto';
}
this._onDidChange.fire();
};
Overlay.prototype.toJSON = function () {
var container = this.options.container.getBoundingClientRect();
var element = this._element.getBoundingClientRect();
var result = {};
if (this.verticalAlignment === 'top') {
result.top = parseFloat(this._element.style.top);
}
else if (this.verticalAlignment === 'bottom') {
result.bottom = parseFloat(this._element.style.bottom);
}
else {
result.top = element.top - container.top;
}
if (this.horiziontalAlignment === 'left') {
result.left = parseFloat(this._element.style.left);
}
else if (this.horiziontalAlignment === 'right') {
result.right = parseFloat(this._element.style.right);
}
else {
result.left = element.left - container.left;
}
result.width = element.width;
result.height = element.height;
return result;
};
Overlay.prototype.setupDrag = function (dragTarget, options) {
var _this = this;
if (options === void 0) { options = { inDragMode: false }; }
var move = new lifecycle_1.MutableDisposable();
var track = function () {
var offset = null;
var iframes = (0, dom_1.disableIframePointEvents)();
move.value = new lifecycle_1.CompositeDisposable({
dispose: function () {
iframes.release();
},
}, (0, events_1.addDisposableListener)(window, 'pointermove', function (e) {
var containerRect = _this.options.container.getBoundingClientRect();
var x = e.clientX - containerRect.left;
var y = e.clientY - containerRect.top;
(0, dom_1.toggleClass)(_this._element, 'dv-resize-container-dragging', true);
var overlayRect = _this._element.getBoundingClientRect();
if (offset === null) {
offset = {
x: e.clientX - overlayRect.left,
y: e.clientY - overlayRect.top,
};
}
var xOffset = Math.max(0, _this.getMinimumWidth(overlayRect.width));
var yOffset = Math.max(0, _this.getMinimumHeight(overlayRect.height));
var top = (0, math_1.clamp)(y - offset.y, -yOffset, Math.max(0, containerRect.height - overlayRect.height + yOffset));
var bottom = (0, math_1.clamp)(offset.y -
y +
containerRect.height -
overlayRect.height, -yOffset, Math.max(0, containerRect.height - overlayRect.height + yOffset));
var left = (0, math_1.clamp)(x - offset.x, -xOffset, Math.max(0, containerRect.width - overlayRect.width + xOffset));
var right = (0, math_1.clamp)(offset.x - x + containerRect.width - overlayRect.width, -xOffset, Math.max(0, containerRect.width - overlayRect.width + xOffset));
var bounds = {};
// Anchor to top or to bottom depending on which one is closer
if (top <= bottom) {
bounds.top = top;
}
else {
bounds.bottom = bottom;
}
// Anchor to left or to right depending on which one is closer
if (left <= right) {
bounds.left = left;
}
else {
bounds.right = right;
}
_this.setBounds(bounds);
}), (0, events_1.addDisposableListener)(window, 'pointerup', function () {
(0, dom_1.toggleClass)(_this._element, 'dv-resize-container-dragging', false);
move.dispose();
_this._onDidChangeEnd.fire();
}));
};
this.addDisposables(move, (0, events_1.addDisposableListener)(dragTarget, 'pointerdown', function (event) {
if (event.defaultPrevented) {
event.preventDefault();
return;
}
// if somebody has marked this event then treat as a defaultPrevented
// without actually calling event.preventDefault()
if ((0, dom_1.quasiDefaultPrevented)(event)) {
return;
}
track();
}), (0, events_1.addDisposableListener)(this.options.content, 'pointerdown', function (event) {
if (event.defaultPrevented) {
return;
}
// if somebody has marked this event then treat as a defaultPrevented
// without actually calling event.preventDefault()
if ((0, dom_1.quasiDefaultPrevented)(event)) {
return;
}
if (event.shiftKey) {
track();
}
}), (0, events_1.addDisposableListener)(this.options.content, 'pointerdown', function () {
arialLevelTracker.push(_this._element);
}, true));
if (options.inDragMode) {
track();
}
};
Overlay.prototype.setupResize = function (direction) {
var _this = this;
var resizeHandleElement = document.createElement('div');
resizeHandleElement.className = "dv-resize-handle-".concat(direction);
this._element.appendChild(resizeHandleElement);
var move = new lifecycle_1.MutableDisposable();
this.addDisposables(move, (0, events_1.addDisposableListener)(resizeHandleElement, 'pointerdown', function (e) {
e.preventDefault();
var startPosition = null;
var iframes = (0, dom_1.disableIframePointEvents)();
move.value = new lifecycle_1.CompositeDisposable((0, events_1.addDisposableListener)(window, 'pointermove', function (e) {
var containerRect = _this.options.container.getBoundingClientRect();
var overlayRect = _this._element.getBoundingClientRect();
var y = e.clientY - containerRect.top;
var x = e.clientX - containerRect.left;
if (startPosition === null) {
// record the initial dimensions since as all subsequence moves are relative to this
startPosition = {
originalY: y,
originalHeight: overlayRect.height,
originalX: x,
originalWidth: overlayRect.width,
};
}
var top = undefined;
var bottom = undefined;
var height = undefined;
var left = undefined;
var right = undefined;
var width = undefined;
var moveTop = function () {
top = (0, math_1.clamp)(y, -Number.MAX_VALUE, startPosition.originalY +
startPosition.originalHeight >
containerRect.height
? _this.getMinimumHeight(containerRect.height)
: Math.max(0, startPosition.originalY +
startPosition.originalHeight -
Overlay.MINIMUM_HEIGHT));
height =
startPosition.originalY +
startPosition.originalHeight -
top;
bottom = containerRect.height - top - height;
};
var moveBottom = function () {
top =
startPosition.originalY -
startPosition.originalHeight;
height = (0, math_1.clamp)(y - top, top < 0 &&
typeof _this.options
.minimumInViewportHeight === 'number'
? -top +
_this.options.minimumInViewportHeight
: Overlay.MINIMUM_HEIGHT, Number.MAX_VALUE);
bottom = containerRect.height - top - height;
};
var moveLeft = function () {
left = (0, math_1.clamp)(x, -Number.MAX_VALUE, startPosition.originalX +
startPosition.originalWidth >
containerRect.width
? _this.getMinimumWidth(containerRect.width)
: Math.max(0, startPosition.originalX +
startPosition.originalWidth -
Overlay.MINIMUM_WIDTH));
width =
startPosition.originalX +
startPosition.originalWidth -
left;
right = containerRect.width - left - width;
};
var moveRight = function () {
left =
startPosition.originalX -
startPosition.originalWidth;
width = (0, math_1.clamp)(x - left, left < 0 &&
typeof _this.options
.minimumInViewportWidth === 'number'
? -left +
_this.options.minimumInViewportWidth
: Overlay.MINIMUM_WIDTH, Number.MAX_VALUE);
right = containerRect.width - left - width;
};
switch (direction) {
case 'top':
moveTop();
break;
case 'bottom':
moveBottom();
break;
case 'left':
moveLeft();
break;
case 'right':
moveRight();
break;
case 'topleft':
moveTop();
moveLeft();
break;
case 'topright':
moveTop();
moveRight();
break;
case 'bottomleft':
moveBottom();
moveLeft();
break;
case 'bottomright':
moveBottom();
moveRight();
break;
}
var bounds = {};
// Anchor to top or to bottom depending on which one is closer
if (top <= bottom) {
bounds.top = top;
}
else {
bounds.bottom = bottom;
}
// Anchor to left or to right depending on which one is closer
if (left <= right) {
bounds.left = left;
}
else {
bounds.right = right;
}
bounds.height = height;
bounds.width = width;
_this.setBounds(bounds);
}), {
dispose: function () {
iframes.release();
},
}, (0, events_1.addDisposableListener)(window, 'pointerup', function () {
move.dispose();
_this._onDidChangeEnd.fire();
}));
}));
};
Overlay.prototype.getMinimumWidth = function (width) {
if (typeof this.options.minimumInViewportWidth === 'number') {
return width - this.options.minimumInViewportWidth;
}
return 0;
};
Overlay.prototype.getMinimumHeight = function (height) {
if (typeof this.options.minimumInViewportHeight === 'number') {
return height - this.options.minimumInViewportHeight;
}
return 0;
};
Overlay.prototype.dispose = function () {
arialLevelTracker.destroy(this._element);
this._element.remove();
_super.prototype.dispose.call(this);
};
Overlay.MINIMUM_HEIGHT = 20;
Overlay.MINIMUM_WIDTH = 20;
return Overlay;
}(lifecycle_1.CompositeDisposable));
exports.Overlay = Overlay;