Skip to content

Commit

Permalink
scroll protection
Browse files Browse the repository at this point in the history
Signed-off-by: Colin Grant <[email protected]>
  • Loading branch information
colin-grant-work authored and vince-fugnitto committed Jun 23, 2020
1 parent 2bba7ec commit 79ee2c7
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 18 deletions.
20 changes: 16 additions & 4 deletions packages/preferences/src/browser/preference-tree-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,13 @@ import { Preference } from './util/preference-types';
interface PreferenceFilterOptions {
minLength?: number;
baseSchemaAltered?: boolean;
requiresFilter?: boolean;
};

const filterDefaults: Required<PreferenceFilterOptions> = {
minLength: 1,
baseSchemaAltered: false,
requiresFilter: true,
};

@injectable()
Expand Down Expand Up @@ -58,7 +60,15 @@ export class PreferencesTreeProvider {
this.updateUnderlyingData({ baseSchemaAltered: true });
this.schemaProvider.onDidPreferenceSchemaChanged(() => this.handleUnderlyingDataChange({ baseSchemaAltered: true }));
this.preferencesEventService.onSearch.event(searchEvent => this.updateDisplay(searchEvent.query));
this.preferencesEventService.onTabScopeSelected.event(scopeEvent => this.handleUnderlyingDataChange({}, scopeEvent));
this.preferencesEventService.onTabScopeSelected.event(scopeEvent => {
const newScope = Number(scopeEvent.scope);
const currentScope = Number(this.currentScope.scope);
const scopeChangesPreferenceVisibility =
((newScope === PreferenceScope.User || newScope === PreferenceScope.Workspace) && currentScope === PreferenceScope.Folder)
|| (newScope === PreferenceScope.Folder && (currentScope === PreferenceScope.User || currentScope === PreferenceScope.Workspace));

this.handleUnderlyingDataChange({ requiresFilter: scopeChangesPreferenceVisibility }, scopeEvent);
});
}

