Lazy search highlight + basic search

This commit is contained in:
Roman Hotsiy 2016-12-29 19:20:29 +02:00
parent fed2f378df
commit 46f6b29547
No known key found for this signature in database
GPG Key ID: 5CB7B3ACABA57CB0
13 changed files with 161 additions and 9 deletions

View File

@ -1,7 +1,7 @@
'use strict';
import { Component, ChangeDetectionStrategy, OnInit } from '@angular/core';
import { Component, ChangeDetectionStrategy, OnInit, ElementRef } from '@angular/core';
import { SpecManager, BaseComponent } from '../base';
import { OptionsService } from '../../services/index';
import { OptionsService, Marker } from '../../services/index';
@Component({
selector: 'api-info',
@ -12,8 +12,13 @@ import { OptionsService } from '../../services/index';
export class ApiInfo extends BaseComponent implements OnInit {
info: any = {};
specUrl: String;
constructor(specMgr: SpecManager, private optionsService: OptionsService) {
constructor(specMgr: SpecManager,
private optionsService: OptionsService,
elRef: ElementRef,
marker: Marker
) {
super(specMgr);
marker.addElement(elRef.nativeElement);
}
init() {

View File

@ -9,6 +9,7 @@
</div>
<div class="menu-content" sticky-sidebar [scrollParent]="options.$scrollParent" [scrollYOffset]="options.scrollYOffset">
<api-logo> </api-logo>
<redoc-search> </redoc-search>
<side-menu> </side-menu>
</div>
<div class="api-content">

View File

@ -0,0 +1 @@
<input #search (keyup)="update(search.value)">

View File

@ -0,0 +1,3 @@
:host {
display: block;
}

View File

@ -0,0 +1,28 @@
'use strict';
import { Component, ChangeDetectionStrategy, OnInit, HostBinding } from '@angular/core';
import { Marker } from '../../services/';
@Component({
selector: 'redoc-search',
styleUrls: ['./redoc-search.css'],
templateUrl: './redoc-search.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class RedocSearch implements OnInit {
logo:any = {};
constructor(private marker: Marker) {
}
init() {
}
update(val) {
this.marker.mark(val);
}
ngOnInit() {
}
}

View File

@ -5,7 +5,7 @@ import { Component, EventEmitter, Input, Output, ElementRef, ChangeDetectorRef,
//import { global } from '@angular/core/src/facade/lang';
import { trigger, state, animate, transition, style } from '@angular/core';
import { BaseComponent, SpecManager } from '../base';
import { ScrollService, MenuService, OptionsService, MenuItem } from '../../services/';
import { ScrollService, MenuService, OptionsService, MenuItem, Marker} from '../../services/';
import { BrowserDomAdapter as DOM } from '../../utils/browser-adapter';
const global = window;
@ -55,7 +55,7 @@ export class SideMenu extends BaseComponent implements OnInit, OnDestroy {
constructor(specMgr:SpecManager, elementRef:ElementRef,
private scrollService:ScrollService, private menuService:MenuService,
optionsService:OptionsService, private detectorRef:ChangeDetectorRef) {
optionsService:OptionsService, private detectorRef:ChangeDetectorRef, private marker:Marker) {
super(specMgr);
this.$element = elementRef.nativeElement;
@ -64,7 +64,8 @@ export class SideMenu extends BaseComponent implements OnInit, OnDestroy {
this.options = optionsService.options;
this.menuService.changed.subscribe((evt) => this.changed(evt));
this.menuService.changedActiveItem.subscribe((evt) => this.changed(evt));
this.menuService.changed.subscribe((evt) => this.detectorRef.detectChanges());
}
changed(item) {
@ -147,4 +148,7 @@ export class SideMenu extends BaseComponent implements OnInit, OnDestroy {
ngOnInit() {
this.preinit();
}
ngAfterViewInit() {
}
}

View File

@ -15,15 +15,16 @@ import { Method } from './Method/method';
import { Warnings } from './Warnings/warnings';
import { SecurityDefinitions } from './SecurityDefinitions/security-definitions';
import { LoadingBar } from './LoadingBar/loading-bar';
import { RedocSearch } from './Search/redoc-search';
import { Redoc } from './Redoc/redoc';
export const REDOC_DIRECTIVES = [
ApiInfo, ApiLogo, JsonSchema, JsonSchemaLazy, ParamsList, RequestSamples, ResponsesList,
ResponsesSamples, SchemaSample, SideMenu, MethodsList, Method, Warnings, Redoc, SecurityDefinitions,
LoadingBar, SideMenuItems
LoadingBar, SideMenuItems, RedocSearch
];
export { ApiInfo, ApiLogo, JsonSchema, JsonSchemaLazy, ParamsList, RequestSamples, ResponsesList,
ResponsesSamples, SchemaSample, SideMenu, MethodsList, Method, Warnings, Redoc, SecurityDefinitions,
LoadingBar, SideMenuItems }
LoadingBar, SideMenuItems, RedocSearch }

View File

@ -16,6 +16,7 @@ import {
AppStateService,
ComponentParser,
ContentProjector,
Marker,
COMPONENT_PARSER_ALLOWED } from './services/';
import { SpecManager } from './utils/spec-manager';
@ -35,6 +36,7 @@ import { SpecManager } from './utils/spec-manager';
ComponentParser,
ContentProjector,
LazyTasksService,
Marker,
{ provide: APP_ID, useValue: 'redoc' },
{ provide: ErrorHandler, useClass: CustomErrorHandler },
{ provide: COMPONENT_PARSER_ALLOWED, useValue: { 'security-definitions': SecurityDefinitions} }

View File

@ -11,3 +11,4 @@ export * from './warnings.service';
export * from './component-parser.service';
export * from './content-projector.service';
export * from './marker.service';

View File

@ -0,0 +1,90 @@
import { Injectable } from '@angular/core';
import * as Mark from 'mark.js';
import { MenuService } from './menu.service';
const ROLL_LEN = 5;
@Injectable()
export class Marker {
permInstances = [];
rolledInstances = new Array(ROLL_LEN);
term: string;
currIdx = -1;
constructor(private menu: MenuService) {
menu.changedActiveItem.subscribe(() => {
this.roll();
});
}
addElement(el: Element) {
this.permInstances.push(new Mark(el));
}
newMarkerAtMenuItem(idx:number) {
let context = this.menu.getEl(idx);
if (this.menu.isTagItem(idx)) {
context = this.menu.getTagInfoEl(idx);
}
let newInst = context && new Mark(context);
if (newInst && this.term) {
newInst.mark(this.term);
}
return newInst;
}
roll() {
let newIdx = this.menu.activeIdx;
let diff = newIdx - this.currIdx;
this.currIdx = newIdx;
if (diff < 0) {
diff = - diff;
for (let i=0; i < Math.min(diff, ROLL_LEN); i++) {
let prevInst = this.rolledInstances.pop();
if(prevInst) prevInst.unmark();
let idx = newIdx - Math.floor(ROLL_LEN/2) + i;
let newMark = this.newMarkerAtMenuItem(idx);
this.rolledInstances.unshift(newMark);
}
} else {
for (let i=0; i < Math.min(diff, ROLL_LEN); i++) {
let oldInst = this.rolledInstances.shift();
oldInst && oldInst.unmark();
let idx = newIdx + Math.floor(ROLL_LEN/2) - i;
let newMark = this.newMarkerAtMenuItem(idx);
this.rolledInstances.push(newMark);
}
}
}
mark(term: string) {
this.term = term || null;
this.remark();
}
remark() {
for (let marker of this.permInstances) {
if (marker) {
marker.unmark();
if (this.term) marker.mark(this.term);
}
}
for (let marker of this.rolledInstances) {
if (marker) {
marker.unmark();
if (this.term) marker.mark(this.term);
}
}
}
unmark() {
this.term = null;
this.remark();
}
updateMark() {
}
}

View File

@ -44,6 +44,7 @@ export interface MenuItem {
@Injectable()
export class MenuService {
changed: EventEmitter<any> = new EventEmitter();
changedActiveItem: EventEmitter<any> = new EventEmitter();
items: MenuItem[];
activeIdx: number = -1;
@ -135,6 +136,7 @@ export class MenuService {
getEl(flatIdx:number):Element {
if (flatIdx < 0) return null;
if (flatIdx > this.flatItems.length - 1) return null;
let currentItem = this.flatItems[flatIdx];
if (!currentItem) return;
if (currentItem.isGroup) currentItem = this.flatItems[flatIdx + 1];
@ -156,6 +158,18 @@ export class MenuService {
return selector ? document.querySelector(selector) : null;
}
isTagItem(flatIdx: number):boolean {
let item = this.flatItems[flatIdx];
return item && item.metadata && item.metadata.type === 'tag';
}
getTagInfoEl(flatIdx: number):Element {
if (!this.isTagItem(flatIdx)) return null;
let el = this.getEl(flatIdx);
return el && el.querySelector('.tag-info');
}
getCurrentEl():Element {
return this.getEl(this.activeIdx);
}
@ -186,7 +200,7 @@ export class MenuService {
cItem.parent.active = true;
cItem = cItem.parent;
}
this.changed.next(item);
this.changedActiveItem.next(item);
}
changeActive(offset = 1):boolean {

View File

@ -6,6 +6,7 @@ declare module "scrollparent"
declare module "slugify"
declare module "url"
declare module "json-pointer";
declare module "mark.js";
declare module "*.css" {
const content: string;

View File

@ -111,6 +111,7 @@
"hint.css": "^2.3.2",
"json-pointer": "^0.6.0",
"json-schema-ref-parser": "^3.1.2",
"mark.js": "github:julmot/mark.js",
"openapi-sampler": "^0.3.3",
"prismjs": "^1.5.1",
"remarkable": "^1.6.2",