mirror of
https://github.com/Redocly/redoc.git
synced 2025-02-07 21:40:32 +03:00
Disable menu items until corresponding content is rendered
This commit is contained in:
parent
4f79d4950a
commit
c0e33bff61
|
@ -16,7 +16,7 @@ import { BaseComponent } from '../base';
|
||||||
import * as detectScollParent from 'scrollparent';
|
import * as detectScollParent from 'scrollparent';
|
||||||
|
|
||||||
import { SpecManager } from '../../utils/spec-manager';
|
import { SpecManager } from '../../utils/spec-manager';
|
||||||
import { OptionsService, Hash, MenuService, AppStateService, SchemaHelper } from '../../services/index';
|
import { OptionsService, Hash, AppStateService, SchemaHelper } from '../../services/index';
|
||||||
import { LazyTasksService } from '../../shared/components/LazyFor/lazy-for';
|
import { LazyTasksService } from '../../shared/components/LazyFor/lazy-for';
|
||||||
import { CustomErrorHandler } from '../../utils/';
|
import { CustomErrorHandler } from '../../utils/';
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
<div *ngFor="let cat of categories; let idx = index" class="menu-cat">
|
<div *ngFor="let cat of categories; let idx = index" class="menu-cat">
|
||||||
|
|
||||||
<label class="menu-cat-header" (click)="activateAndScroll(idx, -1)" [hidden]="cat.headless"
|
<label class="menu-cat-header" (click)="activateAndScroll(idx, -1)" [hidden]="cat.headless"
|
||||||
[ngClass]="{active: cat.active, disabled: !cat.ready}"> {{cat.name}}</label>
|
[ngClass]="{active: cat.active, disabled: !cat.ready && cat.methods.length}"> {{cat.name}}</label>
|
||||||
<ul class="menu-subitems" [@itemAnimation]="cat.active ? 'expanded' : 'collapsed'">
|
<ul class="menu-subitems" [@itemAnimation]="cat.active ? 'expanded' : 'collapsed'">
|
||||||
<li *ngFor="let method of cat.methods; trackBy:summary; let methIdx = index"
|
<li *ngFor="let method of cat.methods; trackBy:summary; let methIdx = index"
|
||||||
[ngClass]="{active: method.active, disabled: !method.ready}"
|
[ngClass]="{active: method.active, disabled: !method.ready}"
|
||||||
|
|
|
@ -38,6 +38,11 @@ $mobile-menu-compact-breakpoint: 550px;
|
||||||
&[hidden] {
|
&[hidden] {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.disabled, &.disabled:hover {
|
||||||
|
cursor: default;
|
||||||
|
color: lighten($text-color, 60%);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-subitems {
|
.menu-subitems {
|
||||||
|
@ -72,6 +77,11 @@ $mobile-menu-compact-breakpoint: 550px;
|
||||||
& li.active {
|
& li.active {
|
||||||
background: darken($side-menu-active-bg-color, 6%);
|
background: darken($side-menu-active-bg-color, 6%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.disabled, &.disabled:hover {
|
||||||
|
cursor: default;
|
||||||
|
color: lighten($text-color, 60%);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,8 @@ export class SideMenu extends BaseComponent implements OnInit {
|
||||||
private $resourcesNav: any;
|
private $resourcesNav: any;
|
||||||
private $scrollParent: any;
|
private $scrollParent: any;
|
||||||
|
|
||||||
|
private firstChange = true;
|
||||||
|
|
||||||
constructor(specMgr:SpecManager, elementRef:ElementRef,
|
constructor(specMgr:SpecManager, elementRef:ElementRef,
|
||||||
private scrollService:ScrollService, private menuService:MenuService, private hash:Hash,
|
private scrollService:ScrollService, private menuService:MenuService, private hash:Hash,
|
||||||
optionsService:OptionsService, private detectorRef:ChangeDetectorRef) {
|
optionsService:OptionsService, private detectorRef:ChangeDetectorRef) {
|
||||||
|
@ -52,20 +54,37 @@ export class SideMenu extends BaseComponent implements OnInit {
|
||||||
this.menuService.changed.subscribe((evt) => this.changed(evt));
|
this.menuService.changed.subscribe((evt) => this.changed(evt));
|
||||||
}
|
}
|
||||||
|
|
||||||
changed({cat, item}) {
|
changed(newItem) {
|
||||||
this.activeCatCaption = cat.name || '';
|
if (newItem) {
|
||||||
this.activeItemCaption = item && item.summary || '';
|
let {cat, item} = newItem;
|
||||||
|
this.activeCatCaption = cat.name || '';
|
||||||
|
this.activeItemCaption = item && item.summary || '';
|
||||||
|
}
|
||||||
|
|
||||||
//safari doesn't update bindings if not run changeDetector manually :(
|
//safari doesn't update bindings if not run changeDetector manually :(
|
||||||
|
|
||||||
this.detectorRef.detectChanges();
|
this.detectorRef.detectChanges();
|
||||||
|
if (this.firstChange) {
|
||||||
|
this.scrollActiveIntoView();
|
||||||
|
this.firstChange = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
activateAndScroll(idx, methodIdx) {
|
scrollActiveIntoView() {
|
||||||
|
let $item = this.$element.querySelector('li.active, label.active');
|
||||||
|
if ($item) $item.scrollIntoView();
|
||||||
|
}
|
||||||
|
|
||||||
|
activateAndScroll(catIdx, methodIdx) {
|
||||||
if (this.mobileMode()) {
|
if (this.mobileMode()) {
|
||||||
this.toggleMobileNav();
|
this.toggleMobileNav();
|
||||||
}
|
}
|
||||||
this.menuService.activate(idx, methodIdx);
|
let menu = this.categories;
|
||||||
|
|
||||||
|
if (!menu[catIdx].ready) return;
|
||||||
|
if (menu[catIdx].methods && menu[catIdx].methods.length && (methodIdx >= 0) &&
|
||||||
|
!menu[catIdx].methods[methodIdx].ready) return;
|
||||||
|
|
||||||
|
this.menuService.activate(catIdx, methodIdx);
|
||||||
this.menuService.scrollToActive();
|
this.menuService.scrollToActive();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,13 +37,13 @@ export class MenuService {
|
||||||
this.scrollUpdate(evt.isScrolledDown);
|
this.scrollUpdate(evt.isScrolledDown);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.changeActive(CHANGE.INITIAL);
|
//this.changeActive(CHANGE.INITIAL);
|
||||||
|
|
||||||
this.hash.value.subscribe((hash) => {
|
this.hash.value.subscribe((hash) => {
|
||||||
if (hash == undefined) return;
|
if (hash == undefined) return;
|
||||||
this.setActiveByHash(hash);
|
this.setActiveByHash(hash);
|
||||||
if (!this.tasks.empty) {
|
if (!this.tasks.empty) {
|
||||||
this.tasks.start(this.activeCatIdx, this.activeMethodIdx);
|
this.tasks.start(this.activeCatIdx, this.activeMethodIdx, this);
|
||||||
this.scrollService.setStickElement(this.getCurrentMethodEl());
|
this.scrollService.setStickElement(this.getCurrentMethodEl());
|
||||||
if (hash) this.scrollToActive();
|
if (hash) this.scrollToActive();
|
||||||
this.appState.stopLoading();
|
this.appState.stopLoading();
|
||||||
|
@ -53,6 +53,14 @@ export class MenuService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enableItem(catIdx, methodIdx) {
|
||||||
|
let cat = this.categories[catIdx];
|
||||||
|
cat.ready = true;
|
||||||
|
cat.methods[methodIdx].ready = true;
|
||||||
|
|
||||||
|
this.changed.next();
|
||||||
|
}
|
||||||
|
|
||||||
get activeMethodPtr() {
|
get activeMethodPtr() {
|
||||||
let cat = this.categories[this.activeCatIdx];
|
let cat = this.categories[this.activeCatIdx];
|
||||||
let ptr = null;
|
let ptr = null;
|
||||||
|
|
|
@ -15,6 +15,7 @@ export interface MenuMethod {
|
||||||
tag: string;
|
tag: string;
|
||||||
pointer: string;
|
pointer: string;
|
||||||
operationId: string;
|
operationId: string;
|
||||||
|
ready: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MenuCategory {
|
export interface MenuCategory {
|
||||||
|
@ -26,6 +27,7 @@ export interface MenuCategory {
|
||||||
description?: string;
|
description?: string;
|
||||||
empty?: string;
|
empty?: string;
|
||||||
virtual?: boolean;
|
virtual?: boolean;
|
||||||
|
ready: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
// global var for this module
|
// global var for this module
|
||||||
|
@ -304,7 +306,7 @@ export class SchemaHelper {
|
||||||
for (let header of (<Array<string>>(schema.info && schema.info['x-redoc-markdown-headers'] || []))) {
|
for (let header of (<Array<string>>(schema.info && schema.info['x-redoc-markdown-headers'] || []))) {
|
||||||
let id = 'section/' + slugify(header);
|
let id = 'section/' + slugify(header);
|
||||||
tag2MethodMapping[id] = {
|
tag2MethodMapping[id] = {
|
||||||
name: header, id: id, virtual: true, methods: [], idx: catIdx
|
name: header, id: id, virtual: true, ready: true, methods: [], idx: catIdx
|
||||||
};
|
};
|
||||||
catIdx++;
|
catIdx++;
|
||||||
}
|
}
|
||||||
|
@ -317,6 +319,7 @@ export class SchemaHelper {
|
||||||
description: tag.description,
|
description: tag.description,
|
||||||
headless: tag.name === '',
|
headless: tag.name === '',
|
||||||
empty: !!tag['x-traitTag'],
|
empty: !!tag['x-traitTag'],
|
||||||
|
ready: !!tag['x-traitTag'],
|
||||||
methods: [],
|
methods: [],
|
||||||
idx: catIdx
|
idx: catIdx
|
||||||
};
|
};
|
||||||
|
|
|
@ -32,6 +32,8 @@ export class LazyTasksService {
|
||||||
private _tasks = [];
|
private _tasks = [];
|
||||||
private _current: number = 0;
|
private _current: number = 0;
|
||||||
private _syncCount: number = 0;
|
private _syncCount: number = 0;
|
||||||
|
private menuService;
|
||||||
|
|
||||||
public loadProgress = new BehaviorSubject<number>(0);
|
public loadProgress = new BehaviorSubject<number>(0);
|
||||||
public allSync = false;
|
public allSync = false;
|
||||||
constructor(public optionsService: OptionsService, private zone: NgZone) {
|
constructor(public optionsService: OptionsService, private zone: NgZone) {
|
||||||
|
@ -61,6 +63,7 @@ export class LazyTasksService {
|
||||||
if (!task) return;
|
if (!task) return;
|
||||||
task._callback(task.idx, true);
|
task._callback(task.idx, true);
|
||||||
this._current++;
|
this._current++;
|
||||||
|
this.menuService.enableItem(task.catIdx, task.idx);
|
||||||
this.loadProgress.next(this._current / this._tasks.length * 100);
|
this.loadProgress.next(this._current / this._tasks.length * 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +73,7 @@ export class LazyTasksService {
|
||||||
if (!task) return;
|
if (!task) return;
|
||||||
task._callback(task.idx, false).then(() => {
|
task._callback(task.idx, false).then(() => {
|
||||||
this._current++;
|
this._current++;
|
||||||
|
this.menuService.enableItem(task.catIdx, task.idx);
|
||||||
setTimeout(()=> this.nextTask());
|
setTimeout(()=> this.nextTask());
|
||||||
this.loadProgress.next(this._current / this._tasks.length * 100);
|
this.loadProgress.next(this._current / this._tasks.length * 100);
|
||||||
}).catch(err => console.error(err));
|
}).catch(err => console.error(err));
|
||||||
|
@ -91,7 +94,8 @@ export class LazyTasksService {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
start(catIdx, metIdx) {
|
start(catIdx, metIdx, menuService) {
|
||||||
|
this.menuService = menuService;
|
||||||
let syncCount = 5;
|
let syncCount = 5;
|
||||||
// I know this is bad practice to detect browsers but there is an issue on Safari only
|
// I know this is bad practice to detect browsers but there is an issue on Safari only
|
||||||
// http://stackoverflow.com/questions/40692365/maintaining-scroll-position-while-inserting-elements-above-glitching-only-in-sa
|
// http://stackoverflow.com/questions/40692365/maintaining-scroll-position-while-inserting-elements-above-glitching-only-in-sa
|
||||||
|
|
Loading…
Reference in New Issue
Block a user