diff --git a/lib/components/Method/method.html b/lib/components/Method/method.html index e677c448..1a428a93 100644 --- a/lib/components/Method/method.html +++ b/lib/components/Method/method.html @@ -1,7 +1,7 @@

- {{data.methodInfo.summary}} + {{data.methodInfo.summary}}

{{data.httpMethod}} diff --git a/lib/components/Method/method.js b/lib/components/Method/method.js index 13aa8178..3ab6f066 100644 --- a/lib/components/Method/method.js +++ b/lib/components/Method/method.js @@ -28,6 +28,11 @@ export default class Method extends BaseComponent { this.data.methodInfo = this.componentSchema; this.data.methodInfo.tags = this.filterMainTags(this.data.methodInfo.tags); this.data.bodyParam = this.findBodyParam(); + if (this.componentSchema.operationId) { + this.data.methodAnchor = 'operation/' + this.componentSchema.operationId; + } else { + this.data.methodAnchor = 'tag/' + this.tag + this.pointer; + } } filterMainTags(tags) { diff --git a/lib/components/MethodsList/methods-list.html b/lib/components/MethodsList/methods-list.html index 4532d941..10e0ccf6 100644 --- a/lib/components/MethodsList/methods-list.html +++ b/lib/components/MethodsList/methods-list.html @@ -1,10 +1,10 @@
-

{{tag.name}}

+

{{tag.name}}

+ [attr.tag]="method.tag" [tag]="method.tag" [attr.operation-id]="method.operationId">
diff --git a/lib/components/SideMenu/side-menu.js b/lib/components/SideMenu/side-menu.js index 614b70bc..fe050c8f 100644 --- a/lib/components/SideMenu/side-menu.js +++ b/lib/components/SideMenu/side-menu.js @@ -3,7 +3,8 @@ import {RedocComponent, BaseComponent} from '../base'; import {redocEvents} from '../../events'; -import {NgZone, ChangeDetectionStrategy, ElementRef} from 'angular2/core'; +import {NgZone, ChangeDetectionStrategy, ElementRef, forwardRef} from 'angular2/core'; +import Redoc from '../Redoc/redoc'; import {document} from 'angular2/src/facade/browser'; import {BrowserDomAdapter} from 'angular2/platform/browser'; import {global} from 'angular2/src/facade/lang'; @@ -60,10 +61,18 @@ export default class SideMenu extends BaseComponent { let hash = this.adapter.getLocation().hash; if (!hash) return; + let el; hash = hash.substr(1); - let tag = hash.split('/')[0]; - let ptr = hash.substr(tag.length); - let el = this.getMethodEl(ptr, tag); + let namespace = hash.split('/')[0]; + let ptr = 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(); } @@ -170,13 +179,18 @@ export default class SideMenu extends BaseComponent { return (methodIdx === 0 && catIdx === 0); } - getMethodEl(ptr, tag) { + 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.getMethodEl(this.activeMethodPtr, this.data.menu[this.activeCatIdx].name); + 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 */ @@ -240,4 +254,5 @@ export default class SideMenu extends BaseComponent { this.changeActive(CHANGE.INITIAL); } } -SideMenu.parameters = SideMenu.parameters.concat([[ElementRef], [BrowserDomAdapter], [NgZone]]); +SideMenu.parameters = SideMenu.parameters.concat([[ElementRef], + [BrowserDomAdapter], [NgZone], [forwardRef(() => Redoc)] ]); diff --git a/lib/components/SideMenu/side-menu.spec.js b/lib/components/SideMenu/side-menu.spec.js index 8b3da94f..9f154f00 100644 --- a/lib/components/SideMenu/side-menu.spec.js +++ b/lib/components/SideMenu/side-menu.spec.js @@ -75,8 +75,22 @@ describe('Redoc components', () => { }); }); - it('should scroll to method when location hash is present', (done) => { - let hash = '#pet/paths/~1pet~1findByStatus/get'; + it('should scroll to method when location hash is present [jp]', (done) => { + let hash = '#tag/pet/paths/~1pet~1findByStatus/get'; + spyOn(component.adapter, '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.adapter, 'getLocation').and.returnValue({hash: hash}); spyOn(component, 'hashScroll').and.callThrough(); spyOn(window, 'scrollTo').and.stub(); @@ -121,8 +135,20 @@ describe('Redoc components', () => { expect(component.data).not.toBeNull(); }); - it('should scroll to method when location hash is present', (done) => { - let hash = '#pet/paths/~1pet~1findByStatus/get'; + it('should scroll to method when location hash is present [jp]', (done) => { + let hash = '#tag/pet/paths/~1pet~1findByStatus/get'; + spyOn(component.adapter, '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.adapter, 'getLocation').and.returnValue({hash: hash}); spyOn(component, 'hashScroll').and.callThrough(); redocEvents.bootstrapped.next(); diff --git a/lib/utils/SchemaManager.js b/lib/utils/SchemaManager.js index 254fd88d..2c11af6a 100644 --- a/lib/utils/SchemaManager.js +++ b/lib/utils/SchemaManager.js @@ -150,7 +150,11 @@ export default class SchemaManager { } if (tagDetails['x-traitTag']) continue; if (!tagDetails.methods) tagDetails.methods = []; - tagDetails.methods.push({pointer: methodPointer, summary: methodSummary}); + tagDetails.methods.push({ + pointer: methodPointer, + summary: methodSummary, + operationId: methodInfo.operationId + }); } } } diff --git a/tests/unit/SchemaManager.spec.js b/tests/unit/SchemaManager.spec.js index 0a2bfbf8..1ec4ec87 100644 --- a/tests/unit/SchemaManager.spec.js +++ b/tests/unit/SchemaManager.spec.js @@ -165,7 +165,7 @@ describe('Utils', () => { info.should.be.an.Object(); info.methods.should.be.an.Array(); for (let methodInfo of info.methods) { - methodInfo.should.have.keys('pointer', 'summary'); + methodInfo.should.have.properties(['pointer', 'summary']); let methSchema = schemaMgr.byPointer(methodInfo.pointer); expect(methSchema).not.toBeNull(); if (methSchema.summary) {