mirror of
https://github.com/Redocly/redoc.git
synced 2024-11-26 02:23:43 +03:00
options and options parsing mechanism
This commit is contained in:
parent
7bbe43e195
commit
db8f9e8a96
|
@ -12,7 +12,7 @@
|
||||||
</nav>
|
</nav>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<redoc scroll-y-offset='50'>
|
<redoc scroll-y-offset="50">
|
||||||
Loading...
|
Loading...
|
||||||
</redoc>
|
</redoc>
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import {BrowserDomAdapter} from 'angular2/platform/browser';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'sticky-sidebar',
|
selector: 'sticky-sidebar',
|
||||||
inputs: ['scrollParent', 'scrollOffsetY']
|
inputs: ['scrollParent', 'scrollYOffset']
|
||||||
})
|
})
|
||||||
@View({
|
@View({
|
||||||
template: `
|
template: `
|
||||||
|
@ -37,7 +37,7 @@ export default class StickySidebar {
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePosition() {
|
updatePosition() {
|
||||||
if ( this.scrollY + this.scrollOffsetY >= this.redocEl.offsetTop) {
|
if ( this.scrollY + this.scrollYOffset >= this.redocEl.offsetTop) {
|
||||||
this.stick();
|
this.stick();
|
||||||
} else {
|
} else {
|
||||||
this.unstick();
|
this.unstick();
|
||||||
|
@ -46,7 +46,7 @@ export default class StickySidebar {
|
||||||
|
|
||||||
stick() {
|
stick() {
|
||||||
this.adapter.setStyle(this.element, 'position', 'fixed');
|
this.adapter.setStyle(this.element, 'position', 'fixed');
|
||||||
this.adapter.setStyle(this.element, 'top', this.scrollOffsetY);
|
this.adapter.setStyle(this.element, 'top', this.scrollYOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
unstick() {
|
unstick() {
|
||||||
|
@ -60,7 +60,7 @@ export default class StickySidebar {
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.redocEl = this.element.offsetParent;
|
this.redocEl = this.element.offsetParent;
|
||||||
this.scrollOffsetY = parseInt(this.scrollOffsetY);
|
this.scrollYOffset = parseInt(this.scrollYOffset);
|
||||||
this.bind();
|
this.bind();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ describe('Common components', () => {
|
||||||
expect(component.stick).not.toHaveBeenCalled();
|
expect(component.stick).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should stick if scrolled more than scrollOffsetY', () => {
|
it('should stick if scrolled more than scrollYOffset', () => {
|
||||||
spyOn(component, 'stick').and.callThrough();
|
spyOn(component, 'stick').and.callThrough();
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
window.scrollY = 40;
|
window.scrollY = 40;
|
||||||
|
@ -65,7 +65,7 @@ describe('Common components', () => {
|
||||||
`<div style="padding-top: 20px">
|
`<div style="padding-top: 20px">
|
||||||
<div style="height: 20px; position: fixed; top: 0;"> </div>
|
<div style="height: 20px; position: fixed; top: 0;"> </div>
|
||||||
<div style="position: relative">
|
<div style="position: relative">
|
||||||
<sticky-sidebar [scrollParent]="options.scrollParent" [scrollOffsetY]="options.scrollOffsetY">
|
<sticky-sidebar [scrollParent]="scrollParent" [scrollYOffset]="options.scrollYOffset">
|
||||||
</sticky-sidebar>
|
</sticky-sidebar>
|
||||||
</div>
|
</div>
|
||||||
</div>`
|
</div>`
|
||||||
|
@ -74,7 +74,7 @@ describe('Common components', () => {
|
||||||
class TestApp {
|
class TestApp {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.options = {};
|
this.options = {};
|
||||||
this.options.scrollParent = window;
|
this.scrollParent = window;
|
||||||
this.options.scrollOffsetY = 20;
|
this.options.scrollYOffset = 20;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<div class="redoc-wrap">
|
<div class="redoc-wrap">
|
||||||
<sticky-sidebar [scrollParent]="options.scrollParent" [scrollOffsetY]="options.scrollOffsetTop">
|
<sticky-sidebar [scrollParent]="scrollParent" [scrollYOffset]="options.scrollYOffset">
|
||||||
<api-logo> </api-logo>
|
<api-logo> </api-logo>
|
||||||
<side-menu> </side-menu>
|
<side-menu> </side-menu>
|
||||||
</sticky-sidebar>
|
</sticky-sidebar>
|
||||||
|
|
|
@ -8,12 +8,14 @@ import ApiLogo from '../ApiLogo/api-logo';
|
||||||
import MethodsList from '../MethodsList/methods-list';
|
import MethodsList from '../MethodsList/methods-list';
|
||||||
import SideMenu from '../SideMenu/side-menu';
|
import SideMenu from '../SideMenu/side-menu';
|
||||||
import StickySidebar from '../../common/components/StickySidebar/sticky-sidebar';
|
import StickySidebar from '../../common/components/StickySidebar/sticky-sidebar';
|
||||||
|
import {options as defaultOptions} from '../../index';
|
||||||
|
|
||||||
import {ChangeDetectionStrategy} from 'angular2/core';
|
import {ChangeDetectionStrategy} from 'angular2/core';
|
||||||
import {ElementRef} from 'angular2/core';
|
import {ElementRef} from 'angular2/core';
|
||||||
import {BrowserDomAdapter} from 'angular2/platform/browser';
|
import {BrowserDomAdapter} from 'angular2/platform/browser';
|
||||||
import detectScollParent from 'scrollparent';
|
import detectScollParent from 'scrollparent';
|
||||||
|
|
||||||
|
let optionNames = new Set(['scrollYOffset']);
|
||||||
|
|
||||||
@RedocComponent({
|
@RedocComponent({
|
||||||
selector: 'redoc',
|
selector: 'redoc',
|
||||||
|
@ -24,20 +26,39 @@ import detectScollParent from 'scrollparent';
|
||||||
changeDetection: ChangeDetectionStrategy.Default
|
changeDetection: ChangeDetectionStrategy.Default
|
||||||
})
|
})
|
||||||
export default class Redoc extends BaseComponent {
|
export default class Redoc extends BaseComponent {
|
||||||
constructor(schemaMgr, elementRef) {
|
constructor(schemaMgr, elementRef, dom) {
|
||||||
super(schemaMgr);
|
super(schemaMgr);
|
||||||
this.element = elementRef.nativeElement;
|
this.element = elementRef.nativeElement;
|
||||||
|
|
||||||
let DOM = new BrowserDomAdapter();
|
this.dom = dom;
|
||||||
let el = this.element;
|
let el = this.element;
|
||||||
this.options = {};
|
|
||||||
|
|
||||||
//parse options (top level component doesn't support inputs)
|
//parse options (top level component doesn't support inputs)
|
||||||
this.options.scrollParent = detectScollParent(el);
|
this.scrollParent = detectScollParent(el);
|
||||||
this.options.scrollOffsetTop = parseInt(DOM.getAttribute(el, 'scroll-y-offset')) || 0;
|
this.parseOptions();
|
||||||
|
this.options = Object.assign({}, defaultOptions, this.options);
|
||||||
|
}
|
||||||
|
|
||||||
|
parseOptions() {
|
||||||
|
let attributesMap = this.dom.attributeMap(this.element);
|
||||||
|
this.options = {};
|
||||||
|
Array.from(attributesMap.keys())
|
||||||
|
//camelCasify
|
||||||
|
.map(k => ({
|
||||||
|
attrName: k,
|
||||||
|
name: k.replace(/-(.)/g, (m, $1) => $1.toUpperCase())
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.filter(option => optionNames.has(option.name))
|
||||||
|
.forEach(option => {
|
||||||
|
this.options[option.name] = attributesMap.get(option.attrName);
|
||||||
|
});
|
||||||
|
|
||||||
|
// post-process options
|
||||||
|
this.options.scrollYOffset = parseInt(this.options.scrollYOffset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Redoc.parameters = Redoc.parameters.concat([[ElementRef]]);
|
Redoc.parameters = Redoc.parameters.concat([[ElementRef], [BrowserDomAdapter]]);
|
||||||
|
|
||||||
// this doesn't work in side-menu.js because of some circular references issue
|
// this doesn't work in side-menu.js because of some circular references issue
|
||||||
SideMenu.parameters = SideMenu.parameters.concat([[Redoc]]);
|
SideMenu.parameters = SideMenu.parameters.concat([[Redoc]]);
|
||||||
|
|
|
@ -49,8 +49,7 @@ describe('Redoc components', () => {
|
||||||
builder.createAsync(TestApp).then(fixture => {
|
builder.createAsync(TestApp).then(fixture => {
|
||||||
let component = getChildDebugElement(fixture.debugElement, 'redoc').componentInstance;
|
let component = getChildDebugElement(fixture.debugElement, 'redoc').componentInstance;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
console.log(component.options.scrollOffsetTop);
|
component.options.scrollYOffset.should.be.equal(50);
|
||||||
component.options.scrollOffsetTop.should.be.equal(50);
|
|
||||||
fixture.destroy();
|
fixture.destroy();
|
||||||
done();
|
done();
|
||||||
}, err => done.fail(err));
|
}, err => done.fail(err));
|
||||||
|
|
|
@ -33,7 +33,7 @@ export default class SideMenu extends BaseComponent {
|
||||||
this.adapter = adapter;
|
this.adapter = adapter;
|
||||||
this.redoc = redoc;
|
this.redoc = redoc;
|
||||||
|
|
||||||
this.scrollParent = this.redoc.options.scrollParent;
|
this.scrollParent = this.redoc.scrollParent;
|
||||||
|
|
||||||
// for some reason constructor is not run inside zone
|
// for some reason constructor is not run inside zone
|
||||||
// as workaround running it manually
|
// as workaround running it manually
|
||||||
|
@ -65,7 +65,7 @@ export default class SideMenu extends BaseComponent {
|
||||||
|
|
||||||
bindEvents() {
|
bindEvents() {
|
||||||
this.prevOffsetY = this.scrollY();
|
this.prevOffsetY = this.scrollY();
|
||||||
this.scrollOffsetY = this.redoc.options.scrollOffsetTop || 0;
|
this.scrollYOffset = this.redoc.options.scrollYOffset;
|
||||||
this._cancel = {};
|
this._cancel = {};
|
||||||
this._cancel.scroll = this.adapter.onAndCancel(this.scrollParent, 'scroll', () => { this.scrollHandler(); });
|
this._cancel.scroll = this.adapter.onAndCancel(this.scrollParent, 'scroll', () => { this.scrollHandler(); });
|
||||||
this._cancel.hash = this.adapter.onAndCancel(global, 'hashchange', evt => this.hashScroll(evt));
|
this._cancel.hash = this.adapter.onAndCancel(global, 'hashchange', evt => this.hashScroll(evt));
|
||||||
|
@ -84,7 +84,7 @@ export default class SideMenu extends BaseComponent {
|
||||||
scrollTo(el) {
|
scrollTo(el) {
|
||||||
// TODO: rewrite this to use offsetTop as more reliable solution
|
// TODO: rewrite this to use offsetTop as more reliable solution
|
||||||
let subjRect = el.getBoundingClientRect();
|
let subjRect = el.getBoundingClientRect();
|
||||||
let offset = this.scrollY() + subjRect.top - this.scrollOffsetY + 1;
|
let offset = this.scrollY() + subjRect.top - this.scrollYOffset + 1;
|
||||||
if (this.scrollParent.scrollTo) {
|
if (this.scrollParent.scrollTo) {
|
||||||
this.scrollParent.scrollTo(0, offset);
|
this.scrollParent.scrollTo(0, offset);
|
||||||
} else {
|
} else {
|
||||||
|
@ -162,11 +162,11 @@ export default class SideMenu extends BaseComponent {
|
||||||
|
|
||||||
/* returns 1 if element if above the view, 0 if in view and -1 below the view */
|
/* returns 1 if element if above the view, 0 if in view and -1 below the view */
|
||||||
getElementInViewPos(el) {
|
getElementInViewPos(el) {
|
||||||
if (Math.floor(el.getBoundingClientRect().top) > this.scrollOffsetY) {
|
if (Math.floor(el.getBoundingClientRect().top) > this.scrollYOffset) {
|
||||||
return INVIEW_POSITION.ABOVE;
|
return INVIEW_POSITION.ABOVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (el.getBoundingClientRect().bottom <= this.scrollOffsetY) {
|
if (el.getBoundingClientRect().bottom <= this.scrollYOffset) {
|
||||||
return INVIEW_POSITION.BELLOW;
|
return INVIEW_POSITION.BELLOW;
|
||||||
}
|
}
|
||||||
return INVIEW_POSITION.INVIEW;
|
return INVIEW_POSITION.INVIEW;
|
||||||
|
|
|
@ -20,9 +20,9 @@ import SchemaManager from 'lib/utils/SchemaManager';
|
||||||
|
|
||||||
let _mockRedoc = {
|
let _mockRedoc = {
|
||||||
options: {
|
options: {
|
||||||
scrollOffsetTop: 0,
|
scrollYOffset: 0
|
||||||
|
},
|
||||||
scrollParent: window
|
scrollParent: window
|
||||||
}
|
|
||||||
};
|
};
|
||||||
describe('Redoc components', () => {
|
describe('Redoc components', () => {
|
||||||
describe('SideMenu Component', () => {
|
describe('SideMenu Component', () => {
|
||||||
|
|
|
@ -6,7 +6,9 @@ import SchemaManager from './utils/SchemaManager';
|
||||||
import {redocEvents} from './events';
|
import {redocEvents} from './events';
|
||||||
export * from './components/index';
|
export * from './components/index';
|
||||||
|
|
||||||
|
export var options = {
|
||||||
|
scrollYOffset: 0
|
||||||
|
};
|
||||||
|
|
||||||
export function init(schemaUrl) {
|
export function init(schemaUrl) {
|
||||||
var promise = new Promise(function(resolve, reject) {
|
var promise = new Promise(function(resolve, reject) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user