Disable menu items until corresponding content is rendered

This commit is contained in:
Roman Hotsiy 2016-11-24 18:12:43 +02:00
parent 4f79d4950a
commit c0e33bff61
No known key found for this signature in database
GPG Key ID: 5CB7B3ACABA57CB0
7 changed files with 57 additions and 13 deletions

View File

@ -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/';

View File

@ -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}"

View File

@ -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%);
}
} }

View File

@ -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();
} }

View File

@ -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;

View File

@ -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
}; };

View File

@ -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