UNPKG

feeles-ide

Version:

The hackable and serializable IDE to make learning material

319 lines (286 loc) 10.4 kB
import _defineProperty from 'babel-runtime/helpers/defineProperty'; import _regeneratorRuntime from 'babel-runtime/regenerator'; import _asyncToGenerator from 'babel-runtime/helpers/asyncToGenerator'; import _Object$getPrototypeOf from 'babel-runtime/core-js/object/get-prototype-of'; import _classCallCheck from 'babel-runtime/helpers/classCallCheck'; import _createClass from 'babel-runtime/helpers/createClass'; import _possibleConstructorReturn from 'babel-runtime/helpers/possibleConstructorReturn'; import _inherits from 'babel-runtime/helpers/inherits'; import React, { PureComponent } from 'react'; import PropTypes from 'prop-types'; import beautify from 'js-beautify'; import RaisedButton from 'material-ui/RaisedButton'; import LinearProgress from 'material-ui/LinearProgress'; import AvStop from 'material-ui/svg-icons/av/stop'; import { red50, red500 } from 'material-ui/styles/colors'; import { SourceFile } from '../../File/'; import ShotCard from './'; import Editor from '../EditorCard/Editor'; import excessiveCare from './excessiveCare'; var getStyle = function getStyle(props, context, state) { var _context$muiTheme = context.muiTheme, palette = _context$muiTheme.palette, spacing = _context$muiTheme.spacing, transitions = _context$muiTheme.transitions; var shooting = state.shooting, height = state.height; // TODO: ちゃんと実装する. 実際には Footer の状態でかわる var maxEditorHeight = window.innerHeight - 200; var editorHeight = Math.min(height + spacing.desktopGutterMore, maxEditorHeight); return { root: { display: 'flex', flexDirection: 'column' }, editor: { position: 'relative', boxSizing: 'border-box', width: '100%', height: editorHeight, transform: 'translate(' + (shooting ? '-500px' : 0) + ')', opacity: shooting ? 0 : 1, transition: transitions.easeOut() }, menu: { position: 'relative', display: 'flex', flexDirection: 'row-reverse', justifyContent: 'space-between', alignItems: 'flex-end', height: 36 }, shoot: { marginRight: 9, marginBottom: 4, transform: '\n rotateY(' + (shooting ? 180 : 0) + 'deg)' }, label: { color: palette.secondaryTextColor, fontSize: '.8rem' }, error: { flex: '0 1 auto', margin: 0, padding: 8, backgroundColor: red50, color: red500, fontFamily: 'Consolas, "Liberation Mono", Menlo, Courier, monospace', overflow: 'scroll' }, restore: { margin: 4 } }; }; var ShotPane = function (_PureComponent) { _inherits(ShotPane, _PureComponent); function ShotPane() { var _ref, _this2 = this; var _temp, _this, _ret; _classCallCheck(this, ShotPane); for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = ShotPane.__proto__ || _Object$getPrototypeOf(ShotPane)).call.apply(_ref, [this].concat(args))), _this), _this.state = { shooting: false, height: 0, error: null, loading: false, canRestore: false, file: _this.props.file || SourceFile.shot('') }, _this.shoot = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() { return _regeneratorRuntime.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: if (!_this.state.shooting) { _context.next = 2; break; } return _context.abrupt('return'); case 2: _context.next = 4; return _this.handleShot(); case 4: _this.setState({ shooting: true }); case 5: case 'end': return _context.stop(); } } }, _callee, _this2); })), _this.handleChange = function (cm) { var canRestore = cm.getValue() !== _this.state.file.text; _this.setState({ canRestore: canRestore }); }, _this.handleRestore = function () { _this.codeMirror.setValue(_this.state.file.text); }, _this.handleViewportChange = function (cm) { var lastLine = cm.lastLine() + 1; var height = cm.heightAtLine(lastLine, 'local'); _this.setState({ height: height }); }, _temp), _possibleConstructorReturn(_this, _ret); } _createClass(ShotPane, [{ key: 'componentDidMount', value: function componentDidMount() { this.codeMirror.on('beforeChange', excessiveCare); this.codeMirror.on('change', this.handleChange); this.codeMirror.on('swapDoc', this.handleChange); this.codeMirror.on('viewportChange', this.handleViewportChange); this.codeMirror.on('swapDoc', this.handleViewportChange); this.handleViewportChange(this.codeMirror); } }, { key: 'componentWillReceiveProps', value: function componentWillReceiveProps(nextProps) { if (this.props.file !== nextProps.file) { var file = nextProps.file || SourceFile.shot(''); this.setState({ file: file }); } } }, { key: 'componentDidUpdate', value: function componentDidUpdate(prevProps, prevState) { var _this3 = this; if (!prevState.shooting && this.state.shooting) { // shooting アニメーションをもとにもどす setTimeout(function () { _this3.setState({ shooting: false }); }, 1000); } if (prevState.height !== this.state.height) { setTimeout(function () { // 表示可能領域が変わったので、トランジション後に再描画する if (_this3.codeMirror) { _this3.codeMirror.refresh(); } }, 300); } } }, { key: 'handleShot', value: function () { var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() { var text, configs, formatted, name, file, request; return _regeneratorRuntime.wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: text = this.codeMirror ? this.codeMirror.getValue('\n') : this.state.file.text; // コードのフォーマット if (this.props.loadConfig('feelesrc').formatOnSendCode || false) { // import .jsbeautifyrc configs = this.props.loadConfig('jsbeautifyrc'); formatted = beautify(text, configs.js || {}); this.codeMirror.setValue(formatted); } // コードをファイルにする name = this.state.file.name; file = SourceFile.shot(text, name); // frame に shot をおくる request = { query: 'shot', value: file.serialize() }; this.props.globalEvent.emit('postMessage', request); case 6: case 'end': return _context2.stop(); } } }, _callee2, this); })); function handleShot() { return _ref3.apply(this, arguments); } return handleShot; }() }, { key: 'render', value: function render() { var _this4 = this; var _props = this.props, localization = _props.localization, getConfig = _props.getConfig, loadConfig = _props.loadConfig; var styles = getStyle(this.props, this.context, this.state); // TODO: Enter で実行か Shift-Enter で実行か var _loadConfig = loadConfig('feelesrc'), sendCodeOnEnter = _loadConfig.sendCodeOnEnter; var shootKey = sendCodeOnEnter ? 'Enter' : 'Ctrl-Enter'; var extraKeys = _defineProperty({}, shootKey, this.shoot); return React.createElement( 'div', null, this.state.error ? React.createElement( 'pre', { style: styles.error }, this.state.error.message ) : null, this.state.loading ? React.createElement(LinearProgress, null) : null, React.createElement( 'div', { style: styles.editor }, React.createElement(Editor, { isSelected: true, isCared: true, file: this.state.file, getConfig: getConfig, codemirrorRef: function codemirrorRef(ref) { return _this4.codeMirror = ref; }, snippets: this.props.completes, extraKeys: extraKeys, lineNumbers: false, findFile: this.props.findFile, loadConfig: this.props.loadConfig, fileView: this.props.fileView }) ), React.createElement( 'div', { style: styles.menu }, React.createElement(RaisedButton, { primary: true, label: localization.shotCard.button, icon: this.state.shooting ? React.createElement(AvStop, null) : ShotCard.icon(), labelPosition: 'before', disabled: this.state.shooting, onClick: this.shoot, style: styles.shoot }), React.createElement( 'span', { style: styles.label }, localization.shotCard.shoot ), React.createElement('div', { style: { flex: 1 } }), React.createElement(RaisedButton, { secondary: true, label: localization.shotCard.restore, onClick: this.handleRestore, style: styles.restore, disabled: !this.state.canRestore }) ) ); } }]); return ShotPane; }(PureComponent); ShotPane.propTypes = { fileView: PropTypes.object.isRequired, files: PropTypes.array.isRequired, findFile: PropTypes.func.isRequired, localization: PropTypes.object.isRequired, getConfig: PropTypes.func.isRequired, loadConfig: PropTypes.func.isRequired, file: PropTypes.object, completes: PropTypes.array, globalEvent: PropTypes.object.isRequired }; ShotPane.contextTypes = { muiTheme: PropTypes.object.isRequired }; export default ShotPane;