Convert Resizer to Typescript and create a Percentage based sizer
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
parent
c1fef5a941
commit
340e79179e
7 changed files with 205 additions and 92 deletions
|
@ -16,9 +16,15 @@ limitations under the License.
|
||||||
|
|
||||||
import FixedDistributor from "./fixed";
|
import FixedDistributor from "./fixed";
|
||||||
import ResizeItem from "../item";
|
import ResizeItem from "../item";
|
||||||
|
import {IConfig} from "../resizer";
|
||||||
|
|
||||||
class CollapseItem extends ResizeItem {
|
interface ICollapseConfig extends IConfig {
|
||||||
notifyCollapsed(collapsed) {
|
toggleSize: number;
|
||||||
|
onCollapsed?(collapsed: boolean, id: string, element: HTMLElement): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
class CollapseItem extends ResizeItem<ICollapseConfig> {
|
||||||
|
notifyCollapsed(collapsed: boolean) {
|
||||||
const callback = this.resizer.config.onCollapsed;
|
const callback = this.resizer.config.onCollapsed;
|
||||||
if (callback) {
|
if (callback) {
|
||||||
callback(collapsed, this.id, this.domNode);
|
callback(collapsed, this.id, this.domNode);
|
||||||
|
@ -26,18 +32,21 @@ class CollapseItem extends ResizeItem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class CollapseDistributor extends FixedDistributor {
|
export default class CollapseDistributor extends FixedDistributor<ICollapseConfig, CollapseItem> {
|
||||||
static createItem(resizeHandle, resizer, sizer) {
|
static createItem(resizeHandle, resizer, sizer) {
|
||||||
return new CollapseItem(resizeHandle, resizer, sizer);
|
return new CollapseItem(resizeHandle, resizer, sizer);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(item, config) {
|
private readonly toggleSize: number;
|
||||||
|
private isCollapsed: boolean;
|
||||||
|
|
||||||
|
constructor(item: CollapseItem) {
|
||||||
super(item);
|
super(item);
|
||||||
this.toggleSize = config && config.toggleSize;
|
this.toggleSize = item.resizer?.config?.toggleSize;
|
||||||
this.isCollapsed = false;
|
this.isCollapsed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
resize(newSize) {
|
public resize(newSize: number) {
|
||||||
const isCollapsedSize = newSize < this.toggleSize;
|
const isCollapsedSize = newSize < this.toggleSize;
|
||||||
if (isCollapsedSize && !this.isCollapsed) {
|
if (isCollapsedSize && !this.isCollapsed) {
|
||||||
this.isCollapsed = true;
|
this.isCollapsed = true;
|
|
@ -16,6 +16,7 @@ limitations under the License.
|
||||||
|
|
||||||
import ResizeItem from "../item";
|
import ResizeItem from "../item";
|
||||||
import Sizer from "../sizer";
|
import Sizer from "../sizer";
|
||||||
|
import Resizer, {IConfig} from "../resizer";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
distributors translate a moving cursor into
|
distributors translate a moving cursor into
|
||||||
|
@ -27,29 +28,34 @@ they have two methods:
|
||||||
within the container bounding box. For internal use.
|
within the container bounding box. For internal use.
|
||||||
This method usually ends up calling `resize` once the start offset is subtracted.
|
This method usually ends up calling `resize` once the start offset is subtracted.
|
||||||
*/
|
*/
|
||||||
export default class FixedDistributor {
|
export default class FixedDistributor<C extends IConfig, I extends ResizeItem<any> = ResizeItem<C>> {
|
||||||
static createItem(resizeHandle, resizer, sizer) {
|
static createItem(resizeHandle: HTMLDivElement, resizer: Resizer, sizer: Sizer) {
|
||||||
return new ResizeItem(resizeHandle, resizer, sizer);
|
return new ResizeItem(resizeHandle, resizer, sizer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static createSizer(containerElement, vertical, reverse) {
|
static createSizer(containerElement: HTMLElement, vertical: boolean, reverse: boolean) {
|
||||||
return new Sizer(containerElement, vertical, reverse);
|
return new Sizer(containerElement, vertical, reverse);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(item) {
|
private readonly beforeOffset: number;
|
||||||
this.item = item;
|
|
||||||
|
constructor(protected item: I) {
|
||||||
this.beforeOffset = item.offset();
|
this.beforeOffset = item.offset();
|
||||||
}
|
}
|
||||||
|
|
||||||
resize(size) {
|
public resize(size: number) {
|
||||||
this.item.setSize(size);
|
this.item.setSize(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
resizeFromContainerOffset(offset) {
|
public resizeFromContainerOffset(offset: number) {
|
||||||
this.resize(offset - this.beforeOffset);
|
this.resize(offset - this.beforeOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
start() {}
|
public start() {
|
||||||
|
this.item.start();
|
||||||
|
}
|
||||||
|
|
||||||
finish() {}
|
public finish() {
|
||||||
|
this.item.finish();
|
||||||
|
}
|
||||||
}
|
}
|
48
src/resizer/distributors/percentage.ts
Normal file
48
src/resizer/distributors/percentage.ts
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Sizer from "../sizer";
|
||||||
|
import FixedDistributor from "./fixed";
|
||||||
|
import {IConfig} from "../resizer";
|
||||||
|
|
||||||
|
class PercentageSizer extends Sizer {
|
||||||
|
public start(item: HTMLElement) {
|
||||||
|
if (this.vertical) {
|
||||||
|
item.style.minHeight = null;
|
||||||
|
} else {
|
||||||
|
item.style.minWidth = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public finish(item: HTMLElement) {
|
||||||
|
const parent = item.offsetParent as HTMLElement;
|
||||||
|
if (this.vertical) {
|
||||||
|
const p = ((item.offsetHeight / parent.offsetHeight) * 100).toFixed(2) + "%";
|
||||||
|
item.style.minHeight = p;
|
||||||
|
item.style.height = p;
|
||||||
|
} else {
|
||||||
|
const p = ((item.offsetWidth / parent.offsetWidth) * 100).toFixed(2) + "%";
|
||||||
|
item.style.minWidth = p;
|
||||||
|
item.style.width = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class PercentageDistributor extends FixedDistributor<IConfig> {
|
||||||
|
static createSizer(containerElement: HTMLElement, vertical: boolean, reverse: boolean) {
|
||||||
|
return new PercentageSizer(containerElement, vertical, reverse);
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,6 +15,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export FixedDistributor from "./distributors/fixed";
|
export {default as FixedDistributor} from "./distributors/fixed";
|
||||||
export CollapseDistributor from "./distributors/collapse";
|
export {default as PercentageDistributor} from "./distributors/percentage";
|
||||||
export Resizer from "./resizer";
|
export {default as CollapseDistributor} from "./distributors/collapse";
|
||||||
|
export {default as Resizer} from "./resizer";
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2019 New Vector Ltd
|
Copyright 2019 New Vector Ltd
|
||||||
|
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -14,63 +15,81 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export default class ResizeItem {
|
import Sizer from "./sizer";
|
||||||
constructor(handle, resizer, sizer) {
|
import Resizer, {IConfig} from "./resizer";
|
||||||
|
|
||||||
|
export default class ResizeItem<C extends IConfig = IConfig> {
|
||||||
|
protected readonly domNode: HTMLElement;
|
||||||
|
protected readonly id: string;
|
||||||
|
protected reverse: boolean;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
handle: HTMLElement,
|
||||||
|
public readonly resizer: Resizer<C>,
|
||||||
|
protected readonly sizer: Sizer,
|
||||||
|
) {
|
||||||
const id = handle.getAttribute("data-id");
|
const id = handle.getAttribute("data-id");
|
||||||
const reverse = resizer.isReverseResizeHandle(handle);
|
const reverse = resizer.isReverseResizeHandle(handle);
|
||||||
const domNode = reverse ? handle.nextElementSibling : handle.previousElementSibling;
|
|
||||||
|
|
||||||
this.domNode = domNode;
|
this.domNode = <HTMLElement>(reverse ? handle.nextElementSibling : handle.previousElementSibling);
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.reverse = reverse;
|
this.reverse = reverse;
|
||||||
this.resizer = resizer;
|
this.resizer = resizer;
|
||||||
this.sizer = sizer;
|
this.sizer = sizer;
|
||||||
}
|
}
|
||||||
|
|
||||||
_copyWith(handle, resizer, sizer) {
|
private copyWith(handle: Element, resizer: Resizer, sizer: Sizer) {
|
||||||
const Ctor = this.constructor;
|
const Ctor = this.constructor as typeof ResizeItem;
|
||||||
return new Ctor(handle, resizer, sizer);
|
return new Ctor(<HTMLElement>handle, resizer, sizer);
|
||||||
}
|
}
|
||||||
|
|
||||||
_advance(forwards) {
|
private advance(forwards: boolean) {
|
||||||
// opposite direction from fromResizeHandle to get back to handle
|
// opposite direction from fromResizeHandle to get back to handle
|
||||||
let handle = this.reverse ?
|
let handle = <HTMLElement>(this.reverse ?
|
||||||
this.domNode.previousElementSibling :
|
this.domNode.previousElementSibling :
|
||||||
this.domNode.nextElementSibling;
|
this.domNode.nextElementSibling);
|
||||||
const moveNext = forwards !== this.reverse; // xor
|
const moveNext = forwards !== this.reverse; // xor
|
||||||
// iterate at least once to avoid infinite loop
|
// iterate at least once to avoid infinite loop
|
||||||
do {
|
do {
|
||||||
if (moveNext) {
|
if (moveNext) {
|
||||||
handle = handle.nextElementSibling;
|
handle = <HTMLElement>handle.nextElementSibling;
|
||||||
} else {
|
} else {
|
||||||
handle = handle.previousElementSibling;
|
handle = <HTMLElement>handle.previousElementSibling;
|
||||||
}
|
}
|
||||||
} while (handle && !this.resizer.isResizeHandle(handle));
|
} while (handle && !this.resizer.isResizeHandle(handle));
|
||||||
|
|
||||||
if (handle) {
|
if (handle) {
|
||||||
const nextHandle = this._copyWith(handle, this.resizer, this.sizer);
|
const nextHandle = this.copyWith(handle, this.resizer, this.sizer);
|
||||||
nextHandle.reverse = this.reverse;
|
nextHandle.reverse = this.reverse;
|
||||||
return nextHandle;
|
return nextHandle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
next() {
|
public next() {
|
||||||
return this._advance(true);
|
return this.advance(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
previous() {
|
public previous() {
|
||||||
return this._advance(false);
|
return this.advance(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
size() {
|
public size() {
|
||||||
return this.sizer.getItemSize(this.domNode);
|
return this.sizer.getItemSize(this.domNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
offset() {
|
public offset() {
|
||||||
return this.sizer.getItemOffset(this.domNode);
|
return this.sizer.getItemOffset(this.domNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
setSize(size) {
|
public start() {
|
||||||
|
this.sizer.start(this.domNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public finish() {
|
||||||
|
this.sizer.finish(this.domNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public setSize(size: number) {
|
||||||
this.sizer.setItemSize(this.domNode, size);
|
this.sizer.setItemSize(this.domNode, size);
|
||||||
const callback = this.resizer.config.onResized;
|
const callback = this.resizer.config.onResized;
|
||||||
if (callback) {
|
if (callback) {
|
||||||
|
@ -78,7 +97,7 @@ export default class ResizeItem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clearSize() {
|
public clearSize() {
|
||||||
this.sizer.clearItemSize(this.domNode);
|
this.sizer.clearItemSize(this.domNode);
|
||||||
const callback = this.resizer.config.onResized;
|
const callback = this.resizer.config.onResized;
|
||||||
if (callback) {
|
if (callback) {
|
||||||
|
@ -86,22 +105,21 @@ export default class ResizeItem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public first() {
|
||||||
first() {
|
|
||||||
const firstHandle = Array.from(this.domNode.parentElement.children).find(el => {
|
const firstHandle = Array.from(this.domNode.parentElement.children).find(el => {
|
||||||
return this.resizer.isResizeHandle(el);
|
return this.resizer.isResizeHandle(<HTMLElement>el);
|
||||||
});
|
});
|
||||||
if (firstHandle) {
|
if (firstHandle) {
|
||||||
return this._copyWith(firstHandle, this.resizer, this.sizer);
|
return this.copyWith(firstHandle, this.resizer, this.sizer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
last() {
|
public last() {
|
||||||
const lastHandle = Array.from(this.domNode.parentElement.children).reverse().find(el => {
|
const lastHandle = Array.from(this.domNode.parentElement.children).reverse().find(el => {
|
||||||
return this.resizer.isResizeHandle(el);
|
return this.resizer.isResizeHandle(<HTMLElement>el);
|
||||||
});
|
});
|
||||||
if (lastHandle) {
|
if (lastHandle) {
|
||||||
return this._copyWith(lastHandle, this.resizer, this.sizer);
|
return this.copyWith(lastHandle, this.resizer, this.sizer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2018 New Vector Ltd
|
Copyright 2018 New Vector Ltd
|
||||||
Copyright 2019 The Matrix.org Foundation C.I.C.
|
Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -27,36 +27,59 @@ classNames:
|
||||||
resizing: string
|
resizing: string
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import FixedDistributor from "./distributors/fixed";
|
||||||
|
import Sizer from "./sizer";
|
||||||
|
import ResizeItem from "./item";
|
||||||
|
|
||||||
|
interface IClassNames {
|
||||||
|
handle?: string;
|
||||||
|
reverse?: string;
|
||||||
|
vertical?: string;
|
||||||
|
resizing?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IConfig {
|
||||||
|
onResizeStart?(): void;
|
||||||
|
onResizeStop?(): void;
|
||||||
|
onResized?(size: number, id: string, element: HTMLElement): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class Resizer<C extends IConfig = IConfig> {
|
||||||
|
private classNames: IClassNames;
|
||||||
|
|
||||||
export default class Resizer {
|
|
||||||
// TODO move vertical/horizontal to config option/container class
|
// TODO move vertical/horizontal to config option/container class
|
||||||
// as it doesn't make sense to mix them within one container/Resizer
|
// as it doesn't make sense to mix them within one container/Resizer
|
||||||
constructor(container, distributorCtor, config) {
|
constructor(
|
||||||
|
private readonly container: HTMLElement,
|
||||||
|
private readonly distributorCtor: {
|
||||||
|
new(item: ResizeItem): FixedDistributor<C, any>;
|
||||||
|
createItem(resizeHandle: HTMLDivElement, resizer: Resizer, sizer: Sizer): ResizeItem;
|
||||||
|
createSizer(containerElement: HTMLElement, vertical: boolean, reverse: boolean): Sizer;
|
||||||
|
},
|
||||||
|
public readonly config?: C,
|
||||||
|
) {
|
||||||
if (!container) {
|
if (!container) {
|
||||||
throw new Error("Resizer requires a non-null `container` arg");
|
throw new Error("Resizer requires a non-null `container` arg");
|
||||||
}
|
}
|
||||||
this.container = container;
|
|
||||||
this.distributorCtor = distributorCtor;
|
|
||||||
this.config = config;
|
|
||||||
this.classNames = {
|
this.classNames = {
|
||||||
handle: "resizer-handle",
|
handle: "resizer-handle",
|
||||||
reverse: "resizer-reverse",
|
reverse: "resizer-reverse",
|
||||||
vertical: "resizer-vertical",
|
vertical: "resizer-vertical",
|
||||||
resizing: "resizer-resizing",
|
resizing: "resizer-resizing",
|
||||||
};
|
};
|
||||||
this._onMouseDown = this._onMouseDown.bind(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setClassNames(classNames) {
|
public setClassNames(classNames: IClassNames) {
|
||||||
this.classNames = classNames;
|
this.classNames = classNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
attach() {
|
public attach() {
|
||||||
this.container.addEventListener("mousedown", this._onMouseDown, false);
|
this.container.addEventListener("mousedown", this.onMouseDown, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
detach() {
|
public detach() {
|
||||||
this.container.removeEventListener("mousedown", this._onMouseDown, false);
|
this.container.removeEventListener("mousedown", this.onMouseDown, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -65,36 +88,36 @@ export default class Resizer {
|
||||||
@param {number} handleIndex the index of the resize handle in the container
|
@param {number} handleIndex the index of the resize handle in the container
|
||||||
@return {Distributor} a new distributor for the given handle
|
@return {Distributor} a new distributor for the given handle
|
||||||
*/
|
*/
|
||||||
forHandleAt(handleIndex) {
|
public forHandleAt(handleIndex: number): FixedDistributor<C> {
|
||||||
const handles = this._getResizeHandles();
|
const handles = this.getResizeHandles();
|
||||||
const handle = handles[handleIndex];
|
const handle = handles[handleIndex];
|
||||||
if (handle) {
|
if (handle) {
|
||||||
const {distributor} = this._createSizerAndDistributor(handle);
|
const {distributor} = this.createSizerAndDistributor(<HTMLDivElement>handle);
|
||||||
return distributor;
|
return distributor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
forHandleWithId(id) {
|
public forHandleWithId(id: string): FixedDistributor<C> {
|
||||||
const handles = this._getResizeHandles();
|
const handles = this.getResizeHandles();
|
||||||
const handle = handles.find((h) => h.getAttribute("data-id") === id);
|
const handle = handles.find((h) => h.getAttribute("data-id") === id);
|
||||||
if (handle) {
|
if (handle) {
|
||||||
const {distributor} = this._createSizerAndDistributor(handle);
|
const {distributor} = this.createSizerAndDistributor(<HTMLDivElement>handle);
|
||||||
return distributor;
|
return distributor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isReverseResizeHandle(el) {
|
public isReverseResizeHandle(el: HTMLElement): boolean {
|
||||||
return el && el.classList.contains(this.classNames.reverse);
|
return el && el.classList.contains(this.classNames.reverse);
|
||||||
}
|
}
|
||||||
|
|
||||||
isResizeHandle(el) {
|
public isResizeHandle(el: HTMLElement): boolean {
|
||||||
return el && el.classList.contains(this.classNames.handle);
|
return el && el.classList.contains(this.classNames.handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onMouseDown(event) {
|
private onMouseDown = (event: MouseEvent) => {
|
||||||
// use closest in case the resize handle contains
|
// use closest in case the resize handle contains
|
||||||
// child dom nodes that can be the target
|
// child dom nodes that can be the target
|
||||||
const resizeHandle = event.target && event.target.closest(`.${this.classNames.handle}`);
|
const resizeHandle = event.target && (<HTMLElement>event.target).closest(`.${this.classNames.handle}`);
|
||||||
if (!resizeHandle || resizeHandle.parentElement !== this.container) {
|
if (!resizeHandle || resizeHandle.parentElement !== this.container) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -109,7 +132,7 @@ export default class Resizer {
|
||||||
this.config.onResizeStart();
|
this.config.onResizeStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
const {sizer, distributor} = this._createSizerAndDistributor(resizeHandle);
|
const {sizer, distributor} = this.createSizerAndDistributor(<HTMLDivElement>resizeHandle);
|
||||||
distributor.start();
|
distributor.start();
|
||||||
|
|
||||||
const onMouseMove = (event) => {
|
const onMouseMove = (event) => {
|
||||||
|
@ -133,21 +156,23 @@ export default class Resizer {
|
||||||
body.addEventListener("mouseup", finishResize, false);
|
body.addEventListener("mouseup", finishResize, false);
|
||||||
document.addEventListener("mouseleave", finishResize, false);
|
document.addEventListener("mouseleave", finishResize, false);
|
||||||
body.addEventListener("mousemove", onMouseMove, false);
|
body.addEventListener("mousemove", onMouseMove, false);
|
||||||
}
|
};
|
||||||
|
|
||||||
_createSizerAndDistributor(resizeHandle) {
|
private createSizerAndDistributor(
|
||||||
|
resizeHandle: HTMLDivElement,
|
||||||
|
): {sizer: Sizer, distributor: FixedDistributor<any>} {
|
||||||
const vertical = resizeHandle.classList.contains(this.classNames.vertical);
|
const vertical = resizeHandle.classList.contains(this.classNames.vertical);
|
||||||
const reverse = this.isReverseResizeHandle(resizeHandle);
|
const reverse = this.isReverseResizeHandle(resizeHandle);
|
||||||
const Distributor = this.distributorCtor;
|
const Distributor = this.distributorCtor;
|
||||||
const sizer = Distributor.createSizer(this.container, vertical, reverse);
|
const sizer = Distributor.createSizer(this.container, vertical, reverse);
|
||||||
const item = Distributor.createItem(resizeHandle, this, sizer);
|
const item = Distributor.createItem(resizeHandle, this, sizer);
|
||||||
const distributor = new Distributor(item, this.config);
|
const distributor = new Distributor(item);
|
||||||
return {sizer, distributor};
|
return {sizer, distributor};
|
||||||
}
|
}
|
||||||
|
|
||||||
_getResizeHandles() {
|
private getResizeHandles() {
|
||||||
return Array.from(this.container.children).filter(el => {
|
return Array.from(this.container.children).filter(el => {
|
||||||
return this.isResizeHandle(el);
|
return this.isResizeHandle(<HTMLElement>el);
|
||||||
});
|
}) as HTMLElement[];
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -19,18 +19,18 @@ implements DOM/CSS operations for resizing.
|
||||||
The sizer determines what CSS mechanism is used for sizing items, like flexbox, ...
|
The sizer determines what CSS mechanism is used for sizing items, like flexbox, ...
|
||||||
*/
|
*/
|
||||||
export default class Sizer {
|
export default class Sizer {
|
||||||
constructor(container, vertical, reverse) {
|
constructor(
|
||||||
this.container = container;
|
protected readonly container: HTMLElement,
|
||||||
this.reverse = reverse;
|
protected readonly vertical: boolean,
|
||||||
this.vertical = vertical;
|
protected readonly reverse: boolean,
|
||||||
}
|
) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@param {Element} item the dom element being resized
|
@param {Element} item the dom element being resized
|
||||||
@return {number} how far the edge of the item is from the edge of the container
|
@return {number} how far the edge of the item is from the edge of the container
|
||||||
*/
|
*/
|
||||||
getItemOffset(item) {
|
public getItemOffset(item: HTMLElement): number {
|
||||||
const offset = (this.vertical ? item.offsetTop : item.offsetLeft) - this._getOffset();
|
const offset = (this.vertical ? item.offsetTop : item.offsetLeft) - this.getOffset();
|
||||||
if (this.reverse) {
|
if (this.reverse) {
|
||||||
return this.getTotalSize() - (offset + this.getItemSize(item));
|
return this.getTotalSize() - (offset + this.getItemSize(item));
|
||||||
} else {
|
} else {
|
||||||
|
@ -42,33 +42,33 @@ export default class Sizer {
|
||||||
@param {Element} item the dom element being resized
|
@param {Element} item the dom element being resized
|
||||||
@return {number} the width/height of an item in the container
|
@return {number} the width/height of an item in the container
|
||||||
*/
|
*/
|
||||||
getItemSize(item) {
|
public getItemSize(item: HTMLElement): number {
|
||||||
return this.vertical ? item.offsetHeight : item.offsetWidth;
|
return this.vertical ? item.offsetHeight : item.offsetWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return {number} the width/height of the container */
|
/** @return {number} the width/height of the container */
|
||||||
getTotalSize() {
|
public getTotalSize(): number {
|
||||||
return this.vertical ? this.container.offsetHeight : this.container.offsetWidth;
|
return this.vertical ? this.container.offsetHeight : this.container.offsetWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return {number} container offset to offsetParent */
|
/** @return {number} container offset to offsetParent */
|
||||||
_getOffset() {
|
private getOffset(): number {
|
||||||
return this.vertical ? this.container.offsetTop : this.container.offsetLeft;
|
return this.vertical ? this.container.offsetTop : this.container.offsetLeft;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return {number} container offset to document */
|
/** @return {number} container offset to document */
|
||||||
_getPageOffset() {
|
private getPageOffset() {
|
||||||
let element = this.container;
|
let element = this.container;
|
||||||
let offset = 0;
|
let offset = 0;
|
||||||
while (element) {
|
while (element) {
|
||||||
const pos = this.vertical ? element.offsetTop : element.offsetLeft;
|
const pos = this.vertical ? element.offsetTop : element.offsetLeft;
|
||||||
offset = offset + pos;
|
offset = offset + pos;
|
||||||
element = element.offsetParent;
|
element = element.offsetParent as HTMLElement;
|
||||||
}
|
}
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
setItemSize(item, size) {
|
public setItemSize(item: HTMLElement, size: number) {
|
||||||
if (this.vertical) {
|
if (this.vertical) {
|
||||||
item.style.height = `${Math.round(size)}px`;
|
item.style.height = `${Math.round(size)}px`;
|
||||||
} else {
|
} else {
|
||||||
|
@ -76,7 +76,7 @@ export default class Sizer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clearItemSize(item) {
|
public clearItemSize(item: HTMLElement) {
|
||||||
if (this.vertical) {
|
if (this.vertical) {
|
||||||
item.style.height = null;
|
item.style.height = null;
|
||||||
} else {
|
} else {
|
||||||
|
@ -84,17 +84,23 @@ export default class Sizer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
public start(item: HTMLElement) {}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
public finish(item: HTMLElement) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@param {MouseEvent} event the mouse event
|
@param {MouseEvent} event the mouse event
|
||||||
@return {number} the distance between the cursor and the edge of the container,
|
@return {number} the distance between the cursor and the edge of the container,
|
||||||
along the applicable axis (vertical or horizontal)
|
along the applicable axis (vertical or horizontal)
|
||||||
*/
|
*/
|
||||||
offsetFromEvent(event) {
|
public offsetFromEvent(event: MouseEvent) {
|
||||||
const pos = this.vertical ? event.pageY : event.pageX;
|
const pos = this.vertical ? event.pageY : event.pageX;
|
||||||
if (this.reverse) {
|
if (this.reverse) {
|
||||||
return (this._getPageOffset() + this.getTotalSize()) - pos;
|
return (this.getPageOffset() + this.getTotalSize()) - pos;
|
||||||
} else {
|
} else {
|
||||||
return pos - this._getPageOffset();
|
return pos - this.getPageOffset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Add table
Add a link
Reference in a new issue