react-ace
Advanced tools
Comparing version 6.4.0 to 6.5.0
@@ -8,2 +8,9 @@ # Changelog | ||
## 6.5.0 | ||
- Upgrade dependencies | ||
- Do not clear active line and active word markers #604 | ||
- New 'placeholder' prop to specify placeholder text #603 | ||
- Added optional prop to disable navigating to end of file #602 | ||
## 6.4.0 | ||
@@ -10,0 +17,0 @@ |
@@ -163,4 +163,4 @@ /* eslint-disable */ | ||
} | ||
cols = loadColumns(); | ||
loadData(cols); | ||
loadColumns(); | ||
loadData(); | ||
addSortIndicators(); | ||
@@ -167,0 +167,0 @@ enableUI(); |
@@ -163,4 +163,4 @@ /* eslint-disable */ | ||
} | ||
cols = loadColumns(); | ||
loadData(cols); | ||
loadColumns(); | ||
loadData(); | ||
addSortIndicators(); | ||
@@ -167,0 +167,0 @@ enableUI(); |
107
docs/Ace.md
@@ -11,14 +11,13 @@ # Ace Editor | ||
```javascript | ||
import React from 'react'; | ||
import { render } from 'react-dom'; | ||
import brace from 'brace'; | ||
import AceEditor from 'react-ace'; | ||
import React from "react"; | ||
import { render } from "react-dom"; | ||
import brace from "brace"; | ||
import AceEditor from "react-ace"; | ||
import 'brace/mode/java'; | ||
import 'brace/theme/github'; | ||
import "brace/mode/java"; | ||
import "brace/theme/github"; | ||
function onChange(newValue) { | ||
console.log('change',newValue); | ||
console.log("change", newValue); | ||
} | ||
@@ -33,53 +32,53 @@ | ||
name="UNIQUE_ID_OF_DIV" | ||
editorProps={{$blockScrolling: true}} | ||
editorProps={{ $blockScrolling: true }} | ||
/>, | ||
document.getElementById('example') | ||
document.getElementById("example") | ||
); | ||
``` | ||
## Available Props | ||
|Prop|Default|Type|Description| | ||
|-----|------|-----|-----| | ||
|name| 'brace-editor'| String |Unique Id to be used for the editor| | ||
|mode| ''| String |Language for parsing and code highlighting| | ||
|theme| ''| String |theme to use| | ||
|value | ''| String | value you want to populate in the code highlighter| | ||
|defaultValue | ''| String |Default value of the editor| | ||
|height| '500px'| String |CSS value for height| | ||
|width| '500px'| String |CSS value for width| | ||
|className| | String |custom className| | ||
|fontSize| 12| Number |pixel value for font-size| | ||
|showGutter| true| Boolean | show gutter | | ||
|showPrintMargin| true| Boolean| show print margin | | ||
|highlightActiveLine| true| Boolean| highlight active line| | ||
|focus| false| Boolean| whether to focus | ||
|cursorStart| 1| Number| the location of the cursor | ||
|wrapEnabled| false| Boolean | Wrapping lines| | ||
|readOnly| false| Boolean| make the editor read only | | ||
|minLines| | Number |Minimum number of lines to be displayed| | ||
|maxLines| | Number |Maximum number of lines to be displayed| | ||
|enableBasicAutocompletion| false| Boolean | Enable basic autocompletion| | ||
|enableLiveAutocompletion| false| Boolean | Enable live autocompletion| | ||
|tabSize| 4| Number| tabSize| | ||
|debounceChangePeriod| null| Number| A debounce delay period for the onChange event| | ||
|onLoad| | Function | called on editor load. The first argument is the instance of the editor | | ||
|onBeforeLoad| | Function | called before editor load. the first argument is an instance of `ace`| | ||
|onChange| | Function | occurs on document change it has 2 arguments the value and the event.| | ||
|onCopy| | Function | triggered by editor `copy` event, and passes text as argument| | ||
|onPaste| | Function | Triggered by editor `paste` event, and passes text as argument| | ||
|onSelectionChange| | Function | triggered by editor `selectionChange` event, and passes a [Selection](https://ace.c9.io/#nav=api&api=selection) as it's first argument and the event as the second| | ||
|onCursorChange| | Function | triggered by editor `changeCursor` event, and passes a [Selection](https://ace.c9.io/#nav=api&api=selection) as it's first argument and the event as the second| | ||
|onFocus| | Function | triggered by editor `focus` event| | ||
|onBlur| | Function | triggered by editor `blur` event.It has two arguments event and editor| | ||
|onInput| | Function | triggered by editor `input` event| | ||
|onScroll| | Function | triggered by editor `scroll` event| | ||
|onValidate| | Function | triggered, when annotations are changed| | ||
|editorProps| | Object | properties to apply directly to the Ace editor instance| | ||
|setOptions| | Object | [options](https://github.com/ajaxorg/ace/wiki/Configuring-Ace) to apply directly to the Ace editor instance| | ||
|keyboardHandler| | String | corresponding to the keybinding mode to set (such as vim or emacs)| | ||
|commands| | Array | new commands to add to the editor | ||
|annotations| | Array | annotations to show in the editor i.e. `[{ row: 0, column: 2, type: 'error', text: 'Some error.'}]`, displayed in the gutter| | ||
|markers| | Array | [markers](https://ace.c9.io/#nav=api&api=edit_session) to show in the editor, i.e. `[{ startRow: 0, startCol: 2, endRow: 1, endCol: 20, className: 'error-marker', type: 'background' }]`. Make sure to define the class (eg. ".error-marker") and set `position: absolute` for it.| | ||
|style| | Object | camelCased properties | | ||
| Prop | Default | Type | Description | | ||
| ------------------------- | -------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| name | 'brace-editor' | String | Unique Id to be used for the editor | | ||
| placeholder | null | String | Placeholder text to be displayed when editor is empty | | ||
| mode | '' | String | Language for parsing and code highlighting | | ||
| theme | '' | String | theme to use | | ||
| value | '' | String | value you want to populate in the code highlighter | | ||
| defaultValue | '' | String | Default value of the editor | | ||
| height | '500px' | String | CSS value for height | | ||
| width | '500px' | String | CSS value for width | | ||
| className | | String | custom className | | ||
| fontSize | 12 | Number | pixel value for font-size | | ||
| showGutter | true | Boolean | show gutter | | ||
| showPrintMargin | true | Boolean | show print margin | | ||
| highlightActiveLine | true | Boolean | highlight active line | | ||
| focus | false | Boolean | whether to focus | | ||
| cursorStart | 1 | Number | the location of the cursor | | ||
| wrapEnabled | false | Boolean | Wrapping lines | | ||
| readOnly | false | Boolean | make the editor read only | | ||
| minLines | | Number | Minimum number of lines to be displayed | | ||
| maxLines | | Number | Maximum number of lines to be displayed | | ||
| enableBasicAutocompletion | false | Boolean | Enable basic autocompletion | | ||
| enableLiveAutocompletion | false | Boolean | Enable live autocompletion | | ||
| tabSize | 4 | Number | tabSize | | ||
| debounceChangePeriod | null | Number | A debounce delay period for the onChange event | | ||
| onLoad | | Function | called on editor load. The first argument is the instance of the editor | | ||
| onBeforeLoad | | Function | called before editor load. the first argument is an instance of `ace` | | ||
| onChange | | Function | occurs on document change it has 2 arguments the value and the event. | | ||
| onCopy | | Function | triggered by editor `copy` event, and passes text as argument | | ||
| onPaste | | Function | Triggered by editor `paste` event, and passes text as argument | | ||
| onSelectionChange | | Function | triggered by editor `selectionChange` event, and passes a [Selection](https://ace.c9.io/#nav=api&api=selection) as it's first argument and the event as the second | | ||
| onCursorChange | | Function | triggered by editor `changeCursor` event, and passes a [Selection](https://ace.c9.io/#nav=api&api=selection) as it's first argument and the event as the second | | ||
| onFocus | | Function | triggered by editor `focus` event | | ||
| onBlur | | Function | triggered by editor `blur` event.It has two arguments event and editor | | ||
| onInput | | Function | triggered by editor `input` event | | ||
| onScroll | | Function | triggered by editor `scroll` event | | ||
| onValidate | | Function | triggered, when annotations are changed | | ||
| editorProps | | Object | properties to apply directly to the Ace editor instance | | ||
| setOptions | | Object | [options](https://github.com/ajaxorg/ace/wiki/Configuring-Ace) to apply directly to the Ace editor instance | | ||
| keyboardHandler | | String | corresponding to the keybinding mode to set (such as vim or emacs) | | ||
| commands | | Array | new commands to add to the editor | | ||
| annotations | | Array | annotations to show in the editor i.e. `[{ row: 0, column: 2, type: 'error', text: 'Some error.'}]`, displayed in the gutter | | ||
| markers | | Array | [markers](https://ace.c9.io/#nav=api&api=edit_session) to show in the editor, i.e. `[{ startRow: 0, startCol: 2, endRow: 1, endCol: 20, className: 'error-marker', type: 'background' }]`. Make sure to define the class (eg. ".error-marker") and set `position: absolute` for it. | | ||
| style | | Object | camelCased properties | |
158
lib/ace.js
@@ -1,2 +0,2 @@ | ||
'use strict'; | ||
"use strict"; | ||
@@ -11,15 +11,15 @@ Object.defineProperty(exports, "__esModule", { | ||
var _react = require('react'); | ||
var _react = require("react"); | ||
var _react2 = _interopRequireDefault(_react); | ||
var _propTypes = require('prop-types'); | ||
var _propTypes = require("prop-types"); | ||
var _propTypes2 = _interopRequireDefault(_propTypes); | ||
var _lodash = require('lodash.isequal'); | ||
var _lodash = require("lodash.isequal"); | ||
var _lodash2 = _interopRequireDefault(_lodash); | ||
var _editorOptions = require('./editorOptions.js'); | ||
var _editorOptions = require("./editorOptions.js"); | ||
@@ -36,3 +36,3 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
var _ace$acequire = ace.acequire('ace/range'), | ||
var _ace$acequire = ace.acequire("ace/range"), | ||
Range = _ace$acequire.Range; | ||
@@ -56,3 +56,3 @@ | ||
_createClass(ReactAce, [{ | ||
key: 'componentDidMount', | ||
key: "componentDidMount", | ||
value: function componentDidMount() { | ||
@@ -81,3 +81,4 @@ var _this2 = this; | ||
annotations = _props.annotations, | ||
markers = _props.markers; | ||
markers = _props.markers, | ||
placeholder = _props.placeholder; | ||
@@ -99,20 +100,25 @@ | ||
this.editor.renderer.setScrollMargin(scrollMargin[0], scrollMargin[1], scrollMargin[2], scrollMargin[3]); | ||
this.editor.getSession().setMode('ace/mode/' + mode); | ||
this.editor.setTheme('ace/theme/' + theme); | ||
this.editor.getSession().setMode("ace/mode/" + mode); | ||
this.editor.setTheme("ace/theme/" + theme); | ||
this.editor.setFontSize(fontSize); | ||
this.editor.getSession().setValue(!defaultValue ? value : defaultValue, cursorStart); | ||
this.editor.navigateFileEnd(); | ||
if (this.props.navigateToFileEnd) { | ||
this.editor.navigateFileEnd(); | ||
} | ||
this.editor.renderer.setShowGutter(showGutter); | ||
this.editor.getSession().setUseWrapMode(wrapEnabled); | ||
this.editor.setShowPrintMargin(showPrintMargin); | ||
this.editor.on('focus', this.onFocus); | ||
this.editor.on('blur', this.onBlur); | ||
this.editor.on('copy', this.onCopy); | ||
this.editor.on('paste', this.onPaste); | ||
this.editor.on('change', this.onChange); | ||
this.editor.on('input', this.onInput); | ||
this.editor.getSession().selection.on('changeSelection', this.onSelectionChange); | ||
this.editor.getSession().selection.on('changeCursor', this.onCursorChange); | ||
this.editor.on("focus", this.onFocus); | ||
this.editor.on("blur", this.onBlur); | ||
this.editor.on("copy", this.onCopy); | ||
this.editor.on("paste", this.onPaste); | ||
this.editor.on("change", this.onChange); | ||
this.editor.on("input", this.onInput); | ||
if (placeholder) { | ||
this.updatePlaceholder(this.editor, placeholder); | ||
} | ||
this.editor.getSession().selection.on("changeSelection", this.onSelectionChange); | ||
this.editor.getSession().selection.on("changeCursor", this.onCursorChange); | ||
if (onValidate) { | ||
this.editor.getSession().on('changeAnnotation', function () { | ||
this.editor.getSession().on("changeAnnotation", function () { | ||
var annotations = _this2.editor.getSession().getAnnotations(); | ||
@@ -122,3 +128,3 @@ _this2.props.onValidate(annotations); | ||
} | ||
this.editor.session.on('changeScrollTop', this.onScroll); | ||
this.editor.session.on("changeScrollTop", this.onScroll); | ||
this.editor.getSession().setAnnotations(annotations || []); | ||
@@ -136,3 +142,3 @@ if (markers && markers.length > 0) { | ||
} else if (this.props[option]) { | ||
console.warn('ReactAce: editor option ' + option + ' was activated but not found. Did you need to import a related tool or did you possibly mispell the option?'); | ||
console.warn("ReactAce: editor option " + option + " was activated but not found. Did you need to import a related tool or did you possibly mispell the option?"); | ||
} | ||
@@ -144,3 +150,3 @@ } | ||
commands.forEach(function (command) { | ||
if (typeof command.exec == 'string') { | ||
if (typeof command.exec == "string") { | ||
_this2.editor.commands.bindKey(command.bindKey, command.exec); | ||
@@ -154,7 +160,7 @@ } else { | ||
if (keyboardHandler) { | ||
this.editor.setKeyboardHandler('ace/keyboard/' + keyboardHandler); | ||
this.editor.setKeyboardHandler("ace/keyboard/" + keyboardHandler); | ||
} | ||
if (className) { | ||
this.refEditor.className += ' ' + className; | ||
this.refEditor.className += " " + className; | ||
} | ||
@@ -173,3 +179,3 @@ | ||
}, { | ||
key: 'componentDidUpdate', | ||
key: "componentDidUpdate", | ||
value: function componentDidUpdate(prevProps) { | ||
@@ -188,4 +194,4 @@ var oldProps = prevProps; | ||
var appliedClasses = this.refEditor.className; | ||
var appliedClassesArray = appliedClasses.trim().split(' '); | ||
var oldClassesArray = oldProps.className.trim().split(' '); | ||
var appliedClassesArray = appliedClasses.trim().split(" "); | ||
var oldClassesArray = oldProps.className.trim().split(" "); | ||
oldClassesArray.forEach(function (oldClass) { | ||
@@ -195,3 +201,3 @@ var index = appliedClassesArray.indexOf(oldClass); | ||
}); | ||
this.refEditor.className = ' ' + nextProps.className + ' ' + appliedClassesArray.join(' '); | ||
this.refEditor.className = " " + nextProps.className + " " + appliedClassesArray.join(" "); | ||
} | ||
@@ -209,11 +215,14 @@ | ||
if (nextProps.placeholder !== oldProps.placeholder) { | ||
this.updatePlaceholder(); | ||
} | ||
if (nextProps.mode !== oldProps.mode) { | ||
this.editor.getSession().setMode('ace/mode/' + nextProps.mode); | ||
this.editor.getSession().setMode("ace/mode/" + nextProps.mode); | ||
} | ||
if (nextProps.theme !== oldProps.theme) { | ||
this.editor.setTheme('ace/theme/' + nextProps.theme); | ||
this.editor.setTheme("ace/theme/" + nextProps.theme); | ||
} | ||
if (nextProps.keyboardHandler !== oldProps.keyboardHandler) { | ||
if (nextProps.keyboardHandler) { | ||
this.editor.setKeyboardHandler('ace/keyboard/' + nextProps.keyboardHandler); | ||
this.editor.setKeyboardHandler("ace/keyboard/" + nextProps.keyboardHandler); | ||
} else { | ||
@@ -258,3 +267,3 @@ this.editor.setKeyboardHandler(null); | ||
}, { | ||
key: 'handleScrollMargins', | ||
key: "handleScrollMargins", | ||
value: function handleScrollMargins() { | ||
@@ -266,3 +275,3 @@ var margins = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [0, 0, 0, 0]; | ||
}, { | ||
key: 'componentWillUnmount', | ||
key: "componentWillUnmount", | ||
value: function componentWillUnmount() { | ||
@@ -273,3 +282,3 @@ this.editor.destroy(); | ||
}, { | ||
key: 'onChange', | ||
key: "onChange", | ||
value: function onChange(event) { | ||
@@ -282,3 +291,3 @@ if (this.props.onChange && !this.silent) { | ||
}, { | ||
key: 'onSelectionChange', | ||
key: "onSelectionChange", | ||
value: function onSelectionChange(event) { | ||
@@ -291,3 +300,3 @@ if (this.props.onSelectionChange) { | ||
}, { | ||
key: 'onCursorChange', | ||
key: "onCursorChange", | ||
value: function onCursorChange(event) { | ||
@@ -300,3 +309,3 @@ if (this.props.onCursorChange) { | ||
}, { | ||
key: 'onInput', | ||
key: "onInput", | ||
value: function onInput(event) { | ||
@@ -306,5 +315,8 @@ if (this.props.onInput) { | ||
} | ||
if (this.props.placeholder) { | ||
this.updatePlaceholder(); | ||
} | ||
} | ||
}, { | ||
key: 'onFocus', | ||
key: "onFocus", | ||
value: function onFocus(event) { | ||
@@ -316,3 +328,3 @@ if (this.props.onFocus) { | ||
}, { | ||
key: 'onBlur', | ||
key: "onBlur", | ||
value: function onBlur(event) { | ||
@@ -324,3 +336,3 @@ if (this.props.onBlur) { | ||
}, { | ||
key: 'onCopy', | ||
key: "onCopy", | ||
value: function onCopy(text) { | ||
@@ -332,3 +344,3 @@ if (this.props.onCopy) { | ||
}, { | ||
key: 'onPaste', | ||
key: "onPaste", | ||
value: function onPaste(text) { | ||
@@ -340,3 +352,3 @@ if (this.props.onPaste) { | ||
}, { | ||
key: 'onScroll', | ||
key: "onScroll", | ||
value: function onScroll() { | ||
@@ -348,3 +360,3 @@ if (this.props.onScroll) { | ||
}, { | ||
key: 'handleOptions', | ||
key: "handleOptions", | ||
value: function handleOptions(props) { | ||
@@ -357,3 +369,3 @@ var setOptions = Object.keys(props.setOptions); | ||
}, { | ||
key: 'handleMarkers', | ||
key: "handleMarkers", | ||
value: function handleMarkers(markers) { | ||
@@ -369,6 +381,6 @@ var _this3 = this; | ||
} | ||
// remove background markers | ||
// remove background markers except active line marker and selected word marker | ||
currentMarkers = this.editor.getSession().getMarkers(false); | ||
for (var _i2 in currentMarkers) { | ||
if (currentMarkers.hasOwnProperty(_i2)) { | ||
if (currentMarkers.hasOwnProperty(_i2) && currentMarkers[_i2].clazz !== "ace_active-line" && currentMarkers[_i2].clazz !== "ace_selected-word") { | ||
this.editor.getSession().removeMarker(currentMarkers[_i2].id); | ||
@@ -393,3 +405,29 @@ } | ||
}, { | ||
key: 'updateRef', | ||
key: "updatePlaceholder", | ||
value: function updatePlaceholder() { | ||
// Adapted from https://stackoverflow.com/questions/26695708/how-can-i-add-placeholder-text-when-the-editor-is-empty | ||
var editor = this.editor; | ||
var placeholder = this.props.placeholder; | ||
var showPlaceholder = !editor.session.getValue().length; | ||
var node = editor.renderer.placeholderNode; | ||
if (!showPlaceholder && node) { | ||
editor.renderer.scroller.removeChild(editor.renderer.placeholderNode); | ||
editor.renderer.placeholderNode = null; | ||
} else if (showPlaceholder && !node) { | ||
node = editor.renderer.placeholderNode = document.createElement("div"); | ||
node.textContent = placeholder || ""; | ||
node.className = "ace_comment ace_placeholder"; | ||
node.style.padding = "0 9px"; | ||
node.style.position = "absolute"; | ||
node.style.zIndex = "3"; | ||
editor.renderer.scroller.appendChild(node); | ||
} else if (showPlaceholder && node) { | ||
node.textContent = placeholder; | ||
} | ||
} | ||
}, { | ||
key: "updateRef", | ||
value: function updateRef(item) { | ||
@@ -399,3 +437,3 @@ this.refEditor = item; | ||
}, { | ||
key: 'render', | ||
key: "render", | ||
value: function render() { | ||
@@ -409,3 +447,3 @@ var _props2 = this.props, | ||
var divStyle = _extends({ width: width, height: height }, style); | ||
return _react2.default.createElement('div', { ref: this.updateRef, id: name, style: divStyle }); | ||
return _react2.default.createElement("div", { ref: this.updateRef, id: name, style: divStyle }); | ||
} | ||
@@ -462,13 +500,15 @@ }]); | ||
enableLiveAutocompletion: _propTypes2.default.oneOfType([_propTypes2.default.bool, _propTypes2.default.array]), | ||
commands: _propTypes2.default.array | ||
navigateToFileEnd: _propTypes2.default.bool, | ||
commands: _propTypes2.default.array, | ||
placeholder: _propTypes2.default.string | ||
}; | ||
ReactAce.defaultProps = { | ||
name: 'brace-editor', | ||
name: "brace-editor", | ||
focus: false, | ||
mode: '', | ||
theme: '', | ||
height: '500px', | ||
width: '500px', | ||
value: '', | ||
mode: "", | ||
theme: "", | ||
height: "500px", | ||
width: "500px", | ||
value: "", | ||
fontSize: 12, | ||
@@ -493,3 +533,5 @@ showGutter: true, | ||
enableBasicAutocompletion: false, | ||
enableLiveAutocompletion: false | ||
enableLiveAutocompletion: false, | ||
placeholder: null, | ||
navigateToFileEnd: true | ||
}; |
{ | ||
"name": "react-ace", | ||
"version": "6.4.0", | ||
"version": "6.5.0", | ||
"description": "A react component for Ace Editor", | ||
@@ -30,3 +30,3 @@ "main": "lib/index.js", | ||
"babel-core": "^6.26.3", | ||
"babel-eslint": "^10.0.0", | ||
"babel-eslint": "^10.0.1", | ||
"babel-loader": "^7.0.0", | ||
@@ -41,18 +41,18 @@ "babel-plugin-transform-object-rest-spread": "^6.26.0", | ||
"enzyme-adapter-react-16": "^1.5.0", | ||
"eslint": "5.6.0", | ||
"eslint": "5.16.0", | ||
"eslint-plugin-import": "^2.14.0", | ||
"eslint-plugin-jsx-a11y": "^6.1.1", | ||
"eslint-plugin-react": "7.11.1", | ||
"husky": "^1.1.1", | ||
"jsdom": "^13.0.0", | ||
"mocha": "5.2.0", | ||
"nyc": "13.2.0", | ||
"husky": "^1.3.1", | ||
"jsdom": "^14.0.0", | ||
"mocha": "6.1.4", | ||
"nyc": "14.0.0", | ||
"prettier": "^1.14.3", | ||
"react": "^16.7.0", | ||
"react-dom": "^16.7.0", | ||
"pretty-quick": "^1.7.0", | ||
"react": "^16.8.3", | ||
"react-dom": "^16.8.3", | ||
"react-test-renderer": "^16.7.0", | ||
"pretty-quick": "^1.7.0", | ||
"rimraf": "2.6.3", | ||
"sinon": "7.2.3", | ||
"webpack": "4.29.3", | ||
"sinon": "7.3.2", | ||
"webpack": "4.30.0", | ||
"webpack-cli": "^3.1.0", | ||
@@ -59,0 +59,0 @@ "webpack-dev-server": ">=3.1.11" |
184
src/ace.js
@@ -1,9 +0,13 @@ | ||
import React, { Component } from 'react' | ||
import PropTypes from 'prop-types' | ||
import isEqual from 'lodash.isequal' | ||
import { editorOptions, editorEvents, getAceInstance,debounce } from './editorOptions.js' | ||
import React, { Component } from "react"; | ||
import PropTypes from "prop-types"; | ||
import isEqual from "lodash.isequal"; | ||
import { | ||
editorOptions, | ||
editorEvents, | ||
getAceInstance, | ||
debounce | ||
} from "./editorOptions.js"; | ||
const ace = getAceInstance(); | ||
const { Range } = ace.acequire('ace/range'); | ||
const { Range } = ace.acequire("ace/range"); | ||
export default class ReactAce extends Component { | ||
@@ -39,2 +43,3 @@ constructor(props) { | ||
markers, | ||
placeholder | ||
} = this.props; | ||
@@ -53,23 +58,40 @@ | ||
if (this.props.debounceChangePeriod) { | ||
this.onChange = this.debounce(this.onChange, this.props.debounceChangePeriod); | ||
this.onChange = this.debounce( | ||
this.onChange, | ||
this.props.debounceChangePeriod | ||
); | ||
} | ||
this.editor.renderer.setScrollMargin(scrollMargin[0], scrollMargin[1], scrollMargin[2], scrollMargin[3]); | ||
this.editor.renderer.setScrollMargin( | ||
scrollMargin[0], | ||
scrollMargin[1], | ||
scrollMargin[2], | ||
scrollMargin[3] | ||
); | ||
this.editor.getSession().setMode(`ace/mode/${mode}`); | ||
this.editor.setTheme(`ace/theme/${theme}`); | ||
this.editor.setFontSize(fontSize); | ||
this.editor.getSession().setValue(!defaultValue ? value : defaultValue, cursorStart); | ||
this.editor.navigateFileEnd(); | ||
this.editor | ||
.getSession() | ||
.setValue(!defaultValue ? value : defaultValue, cursorStart); | ||
if (this.props.navigateToFileEnd) { | ||
this.editor.navigateFileEnd(); | ||
} | ||
this.editor.renderer.setShowGutter(showGutter); | ||
this.editor.getSession().setUseWrapMode(wrapEnabled); | ||
this.editor.setShowPrintMargin(showPrintMargin); | ||
this.editor.on('focus', this.onFocus); | ||
this.editor.on('blur', this.onBlur); | ||
this.editor.on('copy', this.onCopy); | ||
this.editor.on('paste', this.onPaste); | ||
this.editor.on('change', this.onChange); | ||
this.editor.on('input', this.onInput); | ||
this.editor.getSession().selection.on('changeSelection', this.onSelectionChange); | ||
this.editor.getSession().selection.on('changeCursor', this.onCursorChange); | ||
this.editor.on("focus", this.onFocus); | ||
this.editor.on("blur", this.onBlur); | ||
this.editor.on("copy", this.onCopy); | ||
this.editor.on("paste", this.onPaste); | ||
this.editor.on("change", this.onChange); | ||
this.editor.on("input", this.onInput); | ||
if (placeholder) { | ||
this.updatePlaceholder(this.editor, placeholder); | ||
} | ||
this.editor | ||
.getSession() | ||
.selection.on("changeSelection", this.onSelectionChange); | ||
this.editor.getSession().selection.on("changeCursor", this.onCursorChange); | ||
if (onValidate) { | ||
this.editor.getSession().on('changeAnnotation', () => { | ||
this.editor.getSession().on("changeAnnotation", () => { | ||
const annotations = this.editor.getSession().getAnnotations(); | ||
@@ -79,3 +101,3 @@ this.props.onValidate(annotations); | ||
} | ||
this.editor.session.on('changeScrollTop', this.onScroll); | ||
this.editor.session.on("changeScrollTop", this.onScroll); | ||
this.editor.getSession().setAnnotations(annotations || []); | ||
@@ -94,3 +116,3 @@ if (markers && markers.length > 0) { | ||
console.warn( | ||
`ReactAce: editor option ${option} was activated but not found. Did you need to import a related tool or did you possibly mispell the option?`, | ||
`ReactAce: editor option ${option} was activated but not found. Did you need to import a related tool or did you possibly mispell the option?` | ||
); | ||
@@ -103,3 +125,3 @@ } | ||
commands.forEach(command => { | ||
if (typeof command.exec == 'string') { | ||
if (typeof command.exec == "string") { | ||
this.editor.commands.bindKey(command.bindKey, command.exec); | ||
@@ -113,7 +135,7 @@ } else { | ||
if (keyboardHandler) { | ||
this.editor.setKeyboardHandler('ace/keyboard/' + keyboardHandler); | ||
this.editor.setKeyboardHandler("ace/keyboard/" + keyboardHandler); | ||
} | ||
if (className) { | ||
this.refEditor.className += ' ' + className; | ||
this.refEditor.className += " " + className; | ||
} | ||
@@ -145,4 +167,4 @@ | ||
let appliedClasses = this.refEditor.className; | ||
let appliedClassesArray = appliedClasses.trim().split(' '); | ||
let oldClassesArray = oldProps.className.trim().split(' '); | ||
let appliedClassesArray = appliedClasses.trim().split(" "); | ||
let oldClassesArray = oldProps.className.trim().split(" "); | ||
oldClassesArray.forEach(oldClass => { | ||
@@ -152,3 +174,4 @@ let index = appliedClassesArray.indexOf(oldClass); | ||
}); | ||
this.refEditor.className = ' ' + nextProps.className + ' ' + appliedClassesArray.join(' '); | ||
this.refEditor.className = | ||
" " + nextProps.className + " " + appliedClassesArray.join(" "); | ||
} | ||
@@ -166,11 +189,16 @@ | ||
if (nextProps.placeholder !== oldProps.placeholder) { | ||
this.updatePlaceholder(); | ||
} | ||
if (nextProps.mode !== oldProps.mode) { | ||
this.editor.getSession().setMode('ace/mode/' + nextProps.mode); | ||
this.editor.getSession().setMode("ace/mode/" + nextProps.mode); | ||
} | ||
if (nextProps.theme !== oldProps.theme) { | ||
this.editor.setTheme('ace/theme/' + nextProps.theme); | ||
this.editor.setTheme("ace/theme/" + nextProps.theme); | ||
} | ||
if (nextProps.keyboardHandler !== oldProps.keyboardHandler) { | ||
if (nextProps.keyboardHandler) { | ||
this.editor.setKeyboardHandler('ace/keyboard/' + nextProps.keyboardHandler); | ||
this.editor.setKeyboardHandler( | ||
"ace/keyboard/" + nextProps.keyboardHandler | ||
); | ||
} else { | ||
@@ -198,3 +226,6 @@ this.editor.setKeyboardHandler(null); | ||
} | ||
if (!isEqual(nextProps.markers, oldProps.markers) && Array.isArray(nextProps.markers)) { | ||
if ( | ||
!isEqual(nextProps.markers, oldProps.markers) && | ||
Array.isArray(nextProps.markers) | ||
) { | ||
this.handleMarkers(nextProps.markers); | ||
@@ -208,3 +239,6 @@ } | ||
if (prevProps.height !== this.props.height || prevProps.width !== this.props.width) { | ||
if ( | ||
prevProps.height !== this.props.height || | ||
prevProps.width !== this.props.width | ||
) { | ||
this.editor.resize(); | ||
@@ -218,3 +252,8 @@ } | ||
handleScrollMargins(margins = [0, 0, 0, 0]) { | ||
this.editor.renderer.setScrollMargins(margins[0], margins[1], margins[2], margins[3]); | ||
this.editor.renderer.setScrollMargins( | ||
margins[0], | ||
margins[1], | ||
margins[2], | ||
margins[3] | ||
); | ||
} | ||
@@ -250,2 +289,5 @@ | ||
} | ||
if (this.props.placeholder) { | ||
this.updatePlaceholder(); | ||
} | ||
} | ||
@@ -297,6 +339,10 @@ onFocus(event) { | ||
} | ||
// remove background markers | ||
// remove background markers except active line marker and selected word marker | ||
currentMarkers = this.editor.getSession().getMarkers(false); | ||
for (const i in currentMarkers) { | ||
if (currentMarkers.hasOwnProperty(i)) { | ||
if ( | ||
currentMarkers.hasOwnProperty(i) && | ||
currentMarkers[i].clazz !== "ace_active-line" && | ||
currentMarkers[i].clazz !== "ace_selected-word" | ||
) { | ||
this.editor.getSession().removeMarker(currentMarkers[i].id); | ||
@@ -306,8 +352,42 @@ } | ||
// add new markers | ||
markers.forEach(({ startRow, startCol, endRow, endCol, className, type, inFront = false }) => { | ||
const range = new Range(startRow, startCol, endRow, endCol); | ||
this.editor.getSession().addMarker(range, className, type, inFront); | ||
}); | ||
markers.forEach( | ||
({ | ||
startRow, | ||
startCol, | ||
endRow, | ||
endCol, | ||
className, | ||
type, | ||
inFront = false | ||
}) => { | ||
const range = new Range(startRow, startCol, endRow, endCol); | ||
this.editor.getSession().addMarker(range, className, type, inFront); | ||
} | ||
); | ||
} | ||
updatePlaceholder() { | ||
// Adapted from https://stackoverflow.com/questions/26695708/how-can-i-add-placeholder-text-when-the-editor-is-empty | ||
const editor = this.editor; | ||
const { placeholder } = this.props; | ||
const showPlaceholder = !editor.session.getValue().length; | ||
let node = editor.renderer.placeholderNode; | ||
if (!showPlaceholder && node) { | ||
editor.renderer.scroller.removeChild(editor.renderer.placeholderNode); | ||
editor.renderer.placeholderNode = null; | ||
} else if (showPlaceholder && !node) { | ||
node = editor.renderer.placeholderNode = document.createElement("div"); | ||
node.textContent = placeholder || ""; | ||
node.className = "ace_comment ace_placeholder"; | ||
node.style.padding = "0 9px"; | ||
node.style.position = "absolute"; | ||
node.style.zIndex = "3"; | ||
editor.renderer.scroller.appendChild(node); | ||
} else if (showPlaceholder && node) { | ||
node.textContent = placeholder; | ||
} | ||
} | ||
updateRef(item) { | ||
@@ -364,15 +444,23 @@ this.refEditor = item; | ||
wrapEnabled: PropTypes.bool, | ||
enableBasicAutocompletion: PropTypes.oneOfType([PropTypes.bool, PropTypes.array]), | ||
enableLiveAutocompletion: PropTypes.oneOfType([PropTypes.bool, PropTypes.array]), | ||
enableBasicAutocompletion: PropTypes.oneOfType([ | ||
PropTypes.bool, | ||
PropTypes.array | ||
]), | ||
enableLiveAutocompletion: PropTypes.oneOfType([ | ||
PropTypes.bool, | ||
PropTypes.array | ||
]), | ||
navigateToFileEnd: PropTypes.bool, | ||
commands: PropTypes.array, | ||
placeholder: PropTypes.string | ||
}; | ||
ReactAce.defaultProps = { | ||
name: 'brace-editor', | ||
name: "brace-editor", | ||
focus: false, | ||
mode: '', | ||
theme: '', | ||
height: '500px', | ||
width: '500px', | ||
value: '', | ||
mode: "", | ||
theme: "", | ||
height: "500px", | ||
width: "500px", | ||
value: "", | ||
fontSize: 12, | ||
@@ -398,2 +486,4 @@ showGutter: true, | ||
enableLiveAutocompletion: false, | ||
placeholder: null, | ||
navigateToFileEnd: true | ||
}; |
@@ -1,22 +0,20 @@ | ||
import { expect } from 'chai'; | ||
import React from 'react'; | ||
import sinon from 'sinon'; | ||
import ace from 'brace'; | ||
import Enzyme, { mount } from 'enzyme'; | ||
import AceEditor from '../../src/ace.js'; | ||
import brace from 'brace'; // eslint-disable-line no-unused-vars | ||
import Adapter from 'enzyme-adapter-react-16'; | ||
import { expect } from "chai"; | ||
import React from "react"; | ||
import sinon from "sinon"; | ||
import ace from "brace"; | ||
import Enzyme, { mount } from "enzyme"; | ||
import AceEditor from "../../src/ace.js"; | ||
import brace from "brace"; // eslint-disable-line no-unused-vars | ||
import Adapter from "enzyme-adapter-react-16"; | ||
Enzyme.configure({ adapter: new Adapter() }); | ||
describe('Ace Component', () => { | ||
describe("Ace Component", () => { | ||
// Required for the document.getElementById used by Ace can work in the test environment | ||
const domElement = document.getElementById('app'); | ||
const domElement = document.getElementById("app"); | ||
const mountOptions = { | ||
attachTo: domElement, | ||
attachTo: domElement | ||
}; | ||
describe('General', () => { | ||
it('should render without problems with defaults properties', () => { | ||
describe("General", () => { | ||
it("should render without problems with defaults properties", () => { | ||
const wrapper = mount(<AceEditor />, mountOptions); | ||
@@ -26,35 +24,45 @@ expect(wrapper).to.exist; | ||
it('should trigger console warn if editorOption is called', () => { | ||
const stub = sinon.stub(console, 'warn'); | ||
const wrapper = mount(<AceEditor enableBasicAutocompletion={true} />, mountOptions); | ||
it("should trigger console warn if editorOption is called", () => { | ||
const stub = sinon.stub(console, "warn"); | ||
const wrapper = mount( | ||
<AceEditor enableBasicAutocompletion={true} />, | ||
mountOptions | ||
); | ||
expect(wrapper).to.exist; | ||
expect(console.warn.calledWith('ReactAce: editor option enableBasicAutocompletion was activated but not found. Did you need to import a related tool or did you possibly mispell the option?') ).to.be.true; | ||
expect( | ||
console.warn.calledWith( | ||
"ReactAce: editor option enableBasicAutocompletion was activated but not found. Did you need to import a related tool or did you possibly mispell the option?" | ||
) | ||
).to.be.true; | ||
stub.restore(); | ||
}); | ||
it('should render without problems with defaults properties, defaultValue and keyboardHandler', () => { | ||
const wrapper = mount(<AceEditor | ||
keyboardHandler="vim" | ||
defaultValue={'hi james'} | ||
/>, mountOptions); | ||
it("should render without problems with defaults properties, defaultValue and keyboardHandler", () => { | ||
const wrapper = mount( | ||
<AceEditor keyboardHandler="vim" defaultValue={"hi james"} />, | ||
mountOptions | ||
); | ||
expect(wrapper).to.exist; | ||
let editor = wrapper.instance().editor; | ||
expect(editor.getValue()).to.equal('hi james'); | ||
expect(editor.getValue()).to.equal("hi james"); | ||
}); | ||
it('should render editor options not default values', () => { | ||
const wrapper = mount((<AceEditor | ||
keyboardHandler="vim" | ||
setOptions={{ | ||
tabSize: 2 | ||
}} | ||
/>), mountOptions); | ||
it("should render editor options not default values", () => { | ||
const wrapper = mount( | ||
<AceEditor | ||
keyboardHandler="vim" | ||
setOptions={{ | ||
tabSize: 2 | ||
}} | ||
/>, | ||
mountOptions | ||
); | ||
expect(wrapper).to.exist; | ||
let editor = wrapper.instance().editor; | ||
expect(editor.getOption('tabSize')).to.equal(2); | ||
expect(editor.getOption("tabSize")).to.equal(2); | ||
}); | ||
it('should get the ace library from the onBeforeLoad callback', () => { | ||
it("should get the ace library from the onBeforeLoad callback", () => { | ||
const beforeLoadCallback = sinon.spy(); | ||
mount(<AceEditor onBeforeLoad={beforeLoadCallback}/>, mountOptions); | ||
mount(<AceEditor onBeforeLoad={beforeLoadCallback} />, mountOptions); | ||
@@ -65,5 +73,5 @@ expect(beforeLoadCallback.callCount).to.equal(1); | ||
it('should get the editor from the onLoad callback', () => { | ||
it("should get the editor from the onLoad callback", () => { | ||
const loadCallback = sinon.spy(); | ||
const wrapper = mount(<AceEditor onLoad={loadCallback}/>, mountOptions); | ||
const wrapper = mount(<AceEditor onLoad={loadCallback} />, mountOptions); | ||
@@ -77,8 +85,11 @@ // Get the editor | ||
it('should set the editor props to the Ace element', () => { | ||
it("should set the editor props to the Ace element", () => { | ||
const editorProperties = { | ||
react: 'setFromReact', | ||
test: 'setFromTest', | ||
react: "setFromReact", | ||
test: "setFromTest" | ||
}; | ||
const wrapper = mount(<AceEditor editorProps={editorProperties}/>, mountOptions); | ||
const wrapper = mount( | ||
<AceEditor editorProps={editorProperties} />, | ||
mountOptions | ||
); | ||
@@ -91,44 +102,54 @@ const editor = wrapper.instance().editor; | ||
it('should set the command for the Ace element', () => { | ||
it("should set the command for the Ace element", () => { | ||
const commandsMock = [ | ||
{ | ||
name: 'myReactAceTest', | ||
bindKey: {win: 'Ctrl-M', mac: 'Command-M'}, | ||
exec: () => { | ||
}, | ||
name: "myReactAceTest", | ||
bindKey: { win: "Ctrl-M", mac: "Command-M" }, | ||
exec: () => {}, | ||
readOnly: true | ||
}, | ||
{ | ||
name: 'myTestCommand', | ||
bindKey: {win: 'Ctrl-W', mac: 'Command-W'}, | ||
exec: () => { | ||
}, | ||
name: "myTestCommand", | ||
bindKey: { win: "Ctrl-W", mac: "Command-W" }, | ||
exec: () => {}, | ||
readOnly: true | ||
} | ||
]; | ||
const wrapper = mount(<AceEditor commands={commandsMock}/>, mountOptions); | ||
const wrapper = mount( | ||
<AceEditor commands={commandsMock} />, | ||
mountOptions | ||
); | ||
const editor = wrapper.instance().editor; | ||
expect(editor.commands.commands.myReactAceTest).to.deep.equal(commandsMock[0]); | ||
expect(editor.commands.commands.myTestCommand).to.deep.equal(commandsMock[1]); | ||
expect(editor.commands.commands.myReactAceTest).to.deep.equal( | ||
commandsMock[0] | ||
); | ||
expect(editor.commands.commands.myTestCommand).to.deep.equal( | ||
commandsMock[1] | ||
); | ||
}); | ||
it('should change the command binding for the Ace element', () => { | ||
it("should change the command binding for the Ace element", () => { | ||
const commandsMock = [ | ||
{ | ||
bindKey: {win: 'ctrl-d', mac: 'command-d'}, | ||
name: 'selectMoreAfter', | ||
exec: 'selectMoreAfter' | ||
bindKey: { win: "ctrl-d", mac: "command-d" }, | ||
name: "selectMoreAfter", | ||
exec: "selectMoreAfter" | ||
} | ||
]; | ||
const wrapper = mount(<AceEditor commands={commandsMock}/>, mountOptions); | ||
const wrapper = mount( | ||
<AceEditor commands={commandsMock} />, | ||
mountOptions | ||
); | ||
const editor = wrapper.instance().editor; | ||
const expected = [editor.commands.commands.removeline, 'selectMoreAfter'] | ||
expect(editor.commands.commandKeyBinding['ctrl-d']).to.deep.equal(expected); | ||
const expected = [editor.commands.commands.removeline, "selectMoreAfter"]; | ||
expect(editor.commands.commandKeyBinding["ctrl-d"]).to.deep.equal( | ||
expected | ||
); | ||
}); | ||
it('should trigger the focus on mount', () => { | ||
it("should trigger the focus on mount", () => { | ||
const onFocusCallback = sinon.spy(); | ||
mount(<AceEditor focus={true} onFocus={onFocusCallback}/>, mountOptions); | ||
mount(<AceEditor focus={true} onFocus={onFocusCallback} />, mountOptions); | ||
@@ -139,65 +160,100 @@ // Read the focus | ||
it('should set up the markers', () => { | ||
const markers = [{ | ||
startRow: 3, | ||
type: 'text', | ||
className: 'test-marker' | ||
}]; | ||
const wrapper = mount(<AceEditor markers={markers}/>, mountOptions); | ||
it("should set up the placeholder text with no value set", () => { | ||
const placeholder = "Placeholder Text Here"; | ||
const wrapper = mount( | ||
<AceEditor placeholder={placeholder} />, | ||
mountOptions | ||
); | ||
// Read the markers | ||
const editor = wrapper.instance().editor; | ||
expect(editor.getSession().getMarkers()['3'].clazz).to.equal('test-marker'); | ||
expect(editor.getSession().getMarkers()['3'].type).to.equal('text'); | ||
expect(editor.renderer.placeholderNode).to.exist; | ||
expect(editor.renderer.placeholderNode.textContent).to.equal(placeholder); | ||
}); | ||
it('should update the markers', () => { | ||
it("should not set up the placeholder text with value set", () => { | ||
const placeholder = "Placeholder Text Here"; | ||
const wrapper = mount( | ||
<AceEditor placeholder={placeholder} value="Code here" />, | ||
mountOptions | ||
); | ||
// Read the markers | ||
const editor = wrapper.instance().editor; | ||
expect(editor.renderer.placeholderNode).to.not.exist; | ||
}); | ||
it("should set up the markers", () => { | ||
const markers = [ | ||
{ | ||
startRow: 3, | ||
type: "text", | ||
className: "test-marker" | ||
} | ||
]; | ||
const wrapper = mount(<AceEditor markers={markers} />, mountOptions); | ||
// Read the markers | ||
const editor = wrapper.instance().editor; | ||
expect(editor.getSession().getMarkers()["3"].clazz).to.equal( | ||
"test-marker" | ||
); | ||
expect(editor.getSession().getMarkers()["3"].type).to.equal("text"); | ||
}); | ||
it("should update the markers", () => { | ||
const oldMarkers = [ | ||
{ | ||
startRow: 4, | ||
type: 'text', | ||
className: 'test-marker-old' | ||
type: "text", | ||
className: "test-marker-old" | ||
}, | ||
{ | ||
startRow: 7, | ||
type: 'foo', | ||
className: 'test-marker-old', | ||
type: "foo", | ||
className: "test-marker-old", | ||
inFront: true | ||
} | ||
]; | ||
const markers = [{ | ||
startRow: 3, | ||
type: 'text', | ||
className: 'test-marker-new', | ||
inFront: true, | ||
},{ | ||
startRow: 5, | ||
type: 'text', | ||
className: 'test-marker-new' | ||
}]; | ||
const wrapper = mount(<AceEditor markers={oldMarkers}/>, mountOptions); | ||
const markers = [ | ||
{ | ||
startRow: 3, | ||
type: "text", | ||
className: "test-marker-new", | ||
inFront: true | ||
}, | ||
{ | ||
startRow: 5, | ||
type: "text", | ||
className: "test-marker-new" | ||
} | ||
]; | ||
const wrapper = mount(<AceEditor markers={oldMarkers} />, mountOptions); | ||
// Read the markers | ||
const editor = wrapper.instance().editor; | ||
expect(editor.getSession().getMarkers()['3'].clazz).to.equal('test-marker-old'); | ||
expect(editor.getSession().getMarkers()['3'].type).to.equal('text'); | ||
wrapper.setProps({markers}); | ||
expect(editor.getSession().getMarkers()["3"].clazz).to.equal( | ||
"test-marker-old" | ||
); | ||
expect(editor.getSession().getMarkers()["3"].type).to.equal("text"); | ||
wrapper.setProps({ markers }); | ||
const editorB = wrapper.instance().editor; | ||
expect(editorB.getSession().getMarkers()['6'].clazz).to.equal('test-marker-new'); | ||
expect(editorB.getSession().getMarkers()['6'].type).to.equal('text'); | ||
expect(editorB.getSession().getMarkers()["6"].clazz).to.equal( | ||
"test-marker-new" | ||
); | ||
expect(editorB.getSession().getMarkers()["6"].type).to.equal("text"); | ||
}); | ||
it('should clear the markers', () => { | ||
it("should clear the markers", () => { | ||
const oldMarkers = [ | ||
{ | ||
startRow: 4, | ||
type: 'text', | ||
className: 'test-marker-old' | ||
type: "text", | ||
className: "test-marker-old" | ||
}, | ||
{ | ||
startRow: 7, | ||
type: 'foo', | ||
className: 'test-marker-old', | ||
type: "foo", | ||
className: "test-marker-old", | ||
inFront: true | ||
@@ -207,32 +263,73 @@ } | ||
const markers = []; | ||
const wrapper = mount(<AceEditor markers={oldMarkers}/>, mountOptions); | ||
const wrapper = mount(<AceEditor markers={oldMarkers} />, mountOptions); | ||
// Read the markers | ||
const editor = wrapper.instance().editor; | ||
expect(editor.getSession().getMarkers()['3'].clazz).to.equal('test-marker-old'); | ||
expect(editor.getSession().getMarkers()['3'].type).to.equal('text'); | ||
wrapper.setProps({markers}); | ||
expect(Object.keys(editor.getSession().getMarkers())).to.deep.equal([ | ||
"1", | ||
"2", | ||
"3" | ||
]); | ||
expect(editor.getSession().getMarkers()["3"].clazz).to.equal( | ||
"test-marker-old" | ||
); | ||
expect(editor.getSession().getMarkers()["3"].type).to.equal("text"); | ||
wrapper.setProps({ markers }); | ||
const editorB = wrapper.instance().editor; | ||
expect(editorB.getSession().getMarkers()).to.deep.equal({}) | ||
expect(Object.keys(editorB.getSession().getMarkers())).to.deep.equal([ | ||
"1", | ||
"2" | ||
]); | ||
}); | ||
it('should add annotations and clear them', () => { | ||
const annotations = [{ | ||
row: 3, // must be 0 based | ||
column: 4, // must be 0 based | ||
text: 'error.message', // text to show in tooltip | ||
type: 'error' | ||
}] | ||
const wrapper = mount(<AceEditor/>, mountOptions); | ||
it("should not remove active line and selected word highlight when clearing markers", () => { | ||
const newMarkers = [ | ||
{ | ||
startRow: 4, | ||
type: "text", | ||
className: "test-marker" | ||
} | ||
]; | ||
const wrapper = mount( | ||
<AceEditor highlightActiveLine markers={[]} />, | ||
mountOptions | ||
); | ||
const editor = wrapper.instance().editor; | ||
wrapper.setProps({annotations}); | ||
const bgMarkers = editor.getSession().getMarkers(false); | ||
expect(Object.keys(bgMarkers)).to.deep.equal(["1", "2"]); | ||
expect(bgMarkers["1"]).to.have.property("clazz", "ace_active-line"); | ||
expect(bgMarkers["2"]).to.have.property("clazz", "ace_selected-word"); | ||
wrapper.setProps({ markers: newMarkers }); | ||
const bgMarkersNew = editor.getSession().getMarkers(false); | ||
expect(Object.keys(bgMarkersNew)).to.deep.equal(["1", "2", "3"]); | ||
expect(bgMarkersNew["1"]).to.have.property("clazz", "ace_active-line"); | ||
expect(bgMarkersNew["2"]).to.have.property("clazz", "ace_selected-word"); | ||
expect(bgMarkersNew["3"]).to.have.property("clazz", "test-marker"); | ||
}); | ||
it("should add annotations and clear them", () => { | ||
const annotations = [ | ||
{ | ||
row: 3, // must be 0 based | ||
column: 4, // must be 0 based | ||
text: "error.message", // text to show in tooltip | ||
type: "error" | ||
} | ||
]; | ||
const wrapper = mount(<AceEditor />, mountOptions); | ||
const editor = wrapper.instance().editor; | ||
wrapper.setProps({ annotations }); | ||
expect(editor.getSession().getAnnotations()).to.deep.equal(annotations); | ||
wrapper.setProps({annotations: null}); | ||
wrapper.setProps({ annotations: null }); | ||
expect(editor.getSession().getAnnotations()).to.deep.equal([]); | ||
}) | ||
}); | ||
it('should add annotations with changing editor value', () => { | ||
it("should add annotations with changing editor value", () => { | ||
// See https://github.com/securingsincity/react-ace/issues/300 | ||
const annotations = [{ row: 0, column: 0, text: 'error.message', type: 'error' }]; | ||
const annotations = [ | ||
{ row: 0, column: 0, text: "error.message", type: "error" } | ||
]; | ||
const initialText = `Initial | ||
@@ -242,3 +339,6 @@ text`; | ||
text`; | ||
const wrapper = mount(<AceEditor annotations={[]} value={initialText}/>, mountOptions); | ||
const wrapper = mount( | ||
<AceEditor annotations={[]} value={initialText} />, | ||
mountOptions | ||
); | ||
const editor = wrapper.instance().editor; | ||
@@ -250,6 +350,8 @@ wrapper.setProps({ | ||
expect(editor.renderer.$gutterLayer.$annotations).to.have.length(1); | ||
expect(editor.renderer.$gutterLayer.$annotations[0]).to.have.property('className'); | ||
}) | ||
expect(editor.renderer.$gutterLayer.$annotations[0]).to.have.property( | ||
"className" | ||
); | ||
}); | ||
it('should set editor to null on componentWillUnmount', () => { | ||
it("should set editor to null on componentWillUnmount", () => { | ||
const wrapper = mount(<AceEditor />, mountOptions); | ||
@@ -262,14 +364,11 @@ expect(wrapper.getElement().editor).to.not.equal(null); | ||
}); | ||
}); | ||
//inspired from https://github.com/goodtimeaj/debounce-function/blob/master/test/unit/debounce-function.js | ||
describe('Debounce function', () => { | ||
it('function arg should be called when after timeout', (done) => { | ||
const wrapper = mount(<AceEditor/>, mountOptions); | ||
describe("Debounce function", () => { | ||
it("function arg should be called when after timeout", done => { | ||
const wrapper = mount(<AceEditor />, mountOptions); | ||
var flag = false; | ||
var func = wrapper.instance().debounce(function() { | ||
flag = true | ||
flag = true; | ||
}, 100); | ||
@@ -284,8 +383,8 @@ func(); | ||
it('timer should be reset on successive call', (done) => { | ||
const wrapper = mount(<AceEditor/>, mountOptions); | ||
it("timer should be reset on successive call", done => { | ||
const wrapper = mount(<AceEditor />, mountOptions); | ||
var flag = false; | ||
var func = wrapper.instance().debounce(function() { | ||
flag = true | ||
flag = true; | ||
}, 100); | ||
@@ -307,4 +406,4 @@ func(); | ||
it('function should be called only once per period', (done) => { | ||
const wrapper = mount(<AceEditor/>, mountOptions); | ||
it("function should be called only once per period", done => { | ||
const wrapper = mount(<AceEditor />, mountOptions); | ||
@@ -317,3 +416,3 @@ var flag1 = false; | ||
} | ||
flag1 = true | ||
flag1 = true; | ||
}, 100); | ||
@@ -340,18 +439,23 @@ | ||
}); | ||
it('should keep initial value after undo event', () => { | ||
it("should keep initial value after undo event", () => { | ||
const onInput = () => { | ||
const editor = wrapper.instance().editor; | ||
editor.undo(); | ||
expect(editor.getValue()).to.equal('foobar'); | ||
expect(editor.getValue()).to.equal("foobar"); | ||
}; | ||
const wrapper = mount(<AceEditor value="foobar" onInput={onInput} />, mountOptions); | ||
const wrapper = mount( | ||
<AceEditor value="foobar" onInput={onInput} />, | ||
mountOptions | ||
); | ||
}); | ||
}); | ||
describe('Events', () => { | ||
it('should call the onChange method callback', () => { | ||
describe("Events", () => { | ||
it("should call the onChange method callback", () => { | ||
const onChangeCallback = sinon.spy(); | ||
const wrapper = mount(<AceEditor onChange={onChangeCallback}/>, mountOptions); | ||
const wrapper = mount( | ||
<AceEditor onChange={onChangeCallback} />, | ||
mountOptions | ||
); | ||
@@ -362,3 +466,3 @@ // Check is not previously called | ||
// Trigger the change event | ||
const expectText = 'React Ace Test'; | ||
const expectText = "React Ace Test"; | ||
wrapper.instance().editor.setValue(expectText, 1); | ||
@@ -368,9 +472,12 @@ | ||
expect(onChangeCallback.getCall(0).args[0]).to.equal(expectText); | ||
expect(onChangeCallback.getCall(0).args[1].action).to.eq('insert') | ||
expect(onChangeCallback.getCall(0).args[1].action).to.eq("insert"); | ||
}); | ||
it('should limit call to onChange (debounce)', (done) => { | ||
it("should limit call to onChange (debounce)", done => { | ||
const period = 100; | ||
const onChangeCallback = sinon.spy(); | ||
const wrapper = mount(<AceEditor onChange={onChangeCallback} debounceChangePeriod={period}/>, mountOptions); | ||
const wrapper = mount( | ||
<AceEditor onChange={onChangeCallback} debounceChangePeriod={period} />, | ||
mountOptions | ||
); | ||
@@ -381,4 +488,4 @@ // Check is not previously called | ||
// Trigger the change event | ||
const expectText = 'React Ace Test'; | ||
const expectText2 = 'React Ace Test2'; | ||
const expectText = "React Ace Test"; | ||
const expectText2 = "React Ace Test2"; | ||
wrapper.instance().editor.setValue(expectText, 1); | ||
@@ -389,6 +496,6 @@ wrapper.instance().editor.setValue(expectText2, 1); | ||
setTimeout(function(){ | ||
setTimeout(function() { | ||
expect(onChangeCallback.callCount).to.equal(1); | ||
expect(onChangeCallback.getCall(0).args[0]).to.equal(expectText2); | ||
expect(onChangeCallback.getCall(0).args[1].action).to.eq('insert'); | ||
expect(onChangeCallback.getCall(0).args[1].action).to.eq("insert"); | ||
onChangeCallback.resetHistory(); | ||
@@ -398,14 +505,17 @@ wrapper.instance().editor.setValue(expectText2, 1); | ||
expect(onChangeCallback.callCount).to.equal(0); | ||
setTimeout(function(){ | ||
setTimeout(function() { | ||
expect(onChangeCallback.callCount).to.equal(1); | ||
expect(onChangeCallback.getCall(0).args[0]).to.equal(expectText); | ||
expect(onChangeCallback.getCall(0).args[1].action).to.eq('insert'); | ||
expect(onChangeCallback.getCall(0).args[1].action).to.eq("insert"); | ||
done(); | ||
},100); | ||
},100); | ||
}, 100); | ||
}, 100); | ||
}); | ||
it('should call the onCopy method', () => { | ||
it("should call the onCopy method", () => { | ||
const onCopyCallback = sinon.spy(); | ||
const wrapper = mount(<AceEditor onCopy={onCopyCallback}/>, mountOptions); | ||
const wrapper = mount( | ||
<AceEditor onCopy={onCopyCallback} />, | ||
mountOptions | ||
); | ||
@@ -416,3 +526,3 @@ // Check is not previously called | ||
// Trigger the copy event | ||
const expectText = 'React Ace Test'; | ||
const expectText = "React Ace Test"; | ||
wrapper.instance().onCopy(expectText); | ||
@@ -424,5 +534,8 @@ | ||
it('should call the onPaste method', () => { | ||
it("should call the onPaste method", () => { | ||
const onPasteCallback = sinon.spy(); | ||
const wrapper = mount(<AceEditor onPaste={onPasteCallback}/>, mountOptions); | ||
const wrapper = mount( | ||
<AceEditor onPaste={onPasteCallback} />, | ||
mountOptions | ||
); | ||
@@ -433,3 +546,3 @@ // Check is not previously called | ||
// Trigger the Paste event | ||
const expectText = 'React Ace Test'; | ||
const expectText = "React Ace Test"; | ||
wrapper.instance().onPaste(expectText); | ||
@@ -441,5 +554,8 @@ | ||
it('should call the onFocus method callback', () => { | ||
it("should call the onFocus method callback", () => { | ||
const onFocusCallback = sinon.spy(); | ||
const wrapper = mount(<AceEditor onFocus={onFocusCallback}/>, mountOptions); | ||
const wrapper = mount( | ||
<AceEditor onFocus={onFocusCallback} />, | ||
mountOptions | ||
); | ||
@@ -453,7 +569,7 @@ // Check is not previously called | ||
expect(onFocusCallback.callCount).to.equal(1); | ||
expect(onFocusCallback.args.length).to.equal(1) | ||
expect(onFocusCallback.args.length).to.equal(1); | ||
}); | ||
it('should call the onSelectionChange method callback', (done) => { | ||
let onSelectionChange = function(){} | ||
it("should call the onSelectionChange method callback", done => { | ||
let onSelectionChange = function() {}; | ||
const value = ` | ||
@@ -468,13 +584,18 @@ function main(value) { | ||
onSelectionChange = function(selection) { | ||
const content = wrapper.instance().editor.session.getTextRange(selection.getRange()); | ||
expect(content).to.equal(value) | ||
done() | ||
} | ||
wrapper.setProps({onSelectionChange}) | ||
wrapper.instance().editor.getSession().selection.selectAll() | ||
const content = wrapper | ||
.instance() | ||
.editor.session.getTextRange(selection.getRange()); | ||
expect(content).to.equal(value); | ||
done(); | ||
}; | ||
wrapper.setProps({ onSelectionChange }); | ||
wrapper | ||
.instance() | ||
.editor.getSession() | ||
.selection.selectAll(); | ||
}); | ||
it('should call the onCursorChange method callback', (done) => { | ||
let onCursorChange = function(){} | ||
const value =` | ||
it("should call the onCursorChange method callback", done => { | ||
let onCursorChange = function() {}; | ||
const value = ` | ||
function main(value) { | ||
@@ -484,17 +605,28 @@ console.log('hi james') | ||
} | ||
` | ||
`; | ||
const wrapper = mount(<AceEditor value={value} />, mountOptions); | ||
onCursorChange = function (selection) { | ||
expect(selection.getCursor()).to.deep.equal({ row: 0, column: 0 }) | ||
done() | ||
} | ||
wrapper.setProps({onCursorChange}) | ||
expect(wrapper.instance().editor.getSession().selection.getCursor()).to.deep.equal({row: 5, column: 6}) | ||
wrapper.instance().editor.getSession().selection.moveCursorTo(0, 0) | ||
onCursorChange = function(selection) { | ||
expect(selection.getCursor()).to.deep.equal({ row: 0, column: 0 }); | ||
done(); | ||
}; | ||
wrapper.setProps({ onCursorChange }); | ||
expect( | ||
wrapper | ||
.instance() | ||
.editor.getSession() | ||
.selection.getCursor() | ||
).to.deep.equal({ row: 5, column: 6 }); | ||
wrapper | ||
.instance() | ||
.editor.getSession() | ||
.selection.moveCursorTo(0, 0); | ||
}); | ||
it('should call the onBlur method callback', () => { | ||
it("should call the onBlur method callback", () => { | ||
const onBlurCallback = sinon.spy(); | ||
const wrapper = mount(<AceEditor onBlur={onBlurCallback}/>, mountOptions); | ||
const wrapper = mount( | ||
<AceEditor onBlur={onBlurCallback} />, | ||
mountOptions | ||
); | ||
@@ -508,6 +640,6 @@ // Check is not previously called | ||
expect(onBlurCallback.callCount).to.equal(1); | ||
expect(onBlurCallback.args.length).to.equal(1) | ||
expect(onBlurCallback.args.length).to.equal(1); | ||
}); | ||
it('should not trigger a component error to call the events without setting the props', () => { | ||
it("should not trigger a component error to call the events without setting the props", () => { | ||
const wrapper = mount(<AceEditor />, mountOptions); | ||
@@ -517,21 +649,19 @@ | ||
wrapper.instance().onChange(); | ||
wrapper.instance().onCopy('copy'); | ||
wrapper.instance().onPaste('paste'); | ||
wrapper.instance().onCopy("copy"); | ||
wrapper.instance().onPaste("paste"); | ||
wrapper.instance().onFocus(); | ||
wrapper.instance().onBlur(); | ||
}); | ||
}); | ||
describe('ComponentDidUpdate', () => { | ||
it('should update the editorOptions on componentDidUpdate', () => { | ||
describe("ComponentDidUpdate", () => { | ||
it("should update the editorOptions on componentDidUpdate", () => { | ||
const options = { | ||
printMargin: 80 | ||
}; | ||
const wrapper = mount(<AceEditor setOptions={options}/>, mountOptions); | ||
const wrapper = mount(<AceEditor setOptions={options} />, mountOptions); | ||
// Read set value | ||
const editor = wrapper.instance().editor; | ||
expect(editor.getOption('printMargin')).to.equal(options.printMargin); | ||
expect(editor.getOption("printMargin")).to.equal(options.printMargin); | ||
@@ -541,11 +671,12 @@ // Now trigger the componentDidUpdate | ||
printMargin: 200, | ||
animatedScroll: true, | ||
animatedScroll: true | ||
}; | ||
wrapper.setProps({setOptions: newOptions}); | ||
expect(editor.getOption('printMargin')).to.equal(newOptions.printMargin); | ||
expect(editor.getOption('animatedScroll')).to.equal(newOptions.animatedScroll); | ||
wrapper.setProps({ setOptions: newOptions }); | ||
expect(editor.getOption("printMargin")).to.equal(newOptions.printMargin); | ||
expect(editor.getOption("animatedScroll")).to.equal( | ||
newOptions.animatedScroll | ||
); | ||
}); | ||
it('should update the editorOptions on componentDidUpdate', () => { | ||
it("should update the editorOptions on componentDidUpdate", () => { | ||
const wrapper = mount(<AceEditor minLines={1} />, mountOptions); | ||
@@ -555,28 +686,21 @@ | ||
const editor = wrapper.instance().editor; | ||
expect(editor.getOption('minLines')).to.equal(1); | ||
expect(editor.getOption("minLines")).to.equal(1); | ||
wrapper.setProps({minLines: 2}); | ||
expect(editor.getOption('minLines')).to.equal(2); | ||
wrapper.setProps({ minLines: 2 }); | ||
expect(editor.getOption("minLines")).to.equal(2); | ||
}); | ||
it('should update the mode on componentDidUpdate', () => { | ||
it("should update the mode on componentDidUpdate", () => { | ||
const wrapper = mount(<AceEditor mode="javascript" />, mountOptions); | ||
// Read set value | ||
const oldMode = wrapper.first('AceEditor').props() | ||
const oldMode = wrapper.first("AceEditor").props(); | ||
wrapper.setProps({mode: 'elixir'}); | ||
const newMode = wrapper.first('AceEditor').props() | ||
wrapper.setProps({ mode: "elixir" }); | ||
const newMode = wrapper.first("AceEditor").props(); | ||
expect(oldMode).to.not.deep.equal(newMode); | ||
}); | ||
it('should update many props on componentDidUpdate', () => { | ||
const wrapper = mount(( | ||
it("should update many props on componentDidUpdate", () => { | ||
const wrapper = mount( | ||
<AceEditor | ||
@@ -591,10 +715,12 @@ theme="github" | ||
width="200px" | ||
/>), mountOptions); | ||
/>, | ||
mountOptions | ||
); | ||
// Read set value | ||
const oldMode = wrapper.first('AceEditor').props() | ||
const oldMode = wrapper.first("AceEditor").props(); | ||
wrapper.setProps({ | ||
theme: 'solarized', | ||
keyboardHandler: 'emacs', | ||
theme: "solarized", | ||
keyboardHandler: "emacs", | ||
fontSize: 18, | ||
@@ -604,31 +730,28 @@ wrapEnabled: false, | ||
showGutter: true, | ||
height: '120px', | ||
width: '220px' | ||
height: "120px", | ||
width: "220px" | ||
}); | ||
const newMode = wrapper.first('AceEditor').props() | ||
const newMode = wrapper.first("AceEditor").props(); | ||
expect(oldMode).to.not.deep.equal(newMode); | ||
}); | ||
it("should update the className on componentDidUpdate", () => { | ||
const className = "old-class"; | ||
const wrapper = mount(<AceEditor className={className} />, mountOptions); | ||
it('should update the className on componentDidUpdate', () => { | ||
const className = 'old-class'; | ||
const wrapper = mount(<AceEditor className={className}/>, mountOptions); | ||
// Read set value | ||
let editor = wrapper.instance().refEditor; | ||
expect(editor.className).to.equal(' ace_editor ace-tm old-class'); | ||
expect(editor.className).to.equal(" ace_editor ace-tm old-class"); | ||
// Now trigger the componentDidUpdate | ||
const newClassName = 'new-class'; | ||
wrapper.setProps({className: newClassName}); | ||
const newClassName = "new-class"; | ||
wrapper.setProps({ className: newClassName }); | ||
editor = wrapper.instance().refEditor; | ||
expect(editor.className).to.equal(' new-class ace_editor ace-tm'); | ||
expect(editor.className).to.equal(" new-class ace_editor ace-tm"); | ||
}); | ||
it("should update the value on componentDidUpdate", () => { | ||
const startValue = "start value"; | ||
const wrapper = mount(<AceEditor value={startValue} />, mountOptions); | ||
it('should update the value on componentDidUpdate', () => { | ||
const startValue = 'start value'; | ||
const wrapper = mount(<AceEditor value={startValue}/>, mountOptions); | ||
// Read set value | ||
@@ -639,4 +762,4 @@ let editor = wrapper.instance().editor; | ||
// Now trigger the componentDidUpdate | ||
const newValue = 'updated value'; | ||
wrapper.setProps({value: newValue}); | ||
const newValue = "updated value"; | ||
wrapper.setProps({ value: newValue }); | ||
editor = wrapper.instance().editor; | ||
@@ -646,5 +769,8 @@ expect(editor.getValue()).to.equal(newValue); | ||
it('should trigger the focus on componentDidUpdate', () => { | ||
it("should trigger the focus on componentDidUpdate", () => { | ||
const onFocusCallback = sinon.spy(); | ||
const wrapper = mount(<AceEditor onFocus={onFocusCallback}/>, mountOptions); | ||
const wrapper = mount( | ||
<AceEditor onFocus={onFocusCallback} />, | ||
mountOptions | ||
); | ||
@@ -655,9 +781,6 @@ // Read the focus | ||
// Now trigger the componentDidUpdate | ||
wrapper.setProps({focus: true}); | ||
wrapper.setProps({ focus: true }); | ||
expect(onFocusCallback.callCount).to.equal(1); | ||
}); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
2135427
65
9591