protected updateUnderlyingData(options: PreferenceFilterOptions, newScope?: Preference.SelectedScopeDetails): void {
Expand All @@ -75,10 +85,12 @@ export class PreferencesTreeProvider {
if (options.baseSchemaAltered) {
this.baseTree = this.preferencesTreeGenerator.generateTree();
}
const shouldBuildNewTree = options.requiresFilter !== false;
if (shouldBuildNewTree) {
this._currentTree = this.filter(term, Number(this.currentScope.scope), this.baseTree, options);
}

this._currentTree = this.filter(term, Number(this.currentScope.scope), this.baseTree, options);

this.preferencesEventService.onDisplayChanged.fire();
this.preferencesEventService.onDisplayChanged.fire(shouldBuildNewTree || !!options.baseSchemaAltered);
}

protected filter<Tree extends TreeNode>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,5 @@ export class PreferencesEventService {
onSearch = new Emitter<Preference.SearchQuery>();
onEditorScroll = new Emitter<Preference.MouseScrollDetails>();
onNavTreeSelection = new Emitter<Preference.SelectedTreeNode>();
onDisplayChanged = new Emitter<void>();
onDisplayChanged = new Emitter<boolean>();
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export class PreferencesEditorWidget extends ReactWidget {
this.preferenceValueRetrievalService.onPreferenceChanged((preferenceChange): void => {
this.update();
});
this.preferencesEventService.onDisplayChanged.event(() => this.handleChangeDisplay());
this.preferencesEventService.onDisplayChanged.event(didChangeTree => this.handleChangeDisplay(didChangeTree));
this.preferencesEventService.onNavTreeSelection.event(e => this.scrollToEditorElement(e.nodeID));
this.currentDisplay = this.preferenceTreeProvider.currentTree;
this.properties = this.preferenceTreeProvider.propertyList;
Expand Down Expand Up @@ -98,11 +98,12 @@ export class PreferencesEditorWidget extends ReactWidget {
);
}

protected handleChangeDisplay = (): void => {
// This is here to avoid using the synthetic event asynchronously
this.currentDisplay = this.preferenceTreeProvider.currentTree;
this.properties = this.preferenceTreeProvider.propertyList;
this.node.scrollTop = 0;
protected handleChangeDisplay = (didGenerateNewTree: boolean): void => {
if (didGenerateNewTree) {
this.currentDisplay = this.preferenceTreeProvider.currentTree;
this.properties = this.preferenceTreeProvider.propertyList;
this.node.scrollTop = 0;
}
this.update();
};

Expand Down Expand Up @@ -180,7 +181,8 @@ export class PreferencesEditorWidget extends ReactWidget {
if (nodeID) {
const el = document.getElementById(`${nodeID}-editor`);
if (el) {
el.scrollIntoView();
// Timeout to allow render cycle to finish.
setTimeout(() => el.scrollIntoView());
}
}
}
Expand Down
26 changes: 20 additions & 6 deletions packages/preferences/src/browser/views/preference-tree-widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,11 @@ export class PreferencesTreeWidget extends TreeWidget {
@postConstruct()
init(): void {
super.init();
this.preferencesEventService.onDisplayChanged.event(() => this.updateDisplay());
this.preferencesEventService.onDisplayChanged.event(didChangeTree => {
if (didChangeTree) {
this.updateDisplay();
}
});
this.preferencesEventService.onEditorScroll.event(e => {
this.handleEditorScroll(e.firstVisibleChildId);
});
Expand All @@ -70,12 +74,14 @@ export class PreferencesTreeWidget extends TreeWidget {
this.firstVisibleLeafNodeID = firstVisibleChildId;
this.model.expandNode(expansionAncestor);
this.collapseAllExcept(expansionAncestor);
this.model.selectNode(selectionAncestor);
if (selectionAncestor) {
this.model.selectNode(selectionAncestor);
}
}
this.shouldFireSelectionEvents = true;
}

protected collapseAllExcept(openNode: Preference.TreeExtension): void {
protected collapseAllExcept(openNode: Preference.TreeExtension | undefined): void {
const children = (this.model.root as CompositeTreeNode).children as ExpandableTreeNode[];
children.forEach(child => {
if (child !== openNode && child.expanded) {
Expand All @@ -84,15 +90,15 @@ export class PreferencesTreeWidget extends TreeWidget {
});
}

protected getAncestorsForVisibleNode(visibleNodeID: string): { selectionAncestor: SelectableTreeNode, expansionAncestor: ExpandableTreeNode; } {
protected getAncestorsForVisibleNode(visibleNodeID: string): { selectionAncestor: SelectableTreeNode | undefined, expansionAncestor: ExpandableTreeNode | undefined; } {
const isNonLeafNode = visibleNodeID.endsWith('-id');
const isSubgroupNode = isNonLeafNode && visibleNodeID.includes('.');
let expansionAncestor: ExpandableTreeNode;
let selectionAncestor: SelectableTreeNode;

if (isSubgroupNode) {
selectionAncestor = this.model.getNode(visibleNodeID) as SelectableTreeNode;
expansionAncestor = selectionAncestor.parent as ExpandableTreeNode;
expansionAncestor = selectionAncestor?.parent as ExpandableTreeNode;
} else if (isNonLeafNode) {
selectionAncestor = this.model.getNode(visibleNodeID) as SelectableTreeNode;
expansionAncestor = selectionAncestor as Preference.TreeExtension as ExpandableTreeNode;
Expand All @@ -106,7 +112,8 @@ export class PreferencesTreeWidget extends TreeWidget {
selectionAncestor = this.model.getNode(subgroupID) as SelectableTreeNode;
} else {
// The last selectable child that precedes the visible item alphabetically
selectionAncestor = [...expansionAncestor.children].reverse().find(child => child.visible && child.id < visibleNodeID) as SelectableTreeNode || expansionAncestor;
selectionAncestor = [...(expansionAncestor?.children || [])]
.reverse().find(child => child.visible && child.id < visibleNodeID) as SelectableTreeNode || expansionAncestor;
}
}
return { selectionAncestor, expansionAncestor };
Expand All @@ -124,6 +131,13 @@ export class PreferencesTreeWidget extends TreeWidget {
const nodes = Object.keys(this.preferenceTreeProvider.propertyList)
.map(propertyName => ({ [propertyName]: this.preferenceTreeProvider.propertyList[propertyName] }));
this.decorator.fireDidChangeDecorations(nodes);
// If the tree has changed but we know the visible node, scroll to it.
if (this.firstVisibleLeafNodeID) {
const { selectionAncestor } = this.getAncestorsForVisibleNode(this.firstVisibleLeafNodeID);
if (selectionAncestor?.visible) {
this.preferencesEventService.onNavTreeSelection.fire({ nodeID: this.firstVisibleLeafNodeID });
}
}
this.update();
}
}
Expand Down

0 comments on commit 79ee2c7

Please sign in to comment.