@finos/legend-application-marketplace
Version:
Legend Marketplace application core
189 lines • 9.24 kB
JavaScript
/**
* Copyright (c) 2020-present, Goldman Sachs
*
* 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 { NAVIGATION_ZONE_SEPARATOR } from '@finos/legend-application';
import { action, computed, makeObservable, observable } from 'mobx';
import {} from './DataProductViewerState.js';
import { at, guaranteeNonNullable, isNonNullable } from '@finos/legend-shared';
import { DATA_PRODUCT_VIEWER_ACTIVITY_MODE, extractActivityFromAnchor, generateAnchorForActivity, } from './DataProductViewerNavigation.js';
export const DATA_PRODUCT_WIKI_PAGE_SECTIONS = [
DATA_PRODUCT_VIEWER_ACTIVITY_MODE.DESCRIPTION,
DATA_PRODUCT_VIEWER_ACTIVITY_MODE.DIAGRAM_VIEWER,
DATA_PRODUCT_VIEWER_ACTIVITY_MODE.MODELS_DOCUMENTATION,
DATA_PRODUCT_VIEWER_ACTIVITY_MODE.QUICK_START,
DATA_PRODUCT_VIEWER_ACTIVITY_MODE.DATA_ACCESS,
];
const DATA_SPACE_WIKI_PAGE_ANCHORS = DATA_PRODUCT_WIKI_PAGE_SECTIONS.map((activity) => generateAnchorForActivity(activity));
export class DataProductLayoutState {
dataProductViewerState;
currentNavigationZone = '';
isExpandedModeEnabled = false;
frame;
header;
isTopScrollerVisible = false;
wikiPageAnchorIndex = new Map();
wikiPageNavigationCommand;
wikiPageVisibleAnchors = [];
wikiPageScrollIntersectionObserver;
constructor(dataProductViewerState) {
makeObservable(this, {
currentNavigationZone: observable,
isExpandedModeEnabled: observable,
isTopScrollerVisible: observable,
wikiPageAnchorIndex: observable,
wikiPageVisibleAnchors: observable,
frame: observable.ref,
wikiPageNavigationCommand: observable.ref,
isWikiPageFullyRendered: computed,
registerWikiPageScrollObserver: action,
setCurrentNavigationZone: action,
enableExpandedMode: action,
setFrame: action,
setTopScrollerVisible: action,
setWikiPageAnchor: action,
unsetWikiPageAnchor: action,
setWikiPageAnchorToNavigate: action,
updatePageVisibleAnchors: action,
});
this.dataProductViewerState = dataProductViewerState;
}
setCurrentNavigationZone(val) {
this.currentNavigationZone = val;
}
get isWikiPageFullyRendered() {
return (Boolean(this.frame) &&
DATA_PRODUCT_WIKI_PAGE_SECTIONS.includes(this.dataProductViewerState.currentActivity) &&
DATA_SPACE_WIKI_PAGE_ANCHORS.every((anchor) => this.wikiPageAnchorIndex.has(anchor)) &&
Array.from(this.wikiPageAnchorIndex.values()).every(isNonNullable));
}
registerWikiPageScrollObserver() {
if (this.frame && this.isWikiPageFullyRendered) {
const wikiPageIntersectionObserver = new IntersectionObserver((entries, observer) => {
const anchorsWithVisibilityChanged = entries
.map((entry) => {
for (const [key, element] of this.wikiPageAnchorIndex.entries()) {
if (element === entry.target) {
return { key, isIntersecting: entry.isIntersecting };
}
}
return undefined;
})
.filter(isNonNullable);
anchorsWithVisibilityChanged.forEach((entry) => {
this.updatePageVisibleAnchors(entry.key, entry.isIntersecting);
});
// NOTE: sync scroll with menu/address is quite a delicate piece of work
// as it interferes with programatic scroll operations we do elsewhere.
// This is particularly bad when we do a programatic `smooth` scroll, which
// mimic user scrolling behavior and would tangle up with this observer
// Since currently, there's no good mechanism to detect scroll end event, and as such,
// there is no good way to temporarily disable this logic while doing the programmatic
// smooth scroll as such, we avoid supporting programatic smooth scrolling for now
// See https://github.com/w3c/csswg-drafts/issues/3744
// See https://developer.mozilla.org/en-US/docs/Web/API/Document/scrollend_event
if (
// if current navigation zone is not set, do not update zone
this.currentNavigationZone === '' ||
// if there is no visible anchors, do not update zone
!this.wikiPageVisibleAnchors.length ||
// if some of the current visible anchors match or is parent section of the current
// navigation zone, do not update zone
this.wikiPageVisibleAnchors.some((visibleAnchor) => this.currentNavigationZone === visibleAnchor ||
this.currentNavigationZone.startsWith(`${visibleAnchor}${NAVIGATION_ZONE_SEPARATOR}`))) {
return;
}
const anchor = at(this.wikiPageVisibleAnchors, 0);
// this.dataProductViewerState.syncZoneWithNavigation(anchor);
const anchorChunks = anchor.split(NAVIGATION_ZONE_SEPARATOR);
const activity = anchorChunks[0];
if (activity) {
this.dataProductViewerState.setCurrentActivity(extractActivityFromAnchor(activity));
}
}, {
root: this.frame,
threshold: 0.5,
});
Array.from(this.wikiPageAnchorIndex.values()).forEach((el) => wikiPageIntersectionObserver.observe(el));
this.wikiPageScrollIntersectionObserver = wikiPageIntersectionObserver;
}
}
unregisterWikiPageScrollObserver() {
this.wikiPageScrollIntersectionObserver?.disconnect();
this.wikiPageScrollIntersectionObserver = undefined;
this.wikiPageVisibleAnchors = [];
}
updatePageVisibleAnchors(changedAnchor, isIntersecting) {
if (isIntersecting) {
const anchors = this.wikiPageVisibleAnchors.filter((anchor) => changedAnchor !== anchor);
// NOTE: the newly visible anchors should be the furthest one in
// the direction of scroll
anchors.push(changedAnchor);
this.wikiPageVisibleAnchors = anchors;
}
else {
this.wikiPageVisibleAnchors = this.wikiPageVisibleAnchors.filter((anchor) => changedAnchor !== anchor);
}
}
enableExpandedMode(val) {
this.isExpandedModeEnabled = val;
}
setFrame(val) {
this.frame = val;
}
setTopScrollerVisible(val) {
this.isTopScrollerVisible = val;
}
setWikiPageAnchor(anchorKey, element) {
// do not allow overriding existing anchor
if (!this.wikiPageAnchorIndex.has(anchorKey)) {
this.wikiPageAnchorIndex.set(anchorKey, element);
}
}
unsetWikiPageAnchor(anchorKey) {
this.wikiPageAnchorIndex.delete(anchorKey);
}
setWikiPageAnchorToNavigate(val) {
this.wikiPageNavigationCommand = val;
}
navigateWikiPageAnchor() {
if (this.frame &&
this.wikiPageNavigationCommand &&
this.isWikiPageFullyRendered) {
const anchor = this.wikiPageNavigationCommand.anchor;
const matchingWikiPageSection = this.wikiPageAnchorIndex.get(anchor);
const anchorChunks = anchor.split(NAVIGATION_ZONE_SEPARATOR);
if (matchingWikiPageSection) {
this.frame.scrollTop =
matchingWikiPageSection.offsetTop -
(this.header?.getBoundingClientRect().height ?? 0);
}
else if (generateAnchorForActivity(DATA_PRODUCT_VIEWER_ACTIVITY_MODE.DIAGRAM_VIEWER) === anchorChunks[0]) {
this.frame.scrollTop =
guaranteeNonNullable(this.wikiPageAnchorIndex.get(generateAnchorForActivity(DATA_PRODUCT_VIEWER_ACTIVITY_MODE.DIAGRAM_VIEWER))).offsetTop - (this.header?.getBoundingClientRect().height ?? 0);
// const matchingDiagram =
// this.dataProductViewerState.dataSpaceAnalysisResult.diagrams.find(
// (diagram) => generateAnchorForDiagram(diagram) === anchor,
// );
// if (matchingDiagram) {
// this.dataProductViewerState.diagramViewerState.setCurrentDiagram(
// matchingDiagram,
// );
// }
}
this.setWikiPageAnchorToNavigate(undefined);
}
}
}
//# sourceMappingURL=DataProductLayoutState.js.map