Skip to content

Commit

Permalink
Merge branch 'master' into v0.24-rc
Browse files Browse the repository at this point in the history
Conflicts:
	package.json
	tools/amd/bower.json
  • Loading branch information
mtscout6 committed Jun 16, 2015
2 parents 7fbb7be + be423ae commit 396c024
Show file tree
Hide file tree
Showing 17 changed files with 348 additions and 58 deletions.
2 changes: 2 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
],
"rules": {
"comma-spacing": 2,
"comma-style": [2, "last"],
"one-var": [2, { "initialized": "never" }],
"key-spacing": 0,
"no-underscore-dangle": 0,
"no-unused-vars": [2, { "vars": "all", "args": "none" }],
Expand Down
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
v0.23.4 - Tue, 16 Jun 2015 00:37:04 GMT
---------------------------------------

- [0ce46b9](../../commit/0ce46b9) [changed] only autofocus modals when enforceFocus is true (the default)
- [c5855d2](../../commit/c5855d2) [changed] createChainedFunction to chain many functions, and to throw if non-functions are provided.
- [d18dadb](../../commit/d18dadb) [fixed] container content no longer shifts when overflowing
- [66f0f92](../../commit/66f0f92) [added] enforceFocus prop to Modal
- [3869ca2](../../commit/3869ca2) [fixed] Modal doesn't "jump" when container is overflowing



v0.23.3 - Fri, 12 Jun 2015 21:46:30 GMT
---------------------------------------

Expand Down
4 changes: 3 additions & 1 deletion docs/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ const readmeDest = path.join(docsBuilt, 'README.md');
*/
function generateHTML(fileName) {
return new Promise((resolve, reject) => {
Router.run(routes, '/' + fileName, Handler => {
const urlSlug = fileName === 'index.html' ? '/' : `/${fileName}`;

Router.run(routes, urlSlug, Handler => {
let html = React.renderToString(React.createElement(Handler));
html = '<!doctype html>' + html;
let write = fsp.writeFile(path.join(docsBuilt, fileName), html);
Expand Down
1 change: 0 additions & 1 deletion docs/dev-run
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#!/usr/bin/env babel-node
/* eslint no-process-exit: 0 */
import 'colors';
import portfinder from 'portfinder';
Expand Down
1 change: 1 addition & 0 deletions docs/examples/ModalStatic.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const modalInstance = (
<div className='static-modal'>
<Modal title='Modal title'
enforceFocus={false}
backdrop={false}
animation={false}
container={mountNode}
Expand Down
10 changes: 5 additions & 5 deletions docs/src/ComponentsPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ const ComponentsPage = React.createClass({
},

componentDidMount() {
let elem = React.findDOMNode(this.refs.sideNav),
domUtils = Affix.domUtils,
sideNavOffsetTop = domUtils.getOffset(elem).top,
sideNavMarginTop = parseInt(domUtils.getComputedStyles(elem.firstChild).marginTop, 10),
topNavHeight = React.findDOMNode(this.refs.topNav).offsetHeight;
let elem = React.findDOMNode(this.refs.sideNav);
let domUtils = Affix.domUtils;
let sideNavOffsetTop = domUtils.getOffset(elem).top;
let sideNavMarginTop = parseInt(domUtils.getComputedStyles(elem.firstChild).marginTop, 10);
let topNavHeight = React.findDOMNode(this.refs.topNav).offsetHeight;

this.setState({
navOffsetTop: sideNavOffsetTop - topNavHeight - sideNavMarginTop,
Expand Down
3 changes: 1 addition & 2 deletions docs/src/Routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,10 @@ import NotFoundPage from './NotFoundPage';
import {Route, DefaultRoute, NotFoundRoute} from 'react-router';

export default (
<Route name='app' path='/' handler={Root}>
<Route name='home' path='/' handler={Root}>
<DefaultRoute handler={HomePage}/>
<NotFoundRoute handler={NotFoundPage} />

<Route name='home' path='index.html' handler={HomePage} />
<Route name='introduction' path='introduction.html' handler={IntroductionPage} />
<Route name='getting-started' path='getting-started.html' handler={GettingStartedPage} />
<Route name='components' path='components.html' handler={ComponentsPage} />
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"test": "npm run lint && npm run build && karma start --single-run && _mocha --compilers js:babel-core/register test/server/*Spec.js",
"lint": "eslint ./",
"docs-build": "babel-node tools/build-cli.js --docs-only",
"docs": "docs/dev-run",
"docs": "babel-node docs/dev-run",
"docs-prod": "npm run docs-build && NODE_ENV=production babel-node docs/server.js",
"docs-prod-unoptimized": "npm run docs-build -- --dev && NODE_ENV=production babel-node docs/server.js"
},
Expand Down Expand Up @@ -103,4 +103,4 @@
"babel-runtime": "^5.1.10",
"classnames": "^2.0.0"
}
}
}
6 changes: 3 additions & 3 deletions src/CollapsibleNav.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ const CollapsibleNav = React.createClass({
for (let key in nodes) {
if (nodes.hasOwnProperty(key)) {

let n = React.findDOMNode(nodes[key])
, h = n.offsetHeight
, computedStyles = domUtils.getComputedStyles(n);
let n = React.findDOMNode(nodes[key]);
let h = n.offsetHeight;
let computedStyles = domUtils.getComputedStyles(n);

height += (h +
parseInt(computedStyles.marginTop, 10) +
Expand Down
4 changes: 2 additions & 2 deletions src/FadeMixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ export default {
},

componentWillUnmount() {
let els = getElementsAndSelf(React.findDOMNode(this), ['fade']),
container = (this.props.container && React.findDOMNode(this.props.container)) ||
let els = getElementsAndSelf(React.findDOMNode(this), ['fade']);
let container = (this.props.container && React.findDOMNode(this.props.container)) ||
domUtils.ownerDocument(this).body;

if (els.length) {
Expand Down
169 changes: 154 additions & 15 deletions src/Modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,68 @@ import EventListener from './utils/EventListener';
// - Add `modal-body` div if only one child passed in that doesn't already have it
// - Tests

/**
* Gets the correct clientHeight of the modal container
* when the body/window/document you need to use the docElement clientHeight
* @param {HTMLElement} container
* @param {ReactElement|HTMLElement} context
* @return {Number}
*/
function containerClientHeight(container, context) {
let doc = domUtils.ownerDocument(context);

return (container === doc.body || container === doc.documentElement)
? doc.documentElement.clientHeight
: container.clientHeight;
}

function getContainer(context){
return (context.props.container && React.findDOMNode(context.props.container)) ||
domUtils.ownerDocument(context).body;
}

/**
* Firefox doesn't have a focusin event so using capture is easiest way to get bubbling
* IE8 can't do addEventListener, but does have onfocusin, so we use that in ie8
* @param {ReactElement|HTMLElement} context
* @param {Function} handler
*/
function onFocus(context, handler) {
let doc = domUtils.ownerDocument(context);
let useFocusin = !doc.addEventListener;
let remove;

if (useFocusin) {
document.attachEvent('onfocusin', handler);
remove = () => document.detachEvent('onfocusin', handler);
} else {
document.addEventListener('focus', handler, true);
remove = () => document.removeEventListener('focus', handler, true);
}
return { remove };
}

let scrollbarSize;

if (domUtils.canUseDom) {
let scrollDiv = document.createElement('div');

scrollDiv.style.position = 'absolute';
scrollDiv.style.top = '-9999px';
scrollDiv.style.width = '50px';
scrollDiv.style.height = '50px';
scrollDiv.style.overflow = 'scroll';

document.body.appendChild(scrollDiv);

scrollbarSize = scrollDiv.offsetWidth - scrollDiv.clientWidth;

document.body.removeChild(scrollDiv);
scrollDiv = null;
}

const Modal = React.createClass({

mixins: [BootstrapMixin, FadeMixin],

propTypes: {
Expand All @@ -21,7 +82,8 @@ const Modal = React.createClass({
closeButton: React.PropTypes.bool,
animation: React.PropTypes.bool,
onRequestHide: React.PropTypes.func.isRequired,
dialogClassName: React.PropTypes.string
dialogClassName: React.PropTypes.string,
enforceFocus: React.PropTypes.bool
},

getDefaultProps() {
Expand All @@ -30,13 +92,20 @@ const Modal = React.createClass({
backdrop: true,
keyboard: true,
animation: true,
closeButton: true
closeButton: true,
enforceFocus: true
};
},

getInitialState(){
return { };
},

render() {
let modalStyle = {display: 'block'};
let state = this.state;
let modalStyle = { ...state.dialogStyles, display: 'block'};
let dialogClasses = this.getBsClassSet();

delete dialogClasses.modal;
dialogClasses['modal-dialog'] = true;

Expand Down Expand Up @@ -66,7 +135,7 @@ const Modal = React.createClass({
);

return this.props.backdrop ?
this.renderBackdrop(modal) : modal;
this.renderBackdrop(modal, state.backdropStyles) : modal;
},

renderBackdrop(modal) {
Expand All @@ -91,8 +160,8 @@ const Modal = React.createClass({
let closeButton;
if (this.props.closeButton) {
closeButton = (
<button type="button" className="close" aria-hidden="true" onClick={this.props.onRequestHide}>&times;</button>
);
<button type="button" className="close" aria-hidden="true" onClick={this.props.onRequestHide}>&times;</button>
);
}

return (
Expand All @@ -119,30 +188,63 @@ const Modal = React.createClass({
},

componentDidMount() {
const doc = domUtils.ownerDocument(this);
const win = domUtils.ownerWindow(this);

this._onDocumentKeyupListener =
EventListener.listen(domUtils.ownerDocument(this), 'keyup', this.handleDocumentKeyUp);
EventListener.listen(doc, 'keyup', this.handleDocumentKeyUp);

this._onWindowResizeListener =
EventListener.listen(win, 'resize', this.handleWindowResize);

if (this.props.enforceFocus) {
this._onFocusinListener = onFocus(this, this.enforceFocus);
}

let container = getContainer(this);

let container = (this.props.container && React.findDOMNode(this.props.container)) ||
domUtils.ownerDocument(this).body;
container.className += container.className.length ? ' modal-open' : 'modal-open';

this.focusModalContent();
this._containerIsOverflowing = container.scrollHeight > containerClientHeight(container, this);

this._originalPadding = container.style.paddingRight;

if (this._containerIsOverflowing) {
container.style.paddingRight = parseInt(this._originalPadding || 0, 10) + scrollbarSize + 'px';
}

if (this.props.backdrop) {
this.iosClickHack();
}

this.setState(this._getStyles() //eslint-disable-line react/no-did-mount-set-state
, () => this.focusModalContent());
},

componentDidUpdate(prevProps) {
if (this.props.backdrop && this.props.backdrop !== prevProps.backdrop) {
this.iosClickHack();
this.setState(this._getStyles()); //eslint-disable-line react/no-did-update-set-state
}

if (this.props.container !== prevProps.container) {
let container = getContainer(this);
this._containerIsOverflowing = container.scrollHeight > containerClientHeight(container, this);
}
},

componentWillUnmount() {
this._onDocumentKeyupListener.remove();
let container = (this.props.container && React.findDOMNode(this.props.container)) ||
domUtils.ownerDocument(this).body;
this._onWindowResizeListener.remove();

if (this._onFocusinListener) {
this._onFocusinListener.remove();
}

let container = getContainer(this);

container.style.paddingRight = this._originalPadding;

container.className = container.className.replace(/ ?modal-open/, '');

this.restoreLastFocus();
Expand All @@ -162,17 +264,54 @@ const Modal = React.createClass({
}
},

handleWindowResize() {
this.setState(this._getStyles());
},

focusModalContent () {
this.lastFocus = domUtils.ownerDocument(this).activeElement;
let modalContent = React.findDOMNode(this.refs.modal);
modalContent.focus();
if (this.props.enforceFocus) {
this.lastFocus = domUtils.activeElement(this);

let modalContent = React.findDOMNode(this.refs.modal);
modalContent.focus();
}
},

restoreLastFocus () {
if (this.lastFocus) {
this.lastFocus.focus();
this.lastFocus = null;
}
},

enforceFocus() {
if ( !this.isMounted() ) {
return;
}

let active = domUtils.activeElement(this);
let modal = React.findDOMNode(this.refs.modal);

if (modal !== active && !domUtils.contains(modal, active)){
modal.focus();
}
},

_getStyles() {
if ( !domUtils.canUseDom ) { return {}; }

let node = React.findDOMNode(this.refs.modal);
let scrollHt = node.scrollHeight;
let container = getContainer(this);
let containerIsOverflowing = this._containerIsOverflowing;
let modalIsOverflowing = scrollHt > containerClientHeight(container, this);

return {
dialogStyles: {
paddingRight: containerIsOverflowing && !modalIsOverflowing ? scrollbarSize : void 0,
paddingLeft: !containerIsOverflowing && modalIsOverflowing ? scrollbarSize : void 0
}
};
}
});

Expand Down
6 changes: 3 additions & 3 deletions src/Nav.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ const Nav = React.createClass({
},

getCollapsibleDimensionValue() {
let node = React.findDOMNode(this.refs.ul),
height = node.offsetHeight,
computedStyles = domUtils.getComputedStyles(node);
let node = React.findDOMNode(this.refs.ul);
let height = node.offsetHeight;
let computedStyles = domUtils.getComputedStyles(node);

return height + parseInt(computedStyles.marginTop, 10) + parseInt(computedStyles.marginBottom, 10);
},
Expand Down
Loading

0 comments on commit 396c024

Please sign in to comment.