Merge branch 'master' into releases

This commit is contained in:
RedocBot 2016-05-10 08:56:51 +00:00 committed by travis@localhost
commit 383169d6c5
75 changed files with 936 additions and 771 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
@import '../../common/styles/variables';
@import '../../shared/styles/variables';
.api-info-header {
font-weight: normal;

View File

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

View File

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

View File

@ -1,4 +1,4 @@
@import '../../common/styles/variables';
@import '../../shared/styles/variables';
img {
max-height: 150px;

View File

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

View File

@ -1,4 +1,4 @@
@import '../../common/styles/variables';
@import '../../shared/styles/variables';
$lines-width: 1px;
$bullet-size: 1px;
$cell-spacing: 25px;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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>`
})

View File

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

View File

@ -1,4 +1,4 @@
@import '../../common/styles/variables';
@import '../../shared/styles/variables';
$hint-color: #999999;

View File

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

View File

@ -1,4 +1,4 @@
@import '../../common/styles/variables';
@import '../../shared/styles/variables';
:host {
display: block;

View File

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

View File

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

View File

@ -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'] || [];
}
}

View File

@ -1,4 +1,4 @@
@import '../../common/styles/variables';
@import '../../shared/styles/variables';
header {
font-family: $headers-font;

View File

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

View File

@ -1,4 +1,4 @@
@import '../../common/styles/variables';
@import '../../shared/styles/variables';
.responses-list-header {
font-size: 18px;

View File

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

View File

@ -1,4 +1,4 @@
@import '../../common/styles/variables';
@import '../../shared/styles/variables';
tab, tabs {
display: block;

View File

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

View File

@ -1,4 +1,4 @@
@import '../../common/styles/variables';
@import '../../shared/styles/variables';
pre {
background-color: transparent;

View File

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

View File

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

View File

@ -1,4 +1,4 @@
@import '../../common/styles/variables';
@import '../../shared/styles/variables';
$mobile-menu-compact-breakpoint: 550px;
.menu-header {

View File

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

View File

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

View File

@ -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', () => {

View File

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

View File

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

View File

@ -0,0 +1,10 @@
'use strict';
import { EventEmitter } from '@angular/core';
export class RedocEventsService {
constructor() {
this.bootstrapped = new EventEmitter();
this.samplesLanguageChanged = new EventEmitter();
}
}

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

View 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
View 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';

View 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);
}
}

View 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 {
}

View File

@ -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() {

View 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);
});
});

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

View File

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

View File

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

View File

@ -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', () => {

View File

@ -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() {

View File

@ -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', () => {

View File

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

View File

@ -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', () => {

View 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';

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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