diff options
author | Samy Pessé <samypesse@gmail.com> | 2016-12-22 10:18:38 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-12-22 10:18:38 +0100 |
commit | 194ebc3da9641ff96f083f9d8ab43c2d27944f9a (patch) | |
tree | c50988f32ccf18df93ae7ab40be78e9459642818 /packages/gitbook-plugin-theme-default/src/components/Body.js | |
parent | 64ccb6b00b4b63fa0e516d4e35351275b34f8c07 (diff) | |
parent | 16af264360e48e8a833e9efa9ab8d194574dbc70 (diff) | |
download | gitbook-194ebc3da9641ff96f083f9d8ab43c2d27944f9a.zip gitbook-194ebc3da9641ff96f083f9d8ab43c2d27944f9a.tar.gz gitbook-194ebc3da9641ff96f083f9d8ab43c2d27944f9a.tar.bz2 |
Merge pull request #1543 from GitbookIO/dream
React for rendering website with plugins
Diffstat (limited to 'packages/gitbook-plugin-theme-default/src/components/Body.js')
-rw-r--r-- | packages/gitbook-plugin-theme-default/src/components/Body.js | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/packages/gitbook-plugin-theme-default/src/components/Body.js b/packages/gitbook-plugin-theme-default/src/components/Body.js new file mode 100644 index 0000000..c61a2f3 --- /dev/null +++ b/packages/gitbook-plugin-theme-default/src/components/Body.js @@ -0,0 +1,121 @@ +const debounce = require('debounce'); +const GitBook = require('gitbook-core'); +const { React } = GitBook; + +const Page = require('./Page'); +const Toolbar = require('./Toolbar'); + +const HEADINGS_SELECTOR = 'h1[id],h2[id],h3[id],h4[id]'; + +/** + * Get offset of an element relative to a parent container. + * @param {DOMElement} container + * @param {DOMElement} element + * @return {Number} offset + */ +function getOffset(container, element, type = 'Top') { + const parent = element.parentElement; + let base = 0; + + if (parent != container) { + base = getOffset(container, parent, type); + } + + return base + element[`offset${type}`]; +} + +/** + * Find the current heading anchor for a scroll position. + * @param {DOMElement} container + * @param {Number} top + * @return {String} + */ +function getHeadingID(container, top) { + let id; + const headings = container.querySelectorAll(HEADINGS_SELECTOR); + + headings.forEach(heading => { + if (id) { + return; + } + + const offset = getOffset(container, heading); + + if (offset > top) { + id = heading.getAttribute('id'); + } + }); + + return id; +} + +const Body = React.createClass({ + propTypes: { + page: GitBook.PropTypes.Page, + readme: GitBook.PropTypes.Readme, + history: GitBook.PropTypes.History, + updateURI: React.PropTypes.func + }, + + getInitialState() { + this.debouncedOnScroll = debounce(this.onScroll, 300); + return {}; + }, + + /** + * User is scrolling the page, update the location with current section's ID. + */ + onScroll() { + const { scrollContainer } = this; + const { history, updateURI } = this.props; + const { location } = history; + + // Find the id matching the current scroll position + const hash = getHeadingID(scrollContainer, scrollContainer.scrollTop); + + // Update url if changed + if (hash !== location.hash) { + updateURI(location.merge({ hash })); + } + }, + + /** + * Component has been updated with a new location, + * scroll to the right anchor. + */ + componentDidUpdate() { + + }, + + render() { + const { page, readme } = this.props; + + return ( + <GitBook.InjectedComponent matching={{ role: 'body:wrapper' }}> + <div + className="Body page-wrapper" + onScroll={this.debouncedOnScroll} + ref={div => this.scrollContainer = div} + > + <GitBook.InjectedComponent matching={{ role: 'toolbar:wrapper' }}> + <Toolbar title={page.title} readme={readme} /> + </GitBook.InjectedComponent> + <GitBook.InjectedComponent matching={{ role: 'page:wrapper' }}> + <Page page={page} /> + </GitBook.InjectedComponent> + </div> + </GitBook.InjectedComponent> + ); + } +}); + +module.exports = GitBook.connect(Body, + () => { + return {}; + }, + ({ History }, dispatch) => { + return { + updateURI: (location) => dispatch(History.replace(location)) + }; + } +); |