mirror of
https://github.com/Redocly/redoc.git
synced 2024-12-01 21:03:45 +03:00
make scrollYOffset option consume selector and function
This commit is contained in:
parent
db8f9e8a96
commit
1c4a3ca20f
|
@ -12,7 +12,7 @@
|
||||||
</nav>
|
</nav>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<redoc scroll-y-offset="50">
|
<redoc scroll-y-offset="body > nav">
|
||||||
Loading...
|
Loading...
|
||||||
</redoc>
|
</redoc>
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ export default class StickySidebar {
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePosition() {
|
updatePosition() {
|
||||||
if ( this.scrollY + this.scrollYOffset >= 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.scrollYOffset);
|
this.adapter.setStyle(this.element, 'top', this.scrollYOffset());
|
||||||
}
|
}
|
||||||
|
|
||||||
unstick() {
|
unstick() {
|
||||||
|
@ -60,7 +60,6 @@ export default class StickySidebar {
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.redocEl = this.element.offsetParent;
|
this.redocEl = this.element.offsetParent;
|
||||||
this.scrollYOffset = parseInt(this.scrollYOffset);
|
|
||||||
this.bind();
|
this.bind();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,6 @@ class TestApp {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.options = {};
|
this.options = {};
|
||||||
this.scrollParent = window;
|
this.scrollParent = window;
|
||||||
this.options.scrollYOffset = 20;
|
this.options.scrollYOffset = () => 20;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,13 +8,15 @@ 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 {options as defaultOptions} from '../../options';
|
||||||
|
|
||||||
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';
|
||||||
|
|
||||||
|
import {isFunction} from 'angular2/src/facade/lang';
|
||||||
|
|
||||||
let optionNames = new Set(['scrollYOffset']);
|
let optionNames = new Set(['scrollYOffset']);
|
||||||
|
|
||||||
@RedocComponent({
|
@RedocComponent({
|
||||||
|
@ -37,6 +39,7 @@ export default class Redoc extends BaseComponent {
|
||||||
this.scrollParent = detectScollParent(el);
|
this.scrollParent = detectScollParent(el);
|
||||||
this.parseOptions();
|
this.parseOptions();
|
||||||
this.options = Object.assign({}, defaultOptions, this.options);
|
this.options = Object.assign({}, defaultOptions, this.options);
|
||||||
|
this.normalizeOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
parseOptions() {
|
parseOptions() {
|
||||||
|
@ -53,9 +56,28 @@ export default class Redoc extends BaseComponent {
|
||||||
.forEach(option => {
|
.forEach(option => {
|
||||||
this.options[option.name] = attributesMap.get(option.attrName);
|
this.options[option.name] = attributesMap.get(option.attrName);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// post-process options
|
normalizeOptions() {
|
||||||
this.options.scrollYOffset = parseInt(this.options.scrollYOffset);
|
// modify scrollYOffset to always be a function
|
||||||
|
if (!isFunction(this.options.scrollYOffset)) {
|
||||||
|
if (isFinite(this.options.scrollYOffset)) {
|
||||||
|
// if number specified create function that returns this value
|
||||||
|
let numberOffset = parseFloat(this.options.scrollYOffset);
|
||||||
|
this.options.scrollYOffset = () => numberOffset;
|
||||||
|
} else {
|
||||||
|
// if selector or node function that returns bottom offset of this node
|
||||||
|
let el = this.options.scrollYOffset;
|
||||||
|
if (!(el instanceof Node)) {
|
||||||
|
el = this.dom.query(el);
|
||||||
|
}
|
||||||
|
if (!el) {
|
||||||
|
this.options.scrollYOffset = () => 0;
|
||||||
|
} else {
|
||||||
|
this.options.scrollYOffset = () => el.offsetTop + el.offsetHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Redoc.parameters = Redoc.parameters.concat([[ElementRef], [BrowserDomAdapter]]);
|
Redoc.parameters = Redoc.parameters.concat([[ElementRef], [BrowserDomAdapter]]);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import { getChildDebugElement } from 'tests/helpers';
|
import { getChildDebugElement } from 'tests/helpers';
|
||||||
import {Component, View, provide} from 'angular2/core';
|
import {Component, View, ViewMetadata, provide} from 'angular2/core';
|
||||||
import {BrowserDomAdapter} from 'angular2/platform/browser';
|
import {BrowserDomAdapter} from 'angular2/platform/browser';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -14,6 +14,7 @@ import {
|
||||||
|
|
||||||
import Redoc from 'lib/components/Redoc/redoc';
|
import Redoc from 'lib/components/Redoc/redoc';
|
||||||
import SchemaManager from 'lib/utils/SchemaManager';
|
import SchemaManager from 'lib/utils/SchemaManager';
|
||||||
|
import {options} from 'lib/options';
|
||||||
|
|
||||||
describe('Redoc components', () => {
|
describe('Redoc components', () => {
|
||||||
describe('Redoc Component', () => {
|
describe('Redoc Component', () => {
|
||||||
|
@ -45,14 +46,60 @@ describe('Redoc components', () => {
|
||||||
}, err => done.fail(err));
|
}, err => done.fail(err));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should parse component options from host element', (done) => {
|
describe('Options', () => {
|
||||||
builder.createAsync(TestApp).then(fixture => {
|
let component;
|
||||||
let component = getChildDebugElement(fixture.debugElement, 'redoc').componentInstance;
|
let fixture;
|
||||||
fixture.detectChanges();
|
|
||||||
component.options.scrollYOffset.should.be.equal(50);
|
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();
|
fixture.destroy();
|
||||||
done();
|
});
|
||||||
}, err => done.fail(err));
|
|
||||||
|
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) => {
|
||||||
|
options.scrollYOffset = () => 123;
|
||||||
|
build(`<redoc></redoc>`, err => {
|
||||||
|
if (err) return done.fail(err);
|
||||||
|
component.options.scrollYOffset().should.be.equal(123);
|
||||||
|
options.scrollYOffset = 0;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -62,7 +109,7 @@ describe('Redoc components', () => {
|
||||||
@View({
|
@View({
|
||||||
directives: [Redoc],
|
directives: [Redoc],
|
||||||
template:
|
template:
|
||||||
`<redoc scroll-y-offset="50"></redoc>`
|
`<redoc></redoc>`
|
||||||
})
|
})
|
||||||
class TestApp {
|
class TestApp {
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.scrollYOffset + 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.scrollYOffset) {
|
if (Math.floor(el.getBoundingClientRect().top) > this.scrollYOffset()) {
|
||||||
return INVIEW_POSITION.ABOVE;
|
return INVIEW_POSITION.ABOVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (el.getBoundingClientRect().bottom <= this.scrollYOffset) {
|
if (el.getBoundingClientRect().bottom <= this.scrollYOffset()) {
|
||||||
return INVIEW_POSITION.BELLOW;
|
return INVIEW_POSITION.BELLOW;
|
||||||
}
|
}
|
||||||
return INVIEW_POSITION.INVIEW;
|
return INVIEW_POSITION.INVIEW;
|
||||||
|
|
|
@ -20,7 +20,7 @@ import SchemaManager from 'lib/utils/SchemaManager';
|
||||||
|
|
||||||
let _mockRedoc = {
|
let _mockRedoc = {
|
||||||
options: {
|
options: {
|
||||||
scrollYOffset: 0
|
scrollYOffset: () => 0
|
||||||
},
|
},
|
||||||
scrollParent: window
|
scrollParent: window
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,10 +6,6 @@ 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) {
|
||||||
|
|
||||||
|
|
5
lib/options.js
Normal file
5
lib/options.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
export var options = {
|
||||||
|
scrollYOffset: 0
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user