UNPKG

feeles-ide

Version:

The hackable and serializable IDE to make learning material

539 lines (444 loc) 18 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator")); var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator")); var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn")); var _getPrototypeOf3 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf")); var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits")); var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _react = _interopRequireWildcard(require("react")); var _propTypes = _interopRequireDefault(require("prop-types")); var _typestyle = require("typestyle"); var _LinearProgress = _interopRequireDefault(require("@material-ui/core/LinearProgress")); var _jsBeautify = _interopRequireDefault(require("js-beautify")); var _codemirror = require("codemirror"); var _LineWidget = _interopRequireDefault(require("./LineWidget")); var _Editor = _interopRequireDefault(require("./Editor")); var _MenuBar = _interopRequireDefault(require("./MenuBar")); var _AssetPane = _interopRequireDefault(require("./AssetPane")); var _ErrorPane = _interopRequireDefault(require("./ErrorPane")); var _foldAsset = _interopRequireDefault(require("./foldAsset")); var _core = require("@material-ui/core"); var _preserveTrailingSpaceBeautify = _interopRequireDefault(require("../../utils/preserveTrailingSpaceBeautify")); var _dec, _class, _class2, _temp; var cn = { root: (0, _typestyle.style)({ position: 'absolute', width: '100%', height: '100%', display: 'flex', flexDirection: 'column', alignItems: 'stretch' }), editorContainer: (0, _typestyle.style)({ flex: '1 1 auto', position: 'relative' }), barButton: (0, _typestyle.style)({ padding: 0, lineHeight: 2 }), barButtonLabel: (0, _typestyle.style)({ fontSize: '.5rem' }), progress: (0, _typestyle.style)({ borderRadius: 0 }), blank: (0, _typestyle.style)({ flex: '1 1 auto' }) }; var SourceEditor = (_dec = (0, _core.withTheme)(), _dec(_class = (_temp = _class2 = /*#__PURE__*/ function (_PureComponent) { (0, _inherits2.default)(SourceEditor, _PureComponent); function SourceEditor() { var _getPrototypeOf2; var _this; (0, _classCallCheck2.default)(this, SourceEditor); for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = (0, _possibleConstructorReturn2.default)(this, (_getPrototypeOf2 = (0, _getPrototypeOf3.default)(SourceEditor)).call.apply(_getPrototypeOf2, [this].concat(args))); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "state", { file: null, babelError: null, showHint: false, hasHistory: false, hasChanged: false, loading: false, snippets: [], showLineWidget: true }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "handleCodemirror", function (codemirror) { _this.codemirror = codemirror; // アセットの入力で全角文字を使うので, この仕様は消している // this.codemirror.on('beforeChange', zenkakuToHankaku); var onChange = function onChange(cm) { _this.setState({ hasHistory: cm.historySize().undo > 0, hasChanged: cm.getValue('\n') !== _this.state.file.text }); }; _this.codemirror.on('change', onChange); _this.codemirror.on('swapDoc', onChange); _this.codemirror.on('swapDoc', _this.foldAll); _this.foldAll(codemirror); _this.forceUpdate(); }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "foldAll", function (cm) { var opt = { rangeFinder: _foldAsset.default }; for (var line = cm.lineCount() - 1; line >= 0; line--) { cm.foldCode(new _codemirror.Pos(line, 0), opt, 'fold'); } }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "runApp", /*#__PURE__*/ function () { var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/ _regenerator.default.mark(function _callee(href) { var file, text, nextFile; return _regenerator.default.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: file = _this.state.file; if (!(!_this.codemirror || !file)) { _context.next = 3; break; } return _context.abrupt("return"); case 3: _this.beautify(_this.codemirror); // Auto beautify text = _this.codemirror.getValue(); _this.setState({ loading: true, babelError: null }); // Like a watching _context.prev = 6; nextFile = file.set({ text: text }); _context.next = 10; return nextFile.babel(); case 10: _context.next = 12; return _this.props.putFile(file, nextFile); case 12: // 再読み込み _this.props.setLocation(href); _context.next = 20; break; case 15: _context.prev = 15; _context.t0 = _context["catch"](6); _this.props.globalEvent.emit('message.editor', { data: { value: file.name } }); // もう一度ファイルを開かせる _this.setState({ babelError: _context.t0 }); console.info(_context.t0); case 20: _this.setState({ loading: false }); case 21: case "end": return _context.stop(); } } }, _callee, this, [[6, 15]]); })); return function (_x) { return _ref.apply(this, arguments); }; }()); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "handleUndo", function () { _this.codemirror.undo(); }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "handleRestore", function () { var file = _this.state.file; var cm = _this.codemirror; if (!file || !cm) return; var _cm$getScrollInfo = cm.getScrollInfo(), left = _cm$getScrollInfo.left, top = _cm$getScrollInfo.top; _this.codemirror.scrollTo(left, top); // 変更を加える前の状態(前回保存したところ)に戻す while (cm.historySize().undo > 0) { cm.undo(); // ひとつ前に戻す if (cm.getValue() === file.text) { // 前回の保存内容と同じになった break; } } if (cm.getValue() !== file.text) { // 履歴を遡っても同じにはならなかった(履歴が混在している) cm.clearHistory(); cm.setValue(file.text); } _this.codemirror.scrollTo(left, top); _this.runApp(); }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "beautify", function () { var fileView = _this.props.fileView; var file = _this.state.file; if (!file) return; var prevValue = _this.codemirror.getValue(); var setValueWithoutHistory = function setValueWithoutHistory(replacement) { // undo => beautify => setValue することで history を 1 つに var _this$codemirror$getS = _this.codemirror.getScrollInfo(), left = _this$codemirror$getS.left, top = _this$codemirror$getS.top; _this.codemirror.undo(); _this.codemirror.setValue(replacement); _this.codemirror.scrollTo(left, top); }; // import .jsbeautifyrc var configs = {}; try { var runCommand = fileView.getFileByFullPath('.jsbeautifyrc'); if (runCommand) { configs = JSON.parse(runCommand.text); } } catch (error) { console.info(error); } if (file.is('javascript') || file.is('json')) { setValueWithoutHistory((0, _preserveTrailingSpaceBeautify.default)(prevValue, configs.js || {})); } else if (file.is('html')) { setValueWithoutHistory(_jsBeautify.default.html(prevValue, configs.html || {})); } else if (file.is('css')) { setValueWithoutHistory(_jsBeautify.default.css(prevValue, configs.css || {})); } }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "setShowLineWidget", function (showLineWidget) { _this.setState({ showLineWidget: showLineWidget }); }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "saveFileIfNeeded", /*#__PURE__*/ (0, _asyncToGenerator2.default)( /*#__PURE__*/ _regenerator.default.mark(function _callee2() { var cm, file, text, nextFile; return _regenerator.default.wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: cm = _this.codemirror; file = _this.state.file; if (!(!cm || !file)) { _context2.next = 4; break; } return _context2.abrupt("return"); case 4: text = cm.getValue(); // 現在のコード if (!(file.text == text)) { _context2.next = 7; break; } return _context2.abrupt("return"); case 7: // 変わっていない nextFile = file.set({ text: text }); _context2.next = 10; return nextFile.babel(); case 10: _context2.next = 12; return _this.props.putFile(file, nextFile); case 12: case "end": return _context2.stop(); } } }, _callee2, this); }))); return _this; } (0, _createClass2.default)(SourceEditor, [{ key: "componentDidUpdate", value: function componentDidUpdate(prevProps) { if (prevProps.fileView !== this.props.fileView && this.state.file) { this.setState({ snippets: this.props.getConfig('snippets')(this.state.file) }); } if (this.props.filePath && this.props.filePath !== prevProps.filePath) { this.handleUpdateFile(); } } }, { key: "componentDidMount", value: function componentDidMount() { if (this.props.filePath) { this.handleUpdateFile(); } } }, { key: "handleUpdateFile", value: function handleUpdateFile() { var _this$props = this.props, filePath = _this$props.filePath, findFile = _this$props.findFile; var file = findFile(filePath); if (file && file !== this.state.file) { this.setFile(file); } } }, { key: "setFile", value: function setFile(file) { if (!file) return; this.setState({ file: file, showHint: !file.is('json'), snippets: this.props.getConfig('snippets')(file) }); } }, { key: "setValue", value: function setValue(value) { var _this$codemirror$getS2 = this.codemirror.getScrollInfo(), left = _this$codemirror$getS2.left, top = _this$codemirror$getS2.top; this.codemirror.setValue(value); this.codemirror.scrollTo(left, top); } }, { key: "render", value: function render() { var _this2 = this; var localization = this.props.localization; var _this$state = this.state, file = _this$state.file, showHint = _this$state.showHint; if (!file) { return null; } // const snippets = this.props.getConfig('snippets')(file); var extraKeys = { 'Ctrl-Enter': function CtrlEnter() { // Key Binding された操作の直後にカーソルが先頭に戻ってしまう(?)ため, // それをやり過ごしてから実行する window.setTimeout(_this2.runApp, 10); }, 'Ctrl-Alt-B': function CtrlAltB() { // Key Binding された操作の直後にカーソルが先頭に戻ってしまう(?)ため, // それをやり過ごしてから実行する window.setTimeout(_this2.beautify, 10); } }; var foldOptions = { widget: ' ... ', minFoldSize: 1, scanUp: false }; if (file.is('javascript')) { foldOptions.rangeFinder = _foldAsset.default; } return _react.default.createElement("div", { className: cn.root }, _react.default.createElement(_MenuBar.default, { localization: localization, getFiles: this.props.getFiles, href: this.props.href, handleUndo: this.handleUndo, runApp: this.runApp, hasHistory: this.state.hasHistory, hasChanged: this.state.hasChanged, filePath: this.props.filePath, tabs: this.props.tabs, showLineWidget: this.state.showLineWidget, setShowLineWidget: this.setShowLineWidget, label: this.props.label, iconUrl: this.props.iconUrl, filePathToBack: this.props.filePathToBack, globalEvent: this.props.globalEvent, isExpandingEditorCard: this.props.isExpandingEditorCard, setExpandingEditorCard: this.props.setExpandingEditorCard }), this.state.loading ? _react.default.createElement(_LinearProgress.default, { color: "primary", className: cn.progress }) : null, _react.default.createElement("div", { className: cn.editorContainer }, _react.default.createElement(_Editor.default, { file: file, getFiles: this.props.getFiles, getConfig: this.props.getConfig, findFile: this.props.findFile, loadConfig: this.props.loadConfig, fileView: this.props.fileView, showHint: showHint, snippets: this.state.snippets, codemirrorRef: this.handleCodemirror, extraKeys: extraKeys, foldOptions: foldOptions })), _react.default.createElement(_ErrorPane.default, { error: this.state.babelError, localization: localization, onRestore: this.handleRestore, canRestore: this.state.hasHistory }), this.codemirror && this.props.asset && _react.default.createElement(_AssetPane.default, { label: this.props.label, codemirror: this.codemirror, files: this.props.files, findFile: this.props.findFile, putFile: this.props.putFile, runApp: this.runApp, localization: localization, globalEvent: this.props.globalEvent, asset: this.props.asset, filePath: this.props.filePath, filePathToBack: this.props.filePathToBack, isExpandingEditorCard: this.props.isExpandingEditorCard, setExpandingEditorCard: this.props.setExpandingEditorCard, saveFileIfNeeded: this.saveFileIfNeeded }), this.codemirror && _react.default.createElement(_LineWidget.default, { show: this.state.showLineWidget, codemirror: this.codemirror, runApp: this.runApp, localization: localization })); } }]); return SourceEditor; }(_react.PureComponent), (0, _defineProperty2.default)(_class2, "propTypes", { theme: _propTypes.default.object.isRequired, fileView: _propTypes.default.object.isRequired, filePath: _propTypes.default.string.isRequired, files: _propTypes.default.array.isRequired, getFiles: _propTypes.default.func.isRequired, setLocation: _propTypes.default.func.isRequired, href: _propTypes.default.string.isRequired, getConfig: _propTypes.default.func.isRequired, loadConfig: _propTypes.default.func.isRequired, findFile: _propTypes.default.func.isRequired, reboot: _propTypes.default.bool.isRequired, localization: _propTypes.default.object.isRequired, openFileDialog: _propTypes.default.func.isRequired, putFile: _propTypes.default.func.isRequired, tabs: _propTypes.default.array.isRequired, label: _propTypes.default.string.isRequired, iconUrl: _propTypes.default.string.isRequired, filePathToBack: _propTypes.default.string.isRequired, globalEvent: _propTypes.default.object.isRequired, asset: _propTypes.default.object, isExpandingEditorCard: _propTypes.default.bool.isRequired, setExpandingEditorCard: _propTypes.default.func.isRequired }), _temp)) || _class); exports.default = SourceEditor;