Merge pull request #88 from netlify/class-properties-initializers
Class properties initializers
This commit is contained in:
commit
2022e203bf
@ -3,7 +3,10 @@ env:
|
|||||||
es6: true
|
es6: true
|
||||||
|
|
||||||
parser: babel-eslint
|
parser: babel-eslint
|
||||||
plugins: [ "react" ]
|
plugins: [
|
||||||
|
"react",
|
||||||
|
"class-property"
|
||||||
|
]
|
||||||
|
|
||||||
rules:
|
rules:
|
||||||
# Possible Errors
|
# Possible Errors
|
||||||
@ -97,6 +100,8 @@ rules:
|
|||||||
react/self-closing-comp: 1
|
react/self-closing-comp: 1
|
||||||
react/sort-comp: 1
|
react/sort-comp: 1
|
||||||
|
|
||||||
|
class-property/class-property-semicolon: 2
|
||||||
|
|
||||||
# Global scoped method and vars
|
# Global scoped method and vars
|
||||||
globals:
|
globals:
|
||||||
netlify: true
|
netlify: true
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
"babel-runtime": "^6.5.0",
|
"babel-runtime": "^6.5.0",
|
||||||
"css-loader": "^0.23.1",
|
"css-loader": "^0.23.1",
|
||||||
"eslint": "^3.5.0",
|
"eslint": "^3.5.0",
|
||||||
|
"eslint-plugin-class-property": "^1.0.1",
|
||||||
"eslint-plugin-react": "^5.1.1",
|
"eslint-plugin-react": "^5.1.1",
|
||||||
"expect": "^1.20.2",
|
"expect": "^1.20.2",
|
||||||
"exports-loader": "^0.6.3",
|
"exports-loader": "^0.6.3",
|
||||||
|
@ -6,13 +6,9 @@ export default class AuthenticationPage extends React.Component {
|
|||||||
onLogin: React.PropTypes.func.isRequired
|
onLogin: React.PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(props) {
|
state = {};
|
||||||
super(props);
|
|
||||||
this.state = {};
|
|
||||||
this.handleLogin = this.handleLogin.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleLogin(e) {
|
handleLogin = e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
let auth;
|
let auth;
|
||||||
if (document.location.host.split(':')[0] === 'localhost') {
|
if (document.location.host.split(':')[0] === 'localhost') {
|
||||||
@ -28,7 +24,7 @@ export default class AuthenticationPage extends React.Component {
|
|||||||
}
|
}
|
||||||
this.props.onLogin(data);
|
this.props.onLogin(data);
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { loginError } = this.state;
|
const { loginError } = this.state;
|
||||||
|
@ -5,13 +5,9 @@ export default class AuthenticationPage extends React.Component {
|
|||||||
onLogin: React.PropTypes.func.isRequired
|
onLogin: React.PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(props) {
|
state = {};
|
||||||
super(props);
|
|
||||||
this.state = {};
|
|
||||||
this.handleLogin = this.handleLogin.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleLogin(e) {
|
handleLogin = e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const { email, password } = this.state;
|
const { email, password } = this.state;
|
||||||
this.setState({ authenticating: true });
|
this.setState({ authenticating: true });
|
||||||
@ -33,7 +29,7 @@ export default class AuthenticationPage extends React.Component {
|
|||||||
this.setState({ loginError: data.msg });
|
this.setState({ loginError: data.msg });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
handleChange(key) {
|
handleChange(key) {
|
||||||
return (e) => {
|
return (e) => {
|
||||||
|
@ -5,21 +5,16 @@ export default class AuthenticationPage extends React.Component {
|
|||||||
onLogin: React.PropTypes.func.isRequired
|
onLogin: React.PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(props) {
|
state = { email: '' };
|
||||||
super(props);
|
|
||||||
this.state = { email: '' };
|
|
||||||
this.handleLogin = this.handleLogin.bind(this);
|
|
||||||
this.handleEmailChange = this.handleEmailChange.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleLogin(e) {
|
handleLogin = e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.props.onLogin(this.state);
|
this.props.onLogin(this.state);
|
||||||
}
|
};
|
||||||
|
|
||||||
handleEmailChange(e) {
|
handleEmailChange = e => {
|
||||||
this.setState({ email: e.target.value });
|
this.setState({ email: e.target.value });
|
||||||
}
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <form onSubmit={this.handleLogin}>
|
return <form onSubmit={this.handleLogin}>
|
||||||
|
@ -10,26 +10,26 @@ export default class AppHeader extends React.Component {
|
|||||||
|
|
||||||
state = {
|
state = {
|
||||||
createMenuActive: false
|
createMenuActive: false
|
||||||
}
|
};
|
||||||
|
|
||||||
handleCreatePostClick = collectionName => {
|
handleCreatePostClick = collectionName => {
|
||||||
const { onCreateEntryClick } = this.props;
|
const { onCreateEntryClick } = this.props;
|
||||||
if (onCreateEntryClick) {
|
if (onCreateEntryClick) {
|
||||||
onCreateEntryClick(collectionName);
|
onCreateEntryClick(collectionName);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
handleCreateButtonClick = () => {
|
handleCreateButtonClick = () => {
|
||||||
this.setState({
|
this.setState({
|
||||||
createMenuActive: true
|
createMenuActive: true
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
handleCreateMenuHide = () => {
|
handleCreateMenuHide = () => {
|
||||||
this.setState({
|
this.setState({
|
||||||
createMenuActive: false
|
createMenuActive: false
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
|
@ -5,11 +5,8 @@ import PreviewPane from './PreviewPane';
|
|||||||
import styles from './EntryEditor.css';
|
import styles from './EntryEditor.css';
|
||||||
|
|
||||||
export default class EntryEditor extends React.Component {
|
export default class EntryEditor extends React.Component {
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
state = {};
|
||||||
this.state = {};
|
|
||||||
this.handleResize = this.handleResize.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.calculateHeight();
|
this.calculateHeight();
|
||||||
@ -20,9 +17,9 @@ export default class EntryEditor extends React.Component {
|
|||||||
window.removeEventListener('resize', this.handleResize);
|
window.removeEventListener('resize', this.handleResize);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleResize() {
|
handleResize = () => {
|
||||||
this.calculateHeight();
|
this.calculateHeight();
|
||||||
}
|
};
|
||||||
|
|
||||||
calculateHeight() {
|
calculateHeight() {
|
||||||
const height = window.innerHeight - 54;
|
const height = window.innerHeight - 54;
|
||||||
|
@ -8,8 +8,18 @@ export const SEARCH = 'SEARCH';
|
|||||||
const PLACEHOLDER = 'Search or enter a command';
|
const PLACEHOLDER = 'Search or enter a command';
|
||||||
|
|
||||||
class FindBar extends Component {
|
class FindBar extends Component {
|
||||||
constructor(props) {
|
static propTypes = {
|
||||||
super(props);
|
commands: PropTypes.arrayOf(PropTypes.shape({
|
||||||
|
id: PropTypes.string.isRequired,
|
||||||
|
type: PropTypes.string.isRequired,
|
||||||
|
pattern: PropTypes.string.isRequired
|
||||||
|
})).isRequired,
|
||||||
|
defaultCommands: PropTypes.arrayOf(PropTypes.string),
|
||||||
|
runCommand: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
this._compiledCommands = [];
|
this._compiledCommands = [];
|
||||||
this._searchCommand = {
|
this._searchCommand = {
|
||||||
search: true,
|
search: true,
|
||||||
@ -26,18 +36,6 @@ class FindBar extends Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this._getSuggestions = _.memoize(this._getSuggestions, (value, activeScope) => value + activeScope);
|
this._getSuggestions = _.memoize(this._getSuggestions, (value, activeScope) => value + activeScope);
|
||||||
this.compileCommand = this.compileCommand.bind(this);
|
|
||||||
this.matchCommand = this.matchCommand.bind(this);
|
|
||||||
this.maybeRemoveActiveScope = this.maybeRemoveActiveScope.bind(this);
|
|
||||||
this.handleChange = this.handleChange.bind(this);
|
|
||||||
this.handleKeyDown = this.handleKeyDown.bind(this);
|
|
||||||
this.handleInputBlur = this.handleInputBlur.bind(this);
|
|
||||||
this.handleInputFocus = this.handleInputFocus.bind(this);
|
|
||||||
this.handleInputClick = this.handleInputClick.bind(this);
|
|
||||||
this.getSuggestions = this.getSuggestions.bind(this);
|
|
||||||
this.highlightCommandFromMouse = this.highlightCommandFromMouse.bind(this);
|
|
||||||
this.selectCommandFromMouse = this.selectCommandFromMouse.bind(this);
|
|
||||||
this.setIgnoreBlur = this.setIgnoreBlur.bind(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
@ -58,7 +56,7 @@ class FindBar extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generates a regexp and splits a token and param details for a command
|
// Generates a regexp and splits a token and param details for a command
|
||||||
compileCommand(command) {
|
compileCommand = command => {
|
||||||
let regexp = '';
|
let regexp = '';
|
||||||
let param = null;
|
let param = null;
|
||||||
|
|
||||||
@ -79,11 +77,11 @@ class FindBar extends Component {
|
|||||||
token,
|
token,
|
||||||
param
|
param
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
// Check if the entered string matches any command.
|
// Check if the entered string matches any command.
|
||||||
// adds a scope (so user can type param value) and dispatches action for fully matched commands
|
// adds a scope (so user can type param value) and dispatches action for fully matched commands
|
||||||
matchCommand() {
|
matchCommand = () => {
|
||||||
const string = this.state.activeScope ? this.state.activeScope + this.state.value : this.state.value;
|
const string = this.state.activeScope ? this.state.activeScope + this.state.value : this.state.value;
|
||||||
let match;
|
let match;
|
||||||
let command = this._compiledCommands.find(command => {
|
let command = this._compiledCommands.find(command => {
|
||||||
@ -133,20 +131,20 @@ class FindBar extends Component {
|
|||||||
}
|
}
|
||||||
this.props.runCommand(command.type, payload);
|
this.props.runCommand(command.type, payload);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
maybeRemoveActiveScope() {
|
maybeRemoveActiveScope = () => {
|
||||||
if (this.state.value.length === 0 && this.state.activeScope) {
|
if (this.state.value.length === 0 && this.state.activeScope) {
|
||||||
this.setState({
|
this.setState({
|
||||||
activeScope: null,
|
activeScope: null,
|
||||||
placeholder: PLACEHOLDER
|
placeholder: PLACEHOLDER
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
getSuggestions() {
|
getSuggestions = () => {
|
||||||
return this._getSuggestions(this.state.value, this.state.activeScope, this._compiledCommands, this.props.defaultCommands);
|
return this._getSuggestions(this.state.value, this.state.activeScope, this._compiledCommands, this.props.defaultCommands);
|
||||||
}
|
};
|
||||||
|
|
||||||
// Memoized version
|
// Memoized version
|
||||||
_getSuggestions(value, scope, commands, defaultCommands) {
|
_getSuggestions(value, scope, commands, defaultCommands) {
|
||||||
@ -173,7 +171,7 @@ class FindBar extends Component {
|
|||||||
return returnResults;
|
return returnResults;
|
||||||
}
|
}
|
||||||
|
|
||||||
handleKeyDown(event) {
|
handleKeyDown = event => {
|
||||||
let highlightedIndex, index;
|
let highlightedIndex, index;
|
||||||
switch (event.key) {
|
switch (event.key) {
|
||||||
case 'ArrowDown':
|
case 'ArrowDown':
|
||||||
@ -240,37 +238,37 @@ class FindBar extends Component {
|
|||||||
isOpen: true
|
isOpen: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
handleChange(event) {
|
handleChange = event => {
|
||||||
this.setState({
|
this.setState({
|
||||||
value: event.target.value,
|
value: event.target.value,
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
handleInputBlur() {
|
handleInputBlur = () => {
|
||||||
if (this._ignoreBlur) return;
|
if (this._ignoreBlur) return;
|
||||||
this.setState({
|
this.setState({
|
||||||
isOpen: false,
|
isOpen: false,
|
||||||
highlightedIndex: 0
|
highlightedIndex: 0
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
handleInputFocus() {
|
handleInputFocus = () => {
|
||||||
if (this._ignoreBlur) return;
|
if (this._ignoreBlur) return;
|
||||||
this.setState({ isOpen: true });
|
this.setState({ isOpen: true });
|
||||||
}
|
};
|
||||||
|
|
||||||
handleInputClick() {
|
handleInputClick = () => {
|
||||||
if (this.state.isOpen === false)
|
if (this.state.isOpen === false)
|
||||||
this.setState({ isOpen: true });
|
this.setState({ isOpen: true });
|
||||||
}
|
};
|
||||||
|
|
||||||
highlightCommandFromMouse(index) {
|
highlightCommandFromMouse = index => {
|
||||||
this.setState({ highlightedIndex: index });
|
this.setState({ highlightedIndex: index });
|
||||||
}
|
};
|
||||||
|
|
||||||
selectCommandFromMouse(command) {
|
selectCommandFromMouse = command => {
|
||||||
const newState = {
|
const newState = {
|
||||||
isOpen: false,
|
isOpen: false,
|
||||||
highlightedIndex: 0
|
highlightedIndex: 0
|
||||||
@ -283,11 +281,11 @@ class FindBar extends Component {
|
|||||||
this._input.focus();
|
this._input.focus();
|
||||||
this.setIgnoreBlur(false);
|
this.setIgnoreBlur(false);
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
setIgnoreBlur(ignore) {
|
setIgnoreBlur = ignore => {
|
||||||
this._ignoreBlur = ignore;
|
this._ignoreBlur = ignore;
|
||||||
}
|
};
|
||||||
|
|
||||||
renderMenu() {
|
renderMenu() {
|
||||||
const commands = this.getSuggestions().map((command, index) => {
|
const commands = this.getSuggestions().map((command, index) => {
|
||||||
@ -364,14 +362,4 @@ class FindBar extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FindBar.propTypes = {
|
|
||||||
commands: PropTypes.arrayOf(PropTypes.shape({
|
|
||||||
id: PropTypes.string.isRequired,
|
|
||||||
type: PropTypes.string.isRequired,
|
|
||||||
pattern: PropTypes.string.isRequired
|
|
||||||
})).isRequired,
|
|
||||||
defaultCommands: PropTypes.arrayOf(PropTypes.string),
|
|
||||||
runCommand: PropTypes.func.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default FindBar;
|
export default FindBar;
|
||||||
|
@ -6,6 +6,12 @@ import { resolveWidget } from './Widgets';
|
|||||||
import styles from './PreviewPane.css';
|
import styles from './PreviewPane.css';
|
||||||
|
|
||||||
class Preview extends React.Component {
|
class Preview extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
collection: ImmutablePropTypes.map.isRequired,
|
||||||
|
entry: ImmutablePropTypes.map.isRequired,
|
||||||
|
getMedia: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
previewFor(field) {
|
previewFor(field) {
|
||||||
const { entry, getMedia } = this.props;
|
const { entry, getMedia } = this.props;
|
||||||
const widget = resolveWidget(field.get('widget'));
|
const widget = resolveWidget(field.get('widget'));
|
||||||
@ -26,24 +32,12 @@ class Preview extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Preview.propTypes = {
|
|
||||||
collection: ImmutablePropTypes.map.isRequired,
|
|
||||||
entry: ImmutablePropTypes.map.isRequired,
|
|
||||||
getMedia: PropTypes.func.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default class PreviewPane extends React.Component {
|
export default class PreviewPane extends React.Component {
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.handleIframeRef = this.handleIframeRef.bind(this);
|
|
||||||
this.widgetFor = this.widgetFor.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate() {
|
componentDidUpdate() {
|
||||||
this.renderPreview();
|
this.renderPreview();
|
||||||
}
|
}
|
||||||
|
|
||||||
widgetFor(name) {
|
widgetFor = name => {
|
||||||
const { collection, entry, getMedia } = this.props;
|
const { collection, entry, getMedia } = this.props;
|
||||||
const field = collection.get('fields').find((field) => field.get('name') === name);
|
const field = collection.get('fields').find((field) => field.get('name') === name);
|
||||||
const widget = resolveWidget(field.get('widget'));
|
const widget = resolveWidget(field.get('widget'));
|
||||||
@ -52,7 +46,7 @@ export default class PreviewPane extends React.Component {
|
|||||||
value: entry.getIn(['data', field.get('name')]),
|
value: entry.getIn(['data', field.get('name')]),
|
||||||
getMedia: getMedia,
|
getMedia: getMedia,
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
renderPreview() {
|
renderPreview() {
|
||||||
const props = Object.assign({}, this.props, { widgetFor: this.widgetFor });
|
const props = Object.assign({}, this.props, { widgetFor: this.widgetFor });
|
||||||
@ -61,7 +55,7 @@ export default class PreviewPane extends React.Component {
|
|||||||
render(React.createElement(component, props), this.previewEl);
|
render(React.createElement(component, props), this.previewEl);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleIframeRef(ref) {
|
handleIframeRef = ref => {
|
||||||
if (ref) {
|
if (ref) {
|
||||||
registry.getPreviewStyles().forEach((style) => {
|
registry.getPreviewStyles().forEach((style) => {
|
||||||
const linkEl = document.createElement('link');
|
const linkEl = document.createElement('link');
|
||||||
@ -73,7 +67,7 @@ export default class PreviewPane extends React.Component {
|
|||||||
ref.contentDocument.body.appendChild(this.previewEl);
|
ref.contentDocument.body.appendChild(this.previewEl);
|
||||||
this.renderPreview();
|
this.renderPreview();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { collection } = this.props;
|
const { collection } = this.props;
|
||||||
|
@ -3,14 +3,10 @@ import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
|
|||||||
import styles from './Loader.css';
|
import styles from './Loader.css';
|
||||||
|
|
||||||
export default class Loader extends React.Component {
|
export default class Loader extends React.Component {
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
state = {
|
||||||
this.state = {
|
|
||||||
currentItem: 0,
|
currentItem: 0,
|
||||||
};
|
};
|
||||||
this.setAnimation = this.setAnimation.bind(this);
|
|
||||||
this.renderChild = this.renderChild.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
if (this.interval) {
|
if (this.interval) {
|
||||||
@ -18,7 +14,7 @@ export default class Loader extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setAnimation() {
|
setAnimation = () => {
|
||||||
if (this.interval) return;
|
if (this.interval) return;
|
||||||
const { children } = this.props;
|
const { children } = this.props;
|
||||||
|
|
||||||
@ -27,9 +23,9 @@ export default class Loader extends React.Component {
|
|||||||
const nextItem = (this.state.currentItem === children.length - 1) ? 0 : this.state.currentItem + 1;
|
const nextItem = (this.state.currentItem === children.length - 1) ? 0 : this.state.currentItem + 1;
|
||||||
this.setState({ currentItem: nextItem });
|
this.setState({ currentItem: nextItem });
|
||||||
}, 5000);
|
}, 5000);
|
||||||
}
|
};
|
||||||
|
|
||||||
renderChild() {
|
renderChild = () => {
|
||||||
const { children } = this.props;
|
const { children } = this.props;
|
||||||
const { currentItem } = this.state;
|
const { currentItem } = this.state;
|
||||||
if (!children) {
|
if (!children) {
|
||||||
@ -48,7 +44,7 @@ export default class Loader extends React.Component {
|
|||||||
</ReactCSSTransitionGroup>
|
</ReactCSSTransitionGroup>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { active, style, className = '' } = this.props;
|
const { active, style, className = '' } = this.props;
|
||||||
|
@ -3,15 +3,11 @@ import { Icon } from '../index';
|
|||||||
import styles from './Toast.css';
|
import styles from './Toast.css';
|
||||||
|
|
||||||
export default class Toast extends React.Component {
|
export default class Toast extends React.Component {
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
state = {
|
||||||
this.state = {
|
|
||||||
shown: false
|
shown: false
|
||||||
};
|
};
|
||||||
|
|
||||||
this.autoHideTimeout = this.autoHideTimeout.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
if (this.props.show) {
|
if (this.props.show) {
|
||||||
this.autoHideTimeout();
|
this.autoHideTimeout();
|
||||||
@ -32,12 +28,12 @@ export default class Toast extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
autoHideTimeout() {
|
autoHideTimeout = () => {
|
||||||
clearTimeout(this.timeOut);
|
clearTimeout(this.timeOut);
|
||||||
this.timeOut = setTimeout(() => {
|
this.timeOut = setTimeout(() => {
|
||||||
this.setState({ shown: false });
|
this.setState({ shown: false });
|
||||||
}, 4000);
|
}, 4000);
|
||||||
}
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { style, type, className, children } = this.props;
|
const { style, type, className, children } = this.props;
|
||||||
|
@ -8,28 +8,21 @@ import { status, statusDescriptions } from '../constants/publishModes';
|
|||||||
import styles from './UnpublishedListing.css';
|
import styles from './UnpublishedListing.css';
|
||||||
|
|
||||||
class UnpublishedListing extends React.Component {
|
class UnpublishedListing extends React.Component {
|
||||||
constructor(props) {
|
handleChangeStatus = (newStatus, dragProps) => {
|
||||||
super(props);
|
|
||||||
this.renderColumns = this.renderColumns.bind(this);
|
|
||||||
this.handleChangeStatus = this.handleChangeStatus.bind(this);
|
|
||||||
this.requestPublish = this.requestPublish.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleChangeStatus(newStatus, dragProps) {
|
|
||||||
const slug = dragProps.slug;
|
const slug = dragProps.slug;
|
||||||
const collection = dragProps.collection;
|
const collection = dragProps.collection;
|
||||||
const oldStatus = dragProps.ownStatus;
|
const oldStatus = dragProps.ownStatus;
|
||||||
this.props.handleChangeStatus(collection, slug, oldStatus, newStatus);
|
this.props.handleChangeStatus(collection, slug, oldStatus, newStatus);
|
||||||
}
|
};
|
||||||
|
|
||||||
requestPublish(collection, slug, ownStatus) {
|
requestPublish = (collection, slug, ownStatus) => {
|
||||||
if (ownStatus !== status.last()) return;
|
if (ownStatus !== status.last()) return;
|
||||||
if (window.confirm('Are you sure you want to publish this entry?')) {
|
if (window.confirm('Are you sure you want to publish this entry?')) {
|
||||||
this.props.handlePublish(collection, slug, ownStatus);
|
this.props.handlePublish(collection, slug, ownStatus);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
renderColumns(entries, column) {
|
renderColumns = (entries, column) => {
|
||||||
if (!entries) return;
|
if (!entries) return;
|
||||||
|
|
||||||
if (!column) {
|
if (!column) {
|
||||||
@ -74,7 +67,13 @@ class UnpublishedListing extends React.Component {
|
|||||||
)}
|
)}
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
entries: ImmutablePropTypes.orderedMap,
|
||||||
|
handleChangeStatus: PropTypes.func.isRequired,
|
||||||
|
handlePublish: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const columns = this.renderColumns(this.props.entries);
|
const columns = this.renderColumns(this.props.entries);
|
||||||
@ -89,10 +88,4 @@ class UnpublishedListing extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UnpublishedListing.propTypes = {
|
|
||||||
entries: ImmutablePropTypes.orderedMap,
|
|
||||||
handleChangeStatus: PropTypes.func.isRequired,
|
|
||||||
handlePublish: PropTypes.func.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default HTML5DragDrop(UnpublishedListing);
|
export default HTML5DragDrop(UnpublishedListing);
|
||||||
|
@ -2,14 +2,9 @@ import React, { PropTypes } from 'react';
|
|||||||
import DateTime from 'react-datetime';
|
import DateTime from 'react-datetime';
|
||||||
|
|
||||||
export default class DateTimeControl extends React.Component {
|
export default class DateTimeControl extends React.Component {
|
||||||
constructor(props) {
|
handleChange = datetime => {
|
||||||
super(props);
|
|
||||||
this.handleChange = this.handleChange.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleChange(datetime) {
|
|
||||||
this.props.onChange(datetime);
|
this.props.onChange(datetime);
|
||||||
}
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <DateTime value={this.props.value || new Date()} onChange={this.handleChange}/>;
|
return <DateTime value={this.props.value || new Date()} onChange={this.handleChange}/>;
|
||||||
|
@ -5,36 +5,25 @@ import MediaProxy from '../../valueObjects/MediaProxy';
|
|||||||
const MAX_DISPLAY_LENGTH = 50;
|
const MAX_DISPLAY_LENGTH = 50;
|
||||||
|
|
||||||
export default class ImageControl extends React.Component {
|
export default class ImageControl extends React.Component {
|
||||||
constructor(props) {
|
handleFileInputRef = el => {
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.handleChange = this.handleChange.bind(this);
|
|
||||||
this.handleFileInputRef = this.handleFileInputRef.bind(this);
|
|
||||||
this.handleClick = this.handleClick.bind(this);
|
|
||||||
this.handleDragEnter = this.handleDragEnter.bind(this);
|
|
||||||
this.handleDragOver = this.handleDragOver.bind(this);
|
|
||||||
this.renderImageName = this.renderImageName.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleFileInputRef(el) {
|
|
||||||
this._fileInput = el;
|
this._fileInput = el;
|
||||||
}
|
};
|
||||||
|
|
||||||
handleClick(e) {
|
handleClick = e => {
|
||||||
this._fileInput.click();
|
this._fileInput.click();
|
||||||
}
|
};
|
||||||
|
|
||||||
handleDragEnter(e) {
|
handleDragEnter = e => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
};
|
||||||
|
|
||||||
handleDragOver(e) {
|
handleDragOver = e => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
};
|
||||||
|
|
||||||
handleChange(e) {
|
handleChange = e => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
@ -58,9 +47,9 @@ export default class ImageControl extends React.Component {
|
|||||||
this.props.onChange(null);
|
this.props.onChange(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
};
|
||||||
|
|
||||||
renderImageName() {
|
renderImageName = () => {
|
||||||
if (!this.props.value) return null;
|
if (!this.props.value) return null;
|
||||||
if (this.value instanceof MediaProxy) {
|
if (this.value instanceof MediaProxy) {
|
||||||
return truncateMiddle(this.props.value.path, MAX_DISPLAY_LENGTH);
|
return truncateMiddle(this.props.value.path, MAX_DISPLAY_LENGTH);
|
||||||
@ -68,7 +57,7 @@ export default class ImageControl extends React.Component {
|
|||||||
return truncateMiddle(this.props.value, MAX_DISPLAY_LENGTH);
|
return truncateMiddle(this.props.value, MAX_DISPLAY_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const imageName = this.renderImageName();
|
const imageName = this.renderImageName();
|
||||||
|
@ -7,24 +7,31 @@ import { connect } from 'react-redux';
|
|||||||
import { switchVisualMode } from '../../actions/editor';
|
import { switchVisualMode } from '../../actions/editor';
|
||||||
|
|
||||||
class MarkdownControl extends React.Component {
|
class MarkdownControl extends React.Component {
|
||||||
constructor(props, context) {
|
static propTypes = {
|
||||||
super(props, context);
|
editor: PropTypes.object.isRequired,
|
||||||
this.useVisualEditor = this.useVisualEditor.bind(this);
|
onChange: PropTypes.func.isRequired,
|
||||||
this.useRawEditor = this.useRawEditor.bind(this);
|
onAddMedia: PropTypes.func.isRequired,
|
||||||
}
|
getMedia: PropTypes.func.isRequired,
|
||||||
|
switchVisualMode: PropTypes.func.isRequired,
|
||||||
|
value: PropTypes.node,
|
||||||
|
};
|
||||||
|
|
||||||
|
static contextTypes = {
|
||||||
|
plugins: PropTypes.object,
|
||||||
|
};
|
||||||
|
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
this.useRawEditor();
|
this.useRawEditor();
|
||||||
processEditorPlugins(registry.getEditorComponents());
|
processEditorPlugins(registry.getEditorComponents());
|
||||||
}
|
}
|
||||||
|
|
||||||
useVisualEditor() {
|
useVisualEditor = () => {
|
||||||
this.props.switchVisualMode(true);
|
this.props.switchVisualMode(true);
|
||||||
}
|
};
|
||||||
|
|
||||||
useRawEditor() {
|
useRawEditor = () => {
|
||||||
this.props.switchVisualMode(false);
|
this.props.switchVisualMode(false);
|
||||||
}
|
};
|
||||||
|
|
||||||
renderEditor() {
|
renderEditor() {
|
||||||
const { editor, onChange, onAddMedia, getMedia, value } = this.props;
|
const { editor, onChange, onAddMedia, getMedia, value } = this.props;
|
||||||
@ -66,19 +73,6 @@ class MarkdownControl extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MarkdownControl.propTypes = {
|
|
||||||
editor: PropTypes.object.isRequired,
|
|
||||||
onChange: PropTypes.func.isRequired,
|
|
||||||
onAddMedia: PropTypes.func.isRequired,
|
|
||||||
getMedia: PropTypes.func.isRequired,
|
|
||||||
switchVisualMode: PropTypes.func.isRequired,
|
|
||||||
value: PropTypes.node,
|
|
||||||
};
|
|
||||||
|
|
||||||
MarkdownControl.contextTypes = {
|
|
||||||
plugins: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
state => ({ editor: state.editor }),
|
state => ({ editor: state.editor }),
|
||||||
{ switchVisualMode }
|
{ switchVisualMode }
|
||||||
|
@ -73,7 +73,6 @@ const SCHEMA = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class RawEditor extends React.Component {
|
class RawEditor extends React.Component {
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
@ -82,10 +81,6 @@ class RawEditor extends React.Component {
|
|||||||
this.state = {
|
this.state = {
|
||||||
state: content
|
state: content
|
||||||
};
|
};
|
||||||
|
|
||||||
this.handleChange = this.handleChange.bind(this);
|
|
||||||
this.handleDocumentChange = this.handleDocumentChange.bind(this);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -94,14 +89,14 @@ class RawEditor extends React.Component {
|
|||||||
* It also have an onDocumentChange, that get's dispached only when the actual
|
* It also have an onDocumentChange, that get's dispached only when the actual
|
||||||
* content changes
|
* content changes
|
||||||
*/
|
*/
|
||||||
handleChange(state) {
|
handleChange = state => {
|
||||||
this.setState({ state });
|
this.setState({ state });
|
||||||
}
|
};
|
||||||
|
|
||||||
handleDocumentChange(document, state) {
|
handleDocumentChange = (document, state) => {
|
||||||
const content = Plain.serialize(state, { terse: true });
|
const content = Plain.serialize(state, { terse: true });
|
||||||
this.props.onChange(content);
|
this.props.onChange(content);
|
||||||
}
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
|
@ -12,16 +12,6 @@ export default class BlockTypesMenu extends Component {
|
|||||||
expanded: false,
|
expanded: false,
|
||||||
menu: null
|
menu: null
|
||||||
};
|
};
|
||||||
|
|
||||||
this.updateMenuPosition = this.updateMenuPosition.bind(this);
|
|
||||||
this.toggleMenu = this.toggleMenu.bind(this);
|
|
||||||
this.handleOpen = this.handleOpen.bind(this);
|
|
||||||
this.handleBlockTypeClick = this.handleBlockTypeClick.bind(this);
|
|
||||||
this.handlePluginClick = this.handlePluginClick.bind(this);
|
|
||||||
this.handleFileUploadClick = this.handleFileUploadClick.bind(this);
|
|
||||||
this.handleFileUploadChange = this.handleFileUploadChange.bind(this);
|
|
||||||
this.renderBlockTypeButton = this.renderBlockTypeButton.bind(this);
|
|
||||||
this.renderPluginButton = this.renderPluginButton.bind(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -41,7 +31,7 @@ export default class BlockTypesMenu extends Component {
|
|||||||
this.updateMenuPosition();
|
this.updateMenuPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateMenuPosition() {
|
updateMenuPosition = () => {
|
||||||
const { menu } = this.state;
|
const { menu } = this.state;
|
||||||
const { position } = this.props;
|
const { position } = this.props;
|
||||||
if (!menu) return;
|
if (!menu) return;
|
||||||
@ -50,29 +40,29 @@ export default class BlockTypesMenu extends Component {
|
|||||||
menu.style.top = `${position.top}px`;
|
menu.style.top = `${position.top}px`;
|
||||||
menu.style.left = `${position.left - menu.offsetWidth * 2}px`;
|
menu.style.left = `${position.left - menu.offsetWidth * 2}px`;
|
||||||
|
|
||||||
}
|
};
|
||||||
|
|
||||||
toggleMenu() {
|
toggleMenu = () => {
|
||||||
this.setState({ expanded: !this.state.expanded });
|
this.setState({ expanded: !this.state.expanded });
|
||||||
}
|
};
|
||||||
|
|
||||||
handleBlockTypeClick(e, type) {
|
handleBlockTypeClick = (e, type) => {
|
||||||
this.props.onClickBlock(type);
|
this.props.onClickBlock(type);
|
||||||
}
|
};
|
||||||
|
|
||||||
handlePluginClick(e, plugin) {
|
handlePluginClick = (e, plugin) => {
|
||||||
const data = {};
|
const data = {};
|
||||||
plugin.fields.forEach(field => {
|
plugin.fields.forEach(field => {
|
||||||
data[field.name] = window.prompt(field.label);
|
data[field.name] = window.prompt(field.label);
|
||||||
});
|
});
|
||||||
this.props.onClickPlugin(plugin.id, data);
|
this.props.onClickPlugin(plugin.id, data);
|
||||||
}
|
};
|
||||||
|
|
||||||
handleFileUploadClick() {
|
handleFileUploadClick = () => {
|
||||||
this._fileInput.click();
|
this._fileInput.click();
|
||||||
}
|
};
|
||||||
|
|
||||||
handleFileUploadChange(e) {
|
handleFileUploadChange = e => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
@ -92,21 +82,21 @@ export default class BlockTypesMenu extends Component {
|
|||||||
this.props.onClickImage(mediaProxy);
|
this.props.onClickImage(mediaProxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
};
|
||||||
|
|
||||||
renderBlockTypeButton(type, icon) {
|
renderBlockTypeButton = (type, icon) => {
|
||||||
const onClick = e => this.handleBlockTypeClick(e, type);
|
const onClick = e => this.handleBlockTypeClick(e, type);
|
||||||
return (
|
return (
|
||||||
<Icon key={type} type={icon} onClick={onClick} className={styles.icon} />
|
<Icon key={type} type={icon} onClick={onClick} className={styles.icon} />
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
renderPluginButton(plugin) {
|
renderPluginButton = plugin => {
|
||||||
const onClick = e => this.handlePluginClick(e, plugin);
|
const onClick = e => this.handlePluginClick(e, plugin);
|
||||||
return (
|
return (
|
||||||
<Icon key={plugin.id} type={plugin.icon} onClick={onClick} className={styles.icon} />
|
<Icon key={plugin.id} type={plugin.icon} onClick={onClick} className={styles.icon} />
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
renderMenu() {
|
renderMenu() {
|
||||||
const { plugins } = this.props;
|
const { plugins } = this.props;
|
||||||
@ -133,9 +123,9 @@ export default class BlockTypesMenu extends Component {
|
|||||||
/**
|
/**
|
||||||
* When the portal opens, cache the menu element.
|
* When the portal opens, cache the menu element.
|
||||||
*/
|
*/
|
||||||
handleOpen(portal) {
|
handleOpen = portal => {
|
||||||
this.setState({ menu: portal.firstChild });
|
this.setState({ menu: portal.firstChild });
|
||||||
}
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { isOpen } = this.props;
|
const { isOpen } = this.props;
|
||||||
|
@ -4,24 +4,12 @@ import { Icon } from '../../../UI';
|
|||||||
import styles from './StylesMenu.css';
|
import styles from './StylesMenu.css';
|
||||||
|
|
||||||
export default class StylesMenu extends Component {
|
export default class StylesMenu extends Component {
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
menu: null
|
menu: null
|
||||||
};
|
};
|
||||||
|
|
||||||
this.hasMark = this.hasMark.bind(this);
|
|
||||||
this.hasBlock = this.hasBlock.bind(this);
|
|
||||||
this.renderMarkButton = this.renderMarkButton.bind(this);
|
|
||||||
this.renderBlockButton = this.renderBlockButton.bind(this);
|
|
||||||
this.renderLinkButton = this.renderLinkButton.bind(this);
|
|
||||||
this.updateMenuPosition = this.updateMenuPosition.bind(this);
|
|
||||||
this.handleMarkClick = this.handleMarkClick.bind(this);
|
|
||||||
this.handleInlineClick = this.handleInlineClick.bind(this);
|
|
||||||
this.handleBlockClick = this.handleBlockClick.bind(this);
|
|
||||||
this.handleOpen = this.handleOpen.bind(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -35,7 +23,7 @@ export default class StylesMenu extends Component {
|
|||||||
this.updateMenuPosition();
|
this.updateMenuPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateMenuPosition() {
|
updateMenuPosition = () => {
|
||||||
const { menu } = this.state;
|
const { menu } = this.state;
|
||||||
const { position } = this.props;
|
const { position } = this.props;
|
||||||
if (!menu) return;
|
if (!menu) return;
|
||||||
@ -43,30 +31,32 @@ export default class StylesMenu extends Component {
|
|||||||
menu.style.opacity = 1;
|
menu.style.opacity = 1;
|
||||||
menu.style.top = `${position.top - menu.offsetHeight}px`;
|
menu.style.top = `${position.top - menu.offsetHeight}px`;
|
||||||
menu.style.left = `${position.left - menu.offsetWidth / 2 + position.width / 2}px`;
|
menu.style.left = `${position.left - menu.offsetWidth / 2 + position.width / 2}px`;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to set toolbar buttons to active state
|
* Used to set toolbar buttons to active state
|
||||||
*/
|
*/
|
||||||
hasMark(type) {
|
hasMark = type => {
|
||||||
const { marks } = this.props;
|
const { marks } = this.props;
|
||||||
return marks.some(mark => mark.type == type);
|
return marks.some(mark => mark.type == type);
|
||||||
}
|
};
|
||||||
hasBlock(type) {
|
|
||||||
|
hasBlock = type => {
|
||||||
const { blocks } = this.props;
|
const { blocks } = this.props;
|
||||||
return blocks.some(node => node.type == type);
|
return blocks.some(node => node.type == type);
|
||||||
}
|
};
|
||||||
|
|
||||||
hasLinks(type) {
|
hasLinks(type) {
|
||||||
const { inlines } = this.props;
|
const { inlines } = this.props;
|
||||||
return inlines.some(inline => inline.type == 'link');
|
return inlines.some(inline => inline.type == 'link');
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMarkClick(e, type) {
|
handleMarkClick = (e, type) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.props.onClickMark(type);
|
this.props.onClickMark(type);
|
||||||
}
|
};
|
||||||
|
|
||||||
renderMarkButton(type, icon) {
|
renderMarkButton = (type, icon) => {
|
||||||
const isActive = this.hasMark(type);
|
const isActive = this.hasMark(type);
|
||||||
const onMouseDown = e => this.handleMarkClick(e, type);
|
const onMouseDown = e => this.handleMarkClick(e, type);
|
||||||
return (
|
return (
|
||||||
@ -74,14 +64,14 @@ export default class StylesMenu extends Component {
|
|||||||
<Icon type={icon}/>
|
<Icon type={icon}/>
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
handleInlineClick(e, type, isActive) {
|
handleInlineClick = (e, type, isActive) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.props.onClickInline(type, isActive);
|
this.props.onClickInline(type, isActive);
|
||||||
}
|
};
|
||||||
|
|
||||||
renderLinkButton() {
|
renderLinkButton = () => {
|
||||||
const isActive = this.hasLinks();
|
const isActive = this.hasLinks();
|
||||||
const onMouseDown = e => this.handleInlineClick(e, 'link', isActive);
|
const onMouseDown = e => this.handleInlineClick(e, 'link', isActive);
|
||||||
return (
|
return (
|
||||||
@ -89,16 +79,16 @@ export default class StylesMenu extends Component {
|
|||||||
<Icon type="link"/>
|
<Icon type="link"/>
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
handleBlockClick(e, type) {
|
handleBlockClick = (e, type) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const isActive = this.hasBlock(type);
|
const isActive = this.hasBlock(type);
|
||||||
const isList = this.hasBlock('list-item');
|
const isList = this.hasBlock('list-item');
|
||||||
this.props.onClickBlock(type, isActive, isList);
|
this.props.onClickBlock(type, isActive, isList);
|
||||||
}
|
};
|
||||||
|
|
||||||
renderBlockButton(type, icon, checkType) {
|
renderBlockButton = (type, icon, checkType) => {
|
||||||
checkType = checkType || type;
|
checkType = checkType || type;
|
||||||
const isActive = this.hasBlock(checkType);
|
const isActive = this.hasBlock(checkType);
|
||||||
const onMouseDown = e => this.handleBlockClick(e, type);
|
const onMouseDown = e => this.handleBlockClick(e, type);
|
||||||
@ -107,14 +97,14 @@ export default class StylesMenu extends Component {
|
|||||||
<Icon type={icon}/>
|
<Icon type={icon}/>
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When the portal opens, cache the menu element.
|
* When the portal opens, cache the menu element.
|
||||||
*/
|
*/
|
||||||
handleOpen(portal) {
|
handleOpen = portal => {
|
||||||
this.setState({ menu: portal.firstChild });
|
this.setState({ menu: portal.firstChild });
|
||||||
}
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { isOpen } = this.props;
|
const { isOpen } = this.props;
|
||||||
@ -133,7 +123,6 @@ export default class StylesMenu extends Component {
|
|||||||
</Portal>
|
</Portal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StylesMenu.propTypes = {
|
StylesMenu.propTypes = {
|
||||||
|
@ -17,7 +17,6 @@ class VisualEditor extends React.Component {
|
|||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.getMedia = this.getMedia.bind(this);
|
|
||||||
const MarkdownSyntax = getSyntaxes(this.getMedia).markdown;
|
const MarkdownSyntax = getSyntaxes(this.getMedia).markdown;
|
||||||
this.markdown = new MarkupIt(MarkdownSyntax);
|
this.markdown = new MarkupIt(MarkdownSyntax);
|
||||||
|
|
||||||
@ -51,24 +50,13 @@ class VisualEditor extends React.Component {
|
|||||||
state: Raw.deserialize(rawJson, { terse: true })
|
state: Raw.deserialize(rawJson, { terse: true })
|
||||||
};
|
};
|
||||||
|
|
||||||
this.handleChange = this.handleChange.bind(this);
|
|
||||||
this.handleDocumentChange = this.handleDocumentChange.bind(this);
|
|
||||||
this.handleMarkStyleClick = this.handleMarkStyleClick.bind(this);
|
|
||||||
this.handleBlockStyleClick = this.handleBlockStyleClick.bind(this);
|
|
||||||
this.handleInlineClick = this.handleInlineClick.bind(this);
|
|
||||||
this.handleBlockTypeClick = this.handleBlockTypeClick.bind(this);
|
|
||||||
this.handlePluginClick = this.handlePluginClick.bind(this);
|
|
||||||
this.handleImageClick = this.handleImageClick.bind(this);
|
|
||||||
this.focusAndAddParagraph = this.focusAndAddParagraph.bind(this);
|
|
||||||
this.handleKeyDown = this.handleKeyDown.bind(this);
|
|
||||||
this.calculateHoverMenuPosition = _.throttle(this.calculateHoverMenuPosition.bind(this), 30);
|
this.calculateHoverMenuPosition = _.throttle(this.calculateHoverMenuPosition.bind(this), 30);
|
||||||
this.calculateBlockMenuPosition = _.throttle(this.calculateBlockMenuPosition.bind(this), 100);
|
this.calculateBlockMenuPosition = _.throttle(this.calculateBlockMenuPosition.bind(this), 100);
|
||||||
this.renderBlockTypesMenu = this.renderBlockTypesMenu.bind(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getMedia(src) {
|
getMedia = src => {
|
||||||
return this.props.getMedia(src);
|
return this.props.getMedia(src);
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Slate keeps track of selections, scroll position etc.
|
* Slate keeps track of selections, scroll position etc.
|
||||||
@ -76,20 +64,20 @@ class VisualEditor extends React.Component {
|
|||||||
* It also have an onDocumentChange, that get's dispached only when the actual
|
* It also have an onDocumentChange, that get's dispached only when the actual
|
||||||
* content changes
|
* content changes
|
||||||
*/
|
*/
|
||||||
handleChange(state) {
|
handleChange = state => {
|
||||||
if (this.blockEdit) {
|
if (this.blockEdit) {
|
||||||
this.blockEdit = false;
|
this.blockEdit = false;
|
||||||
} else {
|
} else {
|
||||||
this.calculateHoverMenuPosition();
|
this.calculateHoverMenuPosition();
|
||||||
this.setState({ state }, this.calculateBlockMenuPosition);
|
this.setState({ state }, this.calculateBlockMenuPosition);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
handleDocumentChange(document, state) {
|
handleDocumentChange = (document, state) => {
|
||||||
const rawJson = Raw.serialize(state, { terse: true });
|
const rawJson = Raw.serialize(state, { terse: true });
|
||||||
const content = SlateUtils.decode(rawJson);
|
const content = SlateUtils.decode(rawJson);
|
||||||
this.props.onChange(this.markdown.toText(content));
|
this.props.onChange(this.markdown.toText(content));
|
||||||
}
|
};
|
||||||
|
|
||||||
calculateHoverMenuPosition() {
|
calculateHoverMenuPosition() {
|
||||||
const rect = position();
|
const rect = position();
|
||||||
@ -120,7 +108,7 @@ class VisualEditor extends React.Component {
|
|||||||
/**
|
/**
|
||||||
* Toggle marks / blocks when button is clicked
|
* Toggle marks / blocks when button is clicked
|
||||||
*/
|
*/
|
||||||
handleMarkStyleClick(type) {
|
handleMarkStyleClick = type => {
|
||||||
let { state } = this.state;
|
let { state } = this.state;
|
||||||
|
|
||||||
state = state
|
state = state
|
||||||
@ -129,9 +117,9 @@ class VisualEditor extends React.Component {
|
|||||||
.apply();
|
.apply();
|
||||||
|
|
||||||
this.setState({ state });
|
this.setState({ state });
|
||||||
}
|
};
|
||||||
|
|
||||||
handleBlockStyleClick(type, isActive, isList) {
|
handleBlockStyleClick = (type, isActive, isList) => {
|
||||||
let { state } = this.state;
|
let { state } = this.state;
|
||||||
let transform = state.transform();
|
let transform = state.transform();
|
||||||
const { document } = state;
|
const { document } = state;
|
||||||
@ -175,7 +163,7 @@ class VisualEditor extends React.Component {
|
|||||||
|
|
||||||
state = transform.apply();
|
state = transform.apply();
|
||||||
this.setState({ state });
|
this.setState({ state });
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When clicking a link, if the selection has a link in it, remove the link.
|
* When clicking a link, if the selection has a link in it, remove the link.
|
||||||
@ -184,7 +172,7 @@ class VisualEditor extends React.Component {
|
|||||||
* @param {Event} e
|
* @param {Event} e
|
||||||
*/
|
*/
|
||||||
|
|
||||||
handleInlineClick(type, isActive) {
|
handleInlineClick = (type, isActive) => {
|
||||||
let { state } = this.state;
|
let { state } = this.state;
|
||||||
|
|
||||||
if (type === 'link') {
|
if (type === 'link') {
|
||||||
@ -210,10 +198,9 @@ class VisualEditor extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.setState({ state });
|
this.setState({ state });
|
||||||
}
|
};
|
||||||
|
|
||||||
|
handleBlockTypeClick = type => {
|
||||||
handleBlockTypeClick(type) {
|
|
||||||
let { state } = this.state;
|
let { state } = this.state;
|
||||||
|
|
||||||
state = state
|
state = state
|
||||||
@ -225,9 +212,9 @@ class VisualEditor extends React.Component {
|
|||||||
.apply();
|
.apply();
|
||||||
|
|
||||||
this.setState({ state }, this.focusAndAddParagraph);
|
this.setState({ state }, this.focusAndAddParagraph);
|
||||||
}
|
};
|
||||||
|
|
||||||
handlePluginClick(type, data) {
|
handlePluginClick = (type, data) => {
|
||||||
let { state } = this.state;
|
let { state } = this.state;
|
||||||
|
|
||||||
state = state
|
state = state
|
||||||
@ -243,9 +230,9 @@ class VisualEditor extends React.Component {
|
|||||||
.apply();
|
.apply();
|
||||||
|
|
||||||
this.setState({ state });
|
this.setState({ state });
|
||||||
}
|
};
|
||||||
|
|
||||||
handleImageClick(mediaProxy) {
|
handleImageClick = mediaProxy => {
|
||||||
let { state } = this.state;
|
let { state } = this.state;
|
||||||
this.props.onAddMedia(mediaProxy);
|
this.props.onAddMedia(mediaProxy);
|
||||||
|
|
||||||
@ -262,9 +249,9 @@ class VisualEditor extends React.Component {
|
|||||||
.apply();
|
.apply();
|
||||||
|
|
||||||
this.setState({ state });
|
this.setState({ state });
|
||||||
}
|
};
|
||||||
|
|
||||||
focusAndAddParagraph() {
|
focusAndAddParagraph = () => {
|
||||||
const { state } = this.state;
|
const { state } = this.state;
|
||||||
const blocks = state.document.getBlocks();
|
const blocks = state.document.getBlocks();
|
||||||
const last = blocks.last();
|
const last = blocks.last();
|
||||||
@ -278,10 +265,9 @@ class VisualEditor extends React.Component {
|
|||||||
snapshot: false
|
snapshot: false
|
||||||
});
|
});
|
||||||
this.setState({ state:normalized });
|
this.setState({ state:normalized });
|
||||||
}
|
};
|
||||||
|
|
||||||
|
handleKeyDown = evt => {
|
||||||
handleKeyDown(evt) {
|
|
||||||
if (evt.shiftKey && evt.key === 'Enter') {
|
if (evt.shiftKey && evt.key === 'Enter') {
|
||||||
this.blockEdit = true;
|
this.blockEdit = true;
|
||||||
let { state } = this.state;
|
let { state } = this.state;
|
||||||
@ -292,9 +278,9 @@ class VisualEditor extends React.Component {
|
|||||||
|
|
||||||
this.setState({ state });
|
this.setState({ state });
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
renderBlockTypesMenu() {
|
renderBlockTypesMenu = () => {
|
||||||
const currentBlock = this.state.state.blocks.get(0);
|
const currentBlock = this.state.state.blocks.get(0);
|
||||||
const isOpen = (this.props.value !== undefined && currentBlock.isEmpty && currentBlock.type !== 'horizontal-rule');
|
const isOpen = (this.props.value !== undefined && currentBlock.isEmpty && currentBlock.type !== 'horizontal-rule');
|
||||||
|
|
||||||
@ -308,7 +294,7 @@ class VisualEditor extends React.Component {
|
|||||||
onClickImage={this.handleImageClick}
|
onClickImage={this.handleImageClick}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
renderStylesMenu() {
|
renderStylesMenu() {
|
||||||
const { state } = this.state;
|
const { state } = this.state;
|
||||||
|
@ -18,6 +18,14 @@ const EditorComponent = Record({
|
|||||||
|
|
||||||
|
|
||||||
class Plugin extends Component {
|
class Plugin extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
children: PropTypes.element.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
static childContextTypes = {
|
||||||
|
plugins: PropTypes.object
|
||||||
|
};
|
||||||
|
|
||||||
getChildContext() {
|
getChildContext() {
|
||||||
return { plugins: plugins };
|
return { plugins: plugins };
|
||||||
}
|
}
|
||||||
@ -27,13 +35,6 @@ class Plugin extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Plugin.propTypes = {
|
|
||||||
children: PropTypes.element.isRequired
|
|
||||||
};
|
|
||||||
Plugin.childContextTypes = {
|
|
||||||
plugins: PropTypes.object
|
|
||||||
};
|
|
||||||
|
|
||||||
export function newEditorPlugin(config) {
|
export function newEditorPlugin(config) {
|
||||||
const configObj = new EditorComponent({
|
const configObj = new EditorComponent({
|
||||||
id: config.id || config.label.replace(/[^A-Z0-9]+/ig, '_'),
|
id: config.id || config.label.replace(/[^A-Z0-9]+/ig, '_'),
|
||||||
|
@ -1,14 +1,9 @@
|
|||||||
import React, { PropTypes } from 'react';
|
import React, { PropTypes } from 'react';
|
||||||
|
|
||||||
export default class StringControl extends React.Component {
|
export default class StringControl extends React.Component {
|
||||||
constructor(props) {
|
handleChange = e => {
|
||||||
super(props);
|
|
||||||
this.handleChange = this.handleChange.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleChange(e) {
|
|
||||||
this.props.onChange(e.target.value);
|
this.props.onChange(e.target.value);
|
||||||
}
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <input type="text" value={this.props.value || ''} onChange={this.handleChange}/>;
|
return <input type="text" value={this.props.value || ''} onChange={this.handleChange}/>;
|
||||||
|
@ -1,20 +1,14 @@
|
|||||||
import React, { PropTypes } from 'react';
|
import React, { PropTypes } from 'react';
|
||||||
|
|
||||||
export default class StringControl extends React.Component {
|
export default class StringControl extends React.Component {
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.handleChange = this.handleChange.bind(this);
|
|
||||||
this.handleRef = this.handleRef.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.updateHeight();
|
this.updateHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
handleChange(e) {
|
handleChange = e => {
|
||||||
this.props.onChange(e.target.value);
|
this.props.onChange(e.target.value);
|
||||||
this.updateHeight();
|
this.updateHeight();
|
||||||
}
|
};
|
||||||
|
|
||||||
updateHeight() {
|
updateHeight() {
|
||||||
if (this.element.scrollHeight > this.element.clientHeight) {
|
if (this.element.scrollHeight > this.element.clientHeight) {
|
||||||
@ -22,9 +16,9 @@ export default class StringControl extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleRef(ref) {
|
handleRef = ref => {
|
||||||
this.element = ref;
|
this.element = ref;
|
||||||
}
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <textarea ref={this.handleRef} value={this.props.value || ''} onChange={this.handleChange}/>;
|
return <textarea ref={this.handleRef} value={this.props.value || ''} onChange={this.handleChange}/>;
|
||||||
|
@ -21,7 +21,7 @@ class App extends React.Component {
|
|||||||
|
|
||||||
state = {
|
state = {
|
||||||
navDrawerIsVisible: true
|
navDrawerIsVisible: true
|
||||||
}
|
};
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.props.dispatch(loadConfig());
|
this.props.dispatch(loadConfig());
|
||||||
@ -100,7 +100,7 @@ class App extends React.Component {
|
|||||||
this.setState({
|
this.setState({
|
||||||
navDrawerIsVisible: !this.state.navDrawerIsVisible
|
navDrawerIsVisible: !this.state.navDrawerIsVisible
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { navDrawerIsVisible } = this.state;
|
const { navDrawerIsVisible } = this.state;
|
||||||
|
@ -9,6 +9,13 @@ import styles from './CollectionPage.css';
|
|||||||
import CollectionPageHOC from './editorialWorkflow/CollectionPageHOC';
|
import CollectionPageHOC from './editorialWorkflow/CollectionPageHOC';
|
||||||
|
|
||||||
class DashboardPage extends React.Component {
|
class DashboardPage extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
collection: ImmutablePropTypes.map.isRequired,
|
||||||
|
collections: ImmutablePropTypes.orderedMap.isRequired,
|
||||||
|
dispatch: PropTypes.func.isRequired,
|
||||||
|
entries: ImmutablePropTypes.list,
|
||||||
|
};
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const { collection, dispatch } = this.props;
|
const { collection, dispatch } = this.props;
|
||||||
if (collection) {
|
if (collection) {
|
||||||
@ -39,12 +46,6 @@ class DashboardPage extends React.Component {
|
|||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DashboardPage.propTypes = {
|
|
||||||
collection: ImmutablePropTypes.map.isRequired,
|
|
||||||
collections: ImmutablePropTypes.orderedMap.isRequired,
|
|
||||||
dispatch: PropTypes.func.isRequired,
|
|
||||||
entries: ImmutablePropTypes.list,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Instead of checking the publish mode everywhere to dispatch & render the additional editorial workflow stuff,
|
* Instead of checking the publish mode everywhere to dispatch & render the additional editorial workflow stuff,
|
||||||
|
@ -15,11 +15,22 @@ import EntryEditor from '../components/EntryEditor';
|
|||||||
import EntryPageHOC from './editorialWorkflow/EntryPageHOC';
|
import EntryPageHOC from './editorialWorkflow/EntryPageHOC';
|
||||||
|
|
||||||
class EntryPage extends React.Component {
|
class EntryPage extends React.Component {
|
||||||
constructor(props) {
|
static propTypes = {
|
||||||
super(props);
|
addMedia: PropTypes.func.isRequired,
|
||||||
this.createDraft = this.createDraft.bind(this);
|
boundGetMedia: PropTypes.func.isRequired,
|
||||||
this.handlePersistEntry = this.handlePersistEntry.bind(this);
|
changeDraft: PropTypes.func.isRequired,
|
||||||
}
|
collection: ImmutablePropTypes.map.isRequired,
|
||||||
|
createDraftFromEntry: PropTypes.func.isRequired,
|
||||||
|
createEmptyDraft: PropTypes.func.isRequired,
|
||||||
|
discardDraft: PropTypes.func.isRequired,
|
||||||
|
entry: ImmutablePropTypes.map,
|
||||||
|
entryDraft: ImmutablePropTypes.map.isRequired,
|
||||||
|
loadEntry: PropTypes.func.isRequired,
|
||||||
|
persistEntry: PropTypes.func.isRequired,
|
||||||
|
removeMedia: PropTypes.func.isRequired,
|
||||||
|
slug: PropTypes.string,
|
||||||
|
newEntry: PropTypes.bool.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
if (!this.props.newEntry) {
|
if (!this.props.newEntry) {
|
||||||
@ -45,13 +56,13 @@ class EntryPage extends React.Component {
|
|||||||
this.props.discardDraft();
|
this.props.discardDraft();
|
||||||
}
|
}
|
||||||
|
|
||||||
createDraft(entry) {
|
createDraft = entry => {
|
||||||
if (entry) this.props.createDraftFromEntry(entry);
|
if (entry) this.props.createDraftFromEntry(entry);
|
||||||
}
|
};
|
||||||
|
|
||||||
handlePersistEntry() {
|
handlePersistEntry = () => {
|
||||||
this.props.persistEntry(this.props.collection, this.props.entryDraft);
|
this.props.persistEntry(this.props.collection, this.props.entryDraft);
|
||||||
}
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
@ -75,23 +86,6 @@ class EntryPage extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EntryPage.propTypes = {
|
|
||||||
addMedia: PropTypes.func.isRequired,
|
|
||||||
boundGetMedia: PropTypes.func.isRequired,
|
|
||||||
changeDraft: PropTypes.func.isRequired,
|
|
||||||
collection: ImmutablePropTypes.map.isRequired,
|
|
||||||
createDraftFromEntry: PropTypes.func.isRequired,
|
|
||||||
createEmptyDraft: PropTypes.func.isRequired,
|
|
||||||
discardDraft: PropTypes.func.isRequired,
|
|
||||||
entry: ImmutablePropTypes.map,
|
|
||||||
entryDraft: ImmutablePropTypes.map.isRequired,
|
|
||||||
loadEntry: PropTypes.func.isRequired,
|
|
||||||
persistEntry: PropTypes.func.isRequired,
|
|
||||||
removeMedia: PropTypes.func.isRequired,
|
|
||||||
slug: PropTypes.string,
|
|
||||||
newEntry: PropTypes.bool.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
function mapStateToProps(state, ownProps) {
|
function mapStateToProps(state, ownProps) {
|
||||||
const { collections, entryDraft } = state;
|
const { collections, entryDraft } = state;
|
||||||
const collection = collections.get(ownProps.params.name);
|
const collection = collections.get(ownProps.params.name);
|
||||||
|
@ -10,6 +10,11 @@ import styles from '../CollectionPage.css';
|
|||||||
|
|
||||||
export default function CollectionPageHOC(CollectionPage) {
|
export default function CollectionPageHOC(CollectionPage) {
|
||||||
class CollectionPageHOC extends CollectionPage {
|
class CollectionPageHOC extends CollectionPage {
|
||||||
|
static propTypes = {
|
||||||
|
dispatch: PropTypes.func.isRequired,
|
||||||
|
isEditorialWorkflow: PropTypes.bool.isRequired,
|
||||||
|
unpublishedEntries: ImmutablePropTypes.map,
|
||||||
|
};
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const { dispatch, isEditorialWorkflow } = this.props;
|
const { dispatch, isEditorialWorkflow } = this.props;
|
||||||
@ -38,12 +43,6 @@ export default function CollectionPageHOC(CollectionPage) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CollectionPageHOC.propTypes = {
|
|
||||||
dispatch: PropTypes.func.isRequired,
|
|
||||||
isEditorialWorkflow: PropTypes.bool.isRequired,
|
|
||||||
unpublishedEntries: ImmutablePropTypes.map,
|
|
||||||
};
|
|
||||||
|
|
||||||
function mapStateToProps(state) {
|
function mapStateToProps(state) {
|
||||||
const publish_mode = state.config.get('publish_mode');
|
const publish_mode = state.config.get('publish_mode');
|
||||||
const isEditorialWorkflow = (publish_mode === EDITORIAL_WORKFLOW);
|
const isEditorialWorkflow = (publish_mode === EDITORIAL_WORKFLOW);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user