mirror of
https://github.com/Redocly/redoc.git
synced 2024-11-30 20:43:42 +03:00
Merge branch 'master' into releases
This commit is contained in:
commit
383169d6c5
10
.travis.yml
10
.travis.yml
|
@ -6,10 +6,10 @@ branches:
|
|||
- releases
|
||||
matrix:
|
||||
include:
|
||||
- env: JOB=e2e
|
||||
- env: JOB=e2e-guru
|
||||
fast_finish: true
|
||||
allow_failures:
|
||||
- env: JOB=e2e
|
||||
- env: JOB=e2e-guru
|
||||
env:
|
||||
global:
|
||||
- GH_REF: github.com/Rebilly/ReDoc.git
|
||||
|
@ -41,16 +41,16 @@ deploy:
|
|||
secure: PuhWLERrCEFmXmdFpw2OVFlqpOIVDmgwk5JUJOYaFdVCh/smp0+jZCQ4vrdFpuG96rnDVirD+A8xvW6NgsNNaRthLgOB/LRdFN69rU6Gvn3At6wlnC55t5dlhxPvCfnzJcHVBLXX4EmMkjnZqDg2uczXTzPodr3FnQJNuXmP8B33fzDVLyHccvXZ90abwXWVrgRIXPU28niqCR8DOC2OTzs7wqz+BLNkYDRRbyYXsg62HWuD33x5iof5IqBmhzBt3usCGmF3QGcgHrXHdZw3sZnit8+Bua++3KrXR0x6HGXXN1AoXVmCAkCa5OTQ5R3tCRxiJN3P2KLnvWeZR74sTFkovJB/6pGCvbJ/c7Wnuw6sD7SgOUBD359ULB6lAf5OnxBLoNebX4JxxVXF+zA4E3Bl44VxkzDpPWc15xqBPMB5vBREzMVmJ5mExn2s5cmLQjADbl9h0y6gZnhnNJ+iTmqtrVyM0ZkF2rPrzrTdGD+ULmRIlTMkdD1bh+/TJ3RdXT3P4/zNUJmiNnvgnnJVYYvsGaXWF+7uCVHT/8k2RsoSHqgkqh0gkDqGSwVix55y5mC7T2Vk9lMBhm6MvFJXaonOX0kxJS4EDQ3plPd6/ybG+TLhwggYnQ8o9msU5Nt6FpUShKiezjKurIhbQZdwlVivX3tahjW2QjNDO58xGgY=
|
||||
on:
|
||||
tags: true
|
||||
condition: $JOB != e2e
|
||||
condition: $JOB != e2e-guru
|
||||
- skip_cleanup: true
|
||||
provider: script
|
||||
script: npm run branch-release
|
||||
on:
|
||||
branch: master
|
||||
condition: $JOB != e2e
|
||||
condition: $JOB != e2e-guru
|
||||
- skip_cleanup: true
|
||||
provider: script
|
||||
script: npm run deploy
|
||||
on:
|
||||
tags: true
|
||||
condition: $JOB != e2e
|
||||
condition: $JOB != e2e-guru
|
||||
|
|
|
@ -8,7 +8,7 @@ git reset --hard
|
|||
git fetch origin gh-pages:gh-pages
|
||||
git checkout gh-pages
|
||||
cp -R ../releases/* .
|
||||
git checkout master
|
||||
git checkout @{-1}
|
||||
cd -
|
||||
|
||||
# build
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#!/bin/bash
|
||||
if [ "$JOB" = "e2e" ]; then
|
||||
if [ "$JOB" = "e2e-guru" ]; then
|
||||
npm run e2e
|
||||
else
|
||||
npm run unit
|
||||
echo "Starting Basic E2E"
|
||||
npm run e2e
|
||||
fi
|
||||
|
|
|
@ -41,6 +41,7 @@ gulp.task('inlineTemplates', ['sass'], function() {
|
|||
var JS_DEV_DEPS = [
|
||||
'lib/utils/browser-update.js',
|
||||
'node_modules/zone.js/dist/zone.js',
|
||||
'node_modules/zone.js/dist/long-stack-trace-zone.js',
|
||||
'node_modules/reflect-metadata/Reflect.js',
|
||||
'node_modules/babel-polyfill/dist/polyfill.js'
|
||||
];
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
'use strict';
|
||||
|
||||
import {SchemaManager, RedocComponent, BaseComponent} from '../base';
|
||||
import OptionsManager from '../../options';
|
||||
import { SchemaManager, RedocComponent, BaseComponent } from '../base';
|
||||
import { OptionsService } from '../../services/index';
|
||||
|
||||
@RedocComponent({
|
||||
selector: 'api-info',
|
||||
styleUrls: ['./lib/components/ApiInfo/api-info.css'],
|
||||
templateUrl: './lib/components/ApiInfo/api-info.html'
|
||||
})
|
||||
@Reflect.metadata('parameters', [[SchemaManager], [OptionsManager]])
|
||||
export default class ApiInfo extends BaseComponent {
|
||||
constructor(schemaMgr, optionsMgr) {
|
||||
@Reflect.metadata('parameters', [[SchemaManager], [OptionsService]])
|
||||
export class ApiInfo extends BaseComponent {
|
||||
constructor(schemaMgr, optionsService) {
|
||||
super(schemaMgr);
|
||||
this.optionsMgr = optionsMgr;
|
||||
this.optionsService = optionsService;
|
||||
}
|
||||
|
||||
prepareModel() {
|
||||
this.data = this.componentSchema.info;
|
||||
this.specUrl = this.optionsMgr.options.specUrl;
|
||||
this.specUrl = this.optionsService.options.specUrl;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@import '../../common/styles/variables';
|
||||
@import '../../shared/styles/variables';
|
||||
|
||||
.api-info-header {
|
||||
font-weight: normal;
|
||||
|
|
|
@ -1,22 +1,23 @@
|
|||
'use strict';
|
||||
|
||||
import { getChildDebugElement } from 'tests/helpers';
|
||||
import {Component, provide} from 'angular2/core';
|
||||
import { Component, provide } from '@angular/core';
|
||||
|
||||
import {
|
||||
TestComponentBuilder,
|
||||
async,
|
||||
inject,
|
||||
async,
|
||||
beforeEach,
|
||||
beforeEachProviders,
|
||||
it
|
||||
} from 'angular2/testing';
|
||||
} from '@angular/core/testing';
|
||||
|
||||
import ApiInfo from 'lib/components/ApiInfo/api-info';
|
||||
import { TestComponentBuilder } from '@angular/compiler/testing';
|
||||
|
||||
import { ApiInfo } from 'lib/components/ApiInfo/api-info';
|
||||
import SchemaManager from 'lib/utils/SchemaManager';
|
||||
import OptionsManager from 'lib/options';
|
||||
import { OptionsService } from 'lib/services/index';
|
||||
|
||||
let optsMgr = new OptionsManager();
|
||||
let optionsService = new OptionsService();
|
||||
|
||||
describe('Redoc components', () => {
|
||||
describe('ApiInfo Component', () => {
|
||||
|
@ -25,7 +26,7 @@ describe('Redoc components', () => {
|
|||
let fixture;
|
||||
beforeEachProviders(() => [
|
||||
provide(SchemaManager, {useValue: new SchemaManager()}),
|
||||
provide(OptionsManager, {useValue: optsMgr})
|
||||
provide(OptionsService, {useValue: optionsService})
|
||||
]);
|
||||
|
||||
beforeEach(async(inject([TestComponentBuilder, SchemaManager], (tcb, schemaMgr) => {
|
||||
|
@ -39,7 +40,9 @@ describe('Redoc components', () => {
|
|||
component = getChildDebugElement(fixture.debugElement, 'api-info').componentInstance;
|
||||
fixture.detectChanges();
|
||||
done();
|
||||
}, err => done.fail(err));
|
||||
}, err => {
|
||||
done.fail(err);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import {RedocComponent, BaseComponent} from '../base';
|
|||
styleUrls: ['./lib/components/ApiLogo/api-logo.css'],
|
||||
templateUrl: './lib/components/ApiLogo/api-logo.html'
|
||||
})
|
||||
export default class ApiLogo extends BaseComponent {
|
||||
export class ApiLogo extends BaseComponent {
|
||||
constructor(schemaMgr) {
|
||||
super(schemaMgr);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@import '../../common/styles/variables';
|
||||
@import '../../shared/styles/variables';
|
||||
|
||||
img {
|
||||
max-height: 150px;
|
||||
|
|
|
@ -1,18 +1,19 @@
|
|||
'use strict';
|
||||
|
||||
import { getChildDebugElement } from 'tests/helpers';
|
||||
import {Component, provide} from 'angular2/core';
|
||||
import {Component, provide} from '@angular/core';
|
||||
|
||||
import {
|
||||
TestComponentBuilder,
|
||||
async,
|
||||
inject,
|
||||
async,
|
||||
beforeEach,
|
||||
beforeEachProviders,
|
||||
it
|
||||
} from 'angular2/testing';
|
||||
} from '@angular/core/testing';
|
||||
|
||||
import ApiLogo from 'lib/components/ApiLogo/api-logo';
|
||||
import { TestComponentBuilder } from '@angular/compiler/testing';
|
||||
|
||||
import { ApiLogo } from 'lib/components/ApiLogo/api-logo';
|
||||
import SchemaManager from 'lib/utils/SchemaManager';
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@import '../../common/styles/variables';
|
||||
@import '../../shared/styles/variables';
|
||||
$lines-width: 1px;
|
||||
$bullet-size: 1px;
|
||||
$cell-spacing: 25px;
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
'use strict';
|
||||
|
||||
import {Component, ElementRef, ViewContainerRef} from 'angular2/core';
|
||||
import {CORE_DIRECTIVES} from 'angular2/common';
|
||||
import {DynamicComponentLoader} from 'angular2/src/core/linker/dynamic_component_loader';
|
||||
import { Component, ElementRef, ViewContainerRef } from '@angular/core';
|
||||
import { CORE_DIRECTIVES } from '@angular/common';
|
||||
import { DynamicComponentLoader } from '@angular/core';
|
||||
|
||||
import JsonSchema from './json-schema';
|
||||
import OptionsManager from '../../options';
|
||||
import { JsonSchema } from './json-schema';
|
||||
import { OptionsService } from '../../services/index';
|
||||
import SchemaManager from '../../utils/SchemaManager';
|
||||
|
||||
|
||||
|
@ -18,14 +18,15 @@ var cache = {};
|
|||
template: '',
|
||||
directives: [CORE_DIRECTIVES]
|
||||
})
|
||||
@Reflect.metadata('parameters', [[SchemaManager], [ViewContainerRef], [ElementRef], [DynamicComponentLoader], [OptionsManager]])
|
||||
export default class JsonSchemaLazy {
|
||||
@Reflect.metadata('parameters', [[SchemaManager], [ViewContainerRef], [
|
||||
ElementRef], [DynamicComponentLoader], [OptionsService]])
|
||||
export class JsonSchemaLazy {
|
||||
|
||||
constructor(schemaMgr, viewRef, elementRef, dcl, optionsMgr) {
|
||||
constructor(schemaMgr, viewRef, elementRef, dcl, optionsService) {
|
||||
this.viewRef = viewRef;
|
||||
this.elementRef = elementRef;
|
||||
this.dcl = dcl;
|
||||
this.optionsMgr = optionsMgr;
|
||||
this.optionsService = optionsService;
|
||||
this.schemaMgr = schemaMgr;
|
||||
}
|
||||
|
||||
|
@ -35,13 +36,17 @@ export default class JsonSchemaLazy {
|
|||
}
|
||||
|
||||
load() {
|
||||
if (this.optionsMgr.options.disableLazySchemas) return;
|
||||
if (this.optionsService.options.disableLazySchemas) return;
|
||||
if (this.loaded) return;
|
||||
if (this.pointer) {
|
||||
this.dcl.loadNextToLocation(JsonSchema, this.viewRef).then((compRef) => {
|
||||
this.initComponent(compRef);
|
||||
// trigger change detection
|
||||
if (compRef.changeDetectorRef) {
|
||||
compRef.changeDetectorRef.detectChanges();
|
||||
} else {
|
||||
compRef.hostView.changeDetectorRef.detectChanges();
|
||||
}
|
||||
});
|
||||
}
|
||||
this.loaded = true;
|
||||
|
@ -60,7 +65,11 @@ export default class JsonSchemaLazy {
|
|||
if ($element.querySelector('.discriminator-wrap')) {
|
||||
this.dcl.loadNextToLocation(JsonSchema, this.viewRef).then((compRef) => {
|
||||
this.initComponent(compRef);
|
||||
if (compRef.changeDetectorRef) {
|
||||
compRef.changeDetectorRef.detectChanges();
|
||||
} else {
|
||||
compRef.hostView.changeDetectorRef.detectChanges();
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
@ -70,7 +79,11 @@ export default class JsonSchemaLazy {
|
|||
} else {
|
||||
cache[this.pointer] = this.dcl.loadNextToLocation(JsonSchema, this.viewRef).then((compRef) => {
|
||||
this.initComponent(compRef);
|
||||
if (compRef.changeDetectorRef) {
|
||||
compRef.changeDetectorRef.detectChanges();
|
||||
} else {
|
||||
compRef.hostView.changeDetectorRef.detectChanges();
|
||||
}
|
||||
return compRef;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,21 +1,23 @@
|
|||
'use strict';
|
||||
|
||||
import { getChildDebugElement } from 'tests/helpers';
|
||||
import {Component, provide} from 'angular2/core';
|
||||
import {DynamicComponentLoader} from 'angular2/src/core/linker/dynamic_component_loader';
|
||||
import {BrowserDomAdapter} from 'angular2/platform/browser';
|
||||
import { Component, provide } from '@angular/core';
|
||||
import { DynamicComponentLoader } from '@angular/core';
|
||||
import { BrowserDomAdapter } from '@angular/platform-browser/src/browser/browser_adapter';
|
||||
|
||||
import {
|
||||
TestComponentBuilder,
|
||||
inject,
|
||||
beforeEach,
|
||||
beforeEachProviders,
|
||||
it
|
||||
} from 'angular2/testing';
|
||||
} from '@angular/core/testing';
|
||||
|
||||
import JsonSchemaLazy from 'lib/components/JsonSchema/json-schema-lazy';
|
||||
import { TestComponentBuilder } from '@angular/compiler/testing';
|
||||
|
||||
|
||||
import { JsonSchemaLazy } from 'lib/components/JsonSchema/json-schema-lazy';
|
||||
import SchemaManager from 'lib/utils/SchemaManager';
|
||||
import OptionsManager from 'lib/options';
|
||||
import { OptionsService } from 'lib/services/index';
|
||||
|
||||
describe('Redoc components', () => {
|
||||
describe('JsonSchemaLazy Component', () => {
|
||||
|
@ -31,7 +33,7 @@ describe('Redoc components', () => {
|
|||
beforeEachProviders(() => [
|
||||
provide(SchemaManager, {useValue: schemaMgr}),
|
||||
provide(BrowserDomAdapter, {useClass: BrowserDomAdapter}),
|
||||
provide(OptionsManager, {useClass: OptionsManager})
|
||||
provide(OptionsService, {useClass: OptionsService})
|
||||
]);
|
||||
beforeEach(inject([TestComponentBuilder, DynamicComponentLoader], (tcb, dcl) => {
|
||||
builder = tcb;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
'use strict';
|
||||
|
||||
import {ElementRef} from 'angular2/core';
|
||||
import { ElementRef } from '@angular/core';
|
||||
|
||||
import {RedocComponent, BaseComponent, SchemaManager} from '../base';
|
||||
import {DropDown} from '../../common/components/DropDown/dropdown';
|
||||
import { RedocComponent, BaseComponent, SchemaManager } from '../base';
|
||||
import { DropDown } from '../../shared/components/index';
|
||||
import JsonPointer from '../../utils/JsonPointer';
|
||||
|
||||
@RedocComponent({
|
||||
|
@ -14,7 +14,7 @@ import JsonPointer from '../../utils/JsonPointer';
|
|||
inputs: ['isArray', 'final', 'nestOdd', 'childFor', 'skipReadOnly']
|
||||
})
|
||||
@Reflect.metadata('parameters', [[SchemaManager], [ElementRef]])
|
||||
export default class JsonSchema extends BaseComponent {
|
||||
export class JsonSchema extends BaseComponent {
|
||||
constructor(schemaMgr, elementRef) {
|
||||
super(schemaMgr);
|
||||
this.$element = elementRef.nativeElement;
|
||||
|
@ -109,7 +109,7 @@ export default class JsonSchema extends BaseComponent {
|
|||
props = props || [];
|
||||
|
||||
if (schema.additionalProperties && schema.additionalProperties !== false) {
|
||||
let propsSchema = this.prepareAdditionalProperties(schema.additionalProperties);
|
||||
let propsSchema = this.prepareAdditionalProperties(schema);
|
||||
propsSchema._additional = true;
|
||||
props.push(propsSchema);
|
||||
}
|
||||
|
@ -126,8 +126,9 @@ export default class JsonSchema extends BaseComponent {
|
|||
}
|
||||
|
||||
prepareAdditionalProperties(schema) {
|
||||
return JsonSchema.injectPropertyData(schema, '<Additional Properties> *',
|
||||
JsonPointer.join(schema._pointer || this.pointer, ['additionalProperties']));
|
||||
var addProps = schema.additionalProperties;
|
||||
return JsonSchema.injectPropertyData(addProps, '<Additional Properties> *',
|
||||
JsonPointer.join(addProps._pointer || schema._pointer || this.pointer, ['additionalProperties']));
|
||||
}
|
||||
|
||||
static injectPropertyData(propertySchema, propertyName, propPointer) {
|
||||
|
|
|
@ -1,18 +1,19 @@
|
|||
'use strict';
|
||||
|
||||
import { getChildDebugElement } from 'tests/helpers';
|
||||
import {Component, provide} from 'angular2/core';
|
||||
import OptionsManager from 'lib/options';
|
||||
|
||||
import { Component, provide } from '@angular/core';
|
||||
import {
|
||||
TestComponentBuilder,
|
||||
inject,
|
||||
beforeEach,
|
||||
beforeEachProviders,
|
||||
it
|
||||
} from 'angular2/testing';
|
||||
} from '@angular/core/testing';
|
||||
import { TestComponentBuilder } from '@angular/compiler/testing';
|
||||
|
||||
import JsonSchema from 'lib/components/JsonSchema/json-schema';
|
||||
import { OptionsService } from 'lib/services/index';
|
||||
import { getChildDebugElement } from 'tests/helpers';
|
||||
|
||||
|
||||
import { JsonSchema } from 'lib/components/JsonSchema/json-schema';
|
||||
import SchemaManager from 'lib/utils/SchemaManager';
|
||||
|
||||
describe('Redoc components', () => {
|
||||
|
@ -23,7 +24,7 @@ describe('Redoc components', () => {
|
|||
let fixture;
|
||||
beforeEachProviders(() => [
|
||||
provide(SchemaManager, {useValue: schemaMgr}),
|
||||
provide(OptionsManager, {useClass: OptionsManager})
|
||||
provide(OptionsService, {useClass: OptionsService})
|
||||
]);
|
||||
beforeEach(inject([TestComponentBuilder], (tcb) => {
|
||||
builder = tcb;
|
||||
|
|
|
@ -16,11 +16,11 @@
|
|||
<h5>Definition</h5>
|
||||
<span class="method-endpoint">
|
||||
<h5 class="http-method" [ngClass]="data.httpMethod">{{data.httpMethod}}</h5>
|
||||
<span class="api-url">{{data.apiUrl}}</span> <span class="path">{{data.path}}</span>
|
||||
<span class="api-url">{{data.apiUrl}}</span><span class="path">{{data.path}}</span>
|
||||
</span>
|
||||
<div *ngIf="data.bodyParam">
|
||||
<br>
|
||||
<request-samples [pointer]="pointer" [bodySchemaPtr]="data.bodyParam._pointer">
|
||||
<request-samples [pointer]="pointer" [schemaPointer]="data.bodyParam._pointer">
|
||||
</request-samples>
|
||||
</div>
|
||||
<div>
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
'use strict';
|
||||
|
||||
import {JsonPointer} from '../../utils/JsonPointer';
|
||||
import {RedocComponent, BaseComponent} from '../base';
|
||||
import { JsonPointer } from '../../utils/JsonPointer';
|
||||
import { RedocComponent, BaseComponent } from '../base';
|
||||
|
||||
import ParamsList from '../ParamsList/params-list';
|
||||
import ResponsesList from '../ResponsesList/responses-list';
|
||||
import ResponsesSamples from '../ResponsesSamples/responses-samples';
|
||||
import SchemaSample from '../SchemaSample/schema-sample';
|
||||
import RequestSamples from '../RequestSamples/request-samples';
|
||||
import { ParamsList } from '../ParamsList/params-list';
|
||||
import { ResponsesList } from '../ResponsesList/responses-list';
|
||||
import { ResponsesSamples } from '../ResponsesSamples/responses-samples';
|
||||
import { SchemaSample } from '../SchemaSample/schema-sample';
|
||||
import { RequestSamples } from '../RequestSamples/request-samples';
|
||||
|
||||
@RedocComponent({
|
||||
selector: 'method',
|
||||
templateUrl: './lib/components/Method/method.html',
|
||||
styleUrls: ['./lib/components/Method/method.css'],
|
||||
directives: [ParamsList, ResponsesList, ResponsesSamples, SchemaSample, RequestSamples],
|
||||
directives: [ ParamsList, ResponsesList, ResponsesSamples, SchemaSample, RequestSamples ],
|
||||
inputs: ['tag']
|
||||
})
|
||||
export default class Method extends BaseComponent {
|
||||
export class Method extends BaseComponent {
|
||||
constructor(schemaMgr) {
|
||||
super(schemaMgr);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
@import '../../common/styles/variables';
|
||||
@import '../../common/styles/share-link';
|
||||
@import '../../shared/styles/variables';
|
||||
@import '../../shared/styles/share-link';
|
||||
|
||||
:host {
|
||||
padding-bottom: 100px;
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
'use strict';
|
||||
|
||||
import { getChildDebugElement } from 'tests/helpers';
|
||||
import {Component, provide} from 'angular2/core';
|
||||
import {BrowserDomAdapter} from 'angular2/platform/browser';
|
||||
|
||||
import { Component, provide } from '@angular/core';
|
||||
import { BrowserDomAdapter } from '@angular/platform-browser/src/browser/browser_adapter';
|
||||
import {
|
||||
TestComponentBuilder,
|
||||
async,
|
||||
inject,
|
||||
async,
|
||||
beforeEach,
|
||||
beforeEachProviders,
|
||||
it
|
||||
} from 'angular2/testing';
|
||||
} from '@angular/core/testing';
|
||||
import { TestComponentBuilder } from '@angular/compiler/testing';
|
||||
|
||||
import Method from 'lib/components/Method/method';
|
||||
import { getChildDebugElement } from 'tests/helpers';
|
||||
|
||||
import { Method } from 'lib/components/Method/method';
|
||||
import SchemaManager from 'lib/utils/SchemaManager';
|
||||
import OptionsManager from 'lib/options';
|
||||
import { OptionsService, RedocEventsService } from 'lib/services/index';
|
||||
|
||||
describe('Redoc components', () => {
|
||||
describe('Method Component', () => {
|
||||
|
@ -24,7 +24,8 @@ describe('Redoc components', () => {
|
|||
beforeEachProviders(() => [
|
||||
provide(SchemaManager, {useValue: new SchemaManager()}),
|
||||
provide(BrowserDomAdapter, {useClass: BrowserDomAdapter}),
|
||||
provide(OptionsManager, {useClass: OptionsManager})
|
||||
provide(OptionsService, {useClass: OptionsService}),
|
||||
provide(RedocEventsService, {useClass: RedocEventsService})
|
||||
]);
|
||||
beforeEach(async(inject([TestComponentBuilder, SchemaManager], (tcb, schemaMgr) => {
|
||||
builder = tcb;
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
'use strict';
|
||||
|
||||
import {RedocComponent, BaseComponent} from '../base';
|
||||
import Method from '../Method/method';
|
||||
import {EncodeURIComponentPipe} from '../../utils/pipes';
|
||||
import { forwardRef } from '@angular/core';
|
||||
import { RedocComponent, BaseComponent } from '../base';
|
||||
import { Method } from '../Method/method';
|
||||
import { EncodeURIComponentPipe } from '../../utils/pipes';
|
||||
|
||||
@RedocComponent({
|
||||
selector: 'methods-list',
|
||||
templateUrl: './lib/components/MethodsList/methods-list.html',
|
||||
styleUrls: ['./lib/components/MethodsList/methods-list.css'],
|
||||
directives: [Method],
|
||||
pipes: [EncodeURIComponentPipe]
|
||||
directives: [ forwardRef(() => Method) ],
|
||||
pipes: [ EncodeURIComponentPipe ]
|
||||
})
|
||||
export default class MethodsList extends BaseComponent {
|
||||
export class MethodsList extends BaseComponent {
|
||||
|
||||
constructor(schemaMgr) {
|
||||
super(schemaMgr);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
@import '../../common/styles/variables';
|
||||
@import '../../common/styles/share-link';
|
||||
@import '../../shared/styles/variables';
|
||||
@import '../../shared/styles/share-link';
|
||||
|
||||
.tag-info {
|
||||
padding: 40px;
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
'use strict';
|
||||
|
||||
import { getChildDebugElement } from 'tests/helpers';
|
||||
import {Component, provide} from 'angular2/core';
|
||||
import OptionsManager from 'lib/options';
|
||||
import {BrowserDomAdapter} from 'angular2/platform/browser';
|
||||
|
||||
import { Component, provide } from '@angular/core';
|
||||
import { BrowserDomAdapter } from '@angular/platform-browser/src/browser/browser_adapter';
|
||||
import {
|
||||
TestComponentBuilder,
|
||||
inject,
|
||||
async,
|
||||
beforeEach,
|
||||
beforeEachProviders,
|
||||
it
|
||||
} from 'angular2/testing';
|
||||
} from '@angular/core/testing';
|
||||
import { TestComponentBuilder } from '@angular/compiler/testing';
|
||||
|
||||
import MethodsList from 'lib/components/MethodsList/methods-list';
|
||||
import { getChildDebugElement } from 'tests/helpers';
|
||||
|
||||
import { OptionsService, RedocEventsService } from 'lib/services/index';
|
||||
import { MethodsList } from 'lib/components/MethodsList/methods-list';
|
||||
import SchemaManager from 'lib/utils/SchemaManager';
|
||||
|
||||
describe('Redoc components', () => {
|
||||
|
@ -24,8 +24,9 @@ describe('Redoc components', () => {
|
|||
let fixture;
|
||||
beforeEachProviders(() => [
|
||||
provide(SchemaManager, {useValue: new SchemaManager()}),
|
||||
provide(OptionsManager, {useClass: OptionsManager}),
|
||||
provide(BrowserDomAdapter, {useClass: BrowserDomAdapter})
|
||||
provide(OptionsService, {useClass: OptionsService}),
|
||||
provide(BrowserDomAdapter, {useClass: BrowserDomAdapter}),
|
||||
provide(RedocEventsService, {useClass: RedocEventsService})
|
||||
]);
|
||||
beforeEach(async(inject([TestComponentBuilder, SchemaManager], (tcb, schemaMgr) => {
|
||||
builder = tcb;
|
||||
|
@ -56,11 +57,9 @@ describe('Redoc components', () => {
|
|||
});
|
||||
});
|
||||
|
||||
/** Test component that contains an ApiInfo. */
|
||||
@Component({
|
||||
selector: 'test-app',
|
||||
directives: [MethodsList],
|
||||
providers: [SchemaManager],
|
||||
directives: [ MethodsList ],
|
||||
template:
|
||||
`<methods-list></methods-list>`
|
||||
})
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
'use strict';
|
||||
|
||||
import {RedocComponent, BaseComponent} from '../base';
|
||||
import JsonSchema from '../JsonSchema/json-schema';
|
||||
import JsonSchemaLazy from '../JsonSchema/json-schema-lazy';
|
||||
import { RedocComponent, BaseComponent } from '../base';
|
||||
import { JsonSchema } from '../JsonSchema/json-schema';
|
||||
import {JsonSchemaLazy} from '../JsonSchema/json-schema-lazy';
|
||||
|
||||
function safePush(obj, prop, item) {
|
||||
if (!obj[prop]) obj[prop] = [];
|
||||
|
@ -15,7 +15,7 @@ function safePush(obj, prop, item) {
|
|||
styleUrls: ['./lib/components/ParamsList/params-list.css'],
|
||||
directives: [JsonSchema, JsonSchemaLazy]
|
||||
})
|
||||
export default class ParamsList extends BaseComponent {
|
||||
export class ParamsList extends BaseComponent {
|
||||
constructor(schemaMgr) {
|
||||
super(schemaMgr);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@import '../../common/styles/variables';
|
||||
@import '../../shared/styles/variables';
|
||||
|
||||
$hint-color: #999999;
|
||||
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
'use strict';
|
||||
|
||||
import {ChangeDetectionStrategy, provide, enableProdMode} from 'angular2/core';
|
||||
import {ElementRef} from 'angular2/core';
|
||||
import {BrowserDomAdapter, bootstrap} from 'angular2/platform/browser';
|
||||
import detectScollParent from 'scrollparent';
|
||||
import {RedocComponent, BaseComponent} from '../base';
|
||||
import { provide, enableProdMode, ElementRef } from '@angular/core';
|
||||
import { bootstrap } from '@angular/platform-browser-dynamic';
|
||||
import { BrowserDomAdapter } from '@angular/platform-browser/src/browser/browser_adapter';
|
||||
import { RedocComponent, BaseComponent } from '../base';
|
||||
|
||||
import { ApiInfo } from '../ApiInfo/api-info';
|
||||
import { ApiLogo } from '../ApiLogo/api-logo';
|
||||
import { MethodsList } from '../MethodsList/methods-list';
|
||||
import { SideMenu } from '../SideMenu/side-menu';
|
||||
|
||||
import { StickySidebar } from '../../shared/components/index';
|
||||
import SchemaManager from '../../utils/SchemaManager';
|
||||
import { OptionsService, RedocEventsService } from '../../services/index';
|
||||
|
||||
import ApiInfo from '../ApiInfo/api-info';
|
||||
import ApiLogo from '../ApiLogo/api-logo';
|
||||
import MethodsList from '../MethodsList/methods-list';
|
||||
import SideMenu from '../SideMenu/side-menu';
|
||||
import StickySidebar from '../../common/components/StickySidebar/sticky-sidebar';
|
||||
import OptionsManager from '../../options';
|
||||
import {redocEvents} from '../../events';
|
||||
|
||||
import detectScollParent from 'scrollparent';
|
||||
import './redoc-loading-styles.css!css';
|
||||
|
||||
var dom = new BrowserDomAdapter();
|
||||
|
@ -24,23 +24,30 @@ var _modeLocked = false;
|
|||
selector: 'redoc',
|
||||
providers: [
|
||||
SchemaManager,
|
||||
BrowserDomAdapter
|
||||
BrowserDomAdapter,
|
||||
RedocEventsService
|
||||
],
|
||||
templateUrl: './lib/components/Redoc/redoc.html',
|
||||
styleUrls: ['./lib/components/Redoc/redoc.css'],
|
||||
directives: [ApiInfo, ApiLogo, MethodsList, SideMenu, StickySidebar],
|
||||
changeDetection: ChangeDetectionStrategy.Default
|
||||
directives: [ ApiInfo, ApiLogo, MethodsList, SideMenu, StickySidebar ]
|
||||
})
|
||||
@Reflect.metadata('parameters', [
|
||||
[SchemaManager], [OptionsManager], [ElementRef]])
|
||||
export default class Redoc extends BaseComponent {
|
||||
constructor(schemaMgr, optionsMgr, elementRef) {
|
||||
[SchemaManager], [OptionsService], [ElementRef], [RedocEventsService]])
|
||||
export class Redoc extends BaseComponent {
|
||||
constructor(schemaMgr, optionsMgr, elementRef, events) {
|
||||
super(schemaMgr);
|
||||
this.element = elementRef.nativeElement;
|
||||
//parse options (top level component doesn't support inputs)
|
||||
optionsMgr.parseOptions( this.element );
|
||||
optionsMgr.options.$scrollParent = detectScollParent( this.element );
|
||||
this.options = optionsMgr.options;
|
||||
this.events = events;
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout( () => {
|
||||
this.events.bootstrapped.next();
|
||||
});
|
||||
}
|
||||
|
||||
static showLoadingAnimation() {
|
||||
|
@ -58,11 +65,11 @@ export default class Redoc extends BaseComponent {
|
|||
}
|
||||
|
||||
static init(specUrl, options) {
|
||||
var optionsMgr = new OptionsManager();
|
||||
optionsMgr.options = options;
|
||||
optionsMgr.options.specUrl = optionsMgr.options.specUrl || specUrl;
|
||||
var optionsService = new OptionsService(dom);
|
||||
optionsService.options = options;
|
||||
optionsService.options.specUrl = optionsService.options.specUrl || specUrl;
|
||||
var providers = [
|
||||
provide(OptionsManager, {useValue: optionsMgr})
|
||||
provide(OptionsService, {useValue: optionsService})
|
||||
];
|
||||
|
||||
if (Redoc.appRef) {
|
||||
|
@ -71,7 +78,7 @@ export default class Redoc extends BaseComponent {
|
|||
Redoc.showLoadingAnimation();
|
||||
return SchemaManager.instance().load(specUrl)
|
||||
.then(() => {
|
||||
if (!_modeLocked && !optionsMgr.options.debugMode) {
|
||||
if (!_modeLocked && !optionsService.options.debugMode) {
|
||||
enableProdMode();
|
||||
_modeLocked = true;
|
||||
}
|
||||
|
@ -81,8 +88,6 @@ export default class Redoc extends BaseComponent {
|
|||
(appRef) => {
|
||||
Redoc.hideLoadingAnimation();
|
||||
Redoc.appRef = appRef;
|
||||
// setTimeout to allow cached elements to init
|
||||
setTimeout(() => redocEvents.bootstrapped.next());
|
||||
console.log('ReDoc bootstrapped!');
|
||||
},
|
||||
error => {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@import '../../common/styles/variables';
|
||||
@import '../../shared/styles/variables';
|
||||
|
||||
:host {
|
||||
display: block;
|
||||
|
|
|
@ -1,23 +1,24 @@
|
|||
'use strict';
|
||||
|
||||
import { getChildDebugElement } from 'tests/helpers';
|
||||
import {Component, ViewMetadata, provide} from 'angular2/core';
|
||||
import {BrowserDomAdapter} from 'angular2/platform/browser';
|
||||
import { Component, provide } from '@angular/core';
|
||||
import { BrowserDomAdapter } from '@angular/platform-browser/src/browser/browser_adapter';
|
||||
|
||||
import {
|
||||
TestComponentBuilder,
|
||||
inject,
|
||||
async,
|
||||
beforeEach,
|
||||
beforeEachProviders,
|
||||
it
|
||||
} from 'angular2/testing';
|
||||
} from '@angular/core/testing';
|
||||
|
||||
import Redoc from 'lib/components/Redoc/redoc';
|
||||
import { TestComponentBuilder } from '@angular/compiler/testing';
|
||||
|
||||
import { Redoc } from 'lib/components/Redoc/redoc';
|
||||
import SchemaManager from 'lib/utils/SchemaManager';
|
||||
import OptionsManager from 'lib/options';
|
||||
import { OptionsService } from 'lib/services/index';
|
||||
|
||||
let optsMgr = new OptionsManager();
|
||||
let optsMgr = new OptionsService(new BrowserDomAdapter());
|
||||
|
||||
describe('Redoc components', () => {
|
||||
describe('Redoc Component', () => {
|
||||
|
@ -25,7 +26,10 @@ describe('Redoc components', () => {
|
|||
beforeEachProviders(() => [
|
||||
provide(SchemaManager, {useValue: new SchemaManager()}),
|
||||
provide(BrowserDomAdapter, {useValue: new BrowserDomAdapter()}),
|
||||
provide(OptionsManager, {useValue: optsMgr})
|
||||
provide(OptionsService, {useValue: optsMgr})
|
||||
]);
|
||||
beforeEachProviders(() => [
|
||||
provide(OptionsService, {useValue: optsMgr})
|
||||
]);
|
||||
beforeEach(async(inject([TestComponentBuilder, SchemaManager], (tcb, schemaMgr) => {
|
||||
builder = tcb;
|
||||
|
@ -49,62 +53,6 @@ describe('Redoc components', () => {
|
|||
done();
|
||||
}, err => done.fail(err));
|
||||
});
|
||||
|
||||
describe('Options', () => {
|
||||
let component;
|
||||
let fixture;
|
||||
|
||||
function build(tmpl, cb) {
|
||||
builder = builder.overrideView(TestApp,
|
||||
new ViewMetadata({template: tmpl, directives: [Redoc]}));
|
||||
builder.createAsync(TestApp).then(_fixture => {
|
||||
fixture = _fixture;
|
||||
component = getChildDebugElement(fixture.debugElement, 'redoc').componentInstance;
|
||||
fixture.detectChanges();
|
||||
cb();
|
||||
}, err => cb(err));
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
fixture.destroy();
|
||||
});
|
||||
|
||||
it('should parse numeric scrollYOffset', (done) => {
|
||||
build(`<redoc scroll-y-offset="50"></redoc>`, err => {
|
||||
if (err) return done.fail(err);
|
||||
component.options.scrollYOffset().should.be.equal(50);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse selector scrollYOffset', (done) => {
|
||||
build(`<div id="test" style="position: fixed; height: 50px; top:0"> </div>
|
||||
<redoc scroll-y-offset="#test"></redoc>`, err => {
|
||||
if (err) return done.fail(err);
|
||||
component.options.scrollYOffset().should.be.equal(50);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should return 0 for incorrect selector scrollYOffset', (done) => {
|
||||
build(`<div id="test" style="position: fixed; height: 50px; top:0"> </div>
|
||||
<redoc scroll-y-offset="#test2"></redoc>`, err => {
|
||||
if (err) return done.fail(err);
|
||||
component.options.scrollYOffset().should.be.equal(0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle function scrollYOffset', (done) => {
|
||||
optsMgr.options.scrollYOffset = () => 123;
|
||||
build(`<redoc></redoc>`, err => {
|
||||
if (err) return done.fail(err);
|
||||
component.options.scrollYOffset().should.be.equal(123);
|
||||
optsMgr.options.scrollYOffset = 0;
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Redoc init', () => {
|
||||
|
@ -151,7 +99,7 @@ describe('Redoc components', () => {
|
|||
beforeEachProviders(() => [
|
||||
provide(SchemaManager, {useValue: new SchemaManager()}),
|
||||
provide(BrowserDomAdapter, {useValue: new BrowserDomAdapter()}),
|
||||
provide(OptionsManager, {useValue: optsMgr})
|
||||
provide(OptionsService, {useValue: optsMgr})
|
||||
]);
|
||||
beforeEach(async(inject([TestComponentBuilder, SchemaManager], (tcb, schemaMgr) => {
|
||||
builder = tcb;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<header *ngIf="data.bodySchemaPtr || data.samples.length"> Request samples </header>
|
||||
<schema-sample *ngIf="!data.samples.length" [pointer]="data.bodySchemaPtr"> </schema-sample>
|
||||
<header *ngIf="data.schemaPointer || data.samples.length"> Request samples </header>
|
||||
<schema-sample *ngIf="!data.samples.length" [pointer]="data.schemaPointer"> </schema-sample>
|
||||
<tabs *ngIf="data.samples.length" (change)=changeLangNotify($event)>
|
||||
<tab tabTitle="JSON">
|
||||
<schema-sample [pointer]="data.bodySchemaPtr"> </schema-sample>
|
||||
<schema-sample [pointer]="data.schemaPointer"> </schema-sample>
|
||||
</tab>
|
||||
<tab *ngFor="let sample of data.samples" [tabTitle]="sample.lang">
|
||||
<pre innerHtml="{{sample.source | prism:sample.lang}}"></pre>
|
||||
|
|
|
@ -1,49 +1,50 @@
|
|||
'use strict';
|
||||
|
||||
import {ViewChildren, QueryList, ChangeDetectorRef, ChangeDetectionStrategy} from 'angular2/core';
|
||||
import { ViewChildren, QueryList } from '@angular/core';
|
||||
|
||||
import {RedocComponent, BaseComponent, SchemaManager} from '../base';
|
||||
import { RedocComponent, BaseComponent, SchemaManager } from '../base';
|
||||
import JsonPointer from '../../utils/JsonPointer';
|
||||
import {Tabs, Tab} from '../../common/components/Tabs/tabs';
|
||||
import SchemaSample from '../SchemaSample/schema-sample';
|
||||
import {PrismPipe} from '../../utils/pipes';
|
||||
import {redocEvents} from '../../events';
|
||||
import { Tabs, Tab } from '../../shared/components/index';
|
||||
import { SchemaSample } from '../SchemaSample/schema-sample';
|
||||
import { PrismPipe } from '../../utils/pipes';
|
||||
import { RedocEventsService } from '../../services/index';
|
||||
|
||||
@RedocComponent({
|
||||
selector: 'request-samples',
|
||||
templateUrl: './lib/components/RequestSamples/request-samples.html',
|
||||
styleUrls: ['./lib/components/RequestSamples/request-samples.css'],
|
||||
directives: [SchemaSample, Tabs, Tab],
|
||||
inputs: ['bodySchemaPtr'],
|
||||
pipes: [PrismPipe],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
inputs: ['schemaPointer'],
|
||||
pipes: [PrismPipe]
|
||||
})
|
||||
@Reflect.metadata('parameters', [[SchemaManager], [new ViewChildren(Tabs), QueryList], [ChangeDetectorRef]])
|
||||
export default class RequestSamples extends BaseComponent {
|
||||
constructor(schemaMgr, tabs, changeDetector) {
|
||||
@Reflect.metadata('parameters', [[SchemaManager], [RedocEventsService], [new ViewChildren(Tabs), QueryList]])
|
||||
export class RequestSamples extends BaseComponent {
|
||||
constructor(schemaMgr, events, childQuery) {
|
||||
super(schemaMgr);
|
||||
tabs.changes.subscribe(_ => {
|
||||
this.tabs = tabs.first;
|
||||
this.subscribeForEvents(_);
|
||||
childQuery.changes.subscribe(() => {
|
||||
this.childTabs = childQuery.first;
|
||||
});
|
||||
this.changeDetector = changeDetector;
|
||||
this.events = events;
|
||||
}
|
||||
|
||||
init() {
|
||||
this.subscribeForEvents();
|
||||
}
|
||||
|
||||
changeLangNotify(lang) {
|
||||
redocEvents.samplesLanguageChanged.next(lang);
|
||||
this.events.samplesLanguageChanged.next(lang);
|
||||
}
|
||||
|
||||
subscribeForEvents() {
|
||||
if (!this.tabs) return;
|
||||
redocEvents.samplesLanguageChanged.subscribe((sampleLang) => {
|
||||
this.tabs.selectyByTitle(sampleLang);
|
||||
this.changeDetector.markForCheck();
|
||||
this.events.samplesLanguageChanged.subscribe((sampleLang) => {
|
||||
if (!this.childTabs) return;
|
||||
this.childTabs.selectyByTitle(sampleLang);
|
||||
});
|
||||
}
|
||||
|
||||
prepareModel() {
|
||||
this.data = {};
|
||||
this.data.bodySchemaPtr = JsonPointer.join(this.bodySchemaPtr, 'schema');
|
||||
this.data.schemaPointer = JsonPointer.join(this.schemaPointer, 'schema');
|
||||
this.data.samples = this.componentSchema['x-code-samples'] || [];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@import '../../common/styles/variables';
|
||||
@import '../../shared/styles/variables';
|
||||
|
||||
header {
|
||||
font-family: $headers-font;
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
import {RedocComponent, BaseComponent, SchemaManager} from '../base';
|
||||
import JsonPointer from '../../utils/JsonPointer';
|
||||
import JsonSchema from '../JsonSchema/json-schema';
|
||||
import JsonSchemaLazy from '../JsonSchema/json-schema-lazy';
|
||||
import Zippy from '../../common/components/Zippy/zippy';
|
||||
import {statusCodeType} from '../../utils/helpers';
|
||||
import OptionsManager from '../../options';
|
||||
import { JsonSchema } from '../JsonSchema/json-schema';
|
||||
import { JsonSchemaLazy } from '../JsonSchema/json-schema-lazy';
|
||||
import { Zippy } from '../../shared/components/index';
|
||||
import { statusCodeType } from '../../utils/helpers';
|
||||
import { OptionsService } from '../../services/index';
|
||||
|
||||
function isNumeric(n) {
|
||||
return (!isNaN(parseFloat(n)) && isFinite(n));
|
||||
|
@ -18,8 +18,8 @@ function isNumeric(n) {
|
|||
styleUrls: ['./lib/components/ResponsesList/responses-list.css'],
|
||||
directives: [JsonSchema, Zippy, JsonSchemaLazy]
|
||||
})
|
||||
@Reflect.metadata('parameters', [[SchemaManager], [OptionsManager]])
|
||||
export default class ResponsesList extends BaseComponent {
|
||||
@Reflect.metadata('parameters', [[SchemaManager], [OptionsService]])
|
||||
export class ResponsesList extends BaseComponent {
|
||||
constructor(schemaMgr, optionsMgr) {
|
||||
super(schemaMgr);
|
||||
this.options = optionsMgr.options;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@import '../../common/styles/variables';
|
||||
@import '../../shared/styles/variables';
|
||||
|
||||
.responses-list-header {
|
||||
font-size: 18px;
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
'use strict';
|
||||
|
||||
import {RedocComponent, BaseComponent} from '../base';
|
||||
import { forwardRef } from '@angular/core';
|
||||
import { RedocComponent, BaseComponent } from '../base';
|
||||
import JsonPointer from '../../utils/JsonPointer';
|
||||
import {Tabs, Tab} from '../../common/components/Tabs/tabs';
|
||||
import SchemaSample from '../SchemaSample/schema-sample';
|
||||
import {statusCodeType} from '../../utils/helpers';
|
||||
import { Tabs, Tab } from '../../shared/components/index';
|
||||
import { SchemaSample } from '../index';
|
||||
import { statusCodeType } from '../../utils/helpers';
|
||||
|
||||
|
||||
function isNumeric(n) {
|
||||
|
@ -20,9 +21,9 @@ function hasExample(response) {
|
|||
selector: 'responses-samples',
|
||||
templateUrl: './lib/components/ResponsesSamples/responses-samples.html',
|
||||
styleUrls: ['./lib/components/ResponsesSamples/responses-samples.css'],
|
||||
directives: [SchemaSample, Tabs, Tab]
|
||||
directives: [forwardRef( ()=> SchemaSample), Tabs, Tab]
|
||||
})
|
||||
export default class ResponsesSamples extends BaseComponent {
|
||||
export class ResponsesSamples extends BaseComponent {
|
||||
constructor(schemaMgr) {
|
||||
super(schemaMgr);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@import '../../common/styles/variables';
|
||||
@import '../../shared/styles/variables';
|
||||
|
||||
tab, tabs {
|
||||
display: block;
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
'use strict';
|
||||
|
||||
import {ElementRef} from 'angular2/core';
|
||||
import { ElementRef } from '@angular/core';
|
||||
|
||||
import SchemaSampler from 'json-schema-instantiator';
|
||||
|
||||
import {JsonFormatter} from '../../utils/JsonFormatterPipe';
|
||||
import {RedocComponent, BaseComponent, SchemaManager} from '../base';
|
||||
import { RedocComponent, BaseComponent, SchemaManager } from '../base';
|
||||
import { JsonFormatter } from '../../utils/JsonFormatterPipe';
|
||||
|
||||
@RedocComponent({
|
||||
selector: 'schema-sample',
|
||||
|
@ -14,7 +14,7 @@ import {RedocComponent, BaseComponent, SchemaManager} from '../base';
|
|||
styleUrls: ['./lib/components/SchemaSample/schema-sample.css']
|
||||
})
|
||||
@Reflect.metadata('parameters', [[SchemaManager], [ElementRef]])
|
||||
export default class SchemaSample extends BaseComponent {
|
||||
export class SchemaSample extends BaseComponent {
|
||||
constructor(schemaMgr, elementRef) {
|
||||
super(schemaMgr);
|
||||
this.element = elementRef.nativeElement;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@import '../../common/styles/variables';
|
||||
@import '../../shared/styles/variables';
|
||||
|
||||
pre {
|
||||
background-color: transparent;
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<div class="mobile-nav" (click)="toggleMobileNav()">
|
||||
<div #mobile class="mobile-nav" (click)="toggleMobileNav()">
|
||||
<span class="menu-header"> API Reference: </span>
|
||||
<span class="selected-item-info">
|
||||
<span class="selected-tag"> {{activeCatCaption}} </span>
|
||||
<span class="selected-endpoint">{{activeItemCaption}}</span>
|
||||
</span>
|
||||
</div>
|
||||
<div id="resources-nav">
|
||||
<div #desktop id="resources-nav">
|
||||
<h5 class="menu-header"> API reference </h5>
|
||||
<div *ngFor="let cat of data.menu; let idx = index" class="menu-cat">
|
||||
|
||||
|
|
|
@ -1,231 +1,70 @@
|
|||
'use strict';
|
||||
|
||||
import {ChangeDetectorRef, ChangeDetectionStrategy, ElementRef} from 'angular2/core';
|
||||
import {document} from 'angular2/src/facade/browser';
|
||||
import {BrowserDomAdapter} from 'angular2/platform/browser';
|
||||
import {global} from 'angular2/src/facade/lang';
|
||||
import { ElementRef, ChangeDetectorRef } from '@angular/core';
|
||||
import { BrowserDomAdapter } from '@angular/platform-browser/src/browser/browser_adapter';
|
||||
import { global } from '@angular/core/src/facade/lang';
|
||||
|
||||
import {RedocComponent, BaseComponent, SchemaManager} from '../base';
|
||||
import {redocEvents} from '../../events';
|
||||
import OptionsManager from '../../options';
|
||||
|
||||
const CHANGE = {
|
||||
NEXT : 1,
|
||||
BACK : -1,
|
||||
INITIAL : 0
|
||||
};
|
||||
|
||||
const INVIEW_POSITION = {
|
||||
ABOVE : 1,
|
||||
BELLOW: -1,
|
||||
INVIEW: 0
|
||||
};
|
||||
import { RedocComponent, BaseComponent, SchemaManager } from '../base';
|
||||
import { ScrollService, Hash, MenuService, OptionsService } from '../../services/index';
|
||||
|
||||
@RedocComponent({
|
||||
selector: 'side-menu',
|
||||
templateUrl: './lib/components/SideMenu/side-menu.html',
|
||||
styleUrls: ['./lib/components/SideMenu/side-menu.css'],
|
||||
changeDetection: ChangeDetectionStrategy.Default
|
||||
providers: [ScrollService, MenuService, Hash],
|
||||
styleUrls: ['./lib/components/SideMenu/side-menu.css']
|
||||
})
|
||||
@Reflect.metadata('parameters', [[SchemaManager], [ElementRef],
|
||||
[BrowserDomAdapter], [ChangeDetectorRef], [OptionsManager]])
|
||||
export default class SideMenu extends BaseComponent {
|
||||
constructor(schemaMgr, elementRef, dom, changeDetectorRef, optionsMgr) {
|
||||
@Reflect.metadata('parameters', [[SchemaManager], [ElementRef], [BrowserDomAdapter],
|
||||
[ScrollService], [MenuService], [Hash], [OptionsService], [ChangeDetectorRef]])
|
||||
export class SideMenu extends BaseComponent {
|
||||
constructor(schemaMgr, elementRef, dom, scrollService,
|
||||
menuService, hash, optionsService, detectorRef) {
|
||||
super(schemaMgr);
|
||||
this.$element = elementRef.nativeElement;
|
||||
this.changeDetector = changeDetectorRef;
|
||||
this.dom = dom;
|
||||
this.options = optionsMgr.options;
|
||||
this.$scrollParent = this.options.$scrollParent;
|
||||
this.bindEvents();
|
||||
this.activeCatIdx = 0;
|
||||
this.activeMethodIdx = -1;
|
||||
this.prevOffsetY = null;
|
||||
|
||||
redocEvents.bootstrapped.subscribe(() => this.hashScroll());
|
||||
this.scrollService = scrollService;
|
||||
this.menuService = menuService;
|
||||
this.hash = hash;
|
||||
|
||||
this.activeCatCaption = '';
|
||||
this.activeItemCaption = '';
|
||||
|
||||
this.options = optionsService.options;
|
||||
this.detectorRef = detectorRef;
|
||||
|
||||
this.menuService.changed.subscribe((cat, item) => this.changed(cat, item));
|
||||
}
|
||||
|
||||
scrollY() {
|
||||
return (this.$scrollParent.pageYOffset != null) ? this.$scrollParent.pageYOffset : this.$scrollParent.scrollTop;
|
||||
}
|
||||
changed(cat, item) {
|
||||
this.activeCatCaption = cat.name || '';
|
||||
this.activeItemCaption = item && item.summary || '';
|
||||
|
||||
hashScroll(evt) {
|
||||
let hash = this.dom.getLocation().hash;
|
||||
if (!hash) return;
|
||||
|
||||
let $el;
|
||||
hash = hash.substr(1);
|
||||
let namespace = hash.split('/')[0];
|
||||
let ptr = decodeURIComponent(hash.substr(namespace.length + 1));
|
||||
if (namespace === 'operation') {
|
||||
$el = this.getMethodElByOperId(ptr);
|
||||
} else if (namespace === 'tag') {
|
||||
let tag = ptr.split('/')[0];
|
||||
ptr = ptr.substr(tag.length);
|
||||
$el = this.getMethodElByPtr(ptr, tag);
|
||||
}
|
||||
|
||||
if ($el) this.scrollTo($el);
|
||||
if (evt) evt.preventDefault();
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
this.prevOffsetY = this.scrollY();
|
||||
|
||||
//decorate option.scrollYOffset to account mobile nav
|
||||
this.scrollYOffset = () => {
|
||||
let mobileNavOffset = this.$mobileNav.clientHeight;
|
||||
return this.options.scrollYOffset() + mobileNavOffset;
|
||||
};
|
||||
this._cancel = {};
|
||||
this._cancel.scroll = this.dom.onAndCancel(this.$scrollParent, 'scroll', () => { this.scrollHandler(); });
|
||||
this._cancel.hash = this.dom.onAndCancel(global, 'hashchange', evt => this.hashScroll(evt));
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this._cancel.scroll();
|
||||
this._cancel.hash();
|
||||
//safari doesn't update bindings if not run changeDetector manually :(
|
||||
this.detectorRef.detectChanges();
|
||||
}
|
||||
|
||||
activateAndScroll(idx, methodIdx) {
|
||||
if (this.mobileMode()) {
|
||||
this.toggleMobileNav();
|
||||
}
|
||||
this.activate(idx, methodIdx);
|
||||
this.scrollToActive();
|
||||
this.menuService.activate(idx, methodIdx);
|
||||
this.menuService.scrollToActive();
|
||||
}
|
||||
|
||||
scrollTo($el) {
|
||||
// TODO: rewrite this to use offsetTop as more reliable solution
|
||||
let subjRect = $el.getBoundingClientRect();
|
||||
let offset = this.scrollY() + subjRect.top - this.scrollYOffset() + 1;
|
||||
if (this.$scrollParent.scrollTo) {
|
||||
this.$scrollParent.scrollTo(0, offset);
|
||||
} else {
|
||||
this.$scrollParent.scrollTop = offset;
|
||||
}
|
||||
}
|
||||
init() {
|
||||
this.$mobileNav = this.dom.querySelector(this.$element, '.mobile-nav');
|
||||
this.$resourcesNav = this.dom.querySelector(this.$element, '#resources-nav');
|
||||
|
||||
scrollToActive() {
|
||||
this.scrollTo(this.getCurrentMethodEl());
|
||||
}
|
||||
|
||||
activate(catIdx, methodIdx) {
|
||||
let menu = this.data.menu;
|
||||
|
||||
this.activeCatCaption = '';
|
||||
this.activeItemCaption = '';
|
||||
|
||||
menu[this.activeCatIdx].active = false;
|
||||
if (menu[this.activeCatIdx].methods.length) {
|
||||
if (this.activeMethodIdx >= 0) {
|
||||
menu[this.activeCatIdx].methods[this.activeMethodIdx].active = false;
|
||||
}
|
||||
}
|
||||
|
||||
this.activeCatIdx = catIdx;
|
||||
this.activeMethodIdx = methodIdx;
|
||||
menu[catIdx].active = true;
|
||||
this.activeCatCaption = menu[catIdx].name;
|
||||
this.activeMethodPtr = null;
|
||||
if (menu[catIdx].methods.length && (methodIdx > -1)) {
|
||||
let currentItem = menu[catIdx].methods[methodIdx];
|
||||
currentItem.active = true;
|
||||
this.activeMethodPtr = currentItem.pointer;
|
||||
this.activeItemCaption = currentItem.summary;
|
||||
}
|
||||
}
|
||||
|
||||
_calcActiveIndexes(offset) {
|
||||
let menu = this.data.menu;
|
||||
let catCount = menu.length;
|
||||
let catLength = menu[this.activeCatIdx].methods.length;
|
||||
|
||||
let resMethodIdx = this.activeMethodIdx + offset;
|
||||
let resCatIdx = this.activeCatIdx;
|
||||
|
||||
if (resMethodIdx > catLength - 1) {
|
||||
resCatIdx++;
|
||||
resMethodIdx = -1;
|
||||
}
|
||||
if (resMethodIdx < -1) {
|
||||
let prevCatIdx = --resCatIdx;
|
||||
catLength = menu[Math.max(prevCatIdx, 0)].methods.length;
|
||||
resMethodIdx = catLength - 1;
|
||||
}
|
||||
if (resCatIdx > catCount - 1) {
|
||||
resCatIdx = catCount - 1;
|
||||
resMethodIdx = catLength - 1;
|
||||
}
|
||||
if (resCatIdx < 0) {
|
||||
resCatIdx = 0;
|
||||
resMethodIdx = 0;
|
||||
}
|
||||
|
||||
return [resCatIdx, resMethodIdx];
|
||||
}
|
||||
|
||||
changeActive(offset = 1) {
|
||||
let [catIdx, methodIdx] = this._calcActiveIndexes(offset);
|
||||
this.activate(catIdx, methodIdx);
|
||||
return (methodIdx === 0 && catIdx === 0);
|
||||
}
|
||||
|
||||
getMethodElByPtr(ptr, tag) {
|
||||
let selector = ptr ? `[pointer="${ptr}"][tag="${tag}"]` : `[tag="${tag}"]`;
|
||||
return document.querySelector(selector);
|
||||
}
|
||||
|
||||
getMethodElByOperId(operationId) {
|
||||
let selector =`[operation-id="${operationId}"]`;
|
||||
return document.querySelector(selector);
|
||||
}
|
||||
|
||||
getCurrentMethodEl() {
|
||||
return this.getMethodElByPtr(this.activeMethodPtr, this.data.menu[this.activeCatIdx].name);
|
||||
}
|
||||
|
||||
/* returns 1 if element if above the view, 0 if in view and -1 below the view */
|
||||
getElementInViewPos($el) {
|
||||
if (Math.floor($el.getBoundingClientRect().top) > this.scrollYOffset()) {
|
||||
return INVIEW_POSITION.ABOVE;
|
||||
}
|
||||
|
||||
if ($el.getBoundingClientRect().bottom <= this.scrollYOffset()) {
|
||||
return INVIEW_POSITION.BELLOW;
|
||||
}
|
||||
return INVIEW_POSITION.INVIEW;
|
||||
}
|
||||
|
||||
scrollHandler() {
|
||||
let isScrolledDown = (this.scrollY() - this.prevOffsetY > 0);
|
||||
this.prevOffsetY = this.scrollY();
|
||||
let stable = false;
|
||||
while(!stable) {
|
||||
let $activeMethodHost = this.getCurrentMethodEl();
|
||||
if (!$activeMethodHost) return;
|
||||
var elementInViewPos = this.getElementInViewPos($activeMethodHost);
|
||||
if(isScrolledDown && elementInViewPos === INVIEW_POSITION.BELLOW) {
|
||||
stable = this.changeActive(CHANGE.NEXT);
|
||||
continue;
|
||||
}
|
||||
if(!isScrolledDown && elementInViewPos === INVIEW_POSITION.ABOVE ) {
|
||||
stable = this.changeActive(CHANGE.BACK);
|
||||
continue;
|
||||
}
|
||||
stable = true;
|
||||
}
|
||||
this.changeDetector.detectChanges();
|
||||
//decorate option.scrollYOffset to account mobile nav
|
||||
var origOffset = this.options.scrollYOffset;
|
||||
this.options.scrollYOffset = () => {
|
||||
let mobileNavOffset = this.$mobileNav.clientHeight;
|
||||
return origOffset() + mobileNavOffset;
|
||||
};
|
||||
}
|
||||
|
||||
prepareModel() {
|
||||
this.data = {};
|
||||
this.data.menu = Array.from(this.schemaMgr.buildMenuTree().entries()).map(
|
||||
el => ({name: el[0], description: el[1].description, methods: el[1].methods})
|
||||
);
|
||||
this.data.menu = this.menuService.categories;
|
||||
}
|
||||
|
||||
mobileMode() {
|
||||
|
@ -246,9 +85,8 @@ export default class SideMenu extends BaseComponent {
|
|||
}
|
||||
}
|
||||
|
||||
init() {
|
||||
this.$mobileNav = this.dom.querySelector(this.$element, '.mobile-nav');
|
||||
this.$resourcesNav = this.dom.querySelector(this.$element, '#resources-nav');
|
||||
this.changeActive(CHANGE.INITIAL);
|
||||
destroy() {
|
||||
this.scrollService.unbind();
|
||||
this.hash.unbind();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@import '../../common/styles/variables';
|
||||
@import '../../shared/styles/variables';
|
||||
$mobile-menu-compact-breakpoint: 550px;
|
||||
|
||||
.menu-header {
|
||||
|
|
|
@ -1,30 +1,32 @@
|
|||
'use strict';
|
||||
|
||||
import { getChildDebugElement, mouseclick} from 'tests/helpers';
|
||||
import {Component, provide, ViewMetadata} from 'angular2/core';
|
||||
import {BrowserDomAdapter} from 'angular2/platform/browser';
|
||||
import OptionsManager from 'lib/options';
|
||||
import { getChildDebugElement } from 'tests/helpers';
|
||||
import { Component, provide } from '@angular/core';
|
||||
import { BrowserDomAdapter } from '@angular/platform-browser/src/browser/browser_adapter';
|
||||
import { OptionsService, RedocEventsService } from 'lib/services/index';
|
||||
|
||||
import {
|
||||
TestComponentBuilder,
|
||||
inject,
|
||||
async,
|
||||
beforeEach,
|
||||
beforeEachProviders,
|
||||
it
|
||||
} from 'angular2/testing';
|
||||
} from '@angular/core/testing';
|
||||
|
||||
import { TestComponentBuilder } from '@angular/compiler/testing';
|
||||
|
||||
import { MethodsList, SideMenu } from 'lib/components/index';
|
||||
|
||||
import {redocEvents} from 'lib/events';
|
||||
import MethodsList from 'lib/components/MethodsList/methods-list';
|
||||
import SideMenu from 'lib/components/SideMenu/side-menu';
|
||||
import SchemaManager from 'lib/utils/SchemaManager';
|
||||
|
||||
let testOptions = new OptionsManager();
|
||||
let testOptions = new OptionsService();
|
||||
testOptions.options = {
|
||||
scrollYOffset: () => 0,
|
||||
scrollParent: window
|
||||
};
|
||||
|
||||
let redocEvents = new RedocEventsService();
|
||||
|
||||
describe('Redoc components', () => {
|
||||
describe('SideMenu Component', () => {
|
||||
let builder;
|
||||
|
@ -33,166 +35,33 @@ describe('Redoc components', () => {
|
|||
beforeEachProviders(() => [
|
||||
provide(SchemaManager, {useValue: new SchemaManager()}),
|
||||
provide(BrowserDomAdapter, {useValue: new BrowserDomAdapter()}),
|
||||
provide(OptionsManager, {useValue: testOptions})
|
||||
provide(OptionsService, {useValue: testOptions}),
|
||||
provide(RedocEventsService, {useValue: redocEvents})
|
||||
]);
|
||||
beforeEach(async(inject([TestComponentBuilder, SchemaManager], (tcb, schemaMgr) => {
|
||||
builder = tcb;
|
||||
return schemaMgr.load('/tests/schemas/extended-petstore.yml');
|
||||
})));
|
||||
|
||||
beforeEach((done) => {
|
||||
builder.createAsync(TestApp).then(_fixture => {
|
||||
fixture = _fixture;
|
||||
component = getChildDebugElement(fixture.debugElement, 'side-menu').componentInstance;
|
||||
fixture.detectChanges();
|
||||
done();
|
||||
}, err => {
|
||||
throw err;
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
if (fixture) fixture.destroy();
|
||||
});
|
||||
|
||||
describe('window parent case', () => {
|
||||
beforeEach((done) => {
|
||||
builder.createAsync(TestApp).then(_fixture => {
|
||||
fixture = _fixture;
|
||||
component = getChildDebugElement(fixture.debugElement, 'side-menu').componentInstance;
|
||||
fixture.detectChanges();
|
||||
done();
|
||||
}, err => {
|
||||
throw err;
|
||||
});
|
||||
});
|
||||
|
||||
it('should init component and component data', () => {
|
||||
expect(component).not.toBeNull();
|
||||
expect(component.data).not.toBeNull();
|
||||
});
|
||||
|
||||
it('should run hashScroll when redoc bootstrapped', (done) => {
|
||||
spyOn(component.dom, 'getLocation').and.returnValue({hash: ''});
|
||||
spyOn(component, 'hashScroll').and.stub();
|
||||
spyOn(window, 'scrollTo').and.stub();
|
||||
redocEvents.bootstrapped.next();
|
||||
setTimeout(() => {
|
||||
expect(component.hashScroll).toHaveBeenCalled();
|
||||
expect(window.scrollTo).not.toHaveBeenCalled();
|
||||
|
||||
window.scrollTo.and.callThrough();
|
||||
component.hashScroll.and.callThrough();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should scroll to method when location hash is present [jp]', (done) => {
|
||||
let hash = '#tag/pet/paths/~1pet~1findByStatus/get';
|
||||
spyOn(component.dom, 'getLocation').and.returnValue({hash: hash});
|
||||
spyOn(component, 'hashScroll').and.callThrough();
|
||||
spyOn(window, 'scrollTo').and.stub();
|
||||
redocEvents.bootstrapped.next();
|
||||
setTimeout(() => {
|
||||
expect(component.hashScroll).toHaveBeenCalled();
|
||||
let scrollY = window.scrollTo.calls.argsFor(0)[1];
|
||||
expect(scrollY).toBeGreaterThan(0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should scroll to method when location hash is present [operation]', (done) => {
|
||||
let hash = '#operation/getPetById';
|
||||
spyOn(component.dom, 'getLocation').and.returnValue({hash: hash});
|
||||
spyOn(component, 'hashScroll').and.callThrough();
|
||||
spyOn(window, 'scrollTo').and.stub();
|
||||
redocEvents.bootstrapped.next();
|
||||
setTimeout(() => {
|
||||
expect(component.hashScroll).toHaveBeenCalled();
|
||||
let scrollY = window.scrollTo.calls.argsFor(0)[1];
|
||||
expect(scrollY).toBeGreaterThan(0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('scrollable div parent case', () => {
|
||||
let menuNativeEl;
|
||||
beforeEach((done) => {
|
||||
let scollableDivTmpl =
|
||||
`<div style="height: 500px; overflow-y: auto;">
|
||||
<side-menu></side-menu>
|
||||
<methods-list></methods-list>
|
||||
</div>`;
|
||||
builder = builder.overrideView(
|
||||
TestApp, new ViewMetadata({template: scollableDivTmpl, directives: [MethodsList, SideMenu]}));
|
||||
builder.createAsync(TestApp).then(_fixture => {
|
||||
fixture = _fixture;
|
||||
component = getChildDebugElement(fixture.debugElement, 'side-menu').componentInstance;
|
||||
menuNativeEl = getChildDebugElement(fixture.debugElement, 'side-menu').nativeElement;
|
||||
component.options.scrollParent = _fixture.nativeElement.children[0];
|
||||
component.$scrollParent = _fixture.nativeElement.children[0];
|
||||
fixture.detectChanges();
|
||||
done();
|
||||
}, err => {
|
||||
throw err;
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
it('should init component and component data', () => {
|
||||
expect(component).not.toBeNull();
|
||||
expect(component.data).not.toBeNull();
|
||||
});
|
||||
|
||||
it('should scroll to method when location hash is present [jp]', (done) => {
|
||||
let hash = '#tag/pet/paths/~1pet~1findByStatus/get';
|
||||
spyOn(component.dom, 'getLocation').and.returnValue({hash: hash});
|
||||
spyOn(component, 'hashScroll').and.callThrough();
|
||||
redocEvents.bootstrapped.next();
|
||||
setTimeout(() => {
|
||||
expect(component.hashScroll).toHaveBeenCalled();
|
||||
expect(component.$scrollParent.scrollTop).toBeGreaterThan(0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should scroll to method when location hash is present [operation]', (done) => {
|
||||
let hash = '#operation/getPetById';
|
||||
spyOn(component.dom, 'getLocation').and.returnValue({hash: hash});
|
||||
spyOn(component, 'hashScroll').and.callThrough();
|
||||
redocEvents.bootstrapped.next();
|
||||
setTimeout(() => {
|
||||
expect(component.hashScroll).toHaveBeenCalled();
|
||||
expect(component.$scrollParent.scrollTop).toBeGreaterThan(0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should select next/prev menu item when scrolled down/up', () => {
|
||||
component.activeCatIdx.should.be.equal(0);
|
||||
component.activeMethodIdx.should.be.equal(-1);
|
||||
let elTop = component.getCurrentMethodEl().getBoundingClientRect().bottom;
|
||||
|
||||
component.$scrollParent.scrollTop = elTop + 1;
|
||||
//simulate scroll down
|
||||
spyOn(component, 'scrollY').and.returnValue(elTop + 2);
|
||||
component.scrollHandler();
|
||||
component.activeCatIdx.should.be.equal(1);
|
||||
|
||||
|
||||
component.$scrollParent.scrollTop = elTop - 1;
|
||||
//simulate scroll up
|
||||
component.scrollY.and.returnValue(elTop - 2);
|
||||
component.scrollHandler();
|
||||
component.activeCatIdx.should.be.equal(0);
|
||||
});
|
||||
|
||||
it('should activate menu item on click', () => {
|
||||
let menuItemEl = menuNativeEl.querySelector('li');
|
||||
expect(menuItemEl).not.toHaveCssClass('active');
|
||||
mouseclick(menuItemEl);
|
||||
fixture.detectChanges();
|
||||
expect(menuItemEl).toHaveCssClass('active');
|
||||
});
|
||||
|
||||
it('should scroll to appropriate element when click on menu label', () => {
|
||||
component.$scrollParent.scrollTop.should.be.equal(0);
|
||||
let menuItemEl = menuNativeEl.querySelector('li');
|
||||
mouseclick(menuItemEl);
|
||||
component.$scrollParent.scrollTop.should.be.above(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -200,7 +69,6 @@ describe('Redoc components', () => {
|
|||
@Component({
|
||||
selector: 'test-app',
|
||||
directives: [MethodsList, SideMenu],
|
||||
providers: [SchemaManager],
|
||||
template:
|
||||
`<side-menu></side-menu>
|
||||
<methods-list></methods-list>`
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
'use strict';
|
||||
import {Component, ChangeDetectionStrategy} from 'angular2/core';
|
||||
import {CORE_DIRECTIVES, JsonPipe, AsyncPipe} from 'angular2/common';
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { CORE_DIRECTIVES, JsonPipe, AsyncPipe } from '@angular/common';
|
||||
import SchemaManager from '../utils/SchemaManager';
|
||||
import JsonPointer from '../utils/JsonPointer';
|
||||
import {MarkedPipe, JsonPointerEscapePipe} from '../utils/pipes';
|
||||
import { MarkedPipe, JsonPointerEscapePipe } from '../utils/pipes';
|
||||
|
||||
export { SchemaManager };
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
import SchemaManager from 'lib/utils/SchemaManager';
|
||||
import {BaseComponent} from 'lib/components/base';
|
||||
import { BaseComponent } from 'lib/components/base';
|
||||
|
||||
describe('Redoc components', () => {
|
||||
describe('BaseComponent', () => {
|
||||
|
|
|
@ -1,42 +1,16 @@
|
|||
'use strict';
|
||||
|
||||
import ApiInfo from './ApiInfo/api-info';
|
||||
import ApiLogo from './ApiLogo/api-logo';
|
||||
import Method from './Method/method.js';
|
||||
import MethodsList from './MethodsList/methods-list';
|
||||
import ParamsList from './ParamsList/params-list';
|
||||
import Redoc from './Redoc/redoc';
|
||||
import ResponsesList from './ResponsesList/responses-list';
|
||||
import ResponsesSamples from './ResponsesSamples/responses-samples';
|
||||
import SchemaSample from './SchemaSample/schema-sample';
|
||||
import SideMenu from './SideMenu/side-menu';
|
||||
import JsonSchema from './JsonSchema/json-schema';
|
||||
export * from './ApiInfo/api-info';
|
||||
export * from './ApiLogo/api-logo';
|
||||
export * from './JsonSchema/json-schema';
|
||||
export * from './JsonSchema/json-schema-lazy';
|
||||
export * from './ParamsList/params-list';
|
||||
export * from './RequestSamples/request-samples';
|
||||
export * from './ResponsesList/responses-list';
|
||||
export * from './ResponsesSamples/responses-samples';
|
||||
export * from './SchemaSample/schema-sample';
|
||||
export * from './SideMenu/side-menu';
|
||||
export * from './MethodsList/methods-list';
|
||||
export * from './Method/method';
|
||||
|
||||
const REDOC_COMPONENTS = [
|
||||
ApiInfo,
|
||||
ApiLogo,
|
||||
JsonSchema,
|
||||
Method,
|
||||
MethodsList,
|
||||
ParamsList,
|
||||
Redoc,
|
||||
ResponsesList,
|
||||
ResponsesSamples,
|
||||
SchemaSample,
|
||||
SideMenu
|
||||
];
|
||||
|
||||
export {
|
||||
ApiInfo,
|
||||
ApiLogo,
|
||||
JsonSchema,
|
||||
Method,
|
||||
MethodsList,
|
||||
ParamsList,
|
||||
Redoc,
|
||||
ResponsesList,
|
||||
ResponsesSamples,
|
||||
SchemaSample,
|
||||
SideMenu,
|
||||
REDOC_COMPONENTS
|
||||
};
|
||||
export * from './Redoc/redoc';
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
import {EventEmitter} from 'angular2/core';
|
||||
|
||||
var bootsrEmmiter = new EventEmitter();
|
||||
var langChanged = new EventEmitter();
|
||||
export var redocEvents = {
|
||||
bootstrapped: bootsrEmmiter,
|
||||
samplesLanguageChanged: langChanged
|
||||
};
|
10
lib/services/events.service.js
Normal file
10
lib/services/events.service.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
'use strict';
|
||||
|
||||
import { EventEmitter } from '@angular/core';
|
||||
|
||||
export class RedocEventsService {
|
||||
constructor() {
|
||||
this.bootstrapped = new EventEmitter();
|
||||
this.samplesLanguageChanged = new EventEmitter();
|
||||
}
|
||||
}
|
33
lib/services/hash.service.js
Normal file
33
lib/services/hash.service.js
Normal file
|
@ -0,0 +1,33 @@
|
|||
'use strict';
|
||||
import { Injectable, EventEmitter } from '@angular/core';
|
||||
import { BrowserDomAdapter } from '@angular/platform-browser/src/browser/browser_adapter';
|
||||
import { global } from '@angular/core/src/facade/lang';
|
||||
|
||||
import { RedocEventsService } from './events.service';
|
||||
|
||||
@Reflect.metadata('parameters', [[BrowserDomAdapter], [RedocEventsService]])
|
||||
@Injectable()
|
||||
export class Hash {
|
||||
constructor(dom, events) {
|
||||
this.changed = new EventEmitter();
|
||||
this.dom = dom;
|
||||
this.bind();
|
||||
|
||||
events.bootstrapped.subscribe(() => this.changed.next(this.hash));
|
||||
}
|
||||
|
||||
get hash() {
|
||||
return this.dom.getLocation().hash;
|
||||
}
|
||||
|
||||
bind() {
|
||||
this._cancel = this.dom.onAndCancel(global, 'hashchange', (evt) => {
|
||||
this.changed.next(this.hash);
|
||||
evt.preventDefault();
|
||||
});
|
||||
}
|
||||
|
||||
unbind() {
|
||||
this._cancel();
|
||||
}
|
||||
}
|
28
lib/services/hash.service.spec.js
Normal file
28
lib/services/hash.service.spec.js
Normal file
|
@ -0,0 +1,28 @@
|
|||
'use strict';
|
||||
|
||||
import { BrowserDomAdapter } from '@angular/platform-browser/src/browser/browser_adapter';
|
||||
|
||||
import { RedocEventsService } from './events.service';
|
||||
import { Hash } from './hash.service';
|
||||
|
||||
describe('Hash Service', () => {
|
||||
let events = new RedocEventsService();
|
||||
let hashService;
|
||||
|
||||
beforeEach(() => {
|
||||
hashService = new Hash(new BrowserDomAdapter(), events);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
hashService.unbind();
|
||||
});
|
||||
|
||||
it('should trigger changed event after ReDoc bootstrapped', (done) => {
|
||||
spyOn(hashService.changed, 'next').and.callThrough();
|
||||
events.bootstrapped.next();
|
||||
setTimeout(() => {
|
||||
expect(hashService.changed.next).toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
7
lib/services/index.js
Normal file
7
lib/services/index.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
export * from './events.service.js';
|
||||
export * from './options.service.js';
|
||||
export * from './menu.service.js';
|
||||
export * from './scroll.service.js';
|
||||
export * from './hash.service.js';
|
152
lib/services/menu.service.js
Normal file
152
lib/services/menu.service.js
Normal file
|
@ -0,0 +1,152 @@
|
|||
'use strict';
|
||||
import { Injectable, EventEmitter } from '@angular/core';
|
||||
import { ScrollService, INVIEW_POSITION } from './scroll.service.js';
|
||||
import { Hash } from './hash.service.js';
|
||||
import SchemaManager from '../utils/SchemaManager';
|
||||
|
||||
const CHANGE = {
|
||||
NEXT : 1,
|
||||
BACK : -1,
|
||||
INITIAL : 0
|
||||
};
|
||||
|
||||
@Reflect.metadata('parameters', [[Hash], [ScrollService], [SchemaManager]])
|
||||
@Injectable()
|
||||
export class MenuService {
|
||||
constructor(hash, scrollService, schemaMgr) {
|
||||
this.hash = hash;
|
||||
this.scrollService = scrollService;
|
||||
|
||||
this.activeCatIdx = 0;
|
||||
this.activeMethodIdx = -1;
|
||||
this.changed = new EventEmitter();
|
||||
|
||||
this.categories = Array.from(schemaMgr.buildMenuTree().entries()).map(
|
||||
el => ({name: el[0], description: el[1].description, methods: el[1].methods})
|
||||
);
|
||||
|
||||
scrollService.scroll.subscribe((evt) => {
|
||||
this.scrollUpdate(evt.isScrolledDown);
|
||||
});
|
||||
|
||||
this.changeActive(CHANGE.INITIAL);
|
||||
|
||||
this.hash.changed.subscribe((hash) => {
|
||||
this.hashScroll(hash);
|
||||
});
|
||||
}
|
||||
|
||||
scrollUpdate(isScrolledDown) {
|
||||
let stable = false;
|
||||
while(!stable) {
|
||||
let $activeMethodHost = this.getCurrentMethodEl();
|
||||
if (!$activeMethodHost) return;
|
||||
var elementInViewPos = this.scrollService.getElementPos($activeMethodHost);
|
||||
if(isScrolledDown && elementInViewPos === INVIEW_POSITION.BELLOW) {
|
||||
stable = this.changeActive(CHANGE.NEXT);
|
||||
continue;
|
||||
}
|
||||
if(!isScrolledDown && elementInViewPos === INVIEW_POSITION.ABOVE ) {
|
||||
stable = this.changeActive(CHANGE.BACK);
|
||||
continue;
|
||||
}
|
||||
stable = true;
|
||||
}
|
||||
}
|
||||
|
||||
getCurrentMethodEl() {
|
||||
return this.getMethodElByPtr(this.activeMethodPtr,
|
||||
this.categories[this.activeCatIdx].name);
|
||||
}
|
||||
|
||||
getMethodElByPtr(ptr, tag) {
|
||||
let selector = ptr ? `[pointer="${ptr}"][tag="${tag}"]` : `[tag="${tag}"]`;
|
||||
return document.querySelector(selector);
|
||||
}
|
||||
|
||||
getMethodElByOperId(operationId) {
|
||||
let selector =`[operation-id="${operationId}"]`;
|
||||
return document.querySelector(selector);
|
||||
}
|
||||
|
||||
activate(catIdx, methodIdx) {
|
||||
let menu = this.categories;
|
||||
|
||||
menu[this.activeCatIdx].active = false;
|
||||
if (menu[this.activeCatIdx].methods.length) {
|
||||
if (this.activeMethodIdx >= 0) {
|
||||
menu[this.activeCatIdx].methods[this.activeMethodIdx].active = false;
|
||||
}
|
||||
}
|
||||
|
||||
this.activeCatIdx = catIdx;
|
||||
this.activeMethodIdx = methodIdx;
|
||||
menu[catIdx].active = true;
|
||||
this.activeMethodPtr = null;
|
||||
let currentItem;
|
||||
if (menu[catIdx].methods.length && (methodIdx > -1)) {
|
||||
currentItem = menu[catIdx].methods[methodIdx];
|
||||
currentItem.active = true;
|
||||
this.activeMethodPtr = currentItem.pointer;
|
||||
}
|
||||
|
||||
this.changed.next(menu[catIdx], currentItem);
|
||||
}
|
||||
|
||||
_calcActiveIndexes(offset) {
|
||||
let menu = this.categories;
|
||||
let catCount = menu.length;
|
||||
let catLength = menu[this.activeCatIdx].methods.length;
|
||||
|
||||
let resMethodIdx = this.activeMethodIdx + offset;
|
||||
let resCatIdx = this.activeCatIdx;
|
||||
|
||||
if (resMethodIdx > catLength - 1) {
|
||||
resCatIdx++;
|
||||
resMethodIdx = -1;
|
||||
}
|
||||
if (resMethodIdx < -1) {
|
||||
let prevCatIdx = --resCatIdx;
|
||||
catLength = menu[Math.max(prevCatIdx, 0)].methods.length;
|
||||
resMethodIdx = catLength - 1;
|
||||
}
|
||||
if (resCatIdx > catCount - 1) {
|
||||
resCatIdx = catCount - 1;
|
||||
resMethodIdx = catLength - 1;
|
||||
}
|
||||
if (resCatIdx < 0) {
|
||||
resCatIdx = 0;
|
||||
resMethodIdx = 0;
|
||||
}
|
||||
|
||||
return [resCatIdx, resMethodIdx];
|
||||
}
|
||||
|
||||
changeActive(offset = 1) {
|
||||
let [catIdx, methodIdx] = this._calcActiveIndexes(offset);
|
||||
this.activate(catIdx, methodIdx);
|
||||
return (methodIdx === 0 && catIdx === 0);
|
||||
}
|
||||
|
||||
scrollToActive() {
|
||||
this.scrollService.scrollTo(this.getCurrentMethodEl());
|
||||
}
|
||||
|
||||
hashScroll(hash) {
|
||||
if (!hash) return;
|
||||
|
||||
let $el;
|
||||
hash = hash.substr(1);
|
||||
let namespace = hash.split('/')[0];
|
||||
let ptr = decodeURIComponent(hash.substr(namespace.length + 1));
|
||||
if (namespace === 'operation') {
|
||||
$el = this.getMethodElByOperId(ptr);
|
||||
} else if (namespace === 'tag') {
|
||||
let tag = ptr.split('/')[0];
|
||||
ptr = ptr.substr(tag.length);
|
||||
$el = this.getMethodElByPtr(ptr, tag);
|
||||
}
|
||||
|
||||
if ($el) this.scrollService.scrollTo($el);
|
||||
}
|
||||
}
|
126
lib/services/menu.service.spec.js
Normal file
126
lib/services/menu.service.spec.js
Normal file
|
@ -0,0 +1,126 @@
|
|||
'use strict';
|
||||
import { provide, Component } from '@angular/core';
|
||||
import { BrowserDomAdapter } from '@angular/platform-browser/src/browser/browser_adapter';
|
||||
import {
|
||||
inject,
|
||||
beforeEach,
|
||||
describe,
|
||||
beforeEachProviders,
|
||||
it
|
||||
} from '@angular/core/testing';
|
||||
|
||||
import { TestComponentBuilder } from '@angular/compiler/testing';
|
||||
|
||||
import { OptionsService } from './options.service';
|
||||
import { MenuService } from './menu.service';
|
||||
import { Hash } from './hash.service';
|
||||
import { ScrollService } from './scroll.service';
|
||||
import { RedocEventsService } from './events.service';
|
||||
import { MethodsList } from 'lib/components/index';
|
||||
import SchemaManager from 'lib/utils/SchemaManager';
|
||||
|
||||
describe('Menu service', () => {
|
||||
let menu, hashService, scroll;
|
||||
let builder;
|
||||
let schemaMgr;
|
||||
|
||||
beforeEachProviders(() => [
|
||||
provide(BrowserDomAdapter, {useClass: BrowserDomAdapter}),
|
||||
provide(OptionsService, {useClass: OptionsService}),
|
||||
provide(Hash, {useClass: Hash}),
|
||||
provide(ScrollService, {useClass: ScrollService}),
|
||||
provide(RedocEventsService, {useClass: RedocEventsService}),
|
||||
provide(SchemaManager, {useClass: SchemaManager})
|
||||
]);
|
||||
|
||||
beforeEach(inject([Hash, ScrollService, SchemaManager, TestComponentBuilder],
|
||||
(_hash, _scroll, _schemaMgr, tcb) => {
|
||||
hashService = _hash;
|
||||
scroll = _scroll;
|
||||
schemaMgr = _schemaMgr;
|
||||
builder = tcb;
|
||||
}));
|
||||
|
||||
|
||||
beforeEach((done) => {
|
||||
schemaMgr.load('/tests/schemas/extended-petstore.yml').then(() => {
|
||||
menu = new MenuService(hashService, scroll, schemaMgr);
|
||||
done();
|
||||
}).catch((err) => done.fail(err));
|
||||
});
|
||||
|
||||
beforeEach((done) => {
|
||||
builder.createAsync(TestApp).then((fixture) => {
|
||||
fixture.detectChanges();
|
||||
done();
|
||||
}).catch((err) => done.fail(err));
|
||||
});
|
||||
|
||||
|
||||
it('should run hashScroll when hash changed', (done) => {
|
||||
spyOn(menu, 'hashScroll').and.callThrough();
|
||||
hashService.changed.subscribe(() => {
|
||||
expect(menu.hashScroll).toHaveBeenCalled();
|
||||
menu.hashScroll.and.callThrough();
|
||||
done();
|
||||
});
|
||||
hashService.changed.next();
|
||||
});
|
||||
|
||||
it('should scroll to method when location hash is present [jp]', (done) => {
|
||||
let hash = '#tag/pet/paths/~1pet~1findByStatus/get';
|
||||
spyOn(menu, 'hashScroll').and.callThrough();
|
||||
spyOn(window, 'scrollTo').and.stub();
|
||||
hashService.changed.subscribe(() => {
|
||||
expect(menu.hashScroll).toHaveBeenCalled();
|
||||
let scrollY = window.scrollTo.calls.argsFor(0)[1];
|
||||
expect(scrollY).toBeGreaterThan(0);
|
||||
window.scrollTo.and.callThrough();
|
||||
done();
|
||||
});
|
||||
hashService.changed.next(hash);
|
||||
});
|
||||
|
||||
it('should scroll to method when location hash is present [operation]', (done) => {
|
||||
let hash = '#operation/getPetById';
|
||||
spyOn(menu, 'hashScroll').and.callThrough();
|
||||
spyOn(window, 'scrollTo').and.stub();
|
||||
hashService.changed.subscribe(() => {
|
||||
expect(menu.hashScroll).toHaveBeenCalled();
|
||||
let scrollY = window.scrollTo.calls.argsFor(0)[1];
|
||||
expect(scrollY).toBeGreaterThan(0);
|
||||
done();
|
||||
});
|
||||
hashService.changed.next(hash);
|
||||
});
|
||||
|
||||
it('should select next/prev menu item when scrolled down/up', () => {
|
||||
scroll.$scrollParent = document.querySelector('#parent');
|
||||
menu.activeCatIdx.should.be.equal(0);
|
||||
menu.activeMethodIdx.should.be.equal(-1);
|
||||
let elTop = menu.getCurrentMethodEl().getBoundingClientRect().bottom;
|
||||
|
||||
scroll.$scrollParent.scrollTop = elTop + 1;
|
||||
|
||||
//simulate scroll down
|
||||
spyOn(scroll, 'scrollY').and.returnValue(elTop + 2);
|
||||
menu.scrollUpdate(true);
|
||||
menu.activeCatIdx.should.be.equal(1);
|
||||
|
||||
scroll.scrollY.and.returnValue(elTop - 2);
|
||||
scroll.$scrollParent.scrollTop = elTop - 1;
|
||||
menu.scrollUpdate(false);
|
||||
menu.activeCatIdx.should.be.equal(0);
|
||||
});
|
||||
});
|
||||
|
||||
@Component({
|
||||
selector: 'test-app',
|
||||
directives: [ MethodsList ],
|
||||
template:
|
||||
`<div id='parent' style='height: 500px; overflow:auto'>
|
||||
<methods-list></methods-list>
|
||||
</div>`
|
||||
})
|
||||
class TestApp {
|
||||
}
|
|
@ -1,22 +1,23 @@
|
|||
'use strict';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { isFunction, isString } from '@angular/core/src/facade/lang';
|
||||
import { BrowserDomAdapter } from '@angular/platform-browser/src/browser/browser_adapter';
|
||||
import { global } from '@angular/core/src/facade/lang';
|
||||
|
||||
import {isFunction, isString} from 'angular2/src/facade/lang';
|
||||
import {BrowserDomAdapter} from 'angular2/platform/browser';
|
||||
import {global} from 'angular2/src/facade/lang';
|
||||
|
||||
var defaults = {
|
||||
const defaults = {
|
||||
scrollYOffset: 0,
|
||||
disableLazySchemas: false,
|
||||
debugMode: global.redocDebugMode
|
||||
debugMode: global && global.redocDebugMode
|
||||
};
|
||||
|
||||
var OPTION_NAMES = new Set(['scrollYOffset', 'disableLazySchemas', 'specUrl']);
|
||||
const OPTION_NAMES = new Set(['scrollYOffset', 'disableLazySchemas', 'specUrl']);
|
||||
|
||||
@Injectable()
|
||||
@Reflect.metadata('parameters', [[BrowserDomAdapter]])
|
||||
export default class OptionsManager {
|
||||
constructor() {
|
||||
export class OptionsService {
|
||||
constructor(dom) {
|
||||
this._options = defaults;
|
||||
this.dom = new BrowserDomAdapter();
|
||||
this.dom = dom;
|
||||
}
|
||||
|
||||
get options() {
|
55
lib/services/options.service.spec.js
Normal file
55
lib/services/options.service.spec.js
Normal file
|
@ -0,0 +1,55 @@
|
|||
'use strict';
|
||||
|
||||
import { BrowserDomAdapter } from '@angular/platform-browser/src/browser/browser_adapter';
|
||||
import {
|
||||
it
|
||||
} from '@angular/core/testing';
|
||||
|
||||
import { OptionsService } from './options.service';
|
||||
|
||||
describe('Options Service', () => {
|
||||
let tmpDiv;
|
||||
let optionsService;
|
||||
|
||||
function build(html) {
|
||||
tmpDiv = document.createElement('div');
|
||||
tmpDiv.innerHTML = html;
|
||||
document.body.appendChild(tmpDiv);
|
||||
return tmpDiv.lastChild;
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
document.body.removeChild(tmpDiv);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
optionsService = new OptionsService(new BrowserDomAdapter());
|
||||
});
|
||||
|
||||
it('should parse numeric scrollYOffset', () => {
|
||||
var elem = build(`<redoc scroll-y-offset="50"></redoc>`);
|
||||
optionsService.parseOptions(elem);
|
||||
optionsService.options.scrollYOffset().should.be.equal(50);
|
||||
});
|
||||
|
||||
it('should parse selector scrollYOffset', () => {
|
||||
var elem = build(`<div id="test" style="position: fixed; height: 50px; top:0"> </div>
|
||||
<redoc scroll-y-offset="#test"></redoc>`);
|
||||
optionsService.parseOptions(elem);
|
||||
optionsService.options.scrollYOffset().should.be.equal(50);
|
||||
});
|
||||
|
||||
it('should return 0 for incorrect selector scrollYOffset', () => {
|
||||
var elem = build(`<div id="test" style="position: fixed; height: 50px; top:0"> </div>
|
||||
<redoc scroll-y-offset="#test2"></redoc>`);
|
||||
optionsService.parseOptions(elem);
|
||||
optionsService.options.scrollYOffset().should.be.equal(0);
|
||||
});
|
||||
|
||||
it('should handle function scrollYOffset', () => {
|
||||
optionsService.options = { scrollYOffset: () => 123 };
|
||||
var elem = build(`<redoc></redoc>`);
|
||||
optionsService.parseOptions(elem);
|
||||
optionsService.options.scrollYOffset().should.be.equal(123);
|
||||
});
|
||||
});
|
66
lib/services/scroll.service.js
Normal file
66
lib/services/scroll.service.js
Normal file
|
@ -0,0 +1,66 @@
|
|||
'use strict';
|
||||
import { Injectable, EventEmitter } from '@angular/core';
|
||||
import { BrowserDomAdapter } from '@angular/platform-browser/src/browser/browser_adapter';
|
||||
import { OptionsService } from './options.service.js';
|
||||
|
||||
export const INVIEW_POSITION = {
|
||||
ABOVE : 1,
|
||||
BELLOW: -1,
|
||||
INVIEW: 0
|
||||
};
|
||||
|
||||
@Reflect.metadata('parameters', [
|
||||
[BrowserDomAdapter], [OptionsService]])
|
||||
@Injectable()
|
||||
export class ScrollService {
|
||||
constructor(dom, optionsService) {
|
||||
//events.bootstrapped.subscribe(() => this.hashScroll());
|
||||
this.scrollYOffset = () => optionsService.options.scrollYOffset();
|
||||
this.$scrollParent = optionsService.options.$scrollParent;
|
||||
this.scroll = new EventEmitter();
|
||||
this.dom = dom;
|
||||
this.bind();
|
||||
}
|
||||
|
||||
scrollY() {
|
||||
return (this.$scrollParent.pageYOffset != null) ? this.$scrollParent.pageYOffset : this.$scrollParent.scrollTop;
|
||||
}
|
||||
|
||||
/* returns 1 if element if above the view, 0 if in view and -1 below the view */
|
||||
getElementPos($el) {
|
||||
if (Math.floor($el.getBoundingClientRect().top) > this.scrollYOffset()) {
|
||||
return INVIEW_POSITION.ABOVE;
|
||||
}
|
||||
|
||||
if ($el.getBoundingClientRect().bottom <= this.scrollYOffset()) {
|
||||
return INVIEW_POSITION.BELLOW;
|
||||
}
|
||||
return INVIEW_POSITION.INVIEW;
|
||||
}
|
||||
|
||||
scrollTo($el) {
|
||||
// TODO: rewrite this to use offsetTop as more reliable solution
|
||||
let subjRect = $el.getBoundingClientRect();
|
||||
let offset = this.scrollY() + subjRect.top - this.scrollYOffset() + 1;
|
||||
if (this.$scrollParent.scrollTo) {
|
||||
this.$scrollParent.scrollTo(0, offset);
|
||||
} else {
|
||||
this.$scrollParent.scrollTop = offset;
|
||||
}
|
||||
}
|
||||
|
||||
scrollHandler(evt) {
|
||||
let isScrolledDown = (this.scrollY() - this.prevOffsetY > 0);
|
||||
this.prevOffsetY = this.scrollY();
|
||||
this.scroll.next({isScrolledDown, evt});
|
||||
}
|
||||
|
||||
bind() {
|
||||
this.prevOffsetY = this.scrollY();
|
||||
this._cancel = this.dom.onAndCancel(this.$scrollParent, 'scroll', (evt) => { this.scrollHandler(evt); });
|
||||
}
|
||||
|
||||
unbind() {
|
||||
this._cancel();
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
import {Component, EventEmitter, ElementRef} from 'angular2/core';
|
||||
import {CORE_DIRECTIVES} from 'angular2/common';
|
||||
import {Component, EventEmitter, ElementRef} from '@angular/core';
|
||||
import {CORE_DIRECTIVES} from '@angular/common';
|
||||
import DropKick from 'Robdel12/DropKick';
|
||||
import 'Robdel12/DropKick/build/css/dropkick.css!css';
|
||||
|
||||
|
@ -14,7 +14,7 @@ import 'Robdel12/DropKick/build/css/dropkick.css!css';
|
|||
</select>
|
||||
`,
|
||||
directives: [CORE_DIRECTIVES],
|
||||
styleUrls: ['./lib/common/components/DropDown/dropdown.css']
|
||||
styleUrls: ['./lib/shared/components/DropDown/drop-down.css']
|
||||
})
|
||||
@Reflect.metadata('parameters', [[ElementRef]])
|
||||
export class DropDown {
|
|
@ -1,14 +1,14 @@
|
|||
'use strict';
|
||||
|
||||
import {Directive, ElementRef} from 'angular2/core';
|
||||
import {BrowserDomAdapter} from 'angular2/platform/browser';
|
||||
import {Directive, ElementRef} from '@angular/core';
|
||||
import {BrowserDomAdapter} from '@angular/platform-browser/src/browser/browser_adapter';
|
||||
|
||||
@Directive({
|
||||
selector: '[sticky-sidebar]',
|
||||
inputs: ['scrollParent', 'scrollYOffset']
|
||||
})
|
||||
@Reflect.metadata('parameters', [[ElementRef], [BrowserDomAdapter]])
|
||||
export default class StickySidebar {
|
||||
export class StickySidebar {
|
||||
constructor(elementRef, dom) {
|
||||
this.$element = elementRef.nativeElement;
|
||||
this.dom = dom;
|
|
@ -1,18 +1,19 @@
|
|||
'use strict';
|
||||
|
||||
import { getChildDebugElementByType } from 'tests/helpers';
|
||||
import {Component, provide} from 'angular2/core';
|
||||
import {BrowserDomAdapter} from 'angular2/platform/browser';
|
||||
import { Component, provide } from '@angular/core';
|
||||
import { BrowserDomAdapter } from '@angular/platform-browser/src/browser/browser_adapter';
|
||||
|
||||
import {
|
||||
TestComponentBuilder,
|
||||
inject,
|
||||
beforeEach,
|
||||
beforeEachProviders,
|
||||
it
|
||||
} from 'angular2/testing';
|
||||
} from '@angular/core/testing';
|
||||
|
||||
import StickySidebar from 'lib/common/components/StickySidebar/sticky-sidebar';
|
||||
import { TestComponentBuilder } from '@angular/compiler/testing';
|
||||
|
||||
import { StickySidebar } from 'lib/shared/components/index';
|
||||
|
||||
describe('Common components', () => {
|
||||
describe('StickySidebar Component', () => {
|
|
@ -1,7 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
import {Component, EventEmitter} from 'angular2/core';
|
||||
import {CORE_DIRECTIVES} from 'angular2/common';
|
||||
import {Component, EventEmitter} from '@angular/core';
|
||||
import {CORE_DIRECTIVES} from '@angular/common';
|
||||
|
||||
@Component({
|
||||
selector: 'tabs',
|
||||
|
@ -14,7 +14,7 @@ import {CORE_DIRECTIVES} from 'angular2/common';
|
|||
<ng-content></ng-content>
|
||||
`,
|
||||
directives: [CORE_DIRECTIVES],
|
||||
styleUrls: ['./lib/common/components/Tabs/tabs.css']
|
||||
styleUrls: ['./lib/shared/components/Tabs/tabs.css']
|
||||
})
|
||||
export class Tabs {
|
||||
constructor() {
|
|
@ -1,16 +1,17 @@
|
|||
'use strict';
|
||||
|
||||
import { getChildDebugElement, getChildDebugElementAll } from 'tests/helpers';
|
||||
import {Component} from 'angular2/core';
|
||||
import {Component} from '@angular/core';
|
||||
|
||||
import {
|
||||
TestComponentBuilder,
|
||||
inject,
|
||||
beforeEach,
|
||||
it
|
||||
} from 'angular2/testing';
|
||||
} from '@angular/core/testing';
|
||||
|
||||
import {Tabs, Tab} from 'lib/common/components/Tabs/tabs';
|
||||
import { TestComponentBuilder } from '@angular/compiler/testing';
|
||||
|
||||
import {Tabs, Tab} from 'lib/shared/components/index';
|
||||
|
||||
describe('Common components', () => {
|
||||
describe('Tabs Component', () => {
|
|
@ -1,17 +1,17 @@
|
|||
'use strict';
|
||||
|
||||
import {Component, EventEmitter} from 'angular2/core';
|
||||
import {CORE_DIRECTIVES} from 'angular2/common';
|
||||
import {Component, EventEmitter} from '@angular/core';
|
||||
import {CORE_DIRECTIVES} from '@angular/common';
|
||||
|
||||
@Component({
|
||||
selector: 'zippy',
|
||||
events: ['open', 'close'],
|
||||
inputs: ['title', 'visible', 'type', 'empty'],
|
||||
templateUrl: './lib/common/components/Zippy/zippy.html',
|
||||
styleUrls: ['./lib/common/components/Zippy/zippy.css'],
|
||||
templateUrl: './lib/shared/components/Zippy/zippy.html',
|
||||
styleUrls: ['./lib/shared/components/Zippy/zippy.css'],
|
||||
directives: [CORE_DIRECTIVES]
|
||||
})
|
||||
export default class Zippy {
|
||||
export class Zippy {
|
||||
|
||||
constructor() {
|
||||
this.type = 'general';
|
|
@ -1,16 +1,16 @@
|
|||
'use strict';
|
||||
|
||||
import { getChildDebugElement, mouseclick } from 'tests/helpers';
|
||||
import {Component} from 'angular2/core';
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import {
|
||||
TestComponentBuilder,
|
||||
inject,
|
||||
beforeEach,
|
||||
it
|
||||
} from 'angular2/testing';
|
||||
} from '@angular/core/testing';
|
||||
|
||||
import Zippy from 'lib/common/components/Zippy/zippy';
|
||||
import { TestComponentBuilder } from '@angular/compiler/testing';
|
||||
import { Zippy } from 'lib/shared/components/index';
|
||||
|
||||
describe('Common components', () => {
|
||||
describe('Zippy Component', () => {
|
5
lib/shared/components/index.js
Normal file
5
lib/shared/components/index.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
'use strict';
|
||||
export * from './DropDown/drop-down';
|
||||
export * from './StickySidebar/sticky-sidebar';
|
||||
export * from './Tabs/tabs';
|
||||
export * from './Zippy/zippy';
|
|
@ -1,6 +1,6 @@
|
|||
'use strict';
|
||||
import {Pipe} from 'angular2/core';
|
||||
import {isBlank} from 'angular2/src/facade/lang';
|
||||
import {Pipe} from '@angular/core';
|
||||
import {isBlank} from '@angular/core/src/facade/lang';
|
||||
|
||||
var level = 1;
|
||||
const COLLAPSE_LEVEL = 2;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
'use strict';
|
||||
|
||||
import {Pipe} from 'angular2/core';
|
||||
import {isString, stringify, isBlank} from 'angular2/src/facade/lang';
|
||||
import {BaseException} from 'angular2/src/facade/exceptions';
|
||||
import {Pipe} from '@angular/core';
|
||||
import {isString, stringify, isBlank} from '@angular/core/src/facade/lang';
|
||||
import {BaseException} from '@angular/core/src/facade/exceptions';
|
||||
import {JsonPointer} from './JsonPointer';
|
||||
|
||||
import Prism from '../../prismjs-bundle';
|
||||
|
|
16
package.json
16
package.json
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "redoc",
|
||||
"description": "Swagger-generated API Reference Documentation",
|
||||
"version": "0.8.0",
|
||||
"version": "0.9.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/Rebilly/ReDoc"
|
||||
|
@ -32,8 +32,12 @@
|
|||
"jspm": {
|
||||
"configFile": "system.config.js",
|
||||
"dependencies": {
|
||||
"@angular/common": "npm:@angular/common@^2.0.0-rc.1",
|
||||
"@angular/compiler": "npm:@angular/compiler@^2.0.0-rc.1",
|
||||
"@angular/core": "npm:@angular/core@^2.0.0-rc.1",
|
||||
"@angular/platform-browser": "npm:@angular/platform-browser@^2.0.0-rc.1",
|
||||
"@angular/platform-browser-dynamic": "npm:@angular/platform-browser-dynamic@^2.0.0-rc.1",
|
||||
"Robdel12/DropKick": "github:Robdel12/DropKick@^2.1.7",
|
||||
"angular2": "npm:angular2@2.0.0-beta.17",
|
||||
"es6-shim": "github:es-shims/es6-shim@^0.33.6",
|
||||
"hint.css": "npm:hint.css@^2.2.1",
|
||||
"json": "github:systemjs/plugin-json@^0.1.0",
|
||||
|
@ -42,9 +46,11 @@
|
|||
"json-schema-instantiator": "npm:json-schema-instantiator@^0.3.0",
|
||||
"marked": "npm:marked@^0.3.5",
|
||||
"prismjs": "npm:prismjs@^1.3.0",
|
||||
"rxjs": "npm:rxjs@5.0.0-beta.6",
|
||||
"scrollparent": "npm:scrollparent@^0.1.0",
|
||||
"stream-http": "npm:stream-http@^2.3.0",
|
||||
"swagger-parser": "npm:swagger-parser@4.0.0-beta.2"
|
||||
"swagger-parser": "npm:swagger-parser@4.0.0-beta.2",
|
||||
"zone.js": "npm:zone.js@0.6.12"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel": "npm:babel-core@^5.8.34",
|
||||
|
@ -85,7 +91,7 @@
|
|||
"istanbul": "github:gotwarlost/istanbul#source-map",
|
||||
"jasmine-core": "^2.4.1",
|
||||
"jasmine-spec-reporter": "^2.4.0",
|
||||
"jspm": "^0.16.19",
|
||||
"jspm": "^0.16.34",
|
||||
"karma": "^0.13.15",
|
||||
"karma-babel-preprocessor": "^5.2.2",
|
||||
"karma-chrome-launcher": "^0.2.2",
|
||||
|
@ -106,7 +112,7 @@
|
|||
"run-sequence": "^1.1.5",
|
||||
"should": "^8.0.2",
|
||||
"sinon": "^1.17.2",
|
||||
"systemjs-builder": "^0.15.2",
|
||||
"systemjs-builder": "^0.15.16",
|
||||
"vinyl-paths": "^2.0.0",
|
||||
"zone.js": "^0.6.12"
|
||||
}
|
||||
|
|
|
@ -14,7 +14,8 @@ let config = {
|
|||
return loadJson('https://apis-guru.github.io/api-models/api/v1/list.json').then((list) => {
|
||||
global.apisGuruList = list;
|
||||
return browser.getCapabilities().then(function (cap) {
|
||||
browser.isIE = cap.caps_.browserName === 'internet explorer';
|
||||
browser.isIE = cap.browserName === 'internet explorer'
|
||||
|| (cap.caps_ && cap.caps_.browserName === 'internet explorer')
|
||||
});
|
||||
});
|
||||
},
|
||||
|
|
|
@ -29,16 +29,20 @@ System.config({
|
|||
|
||||
meta: {
|
||||
"jspm_packages/npm/json-formatter-js@0.2.0/src/*": {
|
||||
"format": "es6"
|
||||
"format": "esm"
|
||||
},
|
||||
"jspm_packages/npm/json-schema-view-js@0.2.0/src/*": {
|
||||
"format": "es6"
|
||||
"format": "esm"
|
||||
}
|
||||
},
|
||||
|
||||
map: {
|
||||
"@angular/common": "npm:@angular/common@2.0.0-rc.1",
|
||||
"@angular/compiler": "npm:@angular/compiler@2.0.0-rc.1",
|
||||
"@angular/core": "npm:@angular/core@2.0.0-rc.1",
|
||||
"@angular/platform-browser": "npm:@angular/platform-browser@2.0.0-rc.1",
|
||||
"@angular/platform-browser-dynamic": "npm:@angular/platform-browser-dynamic@2.0.0-rc.1",
|
||||
"Robdel12/DropKick": "github:Robdel12/DropKick@2.1.7",
|
||||
"angular2": "npm:angular2@2.0.0-beta.17",
|
||||
"babel": "npm:babel-core@5.8.34",
|
||||
"babel-runtime": "npm:babel-runtime@5.8.34",
|
||||
"clean-css": "npm:clean-css@3.4.6",
|
||||
|
@ -52,10 +56,12 @@ System.config({
|
|||
"json-schema-instantiator": "npm:json-schema-instantiator@0.3.0",
|
||||
"marked": "npm:marked@0.3.5",
|
||||
"prismjs": "npm:prismjs@1.3.0",
|
||||
"rxjs": "npm:rxjs@5.0.0-beta.6",
|
||||
"scrollparent": "npm:scrollparent@0.1.0",
|
||||
"stream-http": "npm:stream-http@2.3.0",
|
||||
"swagger-parser": "npm:swagger-parser@4.0.0-beta.2",
|
||||
"systemjs/plugin-json": "github:systemjs/plugin-json@0.1.2",
|
||||
"zone.js": "npm:zone.js@0.6.12",
|
||||
"github:jspm/nodelibs-assert@0.1.0": {
|
||||
"assert": "npm:assert@1.3.0"
|
||||
},
|
||||
|
@ -131,17 +137,38 @@ System.config({
|
|||
"github:jspm/nodelibs-zlib@0.1.0": {
|
||||
"browserify-zlib": "npm:browserify-zlib@0.1.4"
|
||||
},
|
||||
"npm:@angular/common@2.0.0-rc.1": {
|
||||
"@angular/core": "npm:@angular/core@2.0.0-rc.1",
|
||||
"process": "github:jspm/nodelibs-process@0.1.2"
|
||||
},
|
||||
"npm:@angular/compiler@2.0.0-rc.1": {
|
||||
"@angular/core": "npm:@angular/core@2.0.0-rc.1",
|
||||
"process": "github:jspm/nodelibs-process@0.1.2"
|
||||
},
|
||||
"npm:@angular/core@2.0.0-rc.1": {
|
||||
"process": "github:jspm/nodelibs-process@0.1.2",
|
||||
"rxjs": "npm:rxjs@5.0.0-beta.6",
|
||||
"zone.js": "npm:zone.js@0.6.12"
|
||||
},
|
||||
"npm:@angular/platform-browser-dynamic@2.0.0-rc.1": {
|
||||
"@angular/common": "npm:@angular/common@2.0.0-rc.1",
|
||||
"@angular/compiler": "npm:@angular/compiler@2.0.0-rc.1",
|
||||
"@angular/core": "npm:@angular/core@2.0.0-rc.1",
|
||||
"@angular/platform-browser": "npm:@angular/platform-browser@2.0.0-rc.1",
|
||||
"process": "github:jspm/nodelibs-process@0.1.2"
|
||||
},
|
||||
"npm:@angular/platform-browser@2.0.0-rc.1": {
|
||||
"@angular/common": "npm:@angular/common@2.0.0-rc.1",
|
||||
"@angular/compiler": "npm:@angular/compiler@2.0.0-rc.1",
|
||||
"@angular/core": "npm:@angular/core@2.0.0-rc.1",
|
||||
"process": "github:jspm/nodelibs-process@0.1.2"
|
||||
},
|
||||
"npm:amdefine@1.0.0": {
|
||||
"fs": "github:jspm/nodelibs-fs@0.1.2",
|
||||
"module": "github:jspm/nodelibs-module@0.1.0",
|
||||
"path": "github:jspm/nodelibs-path@0.1.0",
|
||||
"process": "github:jspm/nodelibs-process@0.1.2"
|
||||
},
|
||||
"npm:angular2@2.0.0-beta.17": {
|
||||
"reflect-metadata": "npm:reflect-metadata@0.1.2",
|
||||
"rxjs": "npm:rxjs@5.0.0-beta.7",
|
||||
"zone.js": "npm:zone.js@0.6.12"
|
||||
},
|
||||
"npm:argparse@1.0.7": {
|
||||
"fs": "github:jspm/nodelibs-fs@0.1.2",
|
||||
"path": "github:jspm/nodelibs-path@0.1.0",
|
||||
|
@ -736,10 +763,6 @@ System.config({
|
|||
"string_decoder": "npm:string_decoder@0.10.31",
|
||||
"util-deprecate": "npm:util-deprecate@1.0.2"
|
||||
},
|
||||
"npm:reflect-metadata@0.1.2": {
|
||||
"assert": "github:jspm/nodelibs-assert@0.1.0",
|
||||
"process": "github:jspm/nodelibs-process@0.1.2"
|
||||
},
|
||||
"npm:request@2.72.0": {
|
||||
"aws-sign2": "npm:aws-sign2@0.6.0",
|
||||
"aws4": "npm:aws4@1.3.2",
|
||||
|
@ -778,10 +801,9 @@ System.config({
|
|||
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
|
||||
"process": "github:jspm/nodelibs-process@0.1.2"
|
||||
},
|
||||
"npm:rxjs@5.0.0-beta.7": {
|
||||
"npm:rxjs@5.0.0-beta.6": {
|
||||
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
|
||||
"process": "github:jspm/nodelibs-process@0.1.2",
|
||||
"symbol-observable": "npm:symbol-observable@0.2.4"
|
||||
"process": "github:jspm/nodelibs-process@0.1.2"
|
||||
},
|
||||
"npm:sha.js@2.4.5": {
|
||||
"buffer": "github:jspm/nodelibs-buffer@0.1.0",
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
'use strict';
|
||||
console.log('here');
|
||||
const verifyNoBrowserErrors = require('./helpers').verifyNoBrowserErrors;
|
||||
const scrollToEl = require('./helpers').scrollToEl;
|
||||
const fixFFTest = require('./helpers').fixFFTest;
|
||||
|
@ -50,7 +51,8 @@ describe('Scroll sync', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('APIs.guru specs test', ()=> {
|
||||
if (process.env.JOB === 'e2e-guru') {
|
||||
describe('APIs.guru specs test', ()=> {
|
||||
|
||||
// global.apisGuruList was loaded in onPrepare method of protractor config
|
||||
let apisGuruList = global.apisGuruList;
|
||||
|
@ -80,4 +82,5 @@ describe('APIs.guru specs test', ()=> {
|
|||
url = url.replace('apis-guru.github.io/', 'apis-guru.github.io:80/');
|
||||
basicTests(url, `${apiName}:${apiInfo.info.version}\n${url}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
import {By} from 'angular2/platform/browser';
|
||||
import {By} from '@angular/platform-browser';
|
||||
|
||||
/** Gets a child DebugElement by tag name. */
|
||||
export function getChildDebugElement(parent, tagName) {
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
'use strict';
|
||||
|
||||
import {setBaseTestProviders} from 'angular2/testing';
|
||||
import {setBaseTestProviders} from '@angular/core/testing';
|
||||
|
||||
import {
|
||||
TEST_BROWSER_PLATFORM_PROVIDERS,
|
||||
TEST_BROWSER_APPLICATION_PROVIDERS
|
||||
} from 'angular2/platform/testing/browser';
|
||||
import {
|
||||
TEST_BROWSER_DYNAMIC_PLATFORM_PROVIDERS,
|
||||
TEST_BROWSER_DYNAMIC_APPLICATION_PROVIDERS
|
||||
} from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
ELEMENT_PROBE_PROVIDERS_PROD_MODE
|
||||
} from 'angular2/platform/browser';
|
||||
setBaseTestProviders(TEST_BROWSER_PLATFORM_PROVIDERS, [TEST_BROWSER_APPLICATION_PROVIDERS, ELEMENT_PROBE_PROVIDERS_PROD_MODE]);
|
||||
|
||||
setBaseTestProviders(TEST_BROWSER_DYNAMIC_PLATFORM_PROVIDERS, [TEST_BROWSER_DYNAMIC_APPLICATION_PROVIDERS]);
|
||||
|
|
Loading…
Reference in New Issue
Block a user