mirror of
https://github.com/Redocly/redoc.git
synced 2025-06-01 03:33:04 +03:00
Continue menu refactor
This commit is contained in:
parent
97949a17f9
commit
c41ffe8209
|
@ -1,10 +1,24 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
import { Input, Component, OnInit, ChangeDetectionStrategy, ElementRef } from '@angular/core';
|
import { Input, HostBinding, Component, OnInit, ChangeDetectionStrategy, ElementRef } from '@angular/core';
|
||||||
import JsonPointer from '../../utils/JsonPointer';
|
import JsonPointer from '../../utils/JsonPointer';
|
||||||
import { BaseComponent, SpecManager } from '../base';
|
import { BaseComponent, SpecManager } from '../base';
|
||||||
import { SchemaHelper } from '../../services/schema-helper.service';
|
import { SchemaHelper } from '../../services/schema-helper.service';
|
||||||
import { OptionsService } from '../../services/';
|
import { OptionsService } from '../../services/';
|
||||||
|
|
||||||
|
|
||||||
|
interface MethodInfo {
|
||||||
|
apiUrl: string;
|
||||||
|
httpMethod: string;
|
||||||
|
path: string;
|
||||||
|
info: {
|
||||||
|
tags: string[];
|
||||||
|
description: string;
|
||||||
|
};
|
||||||
|
bodyParam: any;
|
||||||
|
summary: any;
|
||||||
|
anchor: any;
|
||||||
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'method',
|
selector: 'method',
|
||||||
templateUrl: './method.html',
|
templateUrl: './method.html',
|
||||||
|
@ -12,35 +26,47 @@ import { OptionsService } from '../../services/';
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class Method extends BaseComponent implements OnInit {
|
export class Method extends BaseComponent implements OnInit {
|
||||||
@Input() pointer:string;
|
@Input() pointer :string;
|
||||||
@Input() tag:string;
|
@Input() parentTagId :string;
|
||||||
@Input() posInfo: any;
|
|
||||||
|
|
||||||
hidden = true;
|
@HostBinding('attr.operation-id') operationId;
|
||||||
|
|
||||||
method:any;
|
private method: MethodInfo;
|
||||||
|
|
||||||
constructor(specMgr:SpecManager, private optionsService: OptionsService, private el: ElementRef) {
|
constructor(specMgr:SpecManager, private optionsService: OptionsService) {
|
||||||
super(specMgr);
|
super(specMgr);
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
this.method = {};
|
this.operationId = this.componentSchema.operationId;
|
||||||
if (this.optionsService.options.hideHostname) {
|
|
||||||
this.method.apiUrl = this.specMgr.basePath;
|
this.method = {
|
||||||
|
httpMethod: JsonPointer.baseName(this.pointer),
|
||||||
|
path: JsonPointer.baseName(this.pointer, 2),
|
||||||
|
info: {
|
||||||
|
description: this.componentSchema.description,
|
||||||
|
tags: this.filterMainTags(this.componentSchema.tags)
|
||||||
|
},
|
||||||
|
bodyParam: this.findBodyParam(),
|
||||||
|
summary: SchemaHelper.methodSummary(this.componentSchema),
|
||||||
|
apiUrl: this.getBaseUrl(),
|
||||||
|
anchor: this.buildAnchor()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
buildAnchor() {
|
||||||
|
if (this.operationId) {
|
||||||
|
return 'operation/' + encodeURIComponent(this.componentSchema.operationId);
|
||||||
} else {
|
} else {
|
||||||
this.method.apiUrl = this.specMgr.apiUrl;
|
return this.parentTagId + encodeURIComponent(this.pointer);
|
||||||
}
|
}
|
||||||
this.method.httpMethod = JsonPointer.baseName(this.pointer);
|
}
|
||||||
this.method.path = JsonPointer.baseName(this.pointer, 2);
|
|
||||||
this.method.info = this.componentSchema;
|
getBaseUrl():string {
|
||||||
this.method.info.tags = this.filterMainTags(this.method.info.tags);
|
if (this.optionsService.options.hideHostname) {
|
||||||
this.method.bodyParam = this.findBodyParam();
|
return this.specMgr.basePath;
|
||||||
this.method.summary = SchemaHelper.methodSummary(this.componentSchema);
|
|
||||||
if (this.componentSchema.operationId) {
|
|
||||||
this.method.anchor = 'operation/' + encodeURIComponent(this.componentSchema.operationId);
|
|
||||||
} else {
|
} else {
|
||||||
this.method.anchor = this.tag + encodeURIComponent(this.pointer);
|
return this.specMgr.apiUrl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,14 +82,6 @@ export class Method extends BaseComponent implements OnInit {
|
||||||
return bodyParam;
|
return bodyParam;
|
||||||
}
|
}
|
||||||
|
|
||||||
show(res) {
|
|
||||||
if (res) {
|
|
||||||
this.el.nativeElement.firstElementChild.removeAttribute('hidden');
|
|
||||||
} else {
|
|
||||||
this.el.nativeElement.firstElementChild.setAttribute('hidden', 'hidden');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.preinit();
|
this.preinit();
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,8 @@
|
||||||
<h1 class="sharable-header"> <a class="share-link" href="#{{tag.id}}"></a>{{tag.name}} </h1>
|
<h1 class="sharable-header"> <a class="share-link" href="#{{tag.id}}"></a>{{tag.name}} </h1>
|
||||||
<p *ngIf="tag.description" [innerHtml]="tag.description | marked"> </p>
|
<p *ngIf="tag.description" [innerHtml]="tag.description | marked"> </p>
|
||||||
</div>
|
</div>
|
||||||
<method *lazyFor="let method of tag.items; let show = show;" [hidden]="!show"
|
<method *lazyFor="let methodItem of tag.items; let ready = ready;"
|
||||||
[pointer]="method.metadata.pointer" [attr.section]="method.id"
|
[hidden]="!ready" [pointer]="methodItem.metadata.pointer"
|
||||||
[attr.operation-id]="method.metadata.operationId"></method>
|
[parentTagId]="tag.id" [attr.section]="methodItem.id"></method>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
import { Component, Input, OnInit, ChangeDetectionStrategy } from '@angular/core';
|
import { Component, Input, OnInit, ChangeDetectionStrategy } from '@angular/core';
|
||||||
import { BaseComponent, SpecManager } from '../base';
|
import { BaseComponent, SpecManager } from '../base';
|
||||||
import { SchemaHelper } from '../../services/index';
|
import { MenuService } from '../../services/index';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'methods-list',
|
selector: 'methods-list',
|
||||||
|
@ -14,18 +14,19 @@ export class MethodsList extends BaseComponent implements OnInit {
|
||||||
|
|
||||||
tags:Array<any> = [];
|
tags:Array<any> = [];
|
||||||
|
|
||||||
constructor(specMgr:SpecManager) {
|
constructor(specMgr:SpecManager, private menu: MenuService) {
|
||||||
super(specMgr);
|
super(specMgr);
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
let flatMenuItems = SchemaHelper.flatMenu(SchemaHelper.buildMenuTree(this.specMgr.schema));
|
let flatMenuItems = this.menu.flatItems;
|
||||||
this.tags = [];
|
this.tags = [];
|
||||||
let emptyTag = {
|
let emptyTag = {
|
||||||
name: '',
|
name: '',
|
||||||
items: []
|
items: []
|
||||||
}
|
}
|
||||||
flatMenuItems.forEach(menuItem => {
|
flatMenuItems.forEach(menuItem => {
|
||||||
|
// skip items that are not bound to swagger tags/methods
|
||||||
if (!menuItem.metadata) return;
|
if (!menuItem.metadata) return;
|
||||||
|
|
||||||
if (menuItem.metadata.type === 'tag') {
|
if (menuItem.metadata.type === 'tag') {
|
||||||
|
|
|
@ -53,7 +53,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-item-level-0 {
|
.menu-item-level-1 {
|
||||||
> .menu-item-header {
|
> .menu-item-header {
|
||||||
font-family: $headers-font, $headers-font-family;
|
font-family: $headers-font, $headers-font-family;
|
||||||
font-weight: $light;
|
font-weight: $light;
|
||||||
|
@ -61,7 +61,7 @@
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .menu-item-header:hover,
|
> .menu-item-header:not(.disabled):hover,
|
||||||
&.active > .menu-item-header {
|
&.active > .menu-item-header {
|
||||||
color: $primary-color;
|
color: $primary-color;
|
||||||
background: $side-menu-active-bg-color;
|
background: $side-menu-active-bg-color;
|
||||||
|
@ -71,7 +71,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-item-level-1 {
|
.menu-item-level-2 {
|
||||||
> .menu-item-header {
|
> .menu-item-header {
|
||||||
padding-left: 2*$side-menu-item-hpadding;
|
padding-left: 2*$side-menu-item-hpadding;
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,9 +69,17 @@ export class SideMenu extends BaseComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
changed(item) {
|
changed(item) {
|
||||||
if (item) {
|
if (!item) {
|
||||||
this.activeCatCaption = item.name || '';
|
this.activeCatCaption = '';
|
||||||
this.activeItemCaption = item.parent && item.parent.name || '';
|
this.activeItemCaption = '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (item.parent) {
|
||||||
|
this.activeItemCaption = item.name;
|
||||||
|
this.activeCatCaption = item.parent.name;
|
||||||
|
} else {
|
||||||
|
this.activeCatCaption = item.name;
|
||||||
|
this.activeItemCaption = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
//safari doesn't update bindings if not run changeDetector manually :(
|
//safari doesn't update bindings if not run changeDetector manually :(
|
||||||
|
@ -88,12 +96,10 @@ export class SideMenu extends BaseComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
activateAndScroll(item) {
|
activateAndScroll(item) {
|
||||||
if (this.mobileMode()) {
|
if (this.mobileMode) {
|
||||||
this.toggleMobileNav();
|
this.toggleMobileNav();
|
||||||
}
|
}
|
||||||
|
|
||||||
//if (!this.flatItems[idx].ready) return; // TODO: move inside next statement
|
|
||||||
|
|
||||||
this.menuService.activate(item.flatIdx);
|
this.menuService.activate(item.flatIdx);
|
||||||
this.menuService.scrollToActive();
|
this.menuService.scrollToActive();
|
||||||
}
|
}
|
||||||
|
@ -111,7 +117,7 @@ export class SideMenu extends BaseComponent implements OnInit, OnDestroy {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
mobileMode() {
|
get mobileMode() {
|
||||||
return this.$mobileNav.clientHeight > 0;
|
return this.$mobileNav.clientHeight > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,53 +15,45 @@ import * as slugify from 'slugify';
|
||||||
const CHANGE = {
|
const CHANGE = {
|
||||||
NEXT : 1,
|
NEXT : 1,
|
||||||
BACK : -1,
|
BACK : -1,
|
||||||
INITIAL : 0
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class MenuService {
|
export class MenuService {
|
||||||
|
|
||||||
changed: EventEmitter<any> = new EventEmitter();
|
changed: EventEmitter<any> = new EventEmitter();
|
||||||
ready: BehaviorSubject<boolean> = new BehaviorSubject(false);
|
|
||||||
items: Array<MenuItem>;
|
|
||||||
flatItems: Array<MenuItem>;
|
|
||||||
|
|
||||||
activeCatIdx: number = 0;
|
|
||||||
activeMethodIdx: number = -1;
|
|
||||||
|
|
||||||
|
items: MenuItem[];
|
||||||
activeIdx: number = -1;
|
activeIdx: number = -1;
|
||||||
|
|
||||||
|
private _flatItems: MenuItem[];
|
||||||
private _hashSubscription: Subscription;
|
private _hashSubscription: Subscription;
|
||||||
|
private _scrollSubscription: Subscription;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private hash:Hash,
|
private hash:Hash,
|
||||||
private tasks: LazyTasksService,
|
private tasks: LazyTasksService,
|
||||||
private scrollService: ScrollService,
|
private scrollService: ScrollService,
|
||||||
private appState: AppStateService,
|
private appState: AppStateService,
|
||||||
specMgr:SpecManager
|
private specMgr:SpecManager
|
||||||
) {
|
) {
|
||||||
this.hash = hash;
|
this.hash = hash;
|
||||||
this.items = SchemaHelper.buildMenuTree(specMgr.schema);
|
this.buildMenu();
|
||||||
this.flatItems = SchemaHelper.flatMenu(this.items);
|
|
||||||
|
|
||||||
scrollService.scroll.subscribe((evt) => {
|
this._scrollSubscription = scrollService.scroll.subscribe((evt) => {
|
||||||
this.scrollUpdate(evt.isScrolledDown);
|
this.onScroll(evt.isScrolledDown);
|
||||||
});
|
});
|
||||||
|
|
||||||
this._hashSubscription = this.hash.value.subscribe((hash) => {
|
this._hashSubscription = this.hash.value.subscribe((hash) => {
|
||||||
if (hash == undefined) return;
|
this.onHashChange(hash);
|
||||||
this.setActiveByHash(hash);
|
|
||||||
if (!this.tasks.empty) {
|
|
||||||
this.tasks.start(this.activeIdx, this);
|
|
||||||
this.scrollService.setStickElement(this.getCurrentEl());
|
|
||||||
if (hash) this.scrollToActive();
|
|
||||||
this.appState.stopLoading();
|
|
||||||
} else {
|
|
||||||
if (hash) this.scrollToActive();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get flatItems():MenuItem[] {
|
||||||
|
if (!this._flatItems) {
|
||||||
|
this._flatItems = this.flatMenu();
|
||||||
|
}
|
||||||
|
return this._flatItems;
|
||||||
|
}
|
||||||
|
|
||||||
enableItem(idx) {
|
enableItem(idx) {
|
||||||
let item = this.flatItems[idx];
|
let item = this.flatItems[idx];
|
||||||
item.ready = true;
|
item.ready = true;
|
||||||
|
@ -70,6 +62,7 @@ export class MenuService {
|
||||||
idx = item.parent.flatIdx;
|
idx = item.parent.flatIdx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check if previous items can be enabled
|
||||||
let prevItem = this.flatItems[idx -= 1];
|
let prevItem = this.flatItems[idx -= 1];
|
||||||
while(prevItem && (!prevItem.metadata || !prevItem.items)) {
|
while(prevItem && (!prevItem.metadata || !prevItem.items)) {
|
||||||
prevItem.ready = true;
|
prevItem.ready = true;
|
||||||
|
@ -79,11 +72,10 @@ export class MenuService {
|
||||||
this.changed.next();
|
this.changed.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
scrollUpdate(isScrolledDown) {
|
onScroll(isScrolledDown) {
|
||||||
let stable = false;
|
let stable = false;
|
||||||
while(!stable) {
|
while(!stable) {
|
||||||
if(isScrolledDown) {
|
if(isScrolledDown) {
|
||||||
//&& elementInViewPos === INVIEW_POSITION.BELLOW
|
|
||||||
let $nextEl = this.getEl(this.activeIdx + 1);
|
let $nextEl = this.getEl(this.activeIdx + 1);
|
||||||
if (!$nextEl) return;
|
if (!$nextEl) return;
|
||||||
let nextInViewPos = this.scrollService.getElementPos($nextEl, true);
|
let nextInViewPos = this.scrollService.getElementPos($nextEl, true);
|
||||||
|
@ -103,8 +95,21 @@ export class MenuService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getEl(flatIdx) {
|
onHashChange(hash?: string) {
|
||||||
if (flatIdx < 0) flatIdx = 0;
|
if (hash == undefined) return;
|
||||||
|
let activated = this.activateByHash(hash);
|
||||||
|
if (!this.tasks.empty) {
|
||||||
|
this.tasks.start(this.activeIdx, this);
|
||||||
|
this.scrollService.setStickElement(this.getCurrentEl());
|
||||||
|
if (activated) this.scrollToActive();
|
||||||
|
this.appState.stopLoading();
|
||||||
|
} else {
|
||||||
|
if (activated) this.scrollToActive();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getEl(flatIdx:number):Element {
|
||||||
|
if (flatIdx < 0) return null;
|
||||||
let currentItem = this.flatItems[flatIdx];
|
let currentItem = this.flatItems[flatIdx];
|
||||||
let selector = '';
|
let selector = '';
|
||||||
while(currentItem) {
|
while(currentItem) {
|
||||||
|
@ -115,35 +120,37 @@ export class MenuService {
|
||||||
return selector ? document.querySelector(selector) : null;
|
return selector ? document.querySelector(selector) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrentEl() {
|
getCurrentEl():Element {
|
||||||
return this.getEl(this.activeIdx);
|
return this.getEl(this.activeIdx);
|
||||||
}
|
}
|
||||||
|
|
||||||
deactivate(idx) {
|
deactivate(idx) {
|
||||||
if (idx < 0) return;
|
if (idx < 0) return;
|
||||||
|
|
||||||
let prevItem = this.flatItems[idx];
|
let item = this.flatItems[idx];
|
||||||
prevItem.active = false;
|
item.active = false;
|
||||||
if (prevItem.parent) {
|
if (item.parent) {
|
||||||
prevItem.parent.active = false;
|
item.parent.active = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
activate(idx) {
|
activate(idx, force = false) {
|
||||||
|
let item = this.flatItems[idx];
|
||||||
|
if (!force && item && !item.ready) return;
|
||||||
|
|
||||||
this.deactivate(this.activeIdx);
|
this.deactivate(this.activeIdx);
|
||||||
this.activeIdx = idx;
|
this.activeIdx = idx;
|
||||||
if (idx < 0) return;
|
if (idx < 0) return;
|
||||||
|
|
||||||
let currentItem = this.flatItems[this.activeIdx];
|
item.active = true;
|
||||||
currentItem.active = true;
|
if (item.parent) {
|
||||||
if (currentItem.parent) {
|
item.parent.active = true;
|
||||||
currentItem.parent.active = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.changed.next(currentItem);
|
this.changed.next(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
changeActive(offset = 1) {
|
changeActive(offset = 1):boolean {
|
||||||
let noChange = (this.activeIdx <= 0 && offset === -1) ||
|
let noChange = (this.activeIdx <= 0 && offset === -1) ||
|
||||||
(this.activeIdx === this.flatItems.length - 1 && offset === 1);
|
(this.activeIdx === this.flatItems.length - 1 && offset === 1);
|
||||||
this.activate(this.activeIdx + offset);
|
this.activate(this.activeIdx + offset);
|
||||||
|
@ -151,10 +158,11 @@ export class MenuService {
|
||||||
}
|
}
|
||||||
|
|
||||||
scrollToActive() {
|
scrollToActive() {
|
||||||
this.scrollService.scrollTo(this.getCurrentEl());
|
let $el = this.getCurrentEl();
|
||||||
|
if ($el) this.scrollService.scrollTo($el);
|
||||||
}
|
}
|
||||||
|
|
||||||
setActiveByHash(hash) {
|
activateByHash(hash):boolean {
|
||||||
if (!hash) return;
|
if (!hash) return;
|
||||||
let idx = 0;
|
let idx = 0;
|
||||||
hash = hash.substr(1);
|
hash = hash.substr(1);
|
||||||
|
@ -163,17 +171,118 @@ export class MenuService {
|
||||||
if (namespace === 'section' || namespace === 'tag') {
|
if (namespace === 'section' || namespace === 'tag') {
|
||||||
let sectionId = ptr.split('/')[0];
|
let sectionId = ptr.split('/')[0];
|
||||||
ptr = ptr.substr(sectionId.length) || null;
|
ptr = ptr.substr(sectionId.length) || null;
|
||||||
let searchId = ptr || (namespace + '/' + sectionId);
|
|
||||||
|
let searchId;
|
||||||
|
if (namespace === 'section') {
|
||||||
|
searchId = hash;
|
||||||
|
} else {
|
||||||
|
searchId = ptr || (namespace + '/' + sectionId);;
|
||||||
|
}
|
||||||
|
|
||||||
idx = this.flatItems.findIndex(item => item.id === searchId);
|
idx = this.flatItems.findIndex(item => item.id === searchId);
|
||||||
|
if (idx < 0) this.tryScrollToId(searchId);
|
||||||
} else if (namespace === 'operation') {
|
} else if (namespace === 'operation') {
|
||||||
idx = this.flatItems.findIndex(item => {
|
idx = this.flatItems.findIndex(item => {
|
||||||
return item.metadata && item.metadata.operationId === ptr
|
return item.metadata && item.metadata.operationId === ptr
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
this.activate(idx);
|
this.activate(idx, true);
|
||||||
|
return idx >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
tryScrollToId(id) {
|
||||||
|
let $el = document.querySelector(`[section="${id}"]`);
|
||||||
|
if ($el) this.scrollService.scrollTo($el);
|
||||||
|
}
|
||||||
|
|
||||||
|
addMarkdownItems() {
|
||||||
|
let schema = this.specMgr.schema;
|
||||||
|
for (let header of (<Array<string>>(schema.info && schema.info['x-redoc-markdown-headers'] || []))) {
|
||||||
|
let id = 'section/' + slugify(header);
|
||||||
|
let item = {
|
||||||
|
name: header,
|
||||||
|
id: id
|
||||||
|
}
|
||||||
|
this.items.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addTagsAndOperationItems() {
|
||||||
|
let schema = this.specMgr.schema;
|
||||||
|
let menu = this.items;
|
||||||
|
|
||||||
|
let tags = SchemaHelper.getTagsWithMethods(schema);
|
||||||
|
for (let tag of tags || []) {
|
||||||
|
let id = 'tag/' + slugify(tag.name);
|
||||||
|
let item: MenuItem;
|
||||||
|
let items: MenuItem[];
|
||||||
|
|
||||||
|
// don't put empty tag into menu, instead put their methods
|
||||||
|
if (tag.name !== '') {
|
||||||
|
item = {
|
||||||
|
name: tag['x-displayName'] || tag.name,
|
||||||
|
id: id,
|
||||||
|
description: tag.description,
|
||||||
|
metadata: { type: 'tag' }
|
||||||
|
};
|
||||||
|
if (tag.methods && tag.methods.length) {
|
||||||
|
item.items = items = [];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
item = null;
|
||||||
|
items = menu;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (items) {
|
||||||
|
for (let method of tag.methods) {
|
||||||
|
let subItem = {
|
||||||
|
name: SchemaHelper.methodSummary(method),
|
||||||
|
id: method._pointer,
|
||||||
|
description: method.description,
|
||||||
|
metadata: {
|
||||||
|
type: 'method',
|
||||||
|
pointer: method._pointer,
|
||||||
|
operationId: method.operationId
|
||||||
|
},
|
||||||
|
parent: item
|
||||||
|
}
|
||||||
|
items.push(subItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item) menu.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buildMenu() {
|
||||||
|
this.items = this.items || [];
|
||||||
|
this.addMarkdownItems();
|
||||||
|
this.addTagsAndOperationItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
flatMenu():MenuItem[] {
|
||||||
|
let menu = this.items;
|
||||||
|
let res = [];
|
||||||
|
let level = 1;
|
||||||
|
|
||||||
|
let recursive = function(items) {
|
||||||
|
for (let item of items) {
|
||||||
|
res.push(item);
|
||||||
|
item.level = item.level || level;
|
||||||
|
item.flatIdx = res.length - 1;
|
||||||
|
if (item.items) {
|
||||||
|
level++;
|
||||||
|
recursive(item.items);
|
||||||
|
level--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
recursive(menu);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
this._hashSubscription.unsubscribe();
|
this._hashSubscription.unsubscribe();
|
||||||
|
this._scrollSubscription.unsubscribe();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,15 +9,6 @@ interface PropertyPreprocessOptions {
|
||||||
skipReadOnly?: boolean;
|
skipReadOnly?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MenuMethod {
|
|
||||||
active: boolean;
|
|
||||||
summary: string;
|
|
||||||
tag: string;
|
|
||||||
pointer: string;
|
|
||||||
operationId: string;
|
|
||||||
ready: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MenuItem {
|
export interface MenuItem {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
|
@ -305,7 +296,7 @@ export class SchemaHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static getTags(schema) {
|
static getTagsWithMethods(schema) {
|
||||||
let tags = {};
|
let tags = {};
|
||||||
for (let tag of schema.tags || []) {
|
for (let tag of schema.tags || []) {
|
||||||
tags[tag.name] = tag;
|
tags[tag.name] = tag;
|
||||||
|
@ -319,10 +310,11 @@ export class SchemaHelper {
|
||||||
let methodInfo = paths[path][method];
|
let methodInfo = paths[path][method];
|
||||||
let methodTags = methodInfo.tags;
|
let methodTags = methodInfo.tags;
|
||||||
|
|
||||||
|
// empty tag
|
||||||
if (!(methodTags && methodTags.length)) {
|
if (!(methodTags && methodTags.length)) {
|
||||||
methodTags = [''];
|
methodTags = [''];
|
||||||
}
|
}
|
||||||
let methodPointer = JsonPointer.compile([path, method]);
|
let methodPointer = JsonPointer.compile(['paths', path, method]);
|
||||||
for (let tagName of methodTags) {
|
for (let tagName of methodTags) {
|
||||||
let tag = tags[tagName];
|
let tag = tags[tagName];
|
||||||
if (!tag) {
|
if (!tag) {
|
||||||
|
@ -341,84 +333,4 @@ export class SchemaHelper {
|
||||||
|
|
||||||
return Object.keys(tags).map(k => tags[k]);
|
return Object.keys(tags).map(k => tags[k]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static buildMenuTree(schema):MenuItem[] {
|
|
||||||
let tags = SchemaHelper.getTags(schema);
|
|
||||||
|
|
||||||
let menu = [];
|
|
||||||
|
|
||||||
// markdown menu items
|
|
||||||
|
|
||||||
for (let header of (<Array<string>>(schema.info && schema.info['x-redoc-markdown-headers'] || []))) {
|
|
||||||
let id = 'section/' + slugify(header);
|
|
||||||
let item = {
|
|
||||||
name: header,
|
|
||||||
id: id
|
|
||||||
}
|
|
||||||
menu.push(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
// tag menu items
|
|
||||||
for (let tag of tags || []) {
|
|
||||||
let id = 'tag/' + slugify(tag.name);
|
|
||||||
let item:MenuItem;
|
|
||||||
let items:MenuItem[];
|
|
||||||
|
|
||||||
// don't put empty tag into menu, instead put all methods
|
|
||||||
if (tag.name !== '') {
|
|
||||||
item = {
|
|
||||||
name: tag['x-displayName'] || tag.name,
|
|
||||||
id: id,
|
|
||||||
description: tag.description,
|
|
||||||
metadata: { type: 'tag' }
|
|
||||||
};
|
|
||||||
if (tag.methods && tag.methods.length) {
|
|
||||||
item.items = items = [];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
item = null;
|
|
||||||
items = menu;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (items) {
|
|
||||||
for (let method of tag.methods) {
|
|
||||||
let subItem = {
|
|
||||||
name: SchemaHelper.methodSummary(method),
|
|
||||||
id: method._pointer,
|
|
||||||
description: method.description,
|
|
||||||
metadata: {
|
|
||||||
type: 'method',
|
|
||||||
pointer: '/paths' + method._pointer,
|
|
||||||
operationId: method.operationId
|
|
||||||
},
|
|
||||||
parent: item
|
|
||||||
}
|
|
||||||
items.push(subItem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item) menu.push(item);
|
|
||||||
}
|
|
||||||
return menu;
|
|
||||||
}
|
|
||||||
|
|
||||||
static flatMenu(menu: MenuItem[]):MenuItem[] {
|
|
||||||
let res = [];
|
|
||||||
let level = 0;
|
|
||||||
|
|
||||||
let recursive = function(items) {
|
|
||||||
for (let item of items) {
|
|
||||||
res.push(item);
|
|
||||||
item.level = item.level || level;
|
|
||||||
item.flatIdx = res.length - 1;
|
|
||||||
if (item.items) {
|
|
||||||
level++;
|
|
||||||
recursive(item.items);
|
|
||||||
level--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
recursive(menu);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ import { OptionsService } from '../../../services/options.service';
|
||||||
import { isSafari } from '../../../utils/helpers';
|
import { isSafari } from '../../../utils/helpers';
|
||||||
|
|
||||||
export class LazyForRow {
|
export class LazyForRow {
|
||||||
constructor(public $implicit: any, public index: number, public show: boolean) {}
|
constructor(public $implicit: any, public index: number, public ready: boolean) {}
|
||||||
|
|
||||||
get first(): boolean { return this.index === 0; }
|
get first(): boolean { return this.index === 0; }
|
||||||
|
|
||||||
|
@ -145,7 +145,7 @@ export class LazyFor {
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
this.scroll.saveScroll();
|
this.scroll.saveScroll();
|
||||||
|
|
||||||
view.context.show = true;
|
view.context.ready = true;
|
||||||
(<any>view as ChangeDetectorRef).markForCheck();
|
(<any>view as ChangeDetectorRef).markForCheck();
|
||||||
(<any>view as ChangeDetectorRef).detectChanges();
|
(<any>view as ChangeDetectorRef).detectChanges();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user