Do not collapse cards on links and code area #88
Detects clickable elements automatically and exempts them from collapsing cards, also interacting with code area does no longer collapse cards. This commit also fixes subscribing to clicks on document every time card list is loaded, but never unsubscribing. This impacts performance and causes memory leaks. Now, registered event listener is removed every time card list component is destroyed.
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
<template>
|
||||
<Responsive v-on:sizeChanged="sizeChanged()">
|
||||
<Responsive
|
||||
v-on:sizeChanged="sizeChanged()"
|
||||
v-non-collapsing>
|
||||
<div
|
||||
:id="editorId"
|
||||
class="code-area"
|
||||
@@ -18,11 +20,13 @@ import { ScriptingLanguage } from '@/domain/ScriptingLanguage';
|
||||
import { ICategoryCollectionState } from '@/application/Context/State/ICategoryCollectionState';
|
||||
import { CodeBuilderFactory } from '@/application/Context/State/Code/Generation/CodeBuilderFactory';
|
||||
import Responsive from '@/presentation/components/Shared/Responsive.vue';
|
||||
import { NonCollapsing } from '@/presentation/components/Scripts/View/Cards/NonCollapsingDirective';
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
Responsive,
|
||||
},
|
||||
directives: { NonCollapsing },
|
||||
})
|
||||
export default class TheCodeArea extends StatefulVue {
|
||||
public readonly editorId = 'codeEditor';
|
||||
|
||||
@@ -45,13 +45,13 @@ export default class CardList extends StatefulVue {
|
||||
public activeCategoryId?: number = null;
|
||||
|
||||
public created() {
|
||||
this.onOutsideOfActiveCardClicked((element) => {
|
||||
if (hasDirective(element)) {
|
||||
return;
|
||||
document.addEventListener('click', this.outsideClickListener);
|
||||
}
|
||||
this.activeCategoryId = null;
|
||||
});
|
||||
|
||||
public destroyed() {
|
||||
document.removeEventListener('click', this.outsideClickListener);
|
||||
}
|
||||
|
||||
public onSelected(categoryId: number, isExpanded: boolean) {
|
||||
this.activeCategoryId = isExpanded ? categoryId : undefined;
|
||||
}
|
||||
@@ -64,18 +64,42 @@ export default class CardList extends StatefulVue {
|
||||
private setCategories(categories: ReadonlyArray<ICategory>): void {
|
||||
this.categoryIds = categories.map((category) => category.id);
|
||||
}
|
||||
private onOutsideOfActiveCardClicked(callback: (clickedElement: Element) => void) {
|
||||
const outsideClickListener = (event) => {
|
||||
if (!this.activeCategoryId) {
|
||||
|
||||
private onOutsideOfActiveCardClicked(clickedElement: Element): void {
|
||||
if (isClickable(clickedElement) || hasDirective(clickedElement)) {
|
||||
return;
|
||||
}
|
||||
this.collapseAllCards();
|
||||
if (hasDirective(clickedElement)) {
|
||||
return;
|
||||
}
|
||||
this.activeCategoryId = null;
|
||||
}
|
||||
private outsideClickListener(event: PointerEvent) {
|
||||
if (this.areAllCardsCollapsed()) {
|
||||
return;
|
||||
}
|
||||
const element = document.querySelector(`[data-category="${this.activeCategoryId}"]`);
|
||||
if (element && !element.contains(event.target)) {
|
||||
callback(event.target);
|
||||
const target = event.target as Element;
|
||||
if (element && !element.contains(target)) {
|
||||
this.onOutsideOfActiveCardClicked(target);
|
||||
}
|
||||
};
|
||||
document.addEventListener('click', outsideClickListener);
|
||||
}
|
||||
|
||||
private collapseAllCards(): void {
|
||||
this.activeCategoryId = undefined;
|
||||
}
|
||||
private areAllCardsCollapsed(): boolean {
|
||||
return !this.activeCategoryId;
|
||||
}
|
||||
}
|
||||
|
||||
function isClickable(element: Element) {
|
||||
const cursorName = window.getComputedStyle(element).cursor;
|
||||
return [ 'pointer', 'move', 'grab'].some((name) => cursorName === name)
|
||||
|| cursorName.includes('resize')
|
||||
|| [ 'onclick', 'href'].some((attributeName) => element.hasAttribute(attributeName))
|
||||
|| [ 'a', 'button'].some((tagName) => element.closest(`.${tagName}`));
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user