diff --git a/build/tasks/e2e.js b/build/tasks/e2e.js
index 8888188e..c2828e83 100644
--- a/build/tasks/e2e.js
+++ b/build/tasks/e2e.js
@@ -12,7 +12,7 @@ gulp.task('test-server', function (done) {
baseDir: './tests/e2e',
routes: {
'/dist': './dist',
- '/swagger.json': './demo/swagger.json'
+ '/swagger.yml': './demo/swagger.yml'
},
}
}, done);
diff --git a/demo/swagger.yml b/demo/swagger.yml
index 0a41c2ee..7af5f3d8 100644
--- a/demo/swagger.yml
+++ b/demo/swagger.yml
@@ -169,6 +169,21 @@
description: "Pet not found"
405:
description: "Validation exception"
+ x-code-samples:
+ -
+ lang: PHP
+ source: |-
+ $form = new \PetStore\Entities\Pet();
+ $form->setPetId(1);
+ $form->setPetType("Dog");
+ $form->setName("Rex");
+ // set other fields
+
+ try {
+ $pet = $client->pets()->update($form);
+ } catch (UnprocessableEntityException $e) {
+ var_dump($e->getErrors());
+ }
security:
-
petstore_auth:
diff --git a/docs/redoc-vendor-extensions.md b/docs/redoc-vendor-extensions.md
index e6dcac25..5a6bee90 100644
--- a/docs/redoc-vendor-extensions.md
+++ b/docs/redoc-vendor-extensions.md
@@ -1,27 +1,29 @@
# ReDoc vendor extensions
ReDoc makes use of the following [vendor extensions](http://swagger.io/specification/#vendorExtensions)
-### [Info Object](http://swagger.io/specification/#infoObject) vendor extensions
+### [Info Object](http://swagger.io/specification/#infoObject) vendor extensions
#### x-logo
-| Field Name | Type | Description
-| :------------- | :------: |
-| x-logo | [Logo Object](#logoObject) | The information about API logo
-##### Usage in Redoc
+| Field Name | Type | Description |
+| :------------- | :-----------: | :---------- |
+| x-logo | [Logo Object](#logoObject) | The information about API logo |
+
+###### Usage in Redoc
`x-logo` is used to specify API logo. The corresponding image are displayed just above side-menu.
-#### Logo Object
+#### Logo Object
The information about API logo
-##### Fixed fields
-| Field Name | Type | Description
-| :---------- | :------: |
-| url | string | The URL pointing to the spec logo. MUST be in the format of a URL
-| backgroundColor | string | background color to be used. MUST be in [CSS color syntax](https://developer.mozilla.org/en/docs/Web/CSS/color)
+###### Fixed fields
+| Field Name | Type | Description |
+| :-------------- | :------: | :---------- |
+| url | string | The URL pointing to the spec logo. MUST be in the format of a URL
+| backgroundColor | string | background color to be used. MUST be in [CSS color syntax](https://developer.mozilla.org/en/docs/Web/CSS/color) |
-##### x-logo example
-```yaml
+###### x-logo example
+json
+```json
{
"info": {
"version": "1.0.0",
@@ -33,15 +35,14 @@ The information about API logo
}
}
```
+yaml
```yaml
-{
- info:
- version: "1.0.0"
- title: "Swagger Petstore"
- x-logo:
- url: "https://rebilly.github.io/ReDoc/petstore-logo.png"
- backgroundColor: "white"
-}
+info:
+ version: "1.0.0"
+ title: "Swagger Petstore"
+ x-logo:
+ url: "https://rebilly.github.io/ReDoc/petstore-logo.png"
+ backgroundColor: "white"
```
@@ -49,15 +50,16 @@ The information about API logo
### [Tag object](http://swagger.io/specification/#tagObject) vendor extensions
#### x-traitTag
-| Field Name | Type | Description
-| :------------- | :------: |
-| x-traitTag | boolean | In Swagger two operations can have multiply tags. This property distinguish between tags that are used to group operations (default) from tags that are used to mark operation with certain trait (`true` value)
+| Field Name | Type | Description |
+| :------------- | :------: | :---------- |
+| x-traitTag | boolean | In Swagger two operations can have multiply tags. This property distinguish between tags that are used to group operations (default) from tags that are used to mark operation with certain trait (`true` value) |
-##### Usage in Redoc
+###### Usage in Redoc
Tags that have `x-traitTag` set to `true` are listed in side-menu but don't have any subitems (operations). Tag `description` is rendered as well.
This is useful for handling out common things like Pagination, Rate-Limits, etc.
-##### x-traitTag example
+###### x-traitTag example
+json
```json
{
"name": "Pagination",
@@ -65,6 +67,7 @@ This is useful for handling out common things like Pagination, Rate-Limits, etc.
"x-traitTag": true
}
```
+yaml
```yaml
name: Pagination
description: Pagination description (can use markdown syntax)
@@ -74,32 +77,32 @@ x-traitTag: true
### [Operation Object](http://swagger.io/specification/#operationObject) vendor extensions
#### x-code-samples
-| Field Name | Type | Description
-| :------------- | :------: |
-| x-code-samples | [[Code Sample Object](#codeSampleObject)] | A list of code samples associated with operation
+| Field Name | Type | Description |
+| :------------- | :------: | :---------- |
+| x-code-samples | [ [Code Sample Object](#codeSampleObject) ] | A list of code samples associated with operation |
-##### Usage in ReDoc
-x-code-samples are rendered on the right panel of ReDoc
+###### Usage in ReDoc
+`x-code-samples` are rendered on the right panel of ReDoc
-#### Code Sample Object
+#### Code Sample Object
Operation code sample
-##### Fixed fields
-| Field Name | Type | Description
-| :---------- | :------: | :-----------
-| lang | string | Code sample language. Value should be one of the following [list](https://github.com/github/linguist/blob/master/lib/linguist/popular.yml)
-| source | string | Code sample source code
+###### Fixed fields
+| Field Name | Type | Description |
+| :---------- | :------: | :----------- |
+| lang | string | Code sample language. Value should be one of the following [list](https://github.com/github/linguist/blob/master/lib/linguist/popular.yml) |
+| source | string | Code sample source code |
-##### Code Sample Object example
-```yaml
+###### Code Sample Object example
+json
+```json
{
"lang": "JavaScript",
"source": "console.log('Hello World');"
}
```
+yaml
```yaml
-{
- lang: JavaScript
- source: console.log('Hello World');
-}
+lang: JavaScript
+source: console.log('Hello World');
```
diff --git a/lib/common/components/Tabs/tabs.js b/lib/common/components/Tabs/tabs.js
index f091afa9..5345f282 100644
--- a/lib/common/components/Tabs/tabs.js
+++ b/lib/common/components/Tabs/tabs.js
@@ -1,10 +1,11 @@
'use strict';
-import {Component, View} from 'angular2/core';
+import {Component, View, EventEmitter} from 'angular2/core';
import {CORE_DIRECTIVES} from 'angular2/common';
@Component({
- selector: 'tabs'
+ selector: 'tabs',
+ events: ['change']
})
@View({
template: `
@@ -20,13 +21,34 @@ import {CORE_DIRECTIVES} from 'angular2/common';
export class Tabs {
constructor() {
this.tabs = [];
+ this.change = new EventEmitter();
}
- selectTab(tab) {
+ selectTab(tab, notify = true) {
+ if (tab.active) return;
this.tabs.forEach((tab) => {
tab.active = false;
});
tab.active = true;
+ notify && this.change.next(tab.tabTitle);
+ }
+
+ selectyByTitle(tabTitle, notify = false) {
+ let prevActive;
+ let newActive;
+ this.tabs.forEach((tab) => {
+ if (tab.active) prevActive = tab;
+ tab.active = false;
+ if (tab.tabTitle === tabTitle) {
+ newActive = tab;
+ }
+ });
+ if (newActive) {
+ newActive.active = true;
+ } else {
+ prevActive.active = true;
+ }
+ notify && this.change.next(tabTitle);
}
addTab(tab) {
diff --git a/lib/common/components/Tabs/tabs.spec.js b/lib/common/components/Tabs/tabs.spec.js
index 9e7145a7..02e5ea70 100644
--- a/lib/common/components/Tabs/tabs.spec.js
+++ b/lib/common/components/Tabs/tabs.spec.js
@@ -1,6 +1,6 @@
'use strict';
-import { getChildDebugElement, getChildDebugElementAll, mouseclick } from 'tests/helpers';
+import { getChildDebugElement, getChildDebugElementAll } from 'tests/helpers';
import {Component, View} from 'angular2/core';
import {
@@ -16,9 +16,10 @@ describe('Common components', () => {
describe('Tabs Component', () => {
let builder;
let component;
- let nativeElement;
let childDebugEls;
+ let debugEl;
let fixture;
+ let hostComponent;
beforeEach(inject([TestComponentBuilder], (tcb) => {
builder = tcb;
@@ -26,10 +27,10 @@ describe('Common components', () => {
beforeEach((done) => {
builder.createAsync(TestApp).then(_fixture => {
fixture = _fixture;
- let debugEl = getChildDebugElement(fixture.debugElement, 'tabs');
+ hostComponent = fixture.debugElement.componentInstance;
+ debugEl = getChildDebugElement(fixture.debugElement, 'tabs');
childDebugEls = getChildDebugElementAll(debugEl, 'tab');
component = debugEl.componentInstance;
- nativeElement = debugEl.nativeElement;
done();
}, err => done.fail(err));
});
@@ -54,13 +55,82 @@ describe('Common components', () => {
it('should change active tab on click', () => {
fixture.detectChanges();
- let headerEls = nativeElement.querySelectorAll('li');
+ //let headerEls = nativeElement.querySelectorAll('li');
let tabs = childDebugEls.map(debugEl => debugEl.componentInstance);
let [tab1, tab2] = tabs;
- mouseclick(headerEls[0]);
- tab1.active.should.be.false;
- tab2.active.should.be.true;
+ let tabsInst = debugEl.componentInstance;
+ tabsInst.selectTab(tab2);
+ tab1.active.should.be.false();
+ tab2.active.should.be.true();
+ });
+
+ it('should change tab by title and not emit Event', (done) => {
+ fixture.detectChanges();
+ let tabs = childDebugEls.map(debugEl => debugEl.componentInstance);
+ let [tab1, tab2] = tabs;
+ let tab2Title = 'Tab2';
+
+ let tabsInst = debugEl.componentInstance;
+ tabsInst.selectyByTitle(tab2Title);
+ tab1.active.should.be.false();
+ tab2.active.should.be.true();
+
+ setTimeout(() => {
+ hostComponent.eventLog.should.be.deepEqual([]);
+ done();
+ });
+ });
+
+
+ it('should emit event on tab Change', (done) => {
+ fixture.detectChanges();
+ let tabs = childDebugEls.map(debugEl => debugEl.componentInstance);
+ let tab2 = tabs[1];
+ let tabsInst = debugEl.componentInstance;
+ tabsInst.selectTab(tab2, true);
+
+ setTimeout(() => {
+ hostComponent.eventLog.should.be.deepEqual(['Tab2']);
+ done();
+ });
+ });
+
+ it('should emit event on tab change by Title with notify true', (done) => {
+ fixture.detectChanges();
+ let tab2Title = 'Tab2';
+
+ let tabsInst = debugEl.componentInstance;
+ tabsInst.selectyByTitle(tab2Title, true);
+
+ setTimeout(() => {
+ hostComponent.eventLog.should.be.deepEqual(['Tab2']);
+ done();
+ });
+ });
+
+ it('should not emit event on tab change with notify false', (done) => {
+ fixture.detectChanges();
+ let tabs = childDebugEls.map(debugEl => debugEl.componentInstance);
+ let tab2 = tabs[1];
+ let tabsInst = debugEl.componentInstance;
+ tabsInst.selectTab(tab2, false);
+
+ setTimeout(() => {
+ hostComponent.eventLog.should.be.deepEqual([]);
+ done();
+ });
+ });
+
+ it('should leave current tab active if selectyByTitle non existing title', () => {
+ fixture.detectChanges();
+ let tabs = childDebugEls.map(debugEl => debugEl.componentInstance);
+ let [tab1, tab2] = tabs;
+
+ let tabsInst = debugEl.componentInstance;
+ tabsInst.selectyByTitle('badTitle');
+ tab1.active.should.be.true();
+ tab2.active.should.be.false();
});
});
});
@@ -71,10 +141,16 @@ describe('Common components', () => {
@View({
directives: [Tabs, Tab],
template:
- `
+ `
Test
Test
`
})
class TestApp {
+ constructor() {
+ this.eventLog = [];
+ }
+ onEvent(event) {
+ this.eventLog.push(event);
+ }
}
diff --git a/lib/components/RequestSamples/request-samples.html b/lib/components/RequestSamples/request-samples.html
index 2f71bdd2..60ede141 100644
--- a/lib/components/RequestSamples/request-samples.html
+++ b/lib/components/RequestSamples/request-samples.html
@@ -1,6 +1,6 @@
-
+
diff --git a/lib/components/RequestSamples/request-samples.js b/lib/components/RequestSamples/request-samples.js
index 6bebaa32..f193c033 100644
--- a/lib/components/RequestSamples/request-samples.js
+++ b/lib/components/RequestSamples/request-samples.js
@@ -6,17 +6,38 @@ import {Tabs, Tab} from '../../common/components/Tabs/tabs';
import SchemaSample from '../SchemaSample/schema-sample';
import {PrismPipe} from '../../utils/pipes';
+import {ViewChildren, QueryList, ChangeDetectorRef, ChangeDetectionStrategy} from 'angular2/core';
+import {redocEvents} from '../../events';
+
@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]
+ pipes: [PrismPipe],
+ changeDetection: ChangeDetectionStrategy.OnPush
})
export default class RequestSamples extends BaseComponent {
- constructor(schemaMgr) {
+ constructor(schemaMgr, tabs, changeDetector) {
super(schemaMgr);
+ tabs.changes.subscribe(_ => {
+ this.tabs = tabs.first;
+ this.subscribeForEvents(_);
+ });
+ this.changeDetector = changeDetector;
+ }
+
+ changeLangNotify(lang) {
+ redocEvents.samplesLanguageChanged.next(lang);
+ }
+
+ subscribeForEvents() {
+ if (!this.tabs) return;
+ redocEvents.samplesLanguageChanged.subscribe((sampleLang) => {
+ this.tabs.selectyByTitle(sampleLang);
+ this.changeDetector.markForCheck();
+ });
}
prepareModel() {
@@ -25,3 +46,5 @@ export default class RequestSamples extends BaseComponent {
this.data.samples = this.componentSchema['x-code-samples'] || [];
}
}
+
+RequestSamples.parameters = RequestSamples.parameters.concat([ [new ViewChildren(Tabs), QueryList], [ChangeDetectorRef] ]);
diff --git a/lib/events.js b/lib/events.js
index 62fb85dc..77b6a0de 100644
--- a/lib/events.js
+++ b/lib/events.js
@@ -3,6 +3,8 @@
import {EventEmitter} from 'angular2/core';
var bootsrEmmiter = new EventEmitter();
+var langChanged = new EventEmitter();
export var redocEvents = {
- bootstrapped: bootsrEmmiter
+ bootstrapped: bootsrEmmiter,
+ samplesLanguageChanged: langChanged
};
diff --git a/package.json b/package.json
index 458fb67b..0b95f705 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "redoc",
"description": "Swagger-generated API Reference Documentation",
- "version": "0.5.0",
+ "version": "0.5.1",
"repository": {
"type": "git",
"url": "git://github.com/Rebilly/ReDoc"
@@ -10,7 +10,7 @@
"scripts": {
"test": "gulp lint && ./build/run_tests.sh",
"prepublish": "gulp build",
- "postinstall": "jspm install",
+ "postinstall": "npm install jspm && jspm install",
"start": "gulp serve",
"build-dist": "gulp build",
"branch-release": "git reset --hard && branch-release",
diff --git a/tests/e2e/index.html b/tests/e2e/index.html
index 30d11c24..599429c5 100644
--- a/tests/e2e/index.html
+++ b/tests/e2e/index.html
@@ -14,7 +14,7 @@