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