Merge branch 'master' into master
This commit is contained in:
commit
6d998d5f73
23 changed files with 324 additions and 300 deletions
|
@ -55,14 +55,16 @@ class Nav extends React.PureComponent {
|
||||||
this.handleFocusForHelp = this.handleFocus.bind(this, 'help');
|
this.handleFocusForHelp = this.handleFocus.bind(this, 'help');
|
||||||
this.toggleDropdownForAccount = this.toggleDropdown.bind(this, 'account');
|
this.toggleDropdownForAccount = this.toggleDropdown.bind(this, 'account');
|
||||||
this.handleFocusForAccount = this.handleFocus.bind(this, 'account');
|
this.handleFocusForAccount = this.handleFocus.bind(this, 'account');
|
||||||
|
this.closeDropDown = this.closeDropDown.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentDidMount() {
|
||||||
document.addEventListener('mousedown', this.handleClick, false);
|
document.addEventListener('mousedown', this.handleClick, false);
|
||||||
|
document.addEventListener('keydown', this.closeDropDown, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
document.removeEventListener('mousedown', this.handleClick, false);
|
document.removeEventListener('mousedown', this.handleClick, false);
|
||||||
|
document.removeEventListener('keydown', this.closeDropDown, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
setDropdown(dropdown) {
|
setDropdown(dropdown) {
|
||||||
|
@ -71,8 +73,17 @@ class Nav extends React.PureComponent {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
closeDropDown(e) {
|
||||||
|
if (e.keyCode === 27) {
|
||||||
|
this.setDropdown('none');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
handleClick(e) {
|
handleClick(e) {
|
||||||
if (this.node.contains(e.target)) {
|
if (!this.node) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.node && this.node.contains(e.target)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,25 +244,23 @@ class Nav extends React.PureComponent {
|
||||||
<nav className="nav" title="main-navigation" ref={(node) => { this.node = node; }}>
|
<nav className="nav" title="main-navigation" ref={(node) => { this.node = node; }}>
|
||||||
<ul className="nav__items-left" title="project-menu">
|
<ul className="nav__items-left" title="project-menu">
|
||||||
<li className="nav__item-logo">
|
<li className="nav__item-logo">
|
||||||
<InlineSVG src={logoUrl} alt="p5.js logo" />
|
<InlineSVG src={logoUrl} alt="p5.js logo" className="svg__logo" />
|
||||||
</li>
|
</li>
|
||||||
<li className={navDropdownState.file}>
|
<li className={navDropdownState.file}>
|
||||||
<button
|
<button
|
||||||
onClick={this.toggleDropdownForFile}
|
onClick={this.toggleDropdownForFile}
|
||||||
onBlur={this.handleBlur}
|
onBlur={this.handleBlur}
|
||||||
onFocus={this.clearHideTimeout}
|
onFocus={this.clearHideTimeout}
|
||||||
|
onMouseOver={() => {
|
||||||
|
if (this.state.dropdownOpen !== 'none') {
|
||||||
|
this.setDropdown('file');
|
||||||
|
}
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<span className="nav__item-header">File</span>
|
<span className="nav__item-header">File</span>
|
||||||
<InlineSVG className="nav__item-header-triangle" src={triangleUrl} />
|
<InlineSVG className="nav__item-header-triangle" src={triangleUrl} />
|
||||||
</button>
|
</button>
|
||||||
<ul className="nav__dropdown">
|
<ul className="nav__dropdown">
|
||||||
<button
|
|
||||||
onClick={this.toggleDropdownForFile}
|
|
||||||
className="nav__dropdown-heading"
|
|
||||||
>
|
|
||||||
<span>File</span>
|
|
||||||
<InlineSVG src={triangleUrl} />
|
|
||||||
</button>
|
|
||||||
<li className="nav__dropdown-item">
|
<li className="nav__dropdown-item">
|
||||||
<button
|
<button
|
||||||
onClick={this.handleNew}
|
onClick={this.handleNew}
|
||||||
|
@ -331,18 +340,16 @@ class Nav extends React.PureComponent {
|
||||||
onClick={this.toggleDropdownForEdit}
|
onClick={this.toggleDropdownForEdit}
|
||||||
onBlur={this.handleBlur}
|
onBlur={this.handleBlur}
|
||||||
onFocus={this.clearHideTimeout}
|
onFocus={this.clearHideTimeout}
|
||||||
|
onMouseOver={() => {
|
||||||
|
if (this.state.dropdownOpen !== 'none') {
|
||||||
|
this.setDropdown('edit');
|
||||||
|
}
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<span className="nav__item-header">Edit</span>
|
<span className="nav__item-header">Edit</span>
|
||||||
<InlineSVG className="nav__item-header-triangle" src={triangleUrl} />
|
<InlineSVG className="nav__item-header-triangle" src={triangleUrl} />
|
||||||
</button>
|
</button>
|
||||||
<ul className="nav__dropdown" >
|
<ul className="nav__dropdown" >
|
||||||
<button
|
|
||||||
onClick={this.toggleDropdownForEdit}
|
|
||||||
className="nav__dropdown-heading"
|
|
||||||
>
|
|
||||||
<span>Edit</span>
|
|
||||||
<InlineSVG src={triangleUrl} />
|
|
||||||
</button>
|
|
||||||
<li className="nav__dropdown-item">
|
<li className="nav__dropdown-item">
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
@ -393,18 +400,16 @@ class Nav extends React.PureComponent {
|
||||||
onClick={this.toggleDropdownForSketch}
|
onClick={this.toggleDropdownForSketch}
|
||||||
onBlur={this.handleBlur}
|
onBlur={this.handleBlur}
|
||||||
onFocus={this.clearHideTimeout}
|
onFocus={this.clearHideTimeout}
|
||||||
|
onMouseOver={() => {
|
||||||
|
if (this.state.dropdownOpen !== 'none') {
|
||||||
|
this.setDropdown('sketch');
|
||||||
|
}
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<span className="nav__item-header">Sketch</span>
|
<span className="nav__item-header">Sketch</span>
|
||||||
<InlineSVG className="nav__item-header-triangle" src={triangleUrl} />
|
<InlineSVG className="nav__item-header-triangle" src={triangleUrl} />
|
||||||
</button>
|
</button>
|
||||||
<ul className="nav__dropdown">
|
<ul className="nav__dropdown">
|
||||||
<button
|
|
||||||
onClick={this.toggleDropdownForSketch}
|
|
||||||
className="nav__dropdown-heading"
|
|
||||||
>
|
|
||||||
<span>Sketch</span>
|
|
||||||
<InlineSVG src={triangleUrl} />
|
|
||||||
</button>
|
|
||||||
<li className="nav__dropdown-item">
|
<li className="nav__dropdown-item">
|
||||||
<button
|
<button
|
||||||
onClick={this.handleAddFile}
|
onClick={this.handleAddFile}
|
||||||
|
@ -470,18 +475,16 @@ class Nav extends React.PureComponent {
|
||||||
onClick={this.toggleDropdownForHelp}
|
onClick={this.toggleDropdownForHelp}
|
||||||
onBlur={this.handleBlur}
|
onBlur={this.handleBlur}
|
||||||
onFocus={this.clearHideTimeout}
|
onFocus={this.clearHideTimeout}
|
||||||
|
onMouseOver={() => {
|
||||||
|
if (this.state.dropdownOpen !== 'none') {
|
||||||
|
this.setDropdown('help');
|
||||||
|
}
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<span className="nav__item-header">Help & Feedback</span>
|
<span className="nav__item-header">Help & Feedback</span>
|
||||||
<InlineSVG className="nav__item-header-triangle" src={triangleUrl} />
|
<InlineSVG className="nav__item-header-triangle" src={triangleUrl} />
|
||||||
</button>
|
</button>
|
||||||
<ul className="nav__dropdown">
|
<ul className="nav__dropdown">
|
||||||
<button
|
|
||||||
onClick={this.toggleDropdownForHelp}
|
|
||||||
className="nav__dropdown-heading"
|
|
||||||
>
|
|
||||||
<span>Help & Feedback</span>
|
|
||||||
<InlineSVG src={triangleUrl} />
|
|
||||||
</button>
|
|
||||||
<li className="nav__dropdown-item">
|
<li className="nav__dropdown-item">
|
||||||
<button
|
<button
|
||||||
onFocus={this.handleFocusForHelp}
|
onFocus={this.handleFocusForHelp}
|
||||||
|
@ -547,18 +550,16 @@ class Nav extends React.PureComponent {
|
||||||
onClick={this.toggleDropdownForAccount}
|
onClick={this.toggleDropdownForAccount}
|
||||||
onBlur={this.handleBlur}
|
onBlur={this.handleBlur}
|
||||||
onFocus={this.clearHideTimeout}
|
onFocus={this.clearHideTimeout}
|
||||||
|
onMouseOver={() => {
|
||||||
|
if (this.state.dropdownOpen !== 'none') {
|
||||||
|
this.setDropdown('account');
|
||||||
|
}
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
My Account
|
My Account
|
||||||
</button>
|
|
||||||
<InlineSVG className="nav__item-header-triangle" src={triangleUrl} />
|
<InlineSVG className="nav__item-header-triangle" src={triangleUrl} />
|
||||||
<ul className="nav__dropdown">
|
|
||||||
<button
|
|
||||||
onClick={this.toggleDropdown.bind(this, 'account')}
|
|
||||||
className="nav__dropdown-heading"
|
|
||||||
>
|
|
||||||
<span>My Account</span>
|
|
||||||
<InlineSVG src={triangleUrl} />
|
|
||||||
</button>
|
</button>
|
||||||
|
<ul className="nav__dropdown">
|
||||||
<li className="nav__dropdown-item">
|
<li className="nav__dropdown-item">
|
||||||
<Link
|
<Link
|
||||||
to={`/${this.props.user.username}/sketches`}
|
to={`/${this.props.user.username}/sketches`}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// TODO Organize this file by reducer type, ot break this apart into
|
// TODO Organize this file by reducer type, to break this apart into
|
||||||
// multiple files
|
// multiple files
|
||||||
export const UPDATE_FILE_CONTENT = 'UPDATE_FILE_CONTENT';
|
export const UPDATE_FILE_CONTENT = 'UPDATE_FILE_CONTENT';
|
||||||
export const TOGGLE_SKETCH = 'TOGGLE_SKETCH';
|
export const TOGGLE_SKETCH = 'TOGGLE_SKETCH';
|
||||||
|
@ -13,14 +13,6 @@ export const OPEN_PREFERENCES = 'OPEN_PREFERENCES';
|
||||||
export const CLOSE_PREFERENCES = 'CLOSE_PREFERENCES';
|
export const CLOSE_PREFERENCES = 'CLOSE_PREFERENCES';
|
||||||
export const SET_FONT_SIZE = 'SET_FONT_SIZE';
|
export const SET_FONT_SIZE = 'SET_FONT_SIZE';
|
||||||
|
|
||||||
export const INCREASE_INDENTATION = 'INCREASE_INDENTATION';
|
|
||||||
export const DECREASE_INDENTATION = 'DECREASE_INDENTATION';
|
|
||||||
export const UPDATE_INDENTATION = 'UPDATE_INDENTATION';
|
|
||||||
export const SET_INDENTATION = 'SET_INDENTATION';
|
|
||||||
|
|
||||||
export const INDENT_WITH_SPACE = 'INDENT_WITH_SPACE';
|
|
||||||
export const INDENT_WITH_TAB = 'INDENT_WITH_TAB';
|
|
||||||
|
|
||||||
export const AUTH_USER = 'AUTH_USER';
|
export const AUTH_USER = 'AUTH_USER';
|
||||||
export const UNAUTH_USER = 'UNAUTH_USER';
|
export const UNAUTH_USER = 'UNAUTH_USER';
|
||||||
export const AUTH_ERROR = 'AUTH_ERROR';
|
export const AUTH_ERROR = 'AUTH_ERROR';
|
||||||
|
@ -62,6 +54,7 @@ export const UPDATE_FILE_NAME = 'UPDATE_FILE_NAME';
|
||||||
export const DELETE_FILE = 'DELETE_FILE';
|
export const DELETE_FILE = 'DELETE_FILE';
|
||||||
|
|
||||||
export const SET_AUTOSAVE = 'SET_AUTOSAVE';
|
export const SET_AUTOSAVE = 'SET_AUTOSAVE';
|
||||||
|
export const SET_LINEWRAP = 'SET_LINEWRAP';
|
||||||
export const SET_LINT_WARNING = 'SET_LINT_WARNING';
|
export const SET_LINT_WARNING = 'SET_LINT_WARNING';
|
||||||
export const SET_PREFERENCES = 'SET_PREFERENCES';
|
export const SET_PREFERENCES = 'SET_PREFERENCES';
|
||||||
export const SET_TEXT_OUTPUT = 'SET_TEXT_OUTPUT';
|
export const SET_TEXT_OUTPUT = 'SET_TEXT_OUTPUT';
|
||||||
|
|
|
@ -14,6 +14,7 @@ class App extends React.Component {
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.setState({ isMounted: true }); // eslint-disable-line react/no-did-mount-set-state
|
this.setState({ isMounted: true }); // eslint-disable-line react/no-did-mount-set-state
|
||||||
|
document.body.className = 'light';
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
|
|
|
@ -32,58 +32,6 @@ export function setFontSize(value) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setIndentation(value) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
dispatch({
|
|
||||||
type: ActionTypes.SET_INDENTATION,
|
|
||||||
value
|
|
||||||
});
|
|
||||||
const state = getState();
|
|
||||||
if (state.user.authenticated) {
|
|
||||||
const formParams = {
|
|
||||||
preferences: {
|
|
||||||
indentationAmount: value
|
|
||||||
}
|
|
||||||
};
|
|
||||||
updatePreferences(formParams, dispatch);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function indentWithTab() {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
dispatch({
|
|
||||||
type: ActionTypes.INDENT_WITH_TAB
|
|
||||||
});
|
|
||||||
const state = getState();
|
|
||||||
if (state.user.authenticated) {
|
|
||||||
const formParams = {
|
|
||||||
preferences: {
|
|
||||||
isTabIndent: true
|
|
||||||
}
|
|
||||||
};
|
|
||||||
updatePreferences(formParams, dispatch);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function indentWithSpace() {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
dispatch({
|
|
||||||
type: ActionTypes.INDENT_WITH_SPACE
|
|
||||||
});
|
|
||||||
const state = getState();
|
|
||||||
if (state.user.authenticated) {
|
|
||||||
const formParams = {
|
|
||||||
preferences: {
|
|
||||||
isTabIndent: false
|
|
||||||
}
|
|
||||||
};
|
|
||||||
updatePreferences(formParams, dispatch);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setAutosave(value) {
|
export function setAutosave(value) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
|
@ -102,6 +50,24 @@ export function setAutosave(value) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function setLinewrap(value) {
|
||||||
|
return (dispatch, getState) => {
|
||||||
|
dispatch({
|
||||||
|
type: ActionTypes.SET_LINEWRAP,
|
||||||
|
value
|
||||||
|
});
|
||||||
|
const state = getState();
|
||||||
|
if (state.user.authenticated) {
|
||||||
|
const formParams = {
|
||||||
|
preferences: {
|
||||||
|
linewrap: value
|
||||||
|
}
|
||||||
|
};
|
||||||
|
updatePreferences(formParams, dispatch);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function setLintWarning(value) {
|
export function setLintWarning(value) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
|
|
|
@ -50,6 +50,9 @@ const unsavedChangesDotUrl = require('../../../images/unsaved-changes-dot.svg');
|
||||||
const rightArrowUrl = require('../../../images/right-arrow.svg');
|
const rightArrowUrl = require('../../../images/right-arrow.svg');
|
||||||
const leftArrowUrl = require('../../../images/left-arrow.svg');
|
const leftArrowUrl = require('../../../images/left-arrow.svg');
|
||||||
|
|
||||||
|
const IS_TAB_INDENT = false;
|
||||||
|
const INDENTATION_AMOUNT = 2;
|
||||||
|
|
||||||
class Editor extends React.Component {
|
class Editor extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
@ -80,7 +83,7 @@ class Editor extends React.Component {
|
||||||
lineNumbers: true,
|
lineNumbers: true,
|
||||||
styleActiveLine: true,
|
styleActiveLine: true,
|
||||||
inputStyle: 'contenteditable',
|
inputStyle: 'contenteditable',
|
||||||
lineWrapping: false,
|
lineWrapping: this.props.linewrap,
|
||||||
fixedGutter: false,
|
fixedGutter: false,
|
||||||
foldGutter: true,
|
foldGutter: true,
|
||||||
foldOptions: { widget: '\u2026' },
|
foldOptions: { widget: '\u2026' },
|
||||||
|
@ -105,6 +108,7 @@ class Editor extends React.Component {
|
||||||
delete this._cm.options.lint.options.errors;
|
delete this._cm.options.lint.options.errors;
|
||||||
|
|
||||||
this._cm.setOption('extraKeys', {
|
this._cm.setOption('extraKeys', {
|
||||||
|
Tab: cm => cm.replaceSelection(' '.repeat(INDENTATION_AMOUNT)),
|
||||||
[`${metaKey}-Enter`]: () => null,
|
[`${metaKey}-Enter`]: () => null,
|
||||||
[`Shift-${metaKey}-Enter`]: () => null,
|
[`Shift-${metaKey}-Enter`]: () => null,
|
||||||
[`${metaKey}-F`]: 'findPersistent',
|
[`${metaKey}-F`]: 'findPersistent',
|
||||||
|
@ -137,9 +141,6 @@ class Editor extends React.Component {
|
||||||
});
|
});
|
||||||
|
|
||||||
this._cm.getWrapperElement().style['font-size'] = `${this.props.fontSize}px`;
|
this._cm.getWrapperElement().style['font-size'] = `${this.props.fontSize}px`;
|
||||||
this._cm.setOption('indentWithTabs', this.props.isTabIndent);
|
|
||||||
this._cm.setOption('tabSize', this.props.indentationAmount);
|
|
||||||
this._cm.setOption('indentUnit', this.props.indentationAmount);
|
|
||||||
|
|
||||||
this.props.provideController({
|
this.props.provideController({
|
||||||
tidyCode: this.tidyCode,
|
tidyCode: this.tidyCode,
|
||||||
|
@ -174,12 +175,8 @@ class Editor extends React.Component {
|
||||||
if (this.props.fontSize !== prevProps.fontSize) {
|
if (this.props.fontSize !== prevProps.fontSize) {
|
||||||
this._cm.getWrapperElement().style['font-size'] = `${this.props.fontSize}px`;
|
this._cm.getWrapperElement().style['font-size'] = `${this.props.fontSize}px`;
|
||||||
}
|
}
|
||||||
if (this.props.indentationAmount !== prevProps.indentationAmount) {
|
if (this.props.linewrap !== prevProps.linewrap) {
|
||||||
this._cm.setOption('tabSize', this.props.indentationAmount);
|
this._cm.setOption('lineWrapping', this.props.linewrap);
|
||||||
this._cm.setOption('indentUnit', this.props.indentationAmount);
|
|
||||||
}
|
|
||||||
if (this.props.isTabIndent !== prevProps.isTabIndent) {
|
|
||||||
this._cm.setOption('indentWithTabs', this.props.isTabIndent);
|
|
||||||
}
|
}
|
||||||
if (this.props.theme !== prevProps.theme) {
|
if (this.props.theme !== prevProps.theme) {
|
||||||
this._cm.setOption('theme', `p5-${this.props.theme}`);
|
this._cm.setOption('theme', `p5-${this.props.theme}`);
|
||||||
|
@ -254,8 +251,8 @@ class Editor extends React.Component {
|
||||||
|
|
||||||
tidyCode() {
|
tidyCode() {
|
||||||
const beautifyOptions = {
|
const beautifyOptions = {
|
||||||
indent_size: this.props.indentationAmount,
|
indent_size: INDENTATION_AMOUNT,
|
||||||
indent_with_tabs: this.props.isTabIndent
|
indent_with_tabs: IS_TAB_INDENT
|
||||||
};
|
};
|
||||||
|
|
||||||
const mode = this._cm.getOption('mode');
|
const mode = this._cm.getOption('mode');
|
||||||
|
@ -339,6 +336,7 @@ class Editor extends React.Component {
|
||||||
|
|
||||||
Editor.propTypes = {
|
Editor.propTypes = {
|
||||||
lintWarning: PropTypes.bool.isRequired,
|
lintWarning: PropTypes.bool.isRequired,
|
||||||
|
linewrap: PropTypes.bool.isRequired,
|
||||||
lintMessages: PropTypes.arrayOf(PropTypes.shape({
|
lintMessages: PropTypes.arrayOf(PropTypes.shape({
|
||||||
severity: PropTypes.string.isRequired,
|
severity: PropTypes.string.isRequired,
|
||||||
line: PropTypes.number.isRequired,
|
line: PropTypes.number.isRequired,
|
||||||
|
@ -351,8 +349,6 @@ Editor.propTypes = {
|
||||||
})),
|
})),
|
||||||
updateLintMessage: PropTypes.func.isRequired,
|
updateLintMessage: PropTypes.func.isRequired,
|
||||||
clearLintMessage: PropTypes.func.isRequired,
|
clearLintMessage: PropTypes.func.isRequired,
|
||||||
indentationAmount: PropTypes.number.isRequired,
|
|
||||||
isTabIndent: PropTypes.bool.isRequired,
|
|
||||||
updateFileContent: PropTypes.func.isRequired,
|
updateFileContent: PropTypes.func.isRequired,
|
||||||
fontSize: PropTypes.number.isRequired,
|
fontSize: PropTypes.number.isRequired,
|
||||||
file: PropTypes.shape({
|
file: PropTypes.shape({
|
||||||
|
|
|
@ -24,13 +24,29 @@ export class FileNode extends React.Component {
|
||||||
this.hideFileOptions = this.hideFileOptions.bind(this);
|
this.hideFileOptions = this.hideFileOptions.bind(this);
|
||||||
this.showEditFileName = this.showEditFileName.bind(this);
|
this.showEditFileName = this.showEditFileName.bind(this);
|
||||||
this.hideEditFileName = this.hideEditFileName.bind(this);
|
this.hideEditFileName = this.hideEditFileName.bind(this);
|
||||||
|
this.onBlurComponent = this.onBlurComponent.bind(this);
|
||||||
|
this.onFocusComponent = this.onFocusComponent.bind(this);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
isOptionsOpen: false,
|
isOptionsOpen: false,
|
||||||
isEditingName: false,
|
isEditingName: false,
|
||||||
|
isFocused: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onFocusComponent() {
|
||||||
|
this.setState({ isFocused: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
onBlurComponent() {
|
||||||
|
this.setState({ isFocused: false });
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!this.state.isFocused) {
|
||||||
|
this.hideFileOptions();
|
||||||
|
}
|
||||||
|
}, 200);
|
||||||
|
}
|
||||||
|
|
||||||
handleFileClick(e) {
|
handleFileClick(e) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
if (this.props.name !== 'root' && !this.isDeleting) {
|
if (this.props.name !== 'root' && !this.isDeleting) {
|
||||||
|
@ -105,6 +121,7 @@ export class FileNode extends React.Component {
|
||||||
'sidebar__file-item--editing': this.state.isEditingName,
|
'sidebar__file-item--editing': this.state.isEditingName,
|
||||||
'sidebar__file-item--closed': this.props.isFolderClosed
|
'sidebar__file-item--closed': this.props.isFolderClosed
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={itemClass}>
|
<div className={itemClass}>
|
||||||
{(() => { // eslint-disable-line
|
{(() => { // eslint-disable-line
|
||||||
|
@ -156,7 +173,8 @@ export class FileNode extends React.Component {
|
||||||
ref={(element) => { this[`fileOptions-${this.props.id}`] = element; }}
|
ref={(element) => { this[`fileOptions-${this.props.id}`] = element; }}
|
||||||
tabIndex="0"
|
tabIndex="0"
|
||||||
onClick={this.toggleFileOptions}
|
onClick={this.toggleFileOptions}
|
||||||
onBlur={() => setTimeout(this.hideFileOptions, 200)}
|
onBlur={this.onBlurComponent}
|
||||||
|
onFocus={this.onFocusComponent}
|
||||||
>
|
>
|
||||||
<InlineSVG src={downArrowUrl} />
|
<InlineSVG src={downArrowUrl} />
|
||||||
</button>
|
</button>
|
||||||
|
@ -168,7 +186,12 @@ export class FileNode extends React.Component {
|
||||||
<li>
|
<li>
|
||||||
<button
|
<button
|
||||||
aria-label="add file"
|
aria-label="add file"
|
||||||
onClick={this.props.newFile}
|
onClick={() => {
|
||||||
|
this.props.newFile();
|
||||||
|
setTimeout(() => this.hideFileOptions(), 0);
|
||||||
|
}}
|
||||||
|
onBlur={this.onBlurComponent}
|
||||||
|
onFocus={this.onFocusComponent}
|
||||||
className="sidebar__file-item-option"
|
className="sidebar__file-item-option"
|
||||||
>
|
>
|
||||||
Add File
|
Add File
|
||||||
|
@ -183,7 +206,12 @@ export class FileNode extends React.Component {
|
||||||
<li>
|
<li>
|
||||||
<button
|
<button
|
||||||
aria-label="add folder"
|
aria-label="add folder"
|
||||||
onClick={this.props.newFolder}
|
onClick={() => {
|
||||||
|
this.props.newFolder();
|
||||||
|
setTimeout(() => this.hideFileOptions(), 0);
|
||||||
|
}}
|
||||||
|
onBlur={this.onBlurComponent}
|
||||||
|
onFocus={this.onFocusComponent}
|
||||||
className="sidebar__file-item-option"
|
className="sidebar__file-item-option"
|
||||||
>
|
>
|
||||||
Add Folder
|
Add Folder
|
||||||
|
@ -198,7 +226,10 @@ export class FileNode extends React.Component {
|
||||||
this.originalFileName = this.props.name;
|
this.originalFileName = this.props.name;
|
||||||
this.showEditFileName();
|
this.showEditFileName();
|
||||||
setTimeout(() => this.fileNameInput.focus(), 0);
|
setTimeout(() => this.fileNameInput.focus(), 0);
|
||||||
|
setTimeout(() => this.hideFileOptions(), 0);
|
||||||
}}
|
}}
|
||||||
|
onBlur={this.onBlurComponent}
|
||||||
|
onFocus={this.onFocusComponent}
|
||||||
className="sidebar__file-item-option"
|
className="sidebar__file-item-option"
|
||||||
>
|
>
|
||||||
Rename
|
Rename
|
||||||
|
@ -213,6 +244,8 @@ export class FileNode extends React.Component {
|
||||||
setTimeout(() => this.props.deleteFile(this.props.id, this.props.parentId), 100);
|
setTimeout(() => this.props.deleteFile(this.props.id, this.props.parentId), 100);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
onBlur={this.onBlurComponent}
|
||||||
|
onFocus={this.onFocusComponent}
|
||||||
className="sidebar__file-item-option"
|
className="sidebar__file-item-option"
|
||||||
>
|
>
|
||||||
Delete
|
Delete
|
||||||
|
|
|
@ -15,8 +15,8 @@ class Preferences extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.handleUpdateAutosave = this.handleUpdateAutosave.bind(this);
|
this.handleUpdateAutosave = this.handleUpdateAutosave.bind(this);
|
||||||
|
this.handleUpdateLinewrap = this.handleUpdateLinewrap.bind(this);
|
||||||
this.handleUpdateFont = this.handleUpdateFont.bind(this);
|
this.handleUpdateFont = this.handleUpdateFont.bind(this);
|
||||||
this.handleUpdateIndentation = this.handleUpdateIndentation.bind(this);
|
|
||||||
this.handleLintWarning = this.handleLintWarning.bind(this);
|
this.handleLintWarning = this.handleLintWarning.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,25 +34,16 @@ class Preferences extends React.Component {
|
||||||
this.props.setFontSize(value);
|
this.props.setFontSize(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleUpdateIndentation(event) {
|
|
||||||
let value = parseInt(event.target.value, 10);
|
|
||||||
if (Number.isNaN(value)) {
|
|
||||||
value = 2;
|
|
||||||
}
|
|
||||||
if (value > 6) {
|
|
||||||
value = 6;
|
|
||||||
}
|
|
||||||
if (value < 0) {
|
|
||||||
value = 0;
|
|
||||||
}
|
|
||||||
this.props.setIndentation(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleUpdateAutosave(event) {
|
handleUpdateAutosave(event) {
|
||||||
const value = event.target.value === 'true';
|
const value = event.target.value === 'true';
|
||||||
this.props.setAutosave(value);
|
this.props.setAutosave(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleUpdateLinewrap(event) {
|
||||||
|
const value = event.target.value === 'true';
|
||||||
|
this.props.setLinewrap(value);
|
||||||
|
}
|
||||||
|
|
||||||
handleLintWarning(event) {
|
handleLintWarning(event) {
|
||||||
const value = event.target.value === 'true';
|
const value = event.target.value === 'true';
|
||||||
this.props.setLintWarning(value);
|
this.props.setLintWarning(value);
|
||||||
|
@ -144,65 +135,6 @@ class Preferences extends React.Component {
|
||||||
<h6 className="preference__label">Increase</h6>
|
<h6 className="preference__label">Increase</h6>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="preference">
|
|
||||||
<h4 className="preference__title">Indentation amount</h4>
|
|
||||||
<button
|
|
||||||
className="preference__minus-button"
|
|
||||||
onClick={() => this.props.setIndentation(this.props.indentationAmount - 2)}
|
|
||||||
aria-label="decrease indentation amount"
|
|
||||||
disabled={this.props.indentationAmount <= 0}
|
|
||||||
>
|
|
||||||
<InlineSVG src={minusUrl} alt="DecreaseIndentation Amount" />
|
|
||||||
<h6 className="preference__label">Decrease</h6>
|
|
||||||
</button>
|
|
||||||
<input
|
|
||||||
className="preference__value"
|
|
||||||
aria-live="polite"
|
|
||||||
aria-atomic="true"
|
|
||||||
value={this.props.indentationAmount}
|
|
||||||
onChange={this.handleUpdateIndentation}
|
|
||||||
ref={(element) => { this.indentationInput = element; }}
|
|
||||||
onClick={() => {
|
|
||||||
this.indentationInput.select();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
className="preference__plus-button"
|
|
||||||
onClick={() => this.props.setIndentation(this.props.indentationAmount + 2)}
|
|
||||||
aria-label="increase indentation amount"
|
|
||||||
disabled={this.props.indentationAmount >= 6}
|
|
||||||
>
|
|
||||||
<InlineSVG src={plusUrl} alt="IncreaseIndentation Amount" />
|
|
||||||
<h6 className="preference__label">Increase</h6>
|
|
||||||
</button>
|
|
||||||
<input
|
|
||||||
type="radio"
|
|
||||||
onChange={this.props.indentWithSpace}
|
|
||||||
aria-label="indentation with space"
|
|
||||||
name="indentation"
|
|
||||||
id="indentation-space"
|
|
||||||
className="preference__radio-button"
|
|
||||||
value="Spaces"
|
|
||||||
checked={!this.props.isTabIndent}
|
|
||||||
/>
|
|
||||||
<label
|
|
||||||
htmlFor="indentation-space"
|
|
||||||
className="preference__option preference__whitespace-button"
|
|
||||||
>
|
|
||||||
Spaces
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="radio"
|
|
||||||
onChange={this.props.indentWithTab}
|
|
||||||
aria-label="indentation with tab"
|
|
||||||
name="indentation"
|
|
||||||
id="indentation-tab"
|
|
||||||
className="preference__radio-button"
|
|
||||||
value="Tabs"
|
|
||||||
checked={this.props.isTabIndent}
|
|
||||||
/>
|
|
||||||
<label htmlFor="indentation-tab" className="preference__option preference__whitespace-button">Tabs</label>
|
|
||||||
</div>
|
|
||||||
<div className="preference">
|
<div className="preference">
|
||||||
<h4 className="preference__title">Autosave</h4>
|
<h4 className="preference__title">Autosave</h4>
|
||||||
<div className="preference__options">
|
<div className="preference__options">
|
||||||
|
@ -230,6 +162,33 @@ class Preferences extends React.Component {
|
||||||
<label htmlFor="autosave-off" className="preference__option">Off</label>
|
<label htmlFor="autosave-off" className="preference__option">Off</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="preference">
|
||||||
|
<h4 className="preference__title">Word Wrap</h4>
|
||||||
|
<div className="preference__options">
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
onChange={() => this.props.setLinewrap(true)}
|
||||||
|
aria-label="linewrap on"
|
||||||
|
name="linewrap"
|
||||||
|
id="linewrap-on"
|
||||||
|
className="preference__radio-button"
|
||||||
|
value="On"
|
||||||
|
checked={this.props.linewrap}
|
||||||
|
/>
|
||||||
|
<label htmlFor="linewrap-on" className="preference__option">On</label>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
onChange={() => this.props.setLinewrap(false)}
|
||||||
|
aria-label="linewrap off"
|
||||||
|
name="linewrap"
|
||||||
|
id="linewrap-off"
|
||||||
|
className="preference__radio-button"
|
||||||
|
value="Off"
|
||||||
|
checked={!this.props.linewrap}
|
||||||
|
/>
|
||||||
|
<label htmlFor="linewrap-off" className="preference__option">Off</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel>
|
<TabPanel>
|
||||||
<div className="preference">
|
<div className="preference">
|
||||||
|
@ -318,14 +277,11 @@ class Preferences extends React.Component {
|
||||||
|
|
||||||
Preferences.propTypes = {
|
Preferences.propTypes = {
|
||||||
fontSize: PropTypes.number.isRequired,
|
fontSize: PropTypes.number.isRequired,
|
||||||
indentationAmount: PropTypes.number.isRequired,
|
|
||||||
setIndentation: PropTypes.func.isRequired,
|
|
||||||
indentWithSpace: PropTypes.func.isRequired,
|
|
||||||
indentWithTab: PropTypes.func.isRequired,
|
|
||||||
isTabIndent: PropTypes.bool.isRequired,
|
|
||||||
setFontSize: PropTypes.func.isRequired,
|
setFontSize: PropTypes.func.isRequired,
|
||||||
autosave: PropTypes.bool.isRequired,
|
autosave: PropTypes.bool.isRequired,
|
||||||
|
linewrap: PropTypes.bool.isRequired,
|
||||||
setAutosave: PropTypes.func.isRequired,
|
setAutosave: PropTypes.func.isRequired,
|
||||||
|
setLinewrap: PropTypes.func.isRequired,
|
||||||
textOutput: PropTypes.bool.isRequired,
|
textOutput: PropTypes.bool.isRequired,
|
||||||
gridOutput: PropTypes.bool.isRequired,
|
gridOutput: PropTypes.bool.isRequired,
|
||||||
soundOutput: PropTypes.bool.isRequired,
|
soundOutput: PropTypes.bool.isRequired,
|
||||||
|
|
|
@ -12,6 +12,25 @@ class Sidebar extends React.Component {
|
||||||
super(props);
|
super(props);
|
||||||
this.resetSelectedFile = this.resetSelectedFile.bind(this);
|
this.resetSelectedFile = this.resetSelectedFile.bind(this);
|
||||||
this.toggleProjectOptions = this.toggleProjectOptions.bind(this);
|
this.toggleProjectOptions = this.toggleProjectOptions.bind(this);
|
||||||
|
this.onBlurComponent = this.onBlurComponent.bind(this);
|
||||||
|
this.onFocusComponent = this.onFocusComponent.bind(this);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
isFocused: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
onBlurComponent() {
|
||||||
|
this.setState({ isFocused: false });
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!this.state.isFocused) {
|
||||||
|
this.props.closeProjectOptions();
|
||||||
|
}
|
||||||
|
}, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
onFocusComponent() {
|
||||||
|
this.setState({ isFocused: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
resetSelectedFile() {
|
resetSelectedFile() {
|
||||||
|
@ -65,18 +84,35 @@ class Sidebar extends React.Component {
|
||||||
tabIndex="0"
|
tabIndex="0"
|
||||||
ref={(element) => { this.sidebarOptions = element; }}
|
ref={(element) => { this.sidebarOptions = element; }}
|
||||||
onClick={this.toggleProjectOptions}
|
onClick={this.toggleProjectOptions}
|
||||||
onBlur={() => setTimeout(this.props.closeProjectOptions, 200)}
|
onBlur={this.onBlurComponent}
|
||||||
|
onFocus={this.onFocusComponent}
|
||||||
>
|
>
|
||||||
<InlineSVG src={downArrowUrl} />
|
<InlineSVG src={downArrowUrl} />
|
||||||
</button>
|
</button>
|
||||||
<ul className="sidebar__project-options">
|
<ul className="sidebar__project-options">
|
||||||
<li>
|
<li>
|
||||||
<button aria-label="add folder" onClick={this.props.newFolder} >
|
<button
|
||||||
|
aria-label="add folder"
|
||||||
|
onClick={() => {
|
||||||
|
this.props.newFolder();
|
||||||
|
setTimeout(this.props.closeProjectOptions, 0);
|
||||||
|
}}
|
||||||
|
onBlur={this.onBlurComponent}
|
||||||
|
onFocus={this.onFocusComponent}
|
||||||
|
>
|
||||||
Add folder
|
Add folder
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<button aria-label="add file" onClick={this.props.newFile} >
|
<button
|
||||||
|
aria-label="add file"
|
||||||
|
onClick={() => {
|
||||||
|
this.props.newFile();
|
||||||
|
setTimeout(this.props.closeProjectOptions, 0);
|
||||||
|
}}
|
||||||
|
onBlur={this.onBlurComponent}
|
||||||
|
onFocus={this.onFocusComponent}
|
||||||
|
>
|
||||||
Add file
|
Add file
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -124,6 +124,7 @@ class Toolbar extends React.Component {
|
||||||
</a>
|
</a>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
|
maxLength="256"
|
||||||
className="toolbar__project-name-input"
|
className="toolbar__project-name-input"
|
||||||
value={this.props.project.name}
|
value={this.props.project.name}
|
||||||
onChange={this.handleProjectNameChange}
|
onChange={this.handleProjectNameChange}
|
||||||
|
|
|
@ -202,14 +202,11 @@ class IDEView extends React.Component {
|
||||||
>
|
>
|
||||||
<Preferences
|
<Preferences
|
||||||
fontSize={this.props.preferences.fontSize}
|
fontSize={this.props.preferences.fontSize}
|
||||||
indentationAmount={this.props.preferences.indentationAmount}
|
|
||||||
setIndentation={this.props.setIndentation}
|
|
||||||
indentWithSpace={this.props.indentWithSpace}
|
|
||||||
indentWithTab={this.props.indentWithTab}
|
|
||||||
isTabIndent={this.props.preferences.isTabIndent}
|
|
||||||
setFontSize={this.props.setFontSize}
|
setFontSize={this.props.setFontSize}
|
||||||
autosave={this.props.preferences.autosave}
|
autosave={this.props.preferences.autosave}
|
||||||
|
linewrap={this.props.preferences.linewrap}
|
||||||
setAutosave={this.props.setAutosave}
|
setAutosave={this.props.setAutosave}
|
||||||
|
setLinewrap={this.props.setLinewrap}
|
||||||
lintWarning={this.props.preferences.lintWarning}
|
lintWarning={this.props.preferences.lintWarning}
|
||||||
setLintWarning={this.props.setLintWarning}
|
setLintWarning={this.props.setLintWarning}
|
||||||
textOutput={this.props.preferences.textOutput}
|
textOutput={this.props.preferences.textOutput}
|
||||||
|
@ -251,7 +248,9 @@ class IDEView extends React.Component {
|
||||||
defaultSize="50%"
|
defaultSize="50%"
|
||||||
onChange={() => { this.overlay.style.display = 'block'; }}
|
onChange={() => { this.overlay.style.display = 'block'; }}
|
||||||
onDragFinished={() => { this.overlay.style.display = 'none'; }}
|
onDragFinished={() => { this.overlay.style.display = 'none'; }}
|
||||||
resizerStyle={{ marginRight: '0', marginLeft: '-10px' }}
|
resizerStyle={{
|
||||||
|
borderLeftWidth: '2px', borderRightWidth: '2px', width: '2px', margin: '0px 0px'
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<SplitPane
|
<SplitPane
|
||||||
split="horizontal"
|
split="horizontal"
|
||||||
|
@ -264,14 +263,13 @@ class IDEView extends React.Component {
|
||||||
>
|
>
|
||||||
<Editor
|
<Editor
|
||||||
lintWarning={this.props.preferences.lintWarning}
|
lintWarning={this.props.preferences.lintWarning}
|
||||||
|
linewrap={this.props.preferences.linewrap}
|
||||||
lintMessages={this.props.editorAccessibility.lintMessages}
|
lintMessages={this.props.editorAccessibility.lintMessages}
|
||||||
updateLintMessage={this.props.updateLintMessage}
|
updateLintMessage={this.props.updateLintMessage}
|
||||||
clearLintMessage={this.props.clearLintMessage}
|
clearLintMessage={this.props.clearLintMessage}
|
||||||
file={this.props.selectedFile}
|
file={this.props.selectedFile}
|
||||||
updateFileContent={this.props.updateFileContent}
|
updateFileContent={this.props.updateFileContent}
|
||||||
fontSize={this.props.preferences.fontSize}
|
fontSize={this.props.preferences.fontSize}
|
||||||
indentationAmount={this.props.preferences.indentationAmount}
|
|
||||||
isTabIndent={this.props.preferences.isTabIndent}
|
|
||||||
files={this.props.files}
|
files={this.props.files}
|
||||||
editorOptionsVisible={this.props.ide.editorOptionsVisible}
|
editorOptionsVisible={this.props.ide.editorOptionsVisible}
|
||||||
showEditorOptions={this.props.showEditorOptions}
|
showEditorOptions={this.props.showEditorOptions}
|
||||||
|
@ -511,9 +509,8 @@ IDEView.propTypes = {
|
||||||
clearLintMessage: PropTypes.func.isRequired,
|
clearLintMessage: PropTypes.func.isRequired,
|
||||||
preferences: PropTypes.shape({
|
preferences: PropTypes.shape({
|
||||||
fontSize: PropTypes.number.isRequired,
|
fontSize: PropTypes.number.isRequired,
|
||||||
indentationAmount: PropTypes.number.isRequired,
|
|
||||||
isTabIndent: PropTypes.bool.isRequired,
|
|
||||||
autosave: PropTypes.bool.isRequired,
|
autosave: PropTypes.bool.isRequired,
|
||||||
|
linewrap: PropTypes.bool.isRequired,
|
||||||
lintWarning: PropTypes.bool.isRequired,
|
lintWarning: PropTypes.bool.isRequired,
|
||||||
textOutput: PropTypes.bool.isRequired,
|
textOutput: PropTypes.bool.isRequired,
|
||||||
gridOutput: PropTypes.bool.isRequired,
|
gridOutput: PropTypes.bool.isRequired,
|
||||||
|
@ -523,10 +520,8 @@ IDEView.propTypes = {
|
||||||
}).isRequired,
|
}).isRequired,
|
||||||
closePreferences: PropTypes.func.isRequired,
|
closePreferences: PropTypes.func.isRequired,
|
||||||
setFontSize: PropTypes.func.isRequired,
|
setFontSize: PropTypes.func.isRequired,
|
||||||
setIndentation: PropTypes.func.isRequired,
|
|
||||||
indentWithTab: PropTypes.func.isRequired,
|
|
||||||
indentWithSpace: PropTypes.func.isRequired,
|
|
||||||
setAutosave: PropTypes.func.isRequired,
|
setAutosave: PropTypes.func.isRequired,
|
||||||
|
setLinewrap: PropTypes.func.isRequired,
|
||||||
setLintWarning: PropTypes.func.isRequired,
|
setLintWarning: PropTypes.func.isRequired,
|
||||||
setTextOutput: PropTypes.func.isRequired,
|
setTextOutput: PropTypes.func.isRequired,
|
||||||
setGridOutput: PropTypes.func.isRequired,
|
setGridOutput: PropTypes.func.isRequired,
|
||||||
|
|
|
@ -2,9 +2,8 @@ import * as ActionTypes from '../../../constants';
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
indentationAmount: 2,
|
|
||||||
isTabIndent: true,
|
|
||||||
autosave: true,
|
autosave: true,
|
||||||
|
linewrap: true,
|
||||||
lintWarning: false,
|
lintWarning: false,
|
||||||
textOutput: false,
|
textOutput: false,
|
||||||
gridOutput: false,
|
gridOutput: false,
|
||||||
|
@ -17,18 +16,10 @@ const preferences = (state = initialState, action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case ActionTypes.SET_FONT_SIZE:
|
case ActionTypes.SET_FONT_SIZE:
|
||||||
return Object.assign({}, state, { fontSize: action.value });
|
return Object.assign({}, state, { fontSize: action.value });
|
||||||
case ActionTypes.SET_INDENTATION:
|
|
||||||
return Object.assign({}, state, { indentationAmount: action.value });
|
|
||||||
case ActionTypes.INDENT_WITH_TAB:
|
|
||||||
return Object.assign({}, state, {
|
|
||||||
isTabIndent: true
|
|
||||||
});
|
|
||||||
case ActionTypes.INDENT_WITH_SPACE:
|
|
||||||
return Object.assign({}, state, {
|
|
||||||
isTabIndent: false
|
|
||||||
});
|
|
||||||
case ActionTypes.SET_AUTOSAVE:
|
case ActionTypes.SET_AUTOSAVE:
|
||||||
return Object.assign({}, state, { autosave: action.value });
|
return Object.assign({}, state, { autosave: action.value });
|
||||||
|
case ActionTypes.SET_LINEWRAP:
|
||||||
|
return Object.assign({}, state, { linewrap: action.value });
|
||||||
case ActionTypes.SET_LINT_WARNING:
|
case ActionTypes.SET_LINT_WARNING:
|
||||||
return Object.assign({}, state, { lintWarning: action.value });
|
return Object.assign({}, state, { lintWarning: action.value });
|
||||||
case ActionTypes.SET_TEXT_OUTPUT:
|
case ActionTypes.SET_TEXT_OUTPUT:
|
||||||
|
|
|
@ -17,6 +17,7 @@ $themes: (
|
||||||
light: (
|
light: (
|
||||||
logo-color: $p5js-pink,
|
logo-color: $p5js-pink,
|
||||||
primary-text-color: #333,
|
primary-text-color: #333,
|
||||||
|
dropzone-text-color: #333,
|
||||||
modal-button-color: #333,
|
modal-button-color: #333,
|
||||||
heading-text-color: #333,
|
heading-text-color: #333,
|
||||||
secondary-text-color: #a8a8a8,
|
secondary-text-color: #a8a8a8,
|
||||||
|
@ -36,7 +37,7 @@ $themes: (
|
||||||
modal-background-color: #f4f4f4,
|
modal-background-color: #f4f4f4,
|
||||||
modal-button-background-color: #e6e6e6,
|
modal-button-background-color: #e6e6e6,
|
||||||
modal-border-color: rgba(17, 17, 17, 0.3),
|
modal-border-color: rgba(17, 17, 17, 0.3),
|
||||||
modal-boder-selected-color: #B9D0E1,
|
modal-border-selected-color: #B9D0E1,
|
||||||
icon-color: $icon-color,
|
icon-color: $icon-color,
|
||||||
icon-hover-color: $icon-hover-color,
|
icon-hover-color: $icon-hover-color,
|
||||||
icon-toast-hover-color: $white,
|
icon-toast-hover-color: $white,
|
||||||
|
@ -65,6 +66,7 @@ $themes: (
|
||||||
dark: (
|
dark: (
|
||||||
logo-color: $p5js-pink,
|
logo-color: $p5js-pink,
|
||||||
primary-text-color: $white,
|
primary-text-color: $white,
|
||||||
|
dropzone-text-color: $black,
|
||||||
modal-button-color: $white,
|
modal-button-color: $white,
|
||||||
heading-text-color: $white,
|
heading-text-color: $white,
|
||||||
secondary-text-color: #DADADA,
|
secondary-text-color: #DADADA,
|
||||||
|
@ -112,6 +114,7 @@ $themes: (
|
||||||
contrast: (
|
contrast: (
|
||||||
logo-color: $yellow,
|
logo-color: $yellow,
|
||||||
primary-text-color: $yellow,
|
primary-text-color: $yellow,
|
||||||
|
dropzone-text-color: $black,
|
||||||
modal-button-color: #333,
|
modal-button-color: #333,
|
||||||
heading-text-color: #e1e1e1,
|
heading-text-color: #e1e1e1,
|
||||||
secondary-text-color: #e1e1e1,
|
secondary-text-color: #e1e1e1,
|
||||||
|
|
|
@ -51,7 +51,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.tooltipped-n::before,
|
.tooltipped-n::before,
|
||||||
.tooltipped::before,
|
.tooltipped::before
|
||||||
{
|
{
|
||||||
@include themify() {
|
@include themify() {
|
||||||
color: getThemifyVariable('button-background-hover-color');
|
color: getThemifyVariable('button-background-hover-color');
|
||||||
|
|
|
@ -3,15 +3,18 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|
||||||
@include themify() {
|
@include themify() {
|
||||||
border-bottom: 1px dashed map-get($theme-map, 'inactive-text-color');
|
border-bottom: 1px dashed map-get($theme-map, 'inactive-text-color');
|
||||||
}
|
}
|
||||||
|
|
||||||
& button {
|
& button {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav__items-left, .nav__items-right {
|
.nav__items-left,
|
||||||
|
.nav__items-right {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
@ -30,11 +33,14 @@
|
||||||
|
|
||||||
.nav__item {
|
.nav__item {
|
||||||
position: relative;
|
position: relative;
|
||||||
padding: 0 #{10 / $base-font-size}rem;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
|
& button {
|
||||||
|
padding: #{12 / $base-font-size}rem #{10 / $base-font-size}rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav__item:first-child {
|
.nav__item:first-child {
|
||||||
|
@ -55,6 +61,7 @@
|
||||||
color: getThemifyVariable('nav-hover-color');
|
color: getThemifyVariable('nav-hover-color');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav__item-header-triangle polygon {
|
.nav__item-header-triangle polygon {
|
||||||
@include themify() {
|
@include themify() {
|
||||||
fill: getThemifyVariable('nav-hover-color');
|
fill: getThemifyVariable('nav-hover-color');
|
||||||
|
@ -69,23 +76,28 @@
|
||||||
box-shadow: 0 0 18px 0 getThemifyVariable('shadow-color');
|
box-shadow: 0 0 18px 0 getThemifyVariable('shadow-color');
|
||||||
color: getThemifyVariable('dropdown-color');
|
color: getThemifyVariable('dropdown-color');
|
||||||
}
|
}
|
||||||
|
|
||||||
display: none;
|
display: none;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
width: #{180 / $base-font-size}rem;
|
width: #{180 / $base-font-size}rem;
|
||||||
|
|
||||||
.nav__item--open & {
|
.nav__item--open & {
|
||||||
display: flex;
|
display: flex;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
top: 4px;
|
top: #{40 / $base-font-size}rem;
|
||||||
left: 0;
|
left: 0;
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
z-index: 9999;
|
z-index: 9999;
|
||||||
border-radius: #{6 / $base-font-size}rem;
|
border-radius: #{6 / $base-font-size}rem;
|
||||||
|
border-top-left-radius: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav__items-right {
|
.nav__items-right {
|
||||||
padding-right: #{20 / $base-font-size}rem;
|
padding-right: #{20 / $base-font-size}rem;
|
||||||
|
|
||||||
& .nav__dropdown {
|
& .nav__dropdown {
|
||||||
width: #{121 / $base-font-size}rem;
|
width: #{121 / $base-font-size}rem;
|
||||||
}
|
}
|
||||||
|
@ -98,7 +110,8 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav__dropdown a, button {
|
.nav__dropdown a,
|
||||||
|
button {
|
||||||
@include themify() {
|
@include themify() {
|
||||||
color: getThemifyVariable('secondary-text-color');
|
color: getThemifyVariable('secondary-text-color');
|
||||||
}
|
}
|
||||||
|
@ -118,18 +131,21 @@
|
||||||
@include themify() {
|
@include themify() {
|
||||||
border-bottom: 1px dashed map-get($theme-map, 'inactive-text-color');
|
border-bottom: 1px dashed map-get($theme-map, 'inactive-text-color');
|
||||||
}
|
}
|
||||||
|
|
||||||
height: #{(42 - 5) / $base-font-size}rem;
|
height: #{(42 - 5) / $base-font-size}rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
margin: 0 #{16 / $base-font-size}rem;
|
margin: 0 #{16 / $base-font-size}rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
span {
|
span {
|
||||||
@include themify() {
|
@include themify() {
|
||||||
color: getThemifyVariable('nav-hover-color');
|
color: getThemifyVariable('nav-hover-color');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
polygon {
|
polygon {
|
||||||
@include themify() {
|
@include themify() {
|
||||||
fill: getThemifyVariable('nav-hover-color');
|
fill: getThemifyVariable('nav-hover-color');
|
||||||
|
@ -138,10 +154,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav__dropdown-heading a, .nav__dropdown-heading a:hover {
|
.nav__dropdown-heading a,
|
||||||
|
.nav__dropdown-heading a:hover {
|
||||||
@include themify() {
|
@include themify() {
|
||||||
color: getThemifyVariable('inactive-text-color');
|
color: getThemifyVariable('inactive-text-color');
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor: default;
|
cursor: default;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
@ -158,24 +176,30 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 0 #{16 / $base-font-size}rem;
|
padding: 0 #{16 / $base-font-size}rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
& button, & a {
|
|
||||||
|
& button,
|
||||||
|
& a {
|
||||||
@include themify() {
|
@include themify() {
|
||||||
color: getThemifyVariable('dropdown-color');
|
color: getThemifyVariable('dropdown-color');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
@include themify() {
|
@include themify() {
|
||||||
background-color: getThemifyVariable('button-background-hover-color');
|
background-color: getThemifyVariable('button-background-hover-color');
|
||||||
color: getThemifyVariable('button-hover-color')
|
color: getThemifyVariable('button-hover-color')
|
||||||
}
|
}
|
||||||
& button, & a {
|
|
||||||
|
& button,
|
||||||
|
& a {
|
||||||
@include themify() {
|
@include themify() {
|
||||||
color: getThemifyVariable('button-hover-color');
|
color: getThemifyVariable('button-hover-color');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
& button, & a {
|
& button,
|
||||||
|
& a {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -185,7 +209,10 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav__dropdown-item:last-child {
|
.nav__dropdown-item:last-child {
|
||||||
border-radius: 0 0 #{6 / $base-font-size}rem #{6 / $base-font-size}rem;
|
border-radius: 0 0 #{5 / $base-font-size}rem #{5 / $base-font-size}rem;
|
||||||
|
}
|
||||||
|
.nav__dropdown-item:first-child {
|
||||||
|
border-radius: 0 #{5 / $base-font-size}rem 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav__announce {
|
.nav__announce {
|
||||||
|
@ -207,17 +234,28 @@
|
||||||
position: relative;
|
position: relative;
|
||||||
height: #{42 / $base-font-size}rem;
|
height: #{42 / $base-font-size}rem;
|
||||||
width: #{56 / $base-font-size}rem;
|
width: #{56 / $base-font-size}rem;
|
||||||
|
|
||||||
& span {
|
& span {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.svg__logo g > path {
|
||||||
|
@include themify() {
|
||||||
|
fill: getThemifyVariable('logo-color');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.svg__logo g g:first-of-type path {
|
||||||
|
fill: none;
|
||||||
|
}
|
||||||
|
|
||||||
.nav__keyboard-shortcut {
|
.nav__keyboard-shortcut {
|
||||||
font-size: #{12 / $base-font-size}rem;
|
font-size: #{12 / $base-font-size}rem;
|
||||||
font-family: Inconsololata, monospace;
|
font-family: Inconsololata, monospace;
|
||||||
|
|
||||||
@include themify() {
|
@include themify() {
|
||||||
color: getThemifyVariable('keyboard-shortcut-color');
|
color: getThemifyVariable('keyboard-shortcut-color');
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav__dropdown-item:hover & {
|
.nav__dropdown-item:hover & {
|
||||||
@include themify() {
|
@include themify() {
|
||||||
color: getThemifyVariable('button-hover-color');
|
color: getThemifyVariable('button-hover-color');
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
.dropzone {
|
.dropzone {
|
||||||
color: $primary-text-color;
|
@include themify() {
|
||||||
|
color: getThemifyVariable('dropzone-text-color');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.uploader {
|
.uploader {
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
@import 'components/keyboard-shortcuts';
|
@import 'components/keyboard-shortcuts';
|
||||||
@import 'components/copyable-input';
|
@import 'components/copyable-input';
|
||||||
@import 'components/feedback';
|
@import 'components/feedback';
|
||||||
|
@import 'components/uploader';
|
||||||
|
|
||||||
@import 'layout/ide';
|
@import 'layout/ide';
|
||||||
@import 'layout/fullscreen';
|
@import 'layout/fullscreen';
|
||||||
|
|
|
@ -73,8 +73,8 @@ export function validateSignup(formProps) {
|
||||||
errors.confirmPassword = 'Please enter a password confirmation';
|
errors.confirmPassword = 'Please enter a password confirmation';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (formProps.password !== formProps.confirmPassword) {
|
if (formProps.password !== formProps.confirmPassword && formProps.confirmPassword) {
|
||||||
errors.password = 'Passwords must match';
|
errors.confirmPassword = 'Passwords must match';
|
||||||
}
|
}
|
||||||
|
|
||||||
return errors;
|
return errors;
|
||||||
|
|
|
@ -29,6 +29,8 @@ These are the steps that happen when you deploy the application.
|
||||||
|
|
||||||
You'll only need to do this if you're testing the production environment locally.
|
You'll only need to do this if you're testing the production environment locally.
|
||||||
|
|
||||||
|
_Note_: The installation steps assume you are using a Unix-like shell. If you are using Windows, you will need to use `copy` instead of `cp`.
|
||||||
|
|
||||||
1. Clone this repository and `cd` into it
|
1. Clone this repository and `cd` into it
|
||||||
2. `$ npm install`
|
2. `$ npm install`
|
||||||
3. Install MongoDB and make sure it is running
|
3. Install MongoDB and make sure it is running
|
||||||
|
|
|
@ -4,6 +4,8 @@ Follow these instructions to set up your development environment, which you need
|
||||||
|
|
||||||
## Manual Installation
|
## Manual Installation
|
||||||
|
|
||||||
|
_Note_: The installation steps assume you are using a Unix-like shell. If you are using Windows, you will need to use `copy` instead of `cp`.
|
||||||
|
|
||||||
1. Install [node.js](http://nodejs.org/), which also automatically installs the [npm](https://www.npmjs.org) package manager.
|
1. Install [node.js](http://nodejs.org/), which also automatically installs the [npm](https://www.npmjs.org) package manager.
|
||||||
2. [Fork](https://help.github.com/articles/fork-a-repo) the [p5.js Web Editor repository](https://github.com/processing/p5.js-web-editor) into your own GitHub account.
|
2. [Fork](https://help.github.com/articles/fork-a-repo) the [p5.js Web Editor repository](https://github.com/processing/p5.js-web-editor) into your own GitHub account.
|
||||||
3. [Clone](https://help.github.com/articles/cloning-a-repository/) your new fork of the repository from GitHub onto your local computer.
|
3. [Clone](https://help.github.com/articles/cloning-a-repository/) your new fork of the repository from GitHub onto your local computer.
|
||||||
|
@ -31,6 +33,8 @@ Follow these instructions to set up your development environment, which you need
|
||||||
|
|
||||||
## Docker Installation
|
## Docker Installation
|
||||||
|
|
||||||
|
_Note_: The installation steps assume you are using a Unix-like shell. If you are using Windows, you will need to use `copy` instead of `cp`.
|
||||||
|
|
||||||
Using Docker, you can have a complete, consistent development environment without having to manually install dependencies such as Node, Mongo, etc. It also helps isolate these dependencies and their data from other projects that you may have on the same computer that use different/conflicting versions, etc.
|
Using Docker, you can have a complete, consistent development environment without having to manually install dependencies such as Node, Mongo, etc. It also helps isolate these dependencies and their data from other projects that you may have on the same computer that use different/conflicting versions, etc.
|
||||||
|
|
||||||
Note that this takes up a significant amount of space on your machine. Make sure you have at least 5GB free.
|
Note that this takes up a significant amount of space on your machine. Make sure you have at least 5GB free.
|
||||||
|
@ -59,7 +63,7 @@ If you don't have the full server environment running, you can launch a one-off
|
||||||
|
|
||||||
## S3 Bucket Configuration
|
## S3 Bucket Configuration
|
||||||
|
|
||||||
Note that this is optional, unless you are working on the part of the application that allows a user to upload images, videos, etc. Please refer to the folllowing [gist](https://gist.github.com/catarak/70c9301f0fd1ac2d6b58de03f61997e3) to set up an S3 bucket to be used with this project.
|
Note that this is optional, unless you are working on the part of the application that allows a user to upload images, videos, etc. Please refer to the following [gist](https://gist.github.com/catarak/70c9301f0fd1ac2d6b58de03f61997e3) to set up an S3 bucket to be used with this project.
|
||||||
|
|
||||||
If your S3 bucket is in the US East (N Virginia) region (us-east-1), you'll
|
If your S3 bucket is in the US East (N Virginia) region (us-east-1), you'll
|
||||||
need to set a custom URL base for it, because it does not follow the standard
|
need to set a custom URL base for it, because it does not follow the standard
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Preparing a pull request
|
# Preparing a pull request
|
||||||
|
|
||||||
Copied from the [p5.js repository](https://github.com/processing/p5.js).
|
Copied and updated from the [p5.js repository](https://github.com/processing/p5.js).
|
||||||
|
|
||||||
Pull-requests are easier when your code is up to date! You can use git rebase to update your code to incorporate changes from other contributors. Here's how.
|
Pull-requests are easier when your code is up to date! You can use git rebase to update your code to incorporate changes from other contributors. Here's how.
|
||||||
|
|
||||||
|
@ -31,17 +31,19 @@ Then ask git about the latest changes.
|
||||||
### Apply changes from master branch, adds your changes *after*
|
### Apply changes from master branch, adds your changes *after*
|
||||||
git rebase upstream/master
|
git rebase upstream/master
|
||||||
|
|
||||||
|
### Switches back to master branch
|
||||||
|
git checkout master
|
||||||
|
|
||||||
|
### Helps other contributors fully understand the changes that you made
|
||||||
|
git commit -m "Fixed documentation typos"
|
||||||
|
|
||||||
|
### Verifies what git will be committing
|
||||||
|
git status
|
||||||
|
|
||||||
## CONFLICTS
|
## CONFLICTS
|
||||||
You will probably have some conflicts!
|
You may have some conflicts! It's okay. Feel free to ask for help. If merging with the latest upstream master causes conflicts, you can always make a pull request with the upstream repository, which makes the merge conflicts public.
|
||||||
If it’s just lib/p5.js and lib/p5.min.js, it’s easy to fix. just build the project again with grunt.
|
|
||||||
|
|
||||||
grunt
|
|
||||||
git add -u
|
|
||||||
git rebase --continue
|
|
||||||
|
|
||||||
If you have conflicts in other files & you're not sure how to resolve them... ask for help! Lauren, David, Kevin, and Kate are familiar with recent changes and can help you figure out what's new.
|
|
||||||
|
|
||||||
## And finally, for great glory
|
## And finally, for great glory
|
||||||
git push origin
|
git push --set-upstream origin your-branch-name-backup
|
||||||
|
|
||||||
Here's a good reference on rebasing, in case you're intensely curious about the technical details. https://www.atlassian.com/git/tutorials/merging-vs-rebasing
|
Here's a good reference on rebasing, in case you're intensely curious about the technical details. https://www.atlassian.com/git/tutorials/merging-vs-rebasing
|
|
@ -110,7 +110,9 @@ export function getProject(req, res) {
|
||||||
function deleteFilesFromS3(files) {
|
function deleteFilesFromS3(files) {
|
||||||
deleteObjectsFromS3(files.filter((file) => {
|
deleteObjectsFromS3(files.filter((file) => {
|
||||||
if (file.url) {
|
if (file.url) {
|
||||||
if (!process.env.S3_DATE || (process.env.S3_DATE && isBefore(new Date(process.env.S3_DATE), new Date(file.createdAt)))) {
|
if (!process.env.S3_DATE || (
|
||||||
|
process.env.S3_DATE &&
|
||||||
|
isBefore(new Date(process.env.S3_DATE), new Date(file.createdAt)))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -178,7 +178,7 @@ objectsResponse.on('end', () => {
|
||||||
// // console.log('is selected remains');
|
// // console.log('is selected remains');
|
||||||
// // }
|
// // }
|
||||||
|
|
||||||
// // if (file.isSelctedFile) {
|
// // if (file.isSelectedFile) {
|
||||||
// // console.log('changed to isSelected file');
|
// // console.log('changed to isSelected file');
|
||||||
// // }
|
// // }
|
||||||
// project.save((err, savedProject) => {
|
// project.save((err, savedProject) => {
|
||||||
|
|
|
@ -27,6 +27,7 @@ const userSchema = new Schema({
|
||||||
indentationAmount: { type: Number, default: 2 },
|
indentationAmount: { type: Number, default: 2 },
|
||||||
isTabIndent: { type: Boolean, default: false },
|
isTabIndent: { type: Boolean, default: false },
|
||||||
autosave: { type: Boolean, default: true },
|
autosave: { type: Boolean, default: true },
|
||||||
|
linewrap: { type: Boolean, default: true },
|
||||||
lintWarning: { type: Boolean, default: false },
|
lintWarning: { type: Boolean, default: false },
|
||||||
textOutput: { type: Boolean, default: false },
|
textOutput: { type: Boolean, default: false },
|
||||||
gridOutput: { type: Boolean, default: false },
|
gridOutput: { type: Boolean, default: false },
|
||||||
|
|
Loading…
Reference in a new issue