"use strict"; var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; Object.defineProperty(exports, "__esModule", { value: true }); var ace_builds_1 = require("ace-builds"); var PropTypes = require("prop-types"); var React = require("react"); var isEqual = require("lodash.isequal"); var editorOptions_1 = require("./editorOptions"); var ace = editorOptions_1.getAceInstance(); var ReactAce = /** @class */ (function (_super) { __extends(ReactAce, _super); function ReactAce(props) { var _this = _super.call(this, props) || this; editorOptions_1.editorEvents.forEach(function (method) { _this[method] = _this[method].bind(_this); }); _this.debounce = editorOptions_1.debounce; return _this; } ReactAce.prototype.isInShadow = function (node) { var parent = node && node.parentNode; while (parent) { if (parent.toString() === "[object ShadowRoot]") { return true; } parent = parent.parentNode; } return false; }; ReactAce.prototype.componentDidMount = function () { var _this = this; var _a = this.props, className = _a.className, onBeforeLoad = _a.onBeforeLoad, onValidate = _a.onValidate, mode = _a.mode, focus = _a.focus, theme = _a.theme, fontSize = _a.fontSize, value = _a.value, defaultValue = _a.defaultValue, showGutter = _a.showGutter, wrapEnabled = _a.wrapEnabled, showPrintMargin = _a.showPrintMargin, _b = _a.scrollMargin, scrollMargin = _b === void 0 ? [0, 0, 0, 0] : _b, keyboardHandler = _a.keyboardHandler, onLoad = _a.onLoad, commands = _a.commands, annotations = _a.annotations, markers = _a.markers, placeholder = _a.placeholder; this.editor = ace.edit(this.refEditor); if (onBeforeLoad) { onBeforeLoad(ace); } var editorProps = Object.keys(this.props.editorProps); for (var i = 0; i < editorProps.length; i++) { this.editor[editorProps[i]] = this.props.editorProps[editorProps[i]]; } if (this.props.debounceChangePeriod) { this.onChange = this.debounce(this.onChange, this.props.debounceChangePeriod); } this.editor.renderer.setScrollMargin(scrollMargin[0], scrollMargin[1], scrollMargin[2], scrollMargin[3]); if (this.isInShadow(this.refEditor)) { this.editor.renderer.attachToShadowRoot(); } this.editor .getSession() .setMode(typeof mode === "string" ? "ace/mode/" + mode : mode); if (theme && theme !== "") this.editor.setTheme("ace/theme/" + theme); this.editor.setFontSize(typeof fontSize === "number" ? fontSize + "px" : fontSize); this.editor .getSession() .setValue(!defaultValue ? value || "" : defaultValue); 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); if (placeholder) { this.updatePlaceholder(); } this.editor .getSession() .selection.on("changeSelection", this.onSelectionChange); this.editor.getSession().selection.on("changeCursor", this.onCursorChange); if (onValidate) { // @ts-ignore types don't include this.editor.getSession().on("changeAnnotation", function () { // tslint:disable-next-line:no-shadowed-variable var annotations = _this.editor.getSession().getAnnotations(); _this.props.onValidate(annotations); }); } this.editor.session.on("changeScrollTop", this.onScroll); this.editor.getSession().setAnnotations(annotations || []); if (markers && markers.length > 0) { this.handleMarkers(markers); } // get a list of possible options to avoid 'misspelled option errors' var availableOptions = this.editor.$options; editorOptions_1.editorOptions.forEach(function (option) { if (availableOptions.hasOwnProperty(option)) { // @ts-ignore _this.editor.setOption(option, _this.props[option]); } 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?"); } }); this.handleOptions(this.props); if (Array.isArray(commands)) { commands.forEach(function (command) { if (typeof command.exec === "string") { _this.editor.commands.bindKey(command.bindKey, command.exec); } else { _this.editor.commands.addCommand(command); } }); } if (keyboardHandler) { this.editor.setKeyboardHandler("ace/keyboard/" + keyboardHandler); } if (className) { this.refEditor.className += " " + className; } if (onLoad) { onLoad(this.editor); } this.editor.resize(); if (focus) { this.editor.focus(); } }; ReactAce.prototype.componentDidUpdate = function (prevProps) { var oldProps = prevProps; var nextProps = this.props; for (var i = 0; i < editorOptions_1.editorOptions.length; i++) { var option = editorOptions_1.editorOptions[i]; if (nextProps[option] !== oldProps[option]) { // @ts-ignore this.editor.setOption(option, nextProps[option]); } } if (nextProps.className !== oldProps.className) { var appliedClasses = this.refEditor.className; var appliedClassesArray_1 = appliedClasses.trim().split(" "); var oldClassesArray = oldProps.className.trim().split(" "); oldClassesArray.forEach(function (oldClass) { var index = appliedClassesArray_1.indexOf(oldClass); appliedClassesArray_1.splice(index, 1); }); this.refEditor.className = " " + nextProps.className + " " + appliedClassesArray_1.join(" "); } // First process editor value, as it may create a new session (see issue #300) if (this.editor && nextProps.value != null && this.editor.getValue() !== nextProps.value) { // editor.setValue is a synchronous function call, change event is emitted before setValue return. this.silent = true; var pos = this.editor.session.selection.toJSON(); this.editor.setValue(nextProps.value, nextProps.cursorStart); this.editor.session.selection.fromJSON(pos); this.silent = false; } if (nextProps.placeholder !== oldProps.placeholder) { this.updatePlaceholder(); } if (nextProps.mode !== oldProps.mode) { this.editor .getSession() .setMode(typeof nextProps.mode === "string" ? "ace/mode/" + nextProps.mode : nextProps.mode); } if (nextProps.theme !== oldProps.theme) { this.editor.setTheme("ace/theme/" + nextProps.theme); } if (nextProps.keyboardHandler !== oldProps.keyboardHandler) { if (nextProps.keyboardHandler) { this.editor.setKeyboardHandler("ace/keyboard/" + nextProps.keyboardHandler); } else { this.editor.setKeyboardHandler(null); } } if (nextProps.fontSize !== oldProps.fontSize) { this.editor.setFontSize(typeof nextProps.fontSize === "number" ? nextProps.fontSize + "px" : nextProps.fontSize); } if (nextProps.wrapEnabled !== oldProps.wrapEnabled) { this.editor.getSession().setUseWrapMode(nextProps.wrapEnabled); } if (nextProps.showPrintMargin !== oldProps.showPrintMargin) { this.editor.setShowPrintMargin(nextProps.showPrintMargin); } if (nextProps.showGutter !== oldProps.showGutter) { this.editor.renderer.setShowGutter(nextProps.showGutter); } if (!isEqual(nextProps.setOptions, oldProps.setOptions)) { this.handleOptions(nextProps); } if (!isEqual(nextProps.annotations, oldProps.annotations)) { this.editor.getSession().setAnnotations(nextProps.annotations || []); } if (!isEqual(nextProps.markers, oldProps.markers) && Array.isArray(nextProps.markers)) { this.handleMarkers(nextProps.markers); } // this doesn't look like it works at all.... if (!isEqual(nextProps.scrollMargin, oldProps.scrollMargin)) { this.handleScrollMargins(nextProps.scrollMargin); } if (prevProps.height !== this.props.height || prevProps.width !== this.props.width) { this.editor.resize(); } if (this.props.focus && !prevProps.focus) { this.editor.focus(); } }; ReactAce.prototype.handleScrollMargins = function (margins) { if (margins === void 0) { margins = [0, 0, 0, 0]; } this.editor.renderer.setScrollMargin(margins[0], margins[1], margins[2], margins[3]); }; ReactAce.prototype.componentWillUnmount = function () { this.editor.destroy(); this.editor = null; }; ReactAce.prototype.onChange = function (event) { if (this.props.onChange && !this.silent) { var value = this.editor.getValue(); this.props.onChange(value, event); } }; ReactAce.prototype.onSelectionChange = function (event) { if (this.props.onSelectionChange) { var value = this.editor.getSelection(); this.props.onSelectionChange(value, event); } }; ReactAce.prototype.onCursorChange = function (event) { if (this.props.onCursorChange) { var value = this.editor.getSelection(); this.props.onCursorChange(value, event); } }; ReactAce.prototype.onInput = function (event) { if (this.props.onInput) { this.props.onInput(event); } if (this.props.placeholder) { this.updatePlaceholder(); } }; ReactAce.prototype.onFocus = function (event) { if (this.props.onFocus) { this.props.onFocus(event, this.editor); } }; ReactAce.prototype.onBlur = function (event) { if (this.props.onBlur) { this.props.onBlur(event, this.editor); } }; ReactAce.prototype.onCopy = function (_a) { var text = _a.text; if (this.props.onCopy) { this.props.onCopy(text); } }; ReactAce.prototype.onPaste = function (_a) { var text = _a.text; if (this.props.onPaste) { this.props.onPaste(text); } }; ReactAce.prototype.onScroll = function () { if (this.props.onScroll) { this.props.onScroll(this.editor); } }; ReactAce.prototype.handleOptions = function (props) { var setOptions = Object.keys(props.setOptions); for (var y = 0; y < setOptions.length; y++) { // @ts-ignore this.editor.setOption(setOptions[y], props.setOptions[setOptions[y]]); } }; ReactAce.prototype.handleMarkers = function (markers) { var _this = this; // remove foreground markers var currentMarkers = this.editor.getSession().getMarkers(true); for (var i in currentMarkers) { if (currentMarkers.hasOwnProperty(i)) { this.editor.getSession().removeMarker(currentMarkers[i].id); } } // remove background markers except active line marker and selected word marker currentMarkers = this.editor.getSession().getMarkers(false); for (var i in currentMarkers) { if (currentMarkers.hasOwnProperty(i) && currentMarkers[i].clazz !== "ace_active-line" && currentMarkers[i].clazz !== "ace_selected-word") { this.editor.getSession().removeMarker(currentMarkers[i].id); } } // add new markers markers.forEach(function (_a) { var startRow = _a.startRow, startCol = _a.startCol, endRow = _a.endRow, endCol = _a.endCol, className = _a.className, type = _a.type, _b = _a.inFront, inFront = _b === void 0 ? false : _b; var range = new ace_builds_1.Range(startRow, startCol, endRow, endCol); _this.editor.getSession().addMarker(range, className, type, inFront); }); }; ReactAce.prototype.updatePlaceholder = function () { // 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; } }; ReactAce.prototype.updateRef = function (item) { this.refEditor = item; }; ReactAce.prototype.render = function () { var _a = this.props, name = _a.name, width = _a.width, height = _a.height, style = _a.style; var divStyle = __assign({ width: width, height: height }, style); return React.createElement("div", { ref: this.updateRef, id: name, style: divStyle }); }; ReactAce.propTypes = { mode: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), focus: PropTypes.bool, theme: PropTypes.string, name: PropTypes.string, className: PropTypes.string, height: PropTypes.string, width: PropTypes.string, fontSize: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), showGutter: PropTypes.bool, onChange: PropTypes.func, onCopy: PropTypes.func, onPaste: PropTypes.func, onFocus: PropTypes.func, onInput: PropTypes.func, onBlur: PropTypes.func, onScroll: PropTypes.func, value: PropTypes.string, defaultValue: PropTypes.string, onLoad: PropTypes.func, onSelectionChange: PropTypes.func, onCursorChange: PropTypes.func, onBeforeLoad: PropTypes.func, onValidate: PropTypes.func, minLines: PropTypes.number, maxLines: PropTypes.number, readOnly: PropTypes.bool, highlightActiveLine: PropTypes.bool, tabSize: PropTypes.number, showPrintMargin: PropTypes.bool, cursorStart: PropTypes.number, debounceChangePeriod: PropTypes.number, editorProps: PropTypes.object, setOptions: PropTypes.object, style: PropTypes.object, scrollMargin: PropTypes.array, annotations: PropTypes.array, markers: PropTypes.array, keyboardHandler: PropTypes.string, wrapEnabled: PropTypes.bool, enableSnippets: PropTypes.bool, 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: "ace-editor", focus: false, mode: "", theme: "", height: "500px", width: "500px", fontSize: 12, enableSnippets: false, showGutter: true, onChange: null, onPaste: null, onLoad: null, onScroll: null, minLines: null, maxLines: null, readOnly: false, highlightActiveLine: true, showPrintMargin: true, tabSize: 4, cursorStart: 1, editorProps: {}, style: {}, scrollMargin: [0, 0, 0, 0], setOptions: {}, wrapEnabled: false, enableBasicAutocompletion: false, enableLiveAutocompletion: false, placeholder: null, navigateToFileEnd: true }; return ReactAce; }(React.Component)); exports.default = ReactAce; //# sourceMappingURL=ace.js.map