Merge pull request #678 from mattermost/mm-1589

PLT-171 MM-1589 New add channel modal using react-bootstrap.
Этот коммит содержится в:
Corey Hulen
2015-09-14 16:57:54 -07:00
родитель c447db6e78 0ea0233c50
Коммит bfebb41bc0
27 изменённых файлов: 18348 добавлений и 625 удалений

Просмотреть файл

@@ -78,9 +78,10 @@ travis:
mv $(DIST_PATH)/web/static/js/bundle.min.js $(DIST_PATH)/web/static/js/bundle-$(BUILD_NUMBER).min.js mv $(DIST_PATH)/web/static/js/bundle.min.js $(DIST_PATH)/web/static/js/bundle-$(BUILD_NUMBER).min.js
@sed -i'.bak' 's|react-with-addons-0.13.1.js|react-with-addons-0.13.1.min.js|g' $(DIST_PATH)/web/templates/head.html @sed -i'.bak' 's|react-with-addons-0.13.3.js|react-with-addons-0.13.3.min.js|g' $(DIST_PATH)/web/templates/head.html
@sed -i'.bak' 's|jquery-1.11.1.js|jquery-1.11.1.min.js|g' $(DIST_PATH)/web/templates/head.html @sed -i'.bak' 's|jquery-1.11.1.js|jquery-1.11.1.min.js|g' $(DIST_PATH)/web/templates/head.html
@sed -i'.bak' 's|bootstrap-3.3.1.js|bootstrap-3.3.1.min.js|g' $(DIST_PATH)/web/templates/head.html @sed -i'.bak' 's|bootstrap-3.3.5.js|bootstrap-3.3.5.min.js|g' $(DIST_PATH)/web/templates/head.html
@sed -i'.bak' 's|react-bootstrap-0.25.1.js|react-bootstrap-0.25.1.min.js|g' $(DIST_PATH)/web/templates/head.html
@sed -i'.bak' 's|perfect-scrollbar.js|perfect-scrollbar.min.js|g' $(DIST_PATH)/web/templates/head.html @sed -i'.bak' 's|perfect-scrollbar.js|perfect-scrollbar.min.js|g' $(DIST_PATH)/web/templates/head.html
@sed -i'.bak' 's|bundle.js|bundle-$(BUILD_NUMBER).min.js|g' $(DIST_PATH)/web/templates/head.html @sed -i'.bak' 's|bundle.js|bundle-$(BUILD_NUMBER).min.js|g' $(DIST_PATH)/web/templates/head.html
rm $(DIST_PATH)/web/templates/*.bak rm $(DIST_PATH)/web/templates/*.bak
@@ -231,9 +232,10 @@ dist: install
mv $(DIST_PATH)/web/static/js/bundle.min.js $(DIST_PATH)/web/static/js/bundle-$(BUILD_NUMBER).min.js mv $(DIST_PATH)/web/static/js/bundle.min.js $(DIST_PATH)/web/static/js/bundle-$(BUILD_NUMBER).min.js
@sed -i'.bak' 's|react-with-addons-0.13.1.js|react-with-addons-0.13.1.min.js|g' $(DIST_PATH)/web/templates/head.html @sed -i'.bak' 's|react-with-addons-0.13.3.js|react-with-addons-0.13.3.min.js|g' $(DIST_PATH)/web/templates/head.html
@sed -i'.bak' 's|jquery-1.11.1.js|jquery-1.11.1.min.js|g' $(DIST_PATH)/web/templates/head.html @sed -i'.bak' 's|jquery-1.11.1.js|jquery-1.11.1.min.js|g' $(DIST_PATH)/web/templates/head.html
@sed -i'.bak' 's|bootstrap-3.3.1.js|bootstrap-3.3.1.min.js|g' $(DIST_PATH)/web/templates/head.html @sed -i'.bak' 's|bootstrap-3.3.5.js|bootstrap-3.3.5.min.js|g' $(DIST_PATH)/web/templates/head.html
@sed -i'.bak' 's|react-bootstrap-0.25.1.js|react-bootstrap-0.25.1.min.js|g' $(DIST_PATH)/web/templates/head.html
@sed -i'.bak' 's|perfect-scrollbar.js|perfect-scrollbar.min.js|g' $(DIST_PATH)/web/templates/head.html @sed -i'.bak' 's|perfect-scrollbar.js|perfect-scrollbar.min.js|g' $(DIST_PATH)/web/templates/head.html
@sed -i'.bak' 's|bundle.js|bundle-$(BUILD_NUMBER).min.js|g' $(DIST_PATH)/web/templates/head.html @sed -i'.bak' 's|bundle.js|bundle-$(BUILD_NUMBER).min.js|g' $(DIST_PATH)/web/templates/head.html
rm $(DIST_PATH)/web/templates/*.bak rm $(DIST_PATH)/web/templates/*.bak

Просмотреть файл

@@ -18,7 +18,8 @@
"es6": true "es6": true
}, },
"globals": { "globals": {
"React": false "React": false,
"ReactBootstrap": false
}, },
"rules": { "rules": {
"comma-dangle": [2, "never"], "comma-dangle": [2, "never"],

177
web/react/components/change_url_modal.jsx Обычный файл
Просмотреть файл

@@ -0,0 +1,177 @@
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
// See License.txt for license information.
var Modal = ReactBootstrap.Modal;
var Utils = require('../utils/utils.jsx');
export default class ChangeUrlModal extends React.Component {
constructor(props) {
super(props);
this.onURLChanged = this.onURLChanged.bind(this);
this.doSubmit = this.doSubmit.bind(this);
this.doCancel = this.doCancel.bind(this);
this.state = {
currentURL: props.currentURL,
urlError: '',
userEdit: false
};
}
componentWillReceiveProps(nextProps) {
// This check prevents the url being deleted when we re-render
// because of user status check
if (!this.state.userEdit) {
this.setState({
currentURL: nextProps.currentURL
});
}
}
componentDidUpdate(prevProps) {
if (this.props.show === true && prevProps.show === false) {
React.findDOMNode(this.refs.urlinput).select();
}
}
onURLChanged(e) {
const url = e.target.value.trim();
this.setState({currentURL: url.replace(/[^A-Za-z0-9-_]/g, '').toLowerCase(), userEdit: true});
}
getURLError(url) {
let error = []; //eslint-disable-line prefer-const
if (url.length < 2) {
error.push(<span key='error1'>{'Must be longer than two characters'}<br/></span>);
}
if (url.charAt(0) === '-' || url.charAt(0) === '_') {
error.push(<span key='error2'>{'Must start with a letter or number'}<br/></span>);
}
if (url.length > 1 && (url.charAt(url.length - 1) === '-' || url.charAt(url.length - 1) === '_')) {
error.push(<span key='error3'>{'Must end with a letter or number'}<br/></span>);
}
if (url.indexOf('__') > -1) {
error.push(<span key='error4'>{'Can not contain two underscores in a row.'}<br/></span>);
}
// In case of error we don't detect
if (error.length === 0) {
error.push(<span key='errorlast'>{'Invalid URL'}<br/></span>);
}
return error;
}
doSubmit(e) {
e.preventDefault();
const url = React.findDOMNode(this.refs.urlinput).value;
const cleanedURL = Utils.cleanUpUrlable(url);
if (cleanedURL !== url || url.length < 2 || url.indexOf('__') > -1) {
this.setState({urlError: this.getURLError(url)});
return;
}
this.setState({urlError: '', userEdit: false});
this.props.onModalSubmit(url);
}
doCancel() {
this.setState({urlError: '', userEdit: false});
this.props.onModalDismissed();
}
render() {
let urlClass = 'input-group input-group--limit';
let urlError = null;
let serverError = null;
if (this.state.urlError) {
urlClass += ' has-error';
urlError = (<p className='input__help error'>{this.state.urlError}</p>);
}
if (this.props.serverError) {
serverError = <div className='form-group has-error'><p className='input__help error'>{this.props.serverError}</p></div>;
}
const fullTeamUrl = Utils.getTeamURLFromAddressBar();
const teamURL = Utils.getShortenedTeamURL();
return (
<Modal
show={this.props.show}
onHide={this.doCancel}
>
<Modal.Header closeButton={true}>
<Modal.Title>{this.props.title}</Modal.Title>
</Modal.Header>
<form
role='form'
className='form-horizontal'
>
<Modal.Body>
<div className='modal-intro'>{this.props.description}</div>
<div className='form-group'>
<label className='col-sm-2 form__label control-label'>{this.props.urlLabel}</label>
<div className='col-sm-10'>
<div className={urlClass}>
<span
data-toggle='tooltip'
title={fullTeamUrl}
className='input-group-addon'
>
{teamURL}
</span>
<input
type='text'
ref='urlinput'
className='form-control'
maxLength='22'
onChange={this.onURLChanged}
value={this.state.currentURL}
autoFocus={true}
tabIndex='1'
/>
</div>
{urlError}
{serverError}
</div>
</div>
</Modal.Body>
<Modal.Footer>
<button
type='button'
className='btn btn-default'
onClick={this.doCancel}
>
{'Close'}
</button>
<button
onClick={this.doSubmit}
type='submit'
className='btn btn-primary'
tabIndex='2'
>
{this.props.submitButtonText}
</button>
</Modal.Footer>
</form>
</Modal>
);
}
}
ChangeUrlModal.defaultProps = {
show: false,
title: 'Change URL',
desciption: '',
urlLabel: 'URL',
submitButtonText: 'Submit',
currentURL: '',
serverError: ''
};
ChangeUrlModal.propTypes = {
show: React.PropTypes.bool.isRequired,
title: React.PropTypes.string,
description: React.PropTypes.string,
urlLabel: React.PropTypes.string,
submitButtonText: React.PropTypes.string,
currentURL: React.PropTypes.string,
serverError: React.PropTypes.string,
onModalSubmit: React.PropTypes.func.isRequired,
onModalDismissed: React.PropTypes.func.isRequired
};

Просмотреть файл

@@ -52,7 +52,7 @@ export default class FileUpload extends React.Component {
} }
// generate a unique id that can be used by other components to refer back to this upload // generate a unique id that can be used by other components to refer back to this upload
var clientId = utils.generateId(); let clientId = utils.generateId();
// prepare data to be uploaded // prepare data to be uploaded
var formData = new FormData(); var formData = new FormData();

Просмотреть файл

@@ -1,211 +0,0 @@
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
// See License.txt for license information.
var utils = require('../utils/utils.jsx');
var client = require('../utils/client.jsx');
var asyncClient = require('../utils/async_client.jsx');
var UserStore = require('../stores/user_store.jsx');
export default class NewChannelModal extends React.Component {
constructor() {
super();
this.handleSubmit = this.handleSubmit.bind(this);
this.displayNameKeyUp = this.displayNameKeyUp.bind(this);
this.handleClose = this.handleClose.bind(this);
this.state = {channelType: ''};
}
handleSubmit(e) {
e.preventDefault();
var channel = {};
var state = {serverError: ''};
channel.display_name = React.findDOMNode(this.refs.display_name).value.trim();
if (!channel.display_name) {
state.displayNameError = 'This field is required';
state.inValid = true;
} else if (channel.display_name.length > 22) {
state.displayNameError = 'This field must be less than 22 characters';
state.inValid = true;
} else {
state.displayNameError = '';
}
channel.name = React.findDOMNode(this.refs.channel_name).value.trim();
if (!channel.name) {
state.nameError = 'This field is required';
state.inValid = true;
} else if (channel.name.length > 22) {
state.nameError = 'This field must be less than 22 characters';
state.inValid = true;
} else {
var cleanedName = utils.cleanUpUrlable(channel.name);
if (cleanedName !== channel.name) {
state.nameError = "Must be lowercase alphanumeric characters, allowing '-' but not starting or ending with '-'";
state.inValid = true;
} else {
state.nameError = '';
}
}
this.setState(state);
if (state.inValid) {
return;
}
var cu = UserStore.getCurrentUser();
channel.team_id = cu.team_id;
channel.description = React.findDOMNode(this.refs.channel_desc).value.trim();
channel.type = this.state.channelType;
client.createChannel(channel,
function success(data) {
$(React.findDOMNode(this.refs.modal)).modal('hide');
asyncClient.getChannel(data.id);
utils.switchChannel(data);
React.findDOMNode(this.refs.display_name).value = '';
React.findDOMNode(this.refs.channel_name).value = '';
React.findDOMNode(this.refs.channel_desc).value = '';
}.bind(this),
function error(err) {
state.serverError = err.message;
state.inValid = true;
this.setState(state);
}.bind(this)
);
}
displayNameKeyUp() {
var displayName = React.findDOMNode(this.refs.display_name).value.trim();
var channelName = utils.cleanUpUrlable(displayName);
React.findDOMNode(this.refs.channel_name).value = channelName;
}
componentDidMount() {
var self = this;
$(React.findDOMNode(this.refs.modal)).on('show.bs.modal', function onModalShow(e) {
var button = e.relatedTarget;
self.setState({channelType: $(button).attr('data-channeltype')});
});
$(React.findDOMNode(this.refs.modal)).on('hidden.bs.modal', this.handleClose);
}
componentWillUnmount() {
$(React.findDOMNode(this.refs.modal)).off('hidden.bs.modal', this.handleClose);
}
handleClose() {
$(React.findDOMNode(this)).find('.form-control').each(function clearForms() {
this.value = '';
});
this.setState({channelType: '', displayNameError: '', nameError: '', serverError: '', inValid: false});
}
render() {
var displayNameError = null;
var nameError = null;
var serverError = null;
var displayNameClass = 'form-group';
var nameClass = 'form-group';
if (this.state.displayNameError) {
displayNameError = <label className='control-label'>{this.state.displayNameError}</label>;
displayNameClass += ' has-error';
}
if (this.state.nameError) {
nameError = <label className='control-label'>{this.state.nameError}</label>;
nameClass += ' has-error';
}
if (this.state.serverError) {
serverError = <div className='form-group has-error'><label className='control-label'>{this.state.serverError}</label></div>;
}
var channelTerm = 'Channel';
if (this.state.channelType === 'P') {
channelTerm = 'Group';
}
return (
<div
className='modal fade'
id='new_channel'
ref='modal'
tabIndex='-1'
role='dialog'
aria-hidden='true'
>
<div className='modal-dialog'>
<div className='modal-content'>
<div className='modal-header'>
<button
type='button'
className='close'
data-dismiss='modal'
>
<span aria-hidden='true'>&times;</span>
<span className='sr-only'>Cancel</span>
</button>
<h4 className='modal-title'>New {channelTerm}</h4>
</div>
<form role='form'>
<div className='modal-body'>
<div className={displayNameClass}>
<label className='control-label'>Display Name</label>
<input
onKeyUp={this.displayNameKeyUp}
type='text'
ref='display_name'
className='form-control'
placeholder='Enter display name'
maxLength='22'
/>
{displayNameError}
</div>
<div className={nameClass}>
<label className='control-label'>Handle</label>
<input
type='text'
className='form-control'
ref='channel_name'
placeholder="lowercase alphanumeric's only"
maxLength='22'
/>
{nameError}
</div>
<div className='form-group'>
<label className='control-label'>Description</label>
<textarea
className='form-control no-resize'
ref='channel_desc'
rows='3'
placeholder='Description'
maxLength='1024'
/>
</div>
{serverError}
</div>
<div className='modal-footer'>
<button
type='button'
className='btn btn-default'
data-dismiss='modal'
>
Cancel
</button>
<button
onClick={this.handleSubmit}
type='submit'
className='btn btn-primary'
>
Create New {channelTerm}
</button>
</div>
</form>
</div>
</div>
</div>
);
}
}

206
web/react/components/new_channel_flow.jsx Обычный файл
Просмотреть файл

@@ -0,0 +1,206 @@
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
// See License.txt for license information.
var Utils = require('../utils/utils.jsx');
var AsyncClient = require('../utils/async_client.jsx');
var Client = require('../utils/client.jsx');
var UserStore = require('../stores/user_store.jsx');
var NewChannelModal = require('./new_channel_modal.jsx');
var ChangeURLModal = require('./change_url_modal.jsx');
const SHOW_NEW_CHANNEL = 1;
const SHOW_EDIT_URL = 2;
const SHOW_EDIT_URL_THEN_COMPLETE = 3;
export default class NewChannelFlow extends React.Component {
constructor(props) {
super(props);
this.doSubmit = this.doSubmit.bind(this);
this.typeSwitched = this.typeSwitched.bind(this);
this.urlChangeRequested = this.urlChangeRequested.bind(this);
this.urlChangeSubmitted = this.urlChangeSubmitted.bind(this);
this.urlChangeDismissed = this.urlChangeDismissed.bind(this);
this.channelDataChanged = this.channelDataChanged.bind(this);
this.state = {
serverError: '',
channelType: 'O',
flowState: SHOW_NEW_CHANNEL,
channelDisplayName: '',
channelName: '',
channelDescription: '',
nameModified: false
};
}
componentWillReceiveProps(nextProps) {
// If we are being shown, grab channel type from props and clear
if (nextProps.show === true && this.props.show === false) {
this.setState({
serverError: '',
channelType: nextProps.channelType,
flowState: SHOW_NEW_CHANNEL,
channelDisplayName: '',
channelName: '',
channelDescription: '',
nameModified: false
});
}
}
doSubmit() {
var channel = {};
channel.display_name = this.state.channelDisplayName;
if (!channel.display_name) {
this.setState({serverError: 'Invalid Channel Name'});
return;
}
channel.name = this.state.channelName;
if (channel.name.length < 2) {
this.setState({flowState: SHOW_EDIT_URL_THEN_COMPLETE});
return;
}
const cu = UserStore.getCurrentUser();
channel.team_id = cu.team_id;
channel.description = this.state.channelDescription;
channel.type = this.state.channelType;
Client.createChannel(channel,
(data) => {
this.props.onModalDismissed();
AsyncClient.getChannel(data.id);
Utils.switchChannel(data);
},
(err) => {
if (err.message === 'Name must be 2 or more lowercase alphanumeric characters') {
this.setState({flowState: SHOW_EDIT_URL_THEN_COMPLETE});
}
if (err.message === 'A channel with that handle already exists') {
this.setState({serverError: 'A channel with that URL already exists'});
return;
}
this.setState({serverError: err.message});
}
);
}
typeSwitched() {
if (this.state.channelType === 'P') {
this.setState({channelType: 'O'});
} else {
this.setState({channelType: 'P'});
}
}
urlChangeRequested() {
this.setState({flowState: SHOW_EDIT_URL});
}
urlChangeSubmitted(newURL) {
if (this.state.flowState === SHOW_EDIT_URL_THEN_COMPLETE) {
this.setState({channelName: newURL, nameModified: true}, this.doSubmit);
} else {
this.setState({flowState: SHOW_NEW_CHANNEL, serverError: '', channelName: newURL, nameModified: true});
}
}
urlChangeDismissed() {
this.setState({flowState: SHOW_NEW_CHANNEL});
}
channelDataChanged(data) {
this.setState({
channelDisplayName: data.displayName,
channelDescription: data.description
});
if (!this.state.nameModified) {
this.setState({channelName: Utils.cleanUpUrlable(data.displayName.trim())});
}
}
render() {
const channelData = {
name: this.state.channelName,
displayName: this.state.channelDisplayName,
description: this.state.channelDescription
};
let showChannelModal = false;
let showGroupModal = false;
let showChangeURLModal = false;
let changeURLTitle = '';
let changeURLSubmitButtonText = '';
let channelTerm = '';
// Only listen to flow state if we are being shown
if (this.props.show) {
switch (this.state.flowState) {
case SHOW_NEW_CHANNEL:
if (this.state.channelType === 'O') {
showChannelModal = true;
channelTerm = 'Channel';
} else {
showGroupModal = true;
channelTerm = 'Group';
}
break;
case SHOW_EDIT_URL:
showChangeURLModal = true;
changeURLTitle = 'Change ' + channelTerm + ' URL';
changeURLSubmitButtonText = 'Change ' + channelTerm + ' URL';
break;
case SHOW_EDIT_URL_THEN_COMPLETE:
showChangeURLModal = true;
changeURLTitle = 'Set ' + channelTerm + ' URL';
changeURLSubmitButtonText = 'Create ' + channelTerm;
break;
}
}
return (
<span>
<NewChannelModal
show={showChannelModal}
channelType={'O'}
channelData={channelData}
serverError={this.state.serverError}
onSubmitChannel={this.doSubmit}
onModalDismissed={this.props.onModalDismissed}
onTypeSwitched={this.typeSwitched}
onChangeURLPressed={this.urlChangeRequested}
onDataChanged={this.channelDataChanged}
/>
<NewChannelModal
show={showGroupModal}
channelType={'P'}
channelData={channelData}
serverError={this.state.serverError}
onSubmitChannel={this.doSubmit}
onModalDismissed={this.props.onModalDismissed}
onTypeSwitched={this.typeSwitched}
onChangeURLPressed={this.urlChangeRequested}
onDataChanged={this.channelDataChanged}
/>
<ChangeURLModal
show={showChangeURLModal}
title={changeURLTitle}
description={'Some characters are not allowed in URLs and may be removed.'}
urlLabel={channelTerm + ' URL'}
submitButtonText={changeURLSubmitButtonText}
currentURL={this.state.channelName}
serverError={this.state.serverError}
onModalSubmit={this.urlChangeSubmitted}
onModalDismissed={this.urlChangeDismissed}
/>
</span>
);
}
}
NewChannelFlow.defaultProps = {
show: false,
channelType: 'O'
};
NewChannelFlow.propTypes = {
show: React.PropTypes.bool.isRequired,
channelType: React.PropTypes.string.isRequired,
onModalDismissed: React.PropTypes.func.isRequired
};

198
web/react/components/new_channel_modal.jsx Обычный файл
Просмотреть файл

@@ -0,0 +1,198 @@
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
// See License.txt for license information.
const Utils = require('../utils/utils.jsx');
var Modal = ReactBootstrap.Modal;
export default class NewChannelModal extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
this.handleChange = this.handleChange.bind(this);
this.state = {
displayNameError: ''
};
}
componentWillReceiveProps(nextProps) {
if (nextProps.show === true && this.props.show === false) {
this.setState({
displayNameError: ''
});
}
}
handleSubmit(e) {
e.preventDefault();
const displayName = React.findDOMNode(this.refs.display_name).value.trim();
if (displayName.length < 1) {
this.setState({displayNameError: 'This field is required'});
return;
}
this.props.onSubmitChannel();
}
handleChange() {
const newData = {
displayName: React.findDOMNode(this.refs.display_name).value,
description: React.findDOMNode(this.refs.channel_desc).value
};
this.props.onDataChanged(newData);
}
render() {
var displayNameError = null;
var serverError = null;
var displayNameClass = 'form-group';
if (this.state.displayNameError) {
displayNameError = <p className='input__help error'>{this.state.displayNameError}</p>;
displayNameClass += ' has-error';
}
if (this.props.serverError) {
serverError = <div className='form-group has-error'><p className='input__help error'>{this.props.serverError}</p></div>;
}
var channelTerm = '';
var channelSwitchText = '';
switch (this.props.channelType) {
case 'P':
channelTerm = 'Group';
channelSwitchText = (
<div className='modal-intro'>
{'Create a new private group with restricted membership. '}
<a
href='#'
onClick={this.props.onTypeSwitched}
>
{'Create a public channel'}
</a>
</div>
);
break;
case 'O':
channelTerm = 'Channel';
channelSwitchText = (
<div className='modal-intro'>
{'Create a new public channel anyone can join. '}
<a
href='#'
onClick={this.props.onTypeSwitched}
>
{'Create a private group'}
</a>
</div>
);
break;
}
const prettyTeamURL = Utils.getShortenedTeamURL();
return (
<span>
<Modal
show={this.props.show}
onHide={this.props.onModalDismissed}
>
<Modal.Header closeButton={true}>
<Modal.Title>{'New ' + channelTerm}</Modal.Title>
</Modal.Header>
<form
role='form'
className='form-horizontal'
>
<Modal.Body>
<div>
{channelSwitchText}
</div>
<div className={displayNameClass}>
<label className='col-sm-2 form__label control-label'>{'Name'}</label>
<div className='col-sm-10'>
<input
onChange={this.handleChange}
type='text'
ref='display_name'
className='form-control'
placeholder='Ex: "Bugs", "Marketing", "办公室恋情"'
maxLength='22'
value={this.props.channelData.displayName}
autoFocus={true}
tabIndex='1'
/>
{displayNameError}
<p className='input__help'>
{'Channel URL: ' + prettyTeamURL + this.props.channelData.name + ' ('}
<a
href='#'
onClick={this.props.onChangeURLPressed}
>
{'change this URL'}
</a>
{')'}
</p>
</div>
</div>
<div className='form-group less'>
<div className='col-sm-2'>
<label className='form__label control-label'>{'Description'}</label>
<label className='form__label light'>{'(optional)'}</label>
</div>
<div className='col-sm-10'>
<textarea
className='form-control no-resize'
ref='channel_desc'
rows='4'
placeholder='Description'
maxLength='1024'
value={this.props.channelData.description}
onChange={this.handleChange}
tabIndex='2'
/>
<p className='input__help'>
{'The purpose of your channel. To help others decide whether to join.'}
</p>
{serverError}
</div>
</div>
</Modal.Body>
<Modal.Footer>
<button
type='button'
className='btn btn-default'
onClick={this.props.onModalDismissed}
>
{'Cancel'}
</button>
<button
onClick={this.handleSubmit}
type='submit'
className='btn btn-primary'
tabIndex='3'
>
{'Create New ' + channelTerm}
</button>
</Modal.Footer>
</form>
</Modal>
</span>
);
}
}
NewChannelModal.defaultProps = {
show: false,
channelType: 'O',
serverError: ''
};
NewChannelModal.propTypes = {
show: React.PropTypes.bool.isRequired,
channelType: React.PropTypes.string.isRequired,
channelData: React.PropTypes.object.isRequired,
serverError: React.PropTypes.string,
onSubmitChannel: React.PropTypes.func.isRequired,
onModalDismissed: React.PropTypes.func.isRequired,
onTypeSwitched: React.PropTypes.func.isRequired,
onChangeURLPressed: React.PropTypes.func.isRequired,
onDataChanged: React.PropTypes.func.isRequired
};

Просмотреть файл

@@ -12,6 +12,7 @@ var Utils = require('../utils/utils.jsx');
var SidebarHeader = require('./sidebar_header.jsx'); var SidebarHeader = require('./sidebar_header.jsx');
var SearchBox = require('./search_bar.jsx'); var SearchBox = require('./search_bar.jsx');
var Constants = require('../utils/constants.jsx'); var Constants = require('../utils/constants.jsx');
var NewChannelFlow = require('./new_channel_flow.jsx');
export default class Sidebar extends React.Component { export default class Sidebar extends React.Component {
constructor(props) { constructor(props) {
@@ -28,6 +29,7 @@ export default class Sidebar extends React.Component {
this.createChannelElement = this.createChannelElement.bind(this); this.createChannelElement = this.createChannelElement.bind(this);
this.state = this.getStateFromStores(); this.state = this.getStateFromStores();
this.state.modal = '';
this.state.loadingDMChannel = -1; this.state.loadingDMChannel = -1;
} }
getStateFromStores() { getStateFromStores() {
@@ -473,8 +475,18 @@ export default class Sidebar extends React.Component {
); );
} }
let showChannelModal = false;
if (this.state.modal !== '') {
showChannelModal = true;
}
return ( return (
<div> <div>
<NewChannelFlow
show={showChannelModal}
channelType={this.state.modal}
onModalDismissed={() => this.setState({modal: ''})}
/>
<SidebarHeader <SidebarHeader
teamDisplayName={this.props.teamDisplayName} teamDisplayName={this.props.teamDisplayName}
teamType={this.props.teamType} teamType={this.props.teamType}
@@ -508,11 +520,9 @@ export default class Sidebar extends React.Component {
<a <a
className='add-channel-btn' className='add-channel-btn'
href='#' href='#'
data-toggle='modal' onClick={() => this.setState({modal: 'O'})}
data-target='#new_channel'
data-channeltype='O'
> >
+ {'+'}
</a> </a>
</h4> </h4>
</li> </li>
@@ -537,11 +547,9 @@ export default class Sidebar extends React.Component {
<a <a
className='add-channel-btn' className='add-channel-btn'
href='#' href='#'
data-toggle='modal' onClick={() => this.setState({modal: 'P'})}
data-target='#new_channel'
data-channeltype='P'
> >
+ {'+'}
</a> </a>
</h4> </h4>
</li> </li>

Просмотреть файл

@@ -7,7 +7,6 @@
"flux": "2.1.1", "flux": "2.1.1",
"keymirror": "0.1.1", "keymirror": "0.1.1",
"object-assign": "3.0.0", "object-assign": "3.0.0",
"react": "0.13.3",
"react-zeroclipboard-mixin": "0.1.0", "react-zeroclipboard-mixin": "0.1.0",
"twemoji": "1.4.1" "twemoji": "1.4.1"
}, },

Просмотреть файл

@@ -17,7 +17,6 @@ var RenameChannelModal = require('../components/rename_channel_modal.jsx');
var EditPostModal = require('../components/edit_post_modal.jsx'); var EditPostModal = require('../components/edit_post_modal.jsx');
var DeletePostModal = require('../components/delete_post_modal.jsx'); var DeletePostModal = require('../components/delete_post_modal.jsx');
var MoreChannelsModal = require('../components/more_channels.jsx'); var MoreChannelsModal = require('../components/more_channels.jsx');
var NewChannelModal = require('../components/new_channel.jsx');
var PostDeletedModal = require('../components/post_deleted_modal.jsx'); var PostDeletedModal = require('../components/post_deleted_modal.jsx');
var ChannelNotificationsModal = require('../components/channel_notifications.jsx'); var ChannelNotificationsModal = require('../components/channel_notifications.jsx');
var UserSettingsModal = require('../components/user_settings_modal.jsx'); var UserSettingsModal = require('../components/user_settings_modal.jsx');
@@ -153,11 +152,6 @@ function setupChannelPage(teamName, teamType, teamId, channelName, channelId) {
document.getElementById('direct_channel_modal') document.getElementById('direct_channel_modal')
); );
React.render(
<NewChannelModal />,
document.getElementById('new_channel_modal')
);
React.render( React.render(
<PostListContainer />, <PostListContainer />,
document.getElementById('post-list') document.getElementById('post-list')

Просмотреть файл

@@ -1125,3 +1125,14 @@ export function importSlack(file, success, error) {
client.importSlack(formData, success, error); client.importSlack(formData, success, error);
} }
export function getTeamURLFromAddressBar() {
return window.location.href.split('/channels')[0];
}
export function getShortenedTeamURL() {
const teamURL = getTeamURLFromAddressBar();
if (teamURL.length > 24) {
return teamURL.substring(0, 10) + '...' + teamURL.substring(teamURL.length - 12, teamURL.length - 1) + '/';
}
}

33
web/sass-files/sass/partials/_forms.scss Обычный файл
Просмотреть файл

@@ -0,0 +1,33 @@
.form-horizontal {
.modal-intro {
margin: -10px 0 30px;
}
.form__label {
text-align: left;
padding-right: 3px;
font-weight: bold;
font-size: 1.1em;
&.light {
color: #999;
font-size: 1.05em;
font-style: italic;
padding-top: 2px;
}
}
.input__help {
color: #777;
margin: 10px 0 0 10px;
&.error {
color: #a94442;
}
}
.form-control {
font-weight: normal;
}
.form-group {
margin-bottom: 25px;
&.less {
margin-bottom: 10px;
}
}
}

Просмотреть файл

@@ -29,6 +29,7 @@
@import "partials/videos"; @import "partials/videos";
@import "partials/settings"; @import "partials/settings";
@import "partials/modal"; @import "partials/modal";
@import "partials/forms";
@import "partials/mentions"; @import "partials/mentions";
@import "partials/command-box"; @import "partials/command-box";
@import "partials/error"; @import "partials/error";

5
web/static/css/bootstrap-3.3.1.min.css поставляемый

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Разница между файлами не показана из-за своего большого размера Загрузить разницу

5
web/static/css/bootstrap-3.3.5.min.css поставляемый Обычный файл

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

7
web/static/js/bootstrap-3.3.1.min.js поставляемый

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@@ -1,7 +1,7 @@
/*! /*!
* Bootstrap v3.3.1 (http://getbootstrap.com) * Bootstrap v3.3.5 (http://getbootstrap.com)
* Copyright 2011-2014 Twitter, Inc. * Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * Licensed under the MIT license
*/ */
if (typeof jQuery === 'undefined') { if (typeof jQuery === 'undefined') {
@@ -9,6 +9,7 @@ if (typeof jQuery === 'undefined') {
} }
+function ($) { +function ($) {
'use strict';
var version = $.fn.jquery.split(' ')[0].split('.') var version = $.fn.jquery.split(' ')[0].split('.')
if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1)) { if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1)) {
throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher') throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher')
@@ -16,10 +17,10 @@ if (typeof jQuery === 'undefined') {
}(jQuery); }(jQuery);
/* ======================================================================== /* ========================================================================
* Bootstrap: transition.js v3.3.1 * Bootstrap: transition.js v3.3.5
* http://getbootstrap.com/javascript/#transitions * http://getbootstrap.com/javascript/#transitions
* ======================================================================== * ========================================================================
* Copyright 2011-2014 Twitter, Inc. * Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */ * ======================================================================== */
@@ -76,10 +77,10 @@ if (typeof jQuery === 'undefined') {
}(jQuery); }(jQuery);
/* ======================================================================== /* ========================================================================
* Bootstrap: alert.js v3.3.1 * Bootstrap: alert.js v3.3.5
* http://getbootstrap.com/javascript/#alerts * http://getbootstrap.com/javascript/#alerts
* ======================================================================== * ========================================================================
* Copyright 2011-2014 Twitter, Inc. * Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */ * ======================================================================== */
@@ -95,7 +96,7 @@ if (typeof jQuery === 'undefined') {
$(el).on('click', dismiss, this.close) $(el).on('click', dismiss, this.close)
} }
Alert.VERSION = '3.3.1' Alert.VERSION = '3.3.5'
Alert.TRANSITION_DURATION = 150 Alert.TRANSITION_DURATION = 150
@@ -171,10 +172,10 @@ if (typeof jQuery === 'undefined') {
}(jQuery); }(jQuery);
/* ======================================================================== /* ========================================================================
* Bootstrap: button.js v3.3.1 * Bootstrap: button.js v3.3.5
* http://getbootstrap.com/javascript/#buttons * http://getbootstrap.com/javascript/#buttons
* ======================================================================== * ========================================================================
* Copyright 2011-2014 Twitter, Inc. * Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */ * ======================================================================== */
@@ -191,7 +192,7 @@ if (typeof jQuery === 'undefined') {
this.isLoading = false this.isLoading = false
} }
Button.VERSION = '3.3.1' Button.VERSION = '3.3.5'
Button.DEFAULTS = { Button.DEFAULTS = {
loadingText: 'loading...' loadingText: 'loading...'
@@ -203,7 +204,7 @@ if (typeof jQuery === 'undefined') {
var val = $el.is('input') ? 'val' : 'html' var val = $el.is('input') ? 'val' : 'html'
var data = $el.data() var data = $el.data()
state = state + 'Text' state += 'Text'
if (data.resetText == null) $el.data('resetText', $el[val]()) if (data.resetText == null) $el.data('resetText', $el[val]())
@@ -228,15 +229,19 @@ if (typeof jQuery === 'undefined') {
if ($parent.length) { if ($parent.length) {
var $input = this.$element.find('input') var $input = this.$element.find('input')
if ($input.prop('type') == 'radio') { if ($input.prop('type') == 'radio') {
if ($input.prop('checked') && this.$element.hasClass('active')) changed = false if ($input.prop('checked')) changed = false
else $parent.find('.active').removeClass('active') $parent.find('.active').removeClass('active')
this.$element.addClass('active')
} else if ($input.prop('type') == 'checkbox') {
if (($input.prop('checked')) !== this.$element.hasClass('active')) changed = false
this.$element.toggleClass('active')
} }
if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change') $input.prop('checked', this.$element.hasClass('active'))
if (changed) $input.trigger('change')
} else { } else {
this.$element.attr('aria-pressed', !this.$element.hasClass('active')) this.$element.attr('aria-pressed', !this.$element.hasClass('active'))
this.$element.toggleClass('active')
} }
if (changed) this.$element.toggleClass('active')
} }
@@ -279,7 +284,7 @@ if (typeof jQuery === 'undefined') {
var $btn = $(e.target) var $btn = $(e.target)
if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
Plugin.call($btn, 'toggle') Plugin.call($btn, 'toggle')
e.preventDefault() if (!($(e.target).is('input[type="radio"]') || $(e.target).is('input[type="checkbox"]'))) e.preventDefault()
}) })
.on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) { .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) {
$(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type)) $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type))
@@ -288,10 +293,10 @@ if (typeof jQuery === 'undefined') {
}(jQuery); }(jQuery);
/* ======================================================================== /* ========================================================================
* Bootstrap: carousel.js v3.3.1 * Bootstrap: carousel.js v3.3.5
* http://getbootstrap.com/javascript/#carousel * http://getbootstrap.com/javascript/#carousel
* ======================================================================== * ========================================================================
* Copyright 2011-2014 Twitter, Inc. * Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */ * ======================================================================== */
@@ -306,10 +311,10 @@ if (typeof jQuery === 'undefined') {
this.$element = $(element) this.$element = $(element)
this.$indicators = this.$element.find('.carousel-indicators') this.$indicators = this.$element.find('.carousel-indicators')
this.options = options this.options = options
this.paused = this.paused = null
this.sliding = this.sliding = null
this.interval = this.interval = null
this.$active = this.$active = null
this.$items = null this.$items = null
this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this)) this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this))
@@ -319,7 +324,7 @@ if (typeof jQuery === 'undefined') {
.on('mouseleave.bs.carousel', $.proxy(this.cycle, this)) .on('mouseleave.bs.carousel', $.proxy(this.cycle, this))
} }
Carousel.VERSION = '3.3.1' Carousel.VERSION = '3.3.5'
Carousel.TRANSITION_DURATION = 600 Carousel.TRANSITION_DURATION = 600
@@ -359,8 +364,11 @@ if (typeof jQuery === 'undefined') {
} }
Carousel.prototype.getItemForDirection = function (direction, active) { Carousel.prototype.getItemForDirection = function (direction, active) {
var delta = direction == 'prev' ? -1 : 1
var activeIndex = this.getItemIndex(active) var activeIndex = this.getItemIndex(active)
var willWrap = (direction == 'prev' && activeIndex === 0)
|| (direction == 'next' && activeIndex == (this.$items.length - 1))
if (willWrap && !this.options.wrap) return active
var delta = direction == 'prev' ? -1 : 1
var itemIndex = (activeIndex + delta) % this.$items.length var itemIndex = (activeIndex + delta) % this.$items.length
return this.$items.eq(itemIndex) return this.$items.eq(itemIndex)
} }
@@ -405,14 +413,8 @@ if (typeof jQuery === 'undefined') {
var $next = next || this.getItemForDirection(type, $active) var $next = next || this.getItemForDirection(type, $active)
var isCycling = this.interval var isCycling = this.interval
var direction = type == 'next' ? 'left' : 'right' var direction = type == 'next' ? 'left' : 'right'
var fallback = type == 'next' ? 'first' : 'last'
var that = this var that = this
if (!$next.length) {
if (!this.options.wrap) return
$next = this.$element.find('.item')[fallback]()
}
if ($next.hasClass('active')) return (this.sliding = false) if ($next.hasClass('active')) return (this.sliding = false)
var relatedTarget = $next[0] var relatedTarget = $next[0]
@@ -529,10 +531,10 @@ if (typeof jQuery === 'undefined') {
}(jQuery); }(jQuery);
/* ======================================================================== /* ========================================================================
* Bootstrap: collapse.js v3.3.1 * Bootstrap: collapse.js v3.3.5
* http://getbootstrap.com/javascript/#collapse * http://getbootstrap.com/javascript/#collapse
* ======================================================================== * ========================================================================
* Copyright 2011-2014 Twitter, Inc. * Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */ * ======================================================================== */
@@ -546,7 +548,8 @@ if (typeof jQuery === 'undefined') {
var Collapse = function (element, options) { var Collapse = function (element, options) {
this.$element = $(element) this.$element = $(element)
this.options = $.extend({}, Collapse.DEFAULTS, options) this.options = $.extend({}, Collapse.DEFAULTS, options)
this.$trigger = $(this.options.trigger).filter('[href="#' + element.id + '"], [data-target="#' + element.id + '"]') this.$trigger = $('[data-toggle="collapse"][href="#' + element.id + '"],' +
'[data-toggle="collapse"][data-target="#' + element.id + '"]')
this.transitioning = null this.transitioning = null
if (this.options.parent) { if (this.options.parent) {
@@ -558,13 +561,12 @@ if (typeof jQuery === 'undefined') {
if (this.options.toggle) this.toggle() if (this.options.toggle) this.toggle()
} }
Collapse.VERSION = '3.3.1' Collapse.VERSION = '3.3.5'
Collapse.TRANSITION_DURATION = 350 Collapse.TRANSITION_DURATION = 350
Collapse.DEFAULTS = { Collapse.DEFAULTS = {
toggle: true, toggle: true
trigger: '[data-toggle="collapse"]'
} }
Collapse.prototype.dimension = function () { Collapse.prototype.dimension = function () {
@@ -576,7 +578,7 @@ if (typeof jQuery === 'undefined') {
if (this.transitioning || this.$element.hasClass('in')) return if (this.transitioning || this.$element.hasClass('in')) return
var activesData var activesData
var actives = this.$parent && this.$parent.find('> .panel').children('.in, .collapsing') var actives = this.$parent && this.$parent.children('.panel').children('.in, .collapsing')
if (actives && actives.length) { if (actives && actives.length) {
activesData = actives.data('bs.collapse') activesData = actives.data('bs.collapse')
@@ -702,7 +704,7 @@ if (typeof jQuery === 'undefined') {
var data = $this.data('bs.collapse') var data = $this.data('bs.collapse')
var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
if (!data && options.toggle && option == 'show') options.toggle = false if (!data && options.toggle && /show|hide/.test(option)) options.toggle = false
if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
if (typeof option == 'string') data[option]() if (typeof option == 'string') data[option]()
}) })
@@ -733,7 +735,7 @@ if (typeof jQuery === 'undefined') {
var $target = getTargetFromTrigger($this) var $target = getTargetFromTrigger($this)
var data = $target.data('bs.collapse') var data = $target.data('bs.collapse')
var option = data ? 'toggle' : $.extend({}, $this.data(), { trigger: this }) var option = data ? 'toggle' : $this.data()
Plugin.call($target, option) Plugin.call($target, option)
}) })
@@ -741,10 +743,10 @@ if (typeof jQuery === 'undefined') {
}(jQuery); }(jQuery);
/* ======================================================================== /* ========================================================================
* Bootstrap: dropdown.js v3.3.1 * Bootstrap: dropdown.js v3.3.5
* http://getbootstrap.com/javascript/#dropdowns * http://getbootstrap.com/javascript/#dropdowns
* ======================================================================== * ========================================================================
* Copyright 2011-2014 Twitter, Inc. * Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */ * ======================================================================== */
@@ -761,7 +763,41 @@ if (typeof jQuery === 'undefined') {
$(element).on('click.bs.dropdown', this.toggle) $(element).on('click.bs.dropdown', this.toggle)
} }
Dropdown.VERSION = '3.3.1' Dropdown.VERSION = '3.3.5'
function getParent($this) {
var selector = $this.attr('data-target')
if (!selector) {
selector = $this.attr('href')
selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
}
var $parent = selector && $(selector)
return $parent && $parent.length ? $parent : $this.parent()
}
function clearMenus(e) {
if (e && e.which === 3) return
$(backdrop).remove()
$(toggle).each(function () {
var $this = $(this)
var $parent = getParent($this)
var relatedTarget = { relatedTarget: this }
if (!$parent.hasClass('open')) return
if (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return
$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
if (e.isDefaultPrevented()) return
$this.attr('aria-expanded', 'false')
$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
})
}
Dropdown.prototype.toggle = function (e) { Dropdown.prototype.toggle = function (e) {
var $this = $(this) var $this = $(this)
@@ -776,7 +812,10 @@ if (typeof jQuery === 'undefined') {
if (!isActive) { if (!isActive) {
if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
// if mobile we use a backdrop because click events don't delegate // if mobile we use a backdrop because click events don't delegate
$('<div class="dropdown-backdrop"/>').insertAfter($(this)).on('click', clearMenus) $(document.createElement('div'))
.addClass('dropdown-backdrop')
.insertAfter($(this))
.on('click', clearMenus)
} }
var relatedTarget = { relatedTarget: this } var relatedTarget = { relatedTarget: this }
@@ -809,13 +848,13 @@ if (typeof jQuery === 'undefined') {
var $parent = getParent($this) var $parent = getParent($this)
var isActive = $parent.hasClass('open') var isActive = $parent.hasClass('open')
if ((!isActive && e.which != 27) || (isActive && e.which == 27)) { if (!isActive && e.which != 27 || isActive && e.which == 27) {
if (e.which == 27) $parent.find(toggle).trigger('focus') if (e.which == 27) $parent.find(toggle).trigger('focus')
return $this.trigger('click') return $this.trigger('click')
} }
var desc = ' li:not(.divider):visible a' var desc = ' li:not(.disabled):visible a'
var $items = $parent.find('[role="menu"]' + desc + ', [role="listbox"]' + desc) var $items = $parent.find('.dropdown-menu' + desc)
if (!$items.length) return if (!$items.length) return
@@ -828,38 +867,6 @@ if (typeof jQuery === 'undefined') {
$items.eq(index).trigger('focus') $items.eq(index).trigger('focus')
} }
function clearMenus(e) {
if (e && e.which === 3) return
$(backdrop).remove()
$(toggle).each(function () {
var $this = $(this)
var $parent = getParent($this)
var relatedTarget = { relatedTarget: this }
if (!$parent.hasClass('open')) return
$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
if (e.isDefaultPrevented()) return
$this.attr('aria-expanded', 'false')
$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
})
}
function getParent($this) {
var selector = $this.attr('data-target')
if (!selector) {
selector = $this.attr('href')
selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
}
var $parent = selector && $(selector)
return $parent && $parent.length ? $parent : $this.parent()
}
// DROPDOWN PLUGIN DEFINITION // DROPDOWN PLUGIN DEFINITION
// ========================== // ==========================
@@ -897,16 +904,15 @@ if (typeof jQuery === 'undefined') {
.on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() }) .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
.on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle) .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
.on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown) .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)
.on('keydown.bs.dropdown.data-api', '[role="menu"]', Dropdown.prototype.keydown) .on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown)
.on('keydown.bs.dropdown.data-api', '[role="listbox"]', Dropdown.prototype.keydown)
}(jQuery); }(jQuery);
/* ======================================================================== /* ========================================================================
* Bootstrap: modal.js v3.3.1 * Bootstrap: modal.js v3.3.5
* http://getbootstrap.com/javascript/#modals * http://getbootstrap.com/javascript/#modals
* ======================================================================== * ========================================================================
* Copyright 2011-2014 Twitter, Inc. * Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */ * ======================================================================== */
@@ -921,9 +927,12 @@ if (typeof jQuery === 'undefined') {
this.options = options this.options = options
this.$body = $(document.body) this.$body = $(document.body)
this.$element = $(element) this.$element = $(element)
this.$backdrop = this.$dialog = this.$element.find('.modal-dialog')
this.$backdrop = null
this.isShown = null this.isShown = null
this.originalBodyPad = null
this.scrollbarWidth = 0 this.scrollbarWidth = 0
this.ignoreBackdropClick = false
if (this.options.remote) { if (this.options.remote) {
this.$element this.$element
@@ -934,7 +943,7 @@ if (typeof jQuery === 'undefined') {
} }
} }
Modal.VERSION = '3.3.1' Modal.VERSION = '3.3.5'
Modal.TRANSITION_DURATION = 300 Modal.TRANSITION_DURATION = 300
Modal.BACKDROP_TRANSITION_DURATION = 150 Modal.BACKDROP_TRANSITION_DURATION = 150
@@ -968,6 +977,12 @@ if (typeof jQuery === 'undefined') {
this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this)) this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
this.$dialog.on('mousedown.dismiss.bs.modal', function () {
that.$element.one('mouseup.dismiss.bs.modal', function (e) {
if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true
})
})
this.backdrop(function () { this.backdrop(function () {
var transition = $.support.transition && that.$element.hasClass('fade') var transition = $.support.transition && that.$element.hasClass('fade')
@@ -979,23 +994,20 @@ if (typeof jQuery === 'undefined') {
.show() .show()
.scrollTop(0) .scrollTop(0)
if (that.options.backdrop) that.adjustBackdrop()
that.adjustDialog() that.adjustDialog()
if (transition) { if (transition) {
that.$element[0].offsetWidth // force reflow that.$element[0].offsetWidth // force reflow
} }
that.$element that.$element.addClass('in')
.addClass('in')
.attr('aria-hidden', false)
that.enforceFocus() that.enforceFocus()
var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget }) var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
transition ? transition ?
that.$element.find('.modal-dialog') // wait for modal to slide in that.$dialog // wait for modal to slide in
.one('bsTransitionEnd', function () { .one('bsTransitionEnd', function () {
that.$element.trigger('focus').trigger(e) that.$element.trigger('focus').trigger(e)
}) })
@@ -1022,8 +1034,10 @@ if (typeof jQuery === 'undefined') {
this.$element this.$element
.removeClass('in') .removeClass('in')
.attr('aria-hidden', true)
.off('click.dismiss.bs.modal') .off('click.dismiss.bs.modal')
.off('mouseup.dismiss.bs.modal')
this.$dialog.off('mousedown.dismiss.bs.modal')
$.support.transition && this.$element.hasClass('fade') ? $.support.transition && this.$element.hasClass('fade') ?
this.$element this.$element
@@ -1083,13 +1097,19 @@ if (typeof jQuery === 'undefined') {
if (this.isShown && this.options.backdrop) { if (this.isShown && this.options.backdrop) {
var doAnimate = $.support.transition && animate var doAnimate = $.support.transition && animate
this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />') this.$backdrop = $(document.createElement('div'))
.prependTo(this.$element) .addClass('modal-backdrop ' + animate)
.on('click.dismiss.bs.modal', $.proxy(function (e) { .appendTo(this.$body)
this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
if (this.ignoreBackdropClick) {
this.ignoreBackdropClick = false
return
}
if (e.target !== e.currentTarget) return if (e.target !== e.currentTarget) return
this.options.backdrop == 'static' this.options.backdrop == 'static'
? this.$element[0].focus.call(this.$element[0]) ? this.$element[0].focus()
: this.hide.call(this) : this.hide()
}, this)) }, this))
if (doAnimate) this.$backdrop[0].offsetWidth // force reflow if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
@@ -1125,16 +1145,9 @@ if (typeof jQuery === 'undefined') {
// these following methods are used to handle overflowing modals // these following methods are used to handle overflowing modals
Modal.prototype.handleUpdate = function () { Modal.prototype.handleUpdate = function () {
if (this.options.backdrop) this.adjustBackdrop()
this.adjustDialog() this.adjustDialog()
} }
Modal.prototype.adjustBackdrop = function () {
this.$backdrop
.css('height', 0)
.css('height', this.$element[0].scrollHeight)
}
Modal.prototype.adjustDialog = function () { Modal.prototype.adjustDialog = function () {
var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight
@@ -1152,17 +1165,23 @@ if (typeof jQuery === 'undefined') {
} }
Modal.prototype.checkScrollbar = function () { Modal.prototype.checkScrollbar = function () {
this.bodyIsOverflowing = document.body.scrollHeight > document.documentElement.clientHeight var fullWindowWidth = window.innerWidth
if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8
var documentElementRect = document.documentElement.getBoundingClientRect()
fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left)
}
this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth
this.scrollbarWidth = this.measureScrollbar() this.scrollbarWidth = this.measureScrollbar()
} }
Modal.prototype.setScrollbar = function () { Modal.prototype.setScrollbar = function () {
var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10) var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
this.originalBodyPad = document.body.style.paddingRight || ''
if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth) if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)
} }
Modal.prototype.resetScrollbar = function () { Modal.prototype.resetScrollbar = function () {
this.$body.css('padding-right', '') this.$body.css('padding-right', this.originalBodyPad)
} }
Modal.prototype.measureScrollbar = function () { // thx walsh Modal.prototype.measureScrollbar = function () { // thx walsh
@@ -1228,11 +1247,11 @@ if (typeof jQuery === 'undefined') {
}(jQuery); }(jQuery);
/* ======================================================================== /* ========================================================================
* Bootstrap: tooltip.js v3.3.1 * Bootstrap: tooltip.js v3.3.5
* http://getbootstrap.com/javascript/#tooltip * http://getbootstrap.com/javascript/#tooltip
* Inspired by the original jQuery.tipsy by Jason Frame * Inspired by the original jQuery.tipsy by Jason Frame
* ======================================================================== * ========================================================================
* Copyright 2011-2014 Twitter, Inc. * Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */ * ======================================================================== */
@@ -1244,17 +1263,18 @@ if (typeof jQuery === 'undefined') {
// =============================== // ===============================
var Tooltip = function (element, options) { var Tooltip = function (element, options) {
this.type = this.type = null
this.options = this.options = null
this.enabled = this.enabled = null
this.timeout = this.timeout = null
this.hoverState = this.hoverState = null
this.$element = null this.$element = null
this.inState = null
this.init('tooltip', element, options) this.init('tooltip', element, options)
} }
Tooltip.VERSION = '3.3.1' Tooltip.VERSION = '3.3.5'
Tooltip.TRANSITION_DURATION = 150 Tooltip.TRANSITION_DURATION = 150
@@ -1279,7 +1299,12 @@ if (typeof jQuery === 'undefined') {
this.type = type this.type = type
this.$element = $(element) this.$element = $(element)
this.options = this.getOptions(options) this.options = this.getOptions(options)
this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport) this.$viewport = this.options.viewport && $($.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : (this.options.viewport.selector || this.options.viewport))
this.inState = { click: false, hover: false, focus: false }
if (this.$element[0] instanceof document.constructor && !this.options.selector) {
throw new Error('`selector` option must be specified when initializing ' + this.type + ' on the window.document object!')
}
var triggers = this.options.trigger.split(' ') var triggers = this.options.trigger.split(' ')
@@ -1334,16 +1359,20 @@ if (typeof jQuery === 'undefined') {
var self = obj instanceof this.constructor ? var self = obj instanceof this.constructor ?
obj : $(obj.currentTarget).data('bs.' + this.type) obj : $(obj.currentTarget).data('bs.' + this.type)
if (self && self.$tip && self.$tip.is(':visible')) {
self.hoverState = 'in'
return
}
if (!self) { if (!self) {
self = new this.constructor(obj.currentTarget, this.getDelegateOptions()) self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
$(obj.currentTarget).data('bs.' + this.type, self) $(obj.currentTarget).data('bs.' + this.type, self)
} }
if (obj instanceof $.Event) {
self.inState[obj.type == 'focusin' ? 'focus' : 'hover'] = true
}
if (self.tip().hasClass('in') || self.hoverState == 'in') {
self.hoverState = 'in'
return
}
clearTimeout(self.timeout) clearTimeout(self.timeout)
self.hoverState = 'in' self.hoverState = 'in'
@@ -1355,6 +1384,14 @@ if (typeof jQuery === 'undefined') {
}, self.options.delay.show) }, self.options.delay.show)
} }
Tooltip.prototype.isInStateTrue = function () {
for (var key in this.inState) {
if (this.inState[key]) return true
}
return false
}
Tooltip.prototype.leave = function (obj) { Tooltip.prototype.leave = function (obj) {
var self = obj instanceof this.constructor ? var self = obj instanceof this.constructor ?
obj : $(obj.currentTarget).data('bs.' + this.type) obj : $(obj.currentTarget).data('bs.' + this.type)
@@ -1364,6 +1401,12 @@ if (typeof jQuery === 'undefined') {
$(obj.currentTarget).data('bs.' + this.type, self) $(obj.currentTarget).data('bs.' + this.type, self)
} }
if (obj instanceof $.Event) {
self.inState[obj.type == 'focusout' ? 'focus' : 'hover'] = false
}
if (self.isInStateTrue()) return
clearTimeout(self.timeout) clearTimeout(self.timeout)
self.hoverState = 'out' self.hoverState = 'out'
@@ -1410,6 +1453,7 @@ if (typeof jQuery === 'undefined') {
.data('bs.' + this.type, this) .data('bs.' + this.type, this)
this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element) this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
this.$element.trigger('inserted.bs.' + this.type)
var pos = this.getPosition() var pos = this.getPosition()
var actualWidth = $tip[0].offsetWidth var actualWidth = $tip[0].offsetWidth
@@ -1417,13 +1461,12 @@ if (typeof jQuery === 'undefined') {
if (autoPlace) { if (autoPlace) {
var orgPlacement = placement var orgPlacement = placement
var $container = this.options.container ? $(this.options.container) : this.$element.parent() var viewportDim = this.getPosition(this.$viewport)
var containerDim = this.getPosition($container)
placement = placement == 'bottom' && pos.bottom + actualHeight > containerDim.bottom ? 'top' : placement = placement == 'bottom' && pos.bottom + actualHeight > viewportDim.bottom ? 'top' :
placement == 'top' && pos.top - actualHeight < containerDim.top ? 'bottom' : placement == 'top' && pos.top - actualHeight < viewportDim.top ? 'bottom' :
placement == 'right' && pos.right + actualWidth > containerDim.width ? 'left' : placement == 'right' && pos.right + actualWidth > viewportDim.width ? 'left' :
placement == 'left' && pos.left - actualWidth < containerDim.left ? 'right' : placement == 'left' && pos.left - actualWidth < viewportDim.left ? 'right' :
placement placement
$tip $tip
@@ -1464,8 +1507,8 @@ if (typeof jQuery === 'undefined') {
if (isNaN(marginTop)) marginTop = 0 if (isNaN(marginTop)) marginTop = 0
if (isNaN(marginLeft)) marginLeft = 0 if (isNaN(marginLeft)) marginLeft = 0
offset.top = offset.top + marginTop offset.top += marginTop
offset.left = offset.left + marginLeft offset.left += marginLeft
// $.fn.offset doesn't round pixel values // $.fn.offset doesn't round pixel values
// so we use setOffset directly with our own function B-0 // so we use setOffset directly with our own function B-0
@@ -1501,10 +1544,10 @@ if (typeof jQuery === 'undefined') {
this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical) this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical)
} }
Tooltip.prototype.replaceArrow = function (delta, dimension, isHorizontal) { Tooltip.prototype.replaceArrow = function (delta, dimension, isVertical) {
this.arrow() this.arrow()
.css(isHorizontal ? 'left' : 'top', 50 * (1 - delta / dimension) + '%') .css(isVertical ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')
.css(isHorizontal ? 'top' : 'left', '') .css(isVertical ? 'top' : 'left', '')
} }
Tooltip.prototype.setContent = function () { Tooltip.prototype.setContent = function () {
@@ -1517,7 +1560,7 @@ if (typeof jQuery === 'undefined') {
Tooltip.prototype.hide = function (callback) { Tooltip.prototype.hide = function (callback) {
var that = this var that = this
var $tip = this.tip() var $tip = $(this.$tip)
var e = $.Event('hide.bs.' + this.type) var e = $.Event('hide.bs.' + this.type)
function complete() { function complete() {
@@ -1534,7 +1577,7 @@ if (typeof jQuery === 'undefined') {
$tip.removeClass('in') $tip.removeClass('in')
$.support.transition && this.$tip.hasClass('fade') ? $.support.transition && $tip.hasClass('fade') ?
$tip $tip
.one('bsTransitionEnd', complete) .one('bsTransitionEnd', complete)
.emulateTransitionEnd(Tooltip.TRANSITION_DURATION) : .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
@@ -1547,7 +1590,7 @@ if (typeof jQuery === 'undefined') {
Tooltip.prototype.fixTitle = function () { Tooltip.prototype.fixTitle = function () {
var $e = this.$element var $e = this.$element
if ($e.attr('title') || typeof ($e.attr('data-original-title')) != 'string') { if ($e.attr('title') || typeof $e.attr('data-original-title') != 'string') {
$e.attr('data-original-title', $e.attr('title') || '').attr('title', '') $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
} }
} }
@@ -1602,7 +1645,7 @@ if (typeof jQuery === 'undefined') {
var rightEdgeOffset = pos.left + viewportPadding + actualWidth var rightEdgeOffset = pos.left + viewportPadding + actualWidth
if (leftEdgeOffset < viewportDimensions.left) { // left overflow if (leftEdgeOffset < viewportDimensions.left) { // left overflow
delta.left = viewportDimensions.left - leftEdgeOffset delta.left = viewportDimensions.left - leftEdgeOffset
} else if (rightEdgeOffset > viewportDimensions.width) { // right overflow } else if (rightEdgeOffset > viewportDimensions.right) { // right overflow
delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
} }
} }
@@ -1628,7 +1671,13 @@ if (typeof jQuery === 'undefined') {
} }
Tooltip.prototype.tip = function () { Tooltip.prototype.tip = function () {
return (this.$tip = this.$tip || $(this.options.template)) if (!this.$tip) {
this.$tip = $(this.options.template)
if (this.$tip.length != 1) {
throw new Error(this.type + ' `template` option must consist of exactly 1 top-level element!')
}
}
return this.$tip
} }
Tooltip.prototype.arrow = function () { Tooltip.prototype.arrow = function () {
@@ -1657,14 +1706,26 @@ if (typeof jQuery === 'undefined') {
} }
} }
if (e) {
self.inState.click = !self.inState.click
if (self.isInStateTrue()) self.enter(self)
else self.leave(self)
} else {
self.tip().hasClass('in') ? self.leave(self) : self.enter(self) self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
} }
}
Tooltip.prototype.destroy = function () { Tooltip.prototype.destroy = function () {
var that = this var that = this
clearTimeout(this.timeout) clearTimeout(this.timeout)
this.hide(function () { this.hide(function () {
that.$element.off('.' + that.type).removeData('bs.' + that.type) that.$element.off('.' + that.type).removeData('bs.' + that.type)
if (that.$tip) {
that.$tip.detach()
}
that.$tip = null
that.$arrow = null
that.$viewport = null
}) })
} }
@@ -1677,15 +1738,9 @@ if (typeof jQuery === 'undefined') {
var $this = $(this) var $this = $(this)
var data = $this.data('bs.tooltip') var data = $this.data('bs.tooltip')
var options = typeof option == 'object' && option var options = typeof option == 'object' && option
var selector = options && options.selector
if (!data && option == 'destroy') return if (!data && /destroy|hide/.test(option)) return
if (selector) {
if (!data) $this.data('bs.tooltip', (data = {}))
if (!data[selector]) data[selector] = new Tooltip(this, options)
} else {
if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options))) if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
}
if (typeof option == 'string') data[option]() if (typeof option == 'string') data[option]()
}) })
} }
@@ -1707,10 +1762,10 @@ if (typeof jQuery === 'undefined') {
}(jQuery); }(jQuery);
/* ======================================================================== /* ========================================================================
* Bootstrap: popover.js v3.3.1 * Bootstrap: popover.js v3.3.5
* http://getbootstrap.com/javascript/#popovers * http://getbootstrap.com/javascript/#popovers
* ======================================================================== * ========================================================================
* Copyright 2011-2014 Twitter, Inc. * Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */ * ======================================================================== */
@@ -1727,7 +1782,7 @@ if (typeof jQuery === 'undefined') {
if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js') if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
Popover.VERSION = '3.3.1' Popover.VERSION = '3.3.5'
Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, { Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
placement: 'right', placement: 'right',
@@ -1783,11 +1838,6 @@ if (typeof jQuery === 'undefined') {
return (this.$arrow = this.$arrow || this.tip().find('.arrow')) return (this.$arrow = this.$arrow || this.tip().find('.arrow'))
} }
Popover.prototype.tip = function () {
if (!this.$tip) this.$tip = $(this.options.template)
return this.$tip
}
// POPOVER PLUGIN DEFINITION // POPOVER PLUGIN DEFINITION
// ========================= // =========================
@@ -1797,15 +1847,9 @@ if (typeof jQuery === 'undefined') {
var $this = $(this) var $this = $(this)
var data = $this.data('bs.popover') var data = $this.data('bs.popover')
var options = typeof option == 'object' && option var options = typeof option == 'object' && option
var selector = options && options.selector
if (!data && option == 'destroy') return if (!data && /destroy|hide/.test(option)) return
if (selector) {
if (!data) $this.data('bs.popover', (data = {}))
if (!data[selector]) data[selector] = new Popover(this, options)
} else {
if (!data) $this.data('bs.popover', (data = new Popover(this, options))) if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
}
if (typeof option == 'string') data[option]() if (typeof option == 'string') data[option]()
}) })
} }
@@ -1827,10 +1871,10 @@ if (typeof jQuery === 'undefined') {
}(jQuery); }(jQuery);
/* ======================================================================== /* ========================================================================
* Bootstrap: scrollspy.js v3.3.1 * Bootstrap: scrollspy.js v3.3.5
* http://getbootstrap.com/javascript/#scrollspy * http://getbootstrap.com/javascript/#scrollspy
* ======================================================================== * ========================================================================
* Copyright 2011-2014 Twitter, Inc. * Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */ * ======================================================================== */
@@ -1842,10 +1886,8 @@ if (typeof jQuery === 'undefined') {
// ========================== // ==========================
function ScrollSpy(element, options) { function ScrollSpy(element, options) {
var process = $.proxy(this.process, this) this.$body = $(document.body)
this.$scrollElement = $(element).is(document.body) ? $(window) : $(element)
this.$body = $('body')
this.$scrollElement = $(element).is('body') ? $(window) : $(element)
this.options = $.extend({}, ScrollSpy.DEFAULTS, options) this.options = $.extend({}, ScrollSpy.DEFAULTS, options)
this.selector = (this.options.target || '') + ' .nav li > a' this.selector = (this.options.target || '') + ' .nav li > a'
this.offsets = [] this.offsets = []
@@ -1853,12 +1895,12 @@ if (typeof jQuery === 'undefined') {
this.activeTarget = null this.activeTarget = null
this.scrollHeight = 0 this.scrollHeight = 0
this.$scrollElement.on('scroll.bs.scrollspy', process) this.$scrollElement.on('scroll.bs.scrollspy', $.proxy(this.process, this))
this.refresh() this.refresh()
this.process() this.process()
} }
ScrollSpy.VERSION = '3.3.1' ScrollSpy.VERSION = '3.3.5'
ScrollSpy.DEFAULTS = { ScrollSpy.DEFAULTS = {
offset: 10 offset: 10
@@ -1869,19 +1911,18 @@ if (typeof jQuery === 'undefined') {
} }
ScrollSpy.prototype.refresh = function () { ScrollSpy.prototype.refresh = function () {
var that = this
var offsetMethod = 'offset' var offsetMethod = 'offset'
var offsetBase = 0 var offsetBase = 0
if (!$.isWindow(this.$scrollElement[0])) {
offsetMethod = 'position'
offsetBase = this.$scrollElement.scrollTop()
}
this.offsets = [] this.offsets = []
this.targets = [] this.targets = []
this.scrollHeight = this.getScrollHeight() this.scrollHeight = this.getScrollHeight()
var self = this if (!$.isWindow(this.$scrollElement[0])) {
offsetMethod = 'position'
offsetBase = this.$scrollElement.scrollTop()
}
this.$body this.$body
.find(this.selector) .find(this.selector)
@@ -1897,8 +1938,8 @@ if (typeof jQuery === 'undefined') {
}) })
.sort(function (a, b) { return a[0] - b[0] }) .sort(function (a, b) { return a[0] - b[0] })
.each(function () { .each(function () {
self.offsets.push(this[0]) that.offsets.push(this[0])
self.targets.push(this[1]) that.targets.push(this[1])
}) })
} }
@@ -1927,7 +1968,7 @@ if (typeof jQuery === 'undefined') {
for (i = offsets.length; i--;) { for (i = offsets.length; i--;) {
activeTarget != targets[i] activeTarget != targets[i]
&& scrollTop >= offsets[i] && scrollTop >= offsets[i]
&& (!offsets[i + 1] || scrollTop <= offsets[i + 1]) && (offsets[i + 1] === undefined || scrollTop < offsets[i + 1])
&& this.activate(targets[i]) && this.activate(targets[i])
} }
} }
@@ -2003,10 +2044,10 @@ if (typeof jQuery === 'undefined') {
}(jQuery); }(jQuery);
/* ======================================================================== /* ========================================================================
* Bootstrap: tab.js v3.3.1 * Bootstrap: tab.js v3.3.5
* http://getbootstrap.com/javascript/#tabs * http://getbootstrap.com/javascript/#tabs
* ======================================================================== * ========================================================================
* Copyright 2011-2014 Twitter, Inc. * Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */ * ======================================================================== */
@@ -2018,10 +2059,12 @@ if (typeof jQuery === 'undefined') {
// ==================== // ====================
var Tab = function (element) { var Tab = function (element) {
// jscs:disable requireDollarBeforejQueryAssignment
this.element = $(element) this.element = $(element)
// jscs:enable requireDollarBeforejQueryAssignment
} }
Tab.VERSION = '3.3.1' Tab.VERSION = '3.3.5'
Tab.TRANSITION_DURATION = 150 Tab.TRANSITION_DURATION = 150
@@ -2069,7 +2112,7 @@ if (typeof jQuery === 'undefined') {
var $active = container.find('> .active') var $active = container.find('> .active')
var transition = callback var transition = callback
&& $.support.transition && $.support.transition
&& (($active.length && $active.hasClass('fade')) || !!container.find('> .fade').length) && ($active.length && $active.hasClass('fade') || !!container.find('> .fade').length)
function next() { function next() {
$active $active
@@ -2092,7 +2135,7 @@ if (typeof jQuery === 'undefined') {
element.removeClass('fade') element.removeClass('fade')
} }
if (element.parent('.dropdown-menu')) { if (element.parent('.dropdown-menu').length) {
element element
.closest('li.dropdown') .closest('li.dropdown')
.addClass('active') .addClass('active')
@@ -2157,10 +2200,10 @@ if (typeof jQuery === 'undefined') {
}(jQuery); }(jQuery);
/* ======================================================================== /* ========================================================================
* Bootstrap: affix.js v3.3.1 * Bootstrap: affix.js v3.3.5
* http://getbootstrap.com/javascript/#affix * http://getbootstrap.com/javascript/#affix
* ======================================================================== * ========================================================================
* Copyright 2011-2014 Twitter, Inc. * Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */ * ======================================================================== */
@@ -2179,14 +2222,14 @@ if (typeof jQuery === 'undefined') {
.on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this)) .on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this))
this.$element = $(element) this.$element = $(element)
this.affixed = this.affixed = null
this.unpin = this.unpin = null
this.pinnedOffset = null this.pinnedOffset = null
this.checkPosition() this.checkPosition()
} }
Affix.VERSION = '3.3.1' Affix.VERSION = '3.3.5'
Affix.RESET = 'affix affix-top affix-bottom' Affix.RESET = 'affix affix-top affix-bottom'
@@ -2211,7 +2254,7 @@ if (typeof jQuery === 'undefined') {
var colliderTop = initializing ? scrollTop : position.top var colliderTop = initializing ? scrollTop : position.top
var colliderHeight = initializing ? targetHeight : height var colliderHeight = initializing ? targetHeight : height
if (offsetTop != null && colliderTop <= offsetTop) return 'top' if (offsetTop != null && scrollTop <= offsetTop) return 'top'
if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom' if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom'
return false return false
@@ -2236,7 +2279,7 @@ if (typeof jQuery === 'undefined') {
var offset = this.options.offset var offset = this.options.offset
var offsetTop = offset.top var offsetTop = offset.top
var offsetBottom = offset.bottom var offsetBottom = offset.bottom
var scrollHeight = $('body').height() var scrollHeight = Math.max($(document).height(), $(document.body).height())
if (typeof offset != 'object') offsetBottom = offsetTop = offset if (typeof offset != 'object') offsetBottom = offsetTop = offset
if (typeof offsetTop == 'function') offsetTop = offset.top(this.$element) if (typeof offsetTop == 'function') offsetTop = offset.top(this.$element)

7
web/static/js/bootstrap-3.3.5.min.js поставляемый Обычный файл

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

1024
web/static/js/jasny-bootstrap.js Обычный файл

Разница между файлами не показана из-за своего большого размера Загрузить разницу

6
web/static/js/jasny-bootstrap.min.js поставляемый Обычный файл

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

15678
web/static/js/react-bootstrap-0.25.1.js Обычный файл

Разница между файлами не показана из-за своего большого размера Загрузить разницу

14
web/static/js/react-bootstrap-0.25.1.min.js поставляемый Обычный файл

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

16
web/static/js/react-with-addons-0.13.1.min.js поставляемый

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@@ -1,5 +1,5 @@
/** /**
* React (with addons) v0.13.1 * React (with addons) v0.13.3
*/ */
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.React = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){ (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.React = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
/** /**
@@ -710,7 +710,9 @@ var isUnitlessNumber = {
columnCount: true, columnCount: true,
flex: true, flex: true,
flexGrow: true, flexGrow: true,
flexPositive: true,
flexShrink: true, flexShrink: true,
flexNegative: true,
fontWeight: true, fontWeight: true,
lineClamp: true, lineClamp: true,
lineHeight: true, lineHeight: true,
@@ -723,7 +725,9 @@ var isUnitlessNumber = {
// SVG-related properties // SVG-related properties
fillOpacity: true, fillOpacity: true,
strokeOpacity: true strokeDashoffset: true,
strokeOpacity: true,
strokeWidth: true
}; };
/** /**
@@ -3788,6 +3792,7 @@ var HTMLDOMPropertyConfig = {
headers: null, headers: null,
height: MUST_USE_ATTRIBUTE, height: MUST_USE_ATTRIBUTE,
hidden: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE, hidden: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE,
high: null,
href: null, href: null,
hrefLang: null, hrefLang: null,
htmlFor: null, htmlFor: null,
@@ -3798,6 +3803,7 @@ var HTMLDOMPropertyConfig = {
lang: null, lang: null,
list: MUST_USE_ATTRIBUTE, list: MUST_USE_ATTRIBUTE,
loop: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, loop: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
low: null,
manifest: MUST_USE_ATTRIBUTE, manifest: MUST_USE_ATTRIBUTE,
marginHeight: null, marginHeight: null,
marginWidth: null, marginWidth: null,
@@ -3812,6 +3818,7 @@ var HTMLDOMPropertyConfig = {
name: null, name: null,
noValidate: HAS_BOOLEAN_VALUE, noValidate: HAS_BOOLEAN_VALUE,
open: HAS_BOOLEAN_VALUE, open: HAS_BOOLEAN_VALUE,
optimum: null,
pattern: null, pattern: null,
placeholder: null, placeholder: null,
poster: null, poster: null,
@@ -3825,6 +3832,7 @@ var HTMLDOMPropertyConfig = {
rowSpan: null, rowSpan: null,
sandbox: null, sandbox: null,
scope: null, scope: null,
scoped: HAS_BOOLEAN_VALUE,
scrolling: null, scrolling: null,
seamless: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE, seamless: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE,
selected: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, selected: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
@@ -3866,7 +3874,9 @@ var HTMLDOMPropertyConfig = {
itemID: MUST_USE_ATTRIBUTE, itemID: MUST_USE_ATTRIBUTE,
itemRef: MUST_USE_ATTRIBUTE, itemRef: MUST_USE_ATTRIBUTE,
// property is supported for OpenGraph in meta tags. // property is supported for OpenGraph in meta tags.
property: null property: null,
// IE-only attribute that controls focus behavior
unselectable: MUST_USE_ATTRIBUTE
}, },
DOMAttributeNames: { DOMAttributeNames: {
acceptCharset: 'accept-charset', acceptCharset: 'accept-charset',
@@ -4475,7 +4485,7 @@ if ("production" !== "development") {
if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined') { if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined') {
console.debug( console.debug(
'Download the React DevTools for a better development experience: ' + 'Download the React DevTools for a better development experience: ' +
'http://fb.me/react-devtools' 'https://fb.me/react-devtools'
); );
} }
} }
@@ -4502,7 +4512,7 @@ if ("production" !== "development") {
if (!expectedFeatures[i]) { if (!expectedFeatures[i]) {
console.error( console.error(
'One or more ES5 shim/shams expected by React are not available: ' + 'One or more ES5 shim/shams expected by React are not available: ' +
'http://fb.me/react-warning-polyfills' 'https://fb.me/react-warning-polyfills'
); );
break; break;
} }
@@ -4510,7 +4520,7 @@ if ("production" !== "development") {
} }
} }
React.version = '0.13.1'; React.version = '0.13.3';
module.exports = React; module.exports = React;
@@ -6229,7 +6239,7 @@ var ReactClass = {
("production" !== "development" ? warning( ("production" !== "development" ? warning(
this instanceof Constructor, this instanceof Constructor,
'Something is calling a React component directly. Use a factory or ' + 'Something is calling a React component directly. Use a factory or ' +
'JSX instead. See: http://fb.me/react-legacyfactory' 'JSX instead. See: https://fb.me/react-legacyfactory'
) : null); ) : null);
} }
@@ -6439,20 +6449,38 @@ ReactComponent.prototype.forceUpdate = function(callback) {
*/ */
if ("production" !== "development") { if ("production" !== "development") {
var deprecatedAPIs = { var deprecatedAPIs = {
getDOMNode: 'getDOMNode', getDOMNode: [
isMounted: 'isMounted', 'getDOMNode',
replaceProps: 'replaceProps', 'Use React.findDOMNode(component) instead.'
replaceState: 'replaceState', ],
setProps: 'setProps' isMounted: [
'isMounted',
'Instead, make sure to clean up subscriptions and pending requests in ' +
'componentWillUnmount to prevent memory leaks.'
],
replaceProps: [
'replaceProps',
'Instead call React.render again at the top level.'
],
replaceState: [
'replaceState',
'Refactor your code to use setState instead (see ' +
'https://github.com/facebook/react/issues/3236).'
],
setProps: [
'setProps',
'Instead call React.render again at the top level.'
]
}; };
var defineDeprecationWarning = function(methodName, displayName) { var defineDeprecationWarning = function(methodName, info) {
try { try {
Object.defineProperty(ReactComponent.prototype, methodName, { Object.defineProperty(ReactComponent.prototype, methodName, {
get: function() { get: function() {
("production" !== "development" ? warning( ("production" !== "development" ? warning(
false, false,
'%s(...) is deprecated in plain JavaScript React classes.', '%s(...) is deprecated in plain JavaScript React classes. %s',
displayName info[0],
info[1]
) : null); ) : null);
return undefined; return undefined;
} }
@@ -6802,6 +6830,14 @@ var ReactCompositeComponentMixin = {
'Did you mean to define a state property instead?', 'Did you mean to define a state property instead?',
this.getName() || 'a component' this.getName() || 'a component'
) : null); ) : null);
("production" !== "development" ? warning(
!inst.getDefaultProps ||
inst.getDefaultProps.isReactClassApproved,
'getDefaultProps was defined on %s, a plain JavaScript class. ' +
'This is only supported for classes created using React.createClass. ' +
'Use a static property to define defaultProps instead.',
this.getName() || 'a component'
) : null);
("production" !== "development" ? warning( ("production" !== "development" ? warning(
!inst.propTypes, !inst.propTypes,
'propTypes was defined as an instance property on %s. Use a static ' + 'propTypes was defined as an instance property on %s. Use a static ' +
@@ -6838,6 +6874,7 @@ var ReactCompositeComponentMixin = {
this._pendingReplaceState = false; this._pendingReplaceState = false;
this._pendingForceUpdate = false; this._pendingForceUpdate = false;
var childContext;
var renderedElement; var renderedElement;
var previouslyMounting = ReactLifeCycle.currentlyMountingInstance; var previouslyMounting = ReactLifeCycle.currentlyMountingInstance;
@@ -6852,7 +6889,8 @@ var ReactCompositeComponentMixin = {
} }
} }
renderedElement = this._renderValidatedComponent(); childContext = this._getValidatedChildContext(context);
renderedElement = this._renderValidatedComponent(childContext);
} finally { } finally {
ReactLifeCycle.currentlyMountingInstance = previouslyMounting; ReactLifeCycle.currentlyMountingInstance = previouslyMounting;
} }
@@ -6866,7 +6904,7 @@ var ReactCompositeComponentMixin = {
this._renderedComponent, this._renderedComponent,
rootID, rootID,
transaction, transaction,
this._processChildContext(context) this._mergeChildContext(context, childContext)
); );
if (inst.componentDidMount) { if (inst.componentDidMount) {
transaction.getReactMountReady().enqueue(inst.componentDidMount, inst); transaction.getReactMountReady().enqueue(inst.componentDidMount, inst);
@@ -6996,7 +7034,7 @@ var ReactCompositeComponentMixin = {
* @return {object} * @return {object}
* @private * @private
*/ */
_processChildContext: function(currentContext) { _getValidatedChildContext: function(currentContext) {
var inst = this._instance; var inst = this._instance;
var childContext = inst.getChildContext && inst.getChildContext(); var childContext = inst.getChildContext && inst.getChildContext();
if (childContext) { if (childContext) {
@@ -7021,6 +7059,13 @@ var ReactCompositeComponentMixin = {
name name
) : invariant(name in inst.constructor.childContextTypes)); ) : invariant(name in inst.constructor.childContextTypes));
} }
return childContext;
}
return null;
},
_mergeChildContext: function(currentContext, childContext) {
if (childContext) {
return assign({}, currentContext, childContext); return assign({}, currentContext, childContext);
} }
return currentContext; return currentContext;
@@ -7280,6 +7325,10 @@ var ReactCompositeComponentMixin = {
return inst.state; return inst.state;
} }
if (replace && queue.length === 1) {
return queue[0];
}
var nextState = assign({}, replace ? queue[0] : inst.state); var nextState = assign({}, replace ? queue[0] : inst.state);
for (var i = replace ? 1 : 0; i < queue.length; i++) { for (var i = replace ? 1 : 0; i < queue.length; i++) {
var partial = queue[i]; var partial = queue[i];
@@ -7349,13 +7398,14 @@ var ReactCompositeComponentMixin = {
_updateRenderedComponent: function(transaction, context) { _updateRenderedComponent: function(transaction, context) {
var prevComponentInstance = this._renderedComponent; var prevComponentInstance = this._renderedComponent;
var prevRenderedElement = prevComponentInstance._currentElement; var prevRenderedElement = prevComponentInstance._currentElement;
var nextRenderedElement = this._renderValidatedComponent(); var childContext = this._getValidatedChildContext();
var nextRenderedElement = this._renderValidatedComponent(childContext);
if (shouldUpdateReactComponent(prevRenderedElement, nextRenderedElement)) { if (shouldUpdateReactComponent(prevRenderedElement, nextRenderedElement)) {
ReactReconciler.receiveComponent( ReactReconciler.receiveComponent(
prevComponentInstance, prevComponentInstance,
nextRenderedElement, nextRenderedElement,
transaction, transaction,
this._processChildContext(context) this._mergeChildContext(context, childContext)
); );
} else { } else {
// These two IDs are actually the same! But nothing should rely on that. // These two IDs are actually the same! But nothing should rely on that.
@@ -7371,7 +7421,7 @@ var ReactCompositeComponentMixin = {
this._renderedComponent, this._renderedComponent,
thisID, thisID,
transaction, transaction,
context this._mergeChildContext(context, childContext)
); );
this._replaceNodeWithMarkupByID(prevComponentID, nextMarkup); this._replaceNodeWithMarkupByID(prevComponentID, nextMarkup);
} }
@@ -7409,11 +7459,12 @@ var ReactCompositeComponentMixin = {
/** /**
* @private * @private
*/ */
_renderValidatedComponent: function() { _renderValidatedComponent: function(childContext) {
var renderedComponent; var renderedComponent;
var previousContext = ReactContext.current; var previousContext = ReactContext.current;
ReactContext.current = this._processChildContext( ReactContext.current = this._mergeChildContext(
this._currentElement._context this._currentElement._context,
childContext
); );
ReactCurrentOwner.current = this; ReactCurrentOwner.current = this;
try { try {
@@ -7778,6 +7829,7 @@ var ReactDOM = mapObject({
// SVG // SVG
circle: 'circle', circle: 'circle',
clipPath: 'clipPath',
defs: 'defs', defs: 'defs',
ellipse: 'ellipse', ellipse: 'ellipse',
g: 'g', g: 'g',
@@ -7927,11 +7979,13 @@ function assertValidProps(props) {
'Can only set one of `children` or `props.dangerouslySetInnerHTML`.' 'Can only set one of `children` or `props.dangerouslySetInnerHTML`.'
) : invariant(props.children == null)); ) : invariant(props.children == null));
("production" !== "development" ? invariant( ("production" !== "development" ? invariant(
props.dangerouslySetInnerHTML.__html != null, typeof props.dangerouslySetInnerHTML === 'object' &&
'__html' in props.dangerouslySetInnerHTML,
'`props.dangerouslySetInnerHTML` must be in the form `{__html: ...}`. ' + '`props.dangerouslySetInnerHTML` must be in the form `{__html: ...}`. ' +
'Please visit http://fb.me/react-invariant-dangerously-set-inner-html ' + 'Please visit https://fb.me/react-invariant-dangerously-set-inner-html ' +
'for more information.' 'for more information.'
) : invariant(props.dangerouslySetInnerHTML.__html != null)); ) : invariant(typeof props.dangerouslySetInnerHTML === 'object' &&
'__html' in props.dangerouslySetInnerHTML));
} }
if ("production" !== "development") { if ("production" !== "development") {
("production" !== "development" ? warning( ("production" !== "development" ? warning(
@@ -8239,6 +8293,8 @@ ReactDOMComponent.Mixin = {
if (propKey === STYLE) { if (propKey === STYLE) {
if (nextProp) { if (nextProp) {
nextProp = this._previousStyleCopy = assign({}, nextProp); nextProp = this._previousStyleCopy = assign({}, nextProp);
} else {
this._previousStyleCopy = null;
} }
if (lastProp) { if (lastProp) {
// Unset styles on `lastProp` but not on `nextProp`. // Unset styles on `lastProp` but not on `nextProp`.
@@ -10721,7 +10777,7 @@ function warnAndMonitorForKeyUse(message, element, parentType) {
("production" !== "development" ? warning( ("production" !== "development" ? warning(
false, false,
message + '%s%s See http://fb.me/react-warning-keys for more information.', message + '%s%s See https://fb.me/react-warning-keys for more information.',
parentOrOwnerAddendum, parentOrOwnerAddendum,
childOwnerAddendum childOwnerAddendum
) : null); ) : null);
@@ -10845,9 +10901,9 @@ function warnForPropsMutation(propName, element) {
("production" !== "development" ? warning( ("production" !== "development" ? warning(
false, false,
'Don\'t set .props.%s of the React component%s. ' + 'Don\'t set .props.%s of the React component%s. Instead, specify the ' +
'Instead, specify the correct value when ' + 'correct value when initially creating the element or use ' +
'initially creating the element.%s', 'React.cloneElement to make a new element with updated props.%s',
propName, propName,
elementInfo, elementInfo,
ownerInfo ownerInfo
@@ -15236,6 +15292,7 @@ var ReactUpdates = _dereq_(100);
var SyntheticEvent = _dereq_(108); var SyntheticEvent = _dereq_(108);
var assign = _dereq_(29); var assign = _dereq_(29);
var emptyObject = _dereq_(130);
var topLevelTypes = EventConstants.topLevelTypes; var topLevelTypes = EventConstants.topLevelTypes;
@@ -15577,6 +15634,9 @@ assign(
); );
ReactShallowRenderer.prototype.render = function(element, context) { ReactShallowRenderer.prototype.render = function(element, context) {
if (!context) {
context = emptyObject;
}
var transaction = ReactUpdates.ReactReconcileTransaction.getPooled(); var transaction = ReactUpdates.ReactReconcileTransaction.getPooled();
this._render(element, transaction, context); this._render(element, transaction, context);
ReactUpdates.ReactReconcileTransaction.release(transaction); ReactUpdates.ReactReconcileTransaction.release(transaction);
@@ -15717,7 +15777,7 @@ for (eventType in topLevelTypes) {
module.exports = ReactTestUtils; module.exports = ReactTestUtils;
},{"100":100,"108":108,"16":16,"18":18,"21":21,"29":29,"31":31,"33":33,"43":43,"63":63,"65":65,"72":72,"73":73,"77":77}],96:[function(_dereq_,module,exports){ },{"100":100,"108":108,"130":130,"16":16,"18":18,"21":21,"29":29,"31":31,"33":33,"43":43,"63":63,"65":65,"72":72,"73":73,"77":77}],96:[function(_dereq_,module,exports){
/** /**
* Copyright 2013-2015, Facebook, Inc. * Copyright 2013-2015, Facebook, Inc.
* All rights reserved. * All rights reserved.
@@ -16762,6 +16822,7 @@ var MUST_USE_ATTRIBUTE = DOMProperty.injection.MUST_USE_ATTRIBUTE;
var SVGDOMPropertyConfig = { var SVGDOMPropertyConfig = {
Properties: { Properties: {
clipPath: MUST_USE_ATTRIBUTE,
cx: MUST_USE_ATTRIBUTE, cx: MUST_USE_ATTRIBUTE,
cy: MUST_USE_ATTRIBUTE, cy: MUST_USE_ATTRIBUTE,
d: MUST_USE_ATTRIBUTE, d: MUST_USE_ATTRIBUTE,
@@ -16807,6 +16868,7 @@ var SVGDOMPropertyConfig = {
y: MUST_USE_ATTRIBUTE y: MUST_USE_ATTRIBUTE
}, },
DOMAttributeNames: { DOMAttributeNames: {
clipPath: 'clip-path',
fillOpacity: 'fill-opacity', fillOpacity: 'fill-opacity',
fontFamily: 'font-family', fontFamily: 'font-family',
fontSize: 'font-size', fontSize: 'font-size',
@@ -19713,6 +19775,7 @@ var shouldWrap = {
// Force wrapping for SVG elements because if they get created inside a <div>, // Force wrapping for SVG elements because if they get created inside a <div>,
// they will be initialized in the wrong namespace (and will not display). // they will be initialized in the wrong namespace (and will not display).
'circle': true, 'circle': true,
'clipPath': true,
'defs': true, 'defs': true,
'ellipse': true, 'ellipse': true,
'g': true, 'g': true,
@@ -19755,6 +19818,7 @@ var markupWrap = {
'th': trWrap, 'th': trWrap,
'circle': svgWrap, 'circle': svgWrap,
'clipPath': svgWrap,
'defs': svgWrap, 'defs': svgWrap,
'ellipse': svgWrap, 'ellipse': svgWrap,
'g': svgWrap, 'g': svgWrap,
@@ -20100,6 +20164,7 @@ assign(
function isInternalComponentType(type) { function isInternalComponentType(type) {
return ( return (
typeof type === 'function' && typeof type === 'function' &&
typeof type.prototype !== 'undefined' &&
typeof type.prototype.mountComponent === 'function' && typeof type.prototype.mountComponent === 'function' &&
typeof type.prototype.receiveComponent === 'function' typeof type.prototype.receiveComponent === 'function'
); );
@@ -21355,11 +21420,14 @@ module.exports = traverseAllChildren;
* @providesModule update * @providesModule update
*/ */
/* global hasOwnProperty:true */
'use strict'; 'use strict';
var assign = _dereq_(29); var assign = _dereq_(29);
var keyOf = _dereq_(157); var keyOf = _dereq_(157);
var invariant = _dereq_(150); var invariant = _dereq_(150);
var hasOwnProperty = {}.hasOwnProperty;
function shallowCopy(x) { function shallowCopy(x) {
if (Array.isArray(x)) { if (Array.isArray(x)) {
@@ -21419,7 +21487,7 @@ function update(value, spec) {
COMMAND_SET COMMAND_SET
) : invariant(typeof spec === 'object')); ) : invariant(typeof spec === 'object'));
if (spec.hasOwnProperty(COMMAND_SET)) { if (hasOwnProperty.call(spec, COMMAND_SET)) {
("production" !== "development" ? invariant( ("production" !== "development" ? invariant(
Object.keys(spec).length === 1, Object.keys(spec).length === 1,
'Cannot have more than one key in an object with %s', 'Cannot have more than one key in an object with %s',
@@ -21431,7 +21499,7 @@ function update(value, spec) {
var nextValue = shallowCopy(value); var nextValue = shallowCopy(value);
if (spec.hasOwnProperty(COMMAND_MERGE)) { if (hasOwnProperty.call(spec, COMMAND_MERGE)) {
var mergeObj = spec[COMMAND_MERGE]; var mergeObj = spec[COMMAND_MERGE];
("production" !== "development" ? invariant( ("production" !== "development" ? invariant(
mergeObj && typeof mergeObj === 'object', mergeObj && typeof mergeObj === 'object',
@@ -21448,21 +21516,21 @@ function update(value, spec) {
assign(nextValue, spec[COMMAND_MERGE]); assign(nextValue, spec[COMMAND_MERGE]);
} }
if (spec.hasOwnProperty(COMMAND_PUSH)) { if (hasOwnProperty.call(spec, COMMAND_PUSH)) {
invariantArrayCase(value, spec, COMMAND_PUSH); invariantArrayCase(value, spec, COMMAND_PUSH);
spec[COMMAND_PUSH].forEach(function(item) { spec[COMMAND_PUSH].forEach(function(item) {
nextValue.push(item); nextValue.push(item);
}); });
} }
if (spec.hasOwnProperty(COMMAND_UNSHIFT)) { if (hasOwnProperty.call(spec, COMMAND_UNSHIFT)) {
invariantArrayCase(value, spec, COMMAND_UNSHIFT); invariantArrayCase(value, spec, COMMAND_UNSHIFT);
spec[COMMAND_UNSHIFT].forEach(function(item) { spec[COMMAND_UNSHIFT].forEach(function(item) {
nextValue.unshift(item); nextValue.unshift(item);
}); });
} }
if (spec.hasOwnProperty(COMMAND_SPLICE)) { if (hasOwnProperty.call(spec, COMMAND_SPLICE)) {
("production" !== "development" ? invariant( ("production" !== "development" ? invariant(
Array.isArray(value), Array.isArray(value),
'Expected %s target to be an array; got %s', 'Expected %s target to be an array; got %s',
@@ -21488,7 +21556,7 @@ function update(value, spec) {
}); });
} }
if (spec.hasOwnProperty(COMMAND_APPLY)) { if (hasOwnProperty.call(spec, COMMAND_APPLY)) {
("production" !== "development" ? invariant( ("production" !== "development" ? invariant(
typeof spec[COMMAND_APPLY] === 'function', typeof spec[COMMAND_APPLY] === 'function',
'update(): expected spec of %s to be a function; got %s.', 'update(): expected spec of %s to be a function; got %s.',

18
web/static/js/react-with-addons-0.13.3.min.js поставляемый Обычный файл

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@@ -18,12 +18,13 @@
<link rel="manifest" href="/static/config/manifest.json"> <link rel="manifest" href="/static/config/manifest.json">
<!-- Android add to homescreen --> <!-- Android add to homescreen -->
<link rel="stylesheet" href="/static/css/bootstrap-3.3.1.min.css"> <link rel="stylesheet" href="/static/css/bootstrap-3.3.5.min.css">
<link rel="stylesheet" href="/static/css/jasny-bootstrap.min.css" rel="stylesheet"> <link rel="stylesheet" href="/static/css/jasny-bootstrap.min.css" rel="stylesheet">
<script src="/static/js/react-with-addons-0.13.1.js"></script> <script src="/static/js/react-with-addons-0.13.3.js"></script>
<script src="/static/js/jquery-1.11.1.js"></script> <script src="/static/js/jquery-1.11.1.js"></script>
<script src="/static/js/bootstrap-3.3.1.js"></script> <script src="/static/js/bootstrap-3.3.5.js"></script>
<script src="/static/js/react-bootstrap-0.25.1.js"></script>
<link id="favicon" rel="icon" href="/static/images/favicon.ico" type="image/x-icon"> <link id="favicon" rel="icon" href="/static/images/favicon.ico" type="image/x-icon">
<link rel="shortcut icon" href="/static/images/favicon.ico" type="image/x-icon"> <link rel="shortcut icon" href="/static/images/favicon.ico" type="image/x-icon">