318 lines
8.7 KiB
TypeScript
318 lines
8.7 KiB
TypeScript
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
import {
|
|
DataUtil,
|
|
getObjectPropertyValueByKey,
|
|
stringSnakeToCamel,
|
|
getAttributeValueByBreakpoint,
|
|
getViewPort,
|
|
isVisibleElement,
|
|
throttle,
|
|
getCSS,
|
|
ElementStyleUtil,
|
|
} from "../_utils/index";
|
|
//import { CookieComponent } from "./_CookieComponent";
|
|
|
|
export interface ScrollOptions {
|
|
saveState?: boolean;
|
|
}
|
|
|
|
const defaultScrollOptions: ScrollOptions = {
|
|
saveState: true,
|
|
};
|
|
|
|
class ScrollComponent {
|
|
element: HTMLElement;
|
|
options: ScrollOptions;
|
|
id: string;
|
|
|
|
constructor(_element: HTMLElement, options: ScrollOptions) {
|
|
this.element = _element;
|
|
this.options = Object.assign(defaultScrollOptions, options);
|
|
this.id = this.element.getAttribute("id") || "";
|
|
this.update();
|
|
// this.element.setAttribute('data-kt-scrolltop', 'true')
|
|
DataUtil.set(this.element, "scroll", this);
|
|
}
|
|
|
|
private getOption = (name: string) => {
|
|
if (this.element.hasAttribute("data-kt-scroll-" + name) === true) {
|
|
const attr = this.element.getAttribute("data-kt-scroll-" + name) || "";
|
|
let value: string | JSON | boolean = getAttributeValueByBreakpoint(attr);
|
|
if (value !== null && String(value) === "true") {
|
|
value = true;
|
|
} else if (value !== null && String(value) === "false") {
|
|
value = false;
|
|
}
|
|
|
|
return value;
|
|
} else {
|
|
const optionName = stringSnakeToCamel(name);
|
|
const option = getObjectPropertyValueByKey(this.options, optionName);
|
|
if (option) {
|
|
return getAttributeValueByBreakpoint(option);
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
};
|
|
|
|
private getHeightType = () => {
|
|
if (this.getOption("height")) {
|
|
return "height";
|
|
}
|
|
if (this.getOption("min-height")) {
|
|
return "min-height";
|
|
}
|
|
if (this.getOption("max-height")) {
|
|
return "max-height";
|
|
}
|
|
};
|
|
|
|
private getAutoHeight = () => {
|
|
let height: number | string = getViewPort().height;
|
|
const dependencies = this.getOption("dependencies");
|
|
const wrappers = this.getOption("wrappers");
|
|
const offset = this.getOption("offset");
|
|
|
|
// Height dependencies
|
|
if (dependencies !== null) {
|
|
const elements = document.querySelectorAll(dependencies as string);
|
|
if (elements && elements.length > 0) {
|
|
for (let i = 0, len = elements.length; i < len; i++) {
|
|
const element = elements[i] as HTMLElement;
|
|
if (isVisibleElement(element) === false) {
|
|
continue;
|
|
}
|
|
|
|
height = height - parseInt(getCSS(element, "height"));
|
|
height = height - parseInt(getCSS(element, "margin-top"));
|
|
height = height - parseInt(getCSS(element, "margin-bottom"));
|
|
|
|
const borderTop = getCSS(element, "border-top");
|
|
if (borderTop) {
|
|
height = height - parseInt(borderTop);
|
|
}
|
|
|
|
const borderBottom = getCSS(element, "border-bottom");
|
|
if (borderBottom) {
|
|
height = height - parseInt(borderBottom);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Wrappers
|
|
if (wrappers !== null) {
|
|
const elements = document.querySelectorAll(wrappers as string);
|
|
if (elements && elements.length > 0) {
|
|
for (let i = 0, len = elements.length; i < len; i++) {
|
|
const element = elements[i] as HTMLElement;
|
|
|
|
if (!isVisibleElement(element)) {
|
|
continue;
|
|
}
|
|
|
|
height = height - parseInt(getCSS(element, "margin-top"));
|
|
height = height - parseInt(getCSS(element, "margin-bottom"));
|
|
height = height - parseInt(getCSS(element, "padding-top"));
|
|
height = height - parseInt(getCSS(element, "padding-bottom"));
|
|
|
|
const borderTop = getCSS(element, "border-top");
|
|
if (borderTop) {
|
|
height = height - parseInt(borderTop);
|
|
}
|
|
|
|
const borderBottom = getCSS(element, "border-bottom");
|
|
if (borderBottom) {
|
|
height = height - parseInt(borderBottom);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Custom offset
|
|
if (offset !== null) {
|
|
height = height - parseInt(offset as string);
|
|
}
|
|
|
|
height = height - parseInt(getCSS(this.element, "margin-top"));
|
|
height = height - parseInt(getCSS(this.element, "margin-bottom"));
|
|
|
|
const borderTop = getCSS(this.element, "border-top");
|
|
if (borderTop) {
|
|
height = height - parseInt(borderTop);
|
|
}
|
|
|
|
const borderBottom = getCSS(this.element, "border-bottom");
|
|
if (borderBottom) {
|
|
height = height - parseInt(borderBottom);
|
|
}
|
|
|
|
height = String(height) + "px";
|
|
|
|
return height;
|
|
};
|
|
|
|
private setupHeight = () => {
|
|
const height = this.getHeight();
|
|
const heightType = this.getHeightType() as string;
|
|
|
|
// Set height
|
|
if (height !== null && height.length > 0) {
|
|
ElementStyleUtil.set(this.element, heightType, height);
|
|
} else {
|
|
ElementStyleUtil.set(this.element, heightType, "");
|
|
}
|
|
};
|
|
|
|
private setupState = () => {
|
|
if (this.getOption("save-state") === true && this.id) {
|
|
// const cookie = CookieComponent.get(this.id + "st");
|
|
// if (cookie) {
|
|
// const pos = parseInt(cookie);
|
|
|
|
// if (pos > 0) {
|
|
// this.element.scrollTop = pos;
|
|
// }
|
|
// }
|
|
}
|
|
};
|
|
|
|
private setupScrollHandler = () => {
|
|
if (this.getOption("save-state") === true && this.id) {
|
|
this.element.addEventListener("scroll", this.scrollHandler);
|
|
} else {
|
|
this.element.removeEventListener("scroll", this.scrollHandler);
|
|
}
|
|
};
|
|
|
|
private scrollHandler = () => {
|
|
const cookieId = this.id + "st";
|
|
//CookieComponent.set(cookieId, this.element.scrollTop, {});
|
|
};
|
|
|
|
private destroyScrollHandler = () => {
|
|
this.element.removeEventListener("scroll", this.scrollHandler);
|
|
};
|
|
|
|
private resetHeight = () => {
|
|
const heghtType = this.getHeightType();
|
|
if (heghtType) {
|
|
ElementStyleUtil.set(this.element, heghtType, "");
|
|
}
|
|
};
|
|
|
|
///////////////////////
|
|
// ** Public API ** //
|
|
///////////////////////
|
|
public update = () => {
|
|
// Activate/deactivate
|
|
if (
|
|
this.getOption("activate") === true ||
|
|
!this.element.hasAttribute("data-kt-scroll-activate")
|
|
) {
|
|
this.setupHeight();
|
|
this.setupScrollHandler();
|
|
this.setupState();
|
|
} else {
|
|
this.resetHeight();
|
|
this.destroyScrollHandler();
|
|
}
|
|
};
|
|
|
|
public getHeight = () => {
|
|
const heightType = this.getHeightType();
|
|
const height = this.getOption(heightType || "");
|
|
if (height instanceof Function) {
|
|
return height.call(height);
|
|
} else if (
|
|
height !== null &&
|
|
typeof height === "string" &&
|
|
height.toLowerCase() === "auto"
|
|
) {
|
|
return this.getAutoHeight();
|
|
} else {
|
|
return height;
|
|
}
|
|
};
|
|
|
|
public getElement = () => {
|
|
return this.element;
|
|
};
|
|
|
|
// Static methods
|
|
public static hasInstace(element: HTMLElement) {
|
|
return DataUtil.has(element, "scroll");
|
|
}
|
|
|
|
public static getInstance(element: HTMLElement): ScrollComponent | undefined {
|
|
if (element !== null && ScrollComponent.hasInstace(element)) {
|
|
const data = DataUtil.get(element, "scroll");
|
|
if (data) {
|
|
return data as ScrollComponent;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Create Instances
|
|
public static createInstances(selector: string) {
|
|
const elements = document.body.querySelectorAll(selector);
|
|
elements.forEach((element: Element) => {
|
|
const item = element as HTMLElement;
|
|
let scroll = ScrollComponent.getInstance(item);
|
|
if (!scroll) {
|
|
scroll = new ScrollComponent(item, defaultScrollOptions);
|
|
}
|
|
});
|
|
}
|
|
|
|
public static destroyAll(attr: string = '[data-kt-scroll="true"]') {}
|
|
|
|
public static bootstrap(attr: string = '[data-kt-scroll="true"]') {
|
|
ScrollComponent.createInstances(attr);
|
|
ScrollComponent.resize();
|
|
}
|
|
|
|
public static createInstance = (
|
|
element: HTMLElement,
|
|
options: ScrollOptions = defaultScrollOptions
|
|
): ScrollComponent | undefined => {
|
|
let scroll = ScrollComponent.getInstance(element);
|
|
if (!scroll) {
|
|
scroll = new ScrollComponent(element, options);
|
|
}
|
|
return scroll;
|
|
};
|
|
|
|
public static reinitialization(attr: string = '[data-kt-scroll="true"]') {
|
|
ScrollComponent.createInstances(attr);
|
|
}
|
|
|
|
public static updateAll() {
|
|
const elements = document.body.querySelectorAll('[data-kt-scroll="true"]');
|
|
elements.forEach((element: Element) => {
|
|
const instance = ScrollComponent.getInstance(element as HTMLElement);
|
|
if (instance) {
|
|
instance.update();
|
|
}
|
|
});
|
|
}
|
|
|
|
public static resize() {
|
|
// Window Resize Handling
|
|
window.addEventListener("resize", function () {
|
|
let timer;
|
|
throttle(
|
|
timer,
|
|
() => {
|
|
// Locate and update Drawer instances on window resize
|
|
ScrollComponent.updateAll();
|
|
},
|
|
200
|
|
);
|
|
});
|
|
}
|
|
}
|
|
|
|
export { ScrollComponent, defaultScrollOptions };
|