feeles-ide
Version:
The hackable and serializable IDE to make learning material
340 lines (283 loc) • 12.1 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
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 = _interopRequireDefault(require("react"));
var _propTypes = _interopRequireDefault(require("prop-types"));
var _reactDom = _interopRequireDefault(require("react-dom"));
var _typestyle = require("typestyle");
var _core = require("@material-ui/core");
var _Backspace = _interopRequireDefault(require("@material-ui/icons/Backspace"));
var _codemirror = require("codemirror");
var _includes = _interopRequireDefault(require("lodash/includes"));
var _Cancel = _interopRequireDefault(require("@material-ui/icons/Cancel"));
var _SubdirectoryArrowRight = _interopRequireDefault(require("@material-ui/icons/SubdirectoryArrowRight"));
var _colorManipulator = require("@material-ui/core/styles/colorManipulator");
var _isNotDeletableLine = _interopRequireDefault(require("./isNotDeletableLine"));
var _dec, _class, _class2, _temp;
var dummyNode = document.createElement('div');
var cn = {
background: (0, _typestyle.style)({
backgroundColor: 'rgba(0, 0, 0, 0.04)'
}),
blank: (0, _typestyle.style)({
flex: 1
}),
parent: (0, _typestyle.style)({
display: 'flex',
alignItems: 'center',
position: 'relative',
width: '100%'
})
};
var getCn = function getCn(_ref, state) {
var theme = _ref.theme;
var backgroundColor = theme.palette.type === 'light' ? theme.palette.grey[300] : theme.palette.grey[700];
var deleteIconColor = (0, _colorManipulator.fade)(theme.palette.text.primary, 0.26);
return {
button: (0, _typestyle.style)({
margin: theme.spacing.unit,
flexShrink: 0
}),
copy: (0, _typestyle.style)({
transform: "rotateX(".concat(state.above ? 180 : 0, "deg)") // copy してくる方向
}),
paste: (0, _typestyle.style)({
transform: "rotateZ(90deg) rotateY(".concat(state.above ? 180 : 0, "deg)") // paste する方向
}),
clipboard: (0, _typestyle.style)({
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
overflow: 'hidden',
height: 20,
padding: 4,
paddingBottom: 0,
// buggy
borderRadius: 14,
fontSize: 10,
flexGrow: 0,
flexShrink: 1,
transition: theme.transitions.create(['background-color', 'color']),
backgroundColor: state.clipboard ? backgroundColor : 'transparent',
color: state.clipboard ? theme.palette.text.primary : theme.palette.text.disabled
}),
cancel: (0, _typestyle.style)({
fontSize: 16,
color: deleteIconColor,
verticalAlign: 'middle',
cursor: 'pointer',
$nest: {
'&:hover': {
color: (0, _colorManipulator.fade)(deleteIconColor, 0.4)
}
}
})
};
};
var LineWidget = (_dec = (0, _core.withTheme)(), _dec(_class = (_temp = _class2 =
/*#__PURE__*/
function (_React$Component) {
(0, _inherits2.default)(LineWidget, _React$Component);
function LineWidget() {
var _getPrototypeOf2;
var _this;
(0, _classCallCheck2.default)(this, LineWidget);
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)(LineWidget)).call.apply(_getPrototypeOf2, [this].concat(args)));
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "state", {
line: -1,
above: false,
widget: null,
notDeletable: false,
text: '',
clipboard: null
});
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "handleLineWidget", function (cm) {
if ((0, _includes.default)(cm.getSelection(), '\n')) return; // 複数行選択されている場合は omit
// Delete line button
var cursor = cm.getCursor();
if (!cursor.line && !cursor.ch && cursor.sticky === null) {
// runApp した時に0行目に line widget が移るのを防ぐ
// setValue すると LineWidget が消えるみたいなので作り直す
_this.setLineWidget(cm, _this.state.line);
return;
}
if (_this.state.line !== cursor.line) {
// 行が変わっていたら LineWidget も作り直す必要がある
_this.setLineWidget(cm, cursor.line);
}
});
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "handleDone", function () {
// 現在の LineWidget を消す
var _this$state = _this.state,
line = _this$state.line,
widget = _this$state.widget;
if (line > -1) {
_this.props.codemirror.removeLineClass(line, 'wrap', cn.background); // 背景色を戻す
}
if (widget) {
widget.clear();
}
_this.setState({
widget: null,
line: -1
});
});
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "handleLineDeleteClick", function () {
var cm = _this.props.codemirror;
var line = _this.state.line;
var cursor = cm.getCursor();
var from = new _codemirror.Pos(line, 0);
var to = new _codemirror.Pos(line + 1, 0);
cm.replaceRange('', from, to, 'change'); // 1行削除
cm.focus(); // ボタンを押したのでフォーカスが外れている. それを戻す
cm.setCursor(new _codemirror.Pos(line, cursor.ch)); // カーソルを新しい位置に
_this.setLineWidget(cm, line); // 次の行(消したのでlineは同じ)に移動
});
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "handleBlur", function (cm) {
// 背景色だけが残らないようにする
if (!_this.props.show && _this.state.line > -1) {
cm.removeLineClass(_this.state.line, 'wrap', cn.background); // 背景色を戻す
}
});
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "handleLineCopyClick", function () {
var cm = _this.props.codemirror;
var line = _this.state.line;
var text = cm.getLine(line);
_this.setState({
clipboard: text
});
cm.focus();
});
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "handleLinePasteClick", function () {
var cm = _this.props.codemirror;
var _this$state2 = _this.state,
line = _this$state2.line,
above = _this$state2.above,
clipboard = _this$state2.clipboard;
if (!clipboard) return;
var pos = new _codemirror.Pos(above ? line : line + 1, 0);
cm.replaceRange(clipboard + '\n', pos, pos);
_this.setState({
clipboard: null
});
_this.props.runApp();
});
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "clearClipboard", function () {
_this.setState({
clipboard: null
});
});
return _this;
}
(0, _createClass2.default)(LineWidget, [{
key: "componentDidMount",
value: function componentDidMount() {
var codemirror = this.props.codemirror;
codemirror.on('cursorActivity', this.handleLineWidget);
codemirror.on('blur', this.handleBlur);
}
}, {
key: "componentDidUpdate",
value: function componentDidUpdate(prevProps) {
var line = this.state.line;
if (!prevProps.show && this.props.show && line > -1) {
this.setLineWidget(this.props.codemirror, line);
}
if (prevProps.show && !this.props.show && line > -1) {
this.handleDone();
}
}
}, {
key: "setLineWidget",
value: function setLineWidget(cm, line) {
if (!this.props.show) return; // 前回の Widget を消す
if (this.state.line > -1) {
cm.removeLineClass(this.state.line, 'wrap', cn.background); // 背景色を戻す
}
if (this.state.widget) {
this.state.widget.clear();
}
if (line === -1) return; // カーソルが定まっていない
// Widget を作って出す
cm.addLineClass(line, 'wrap', cn.background); // 背景色をつける
var parent = document.createElement('div');
parent.classList.add(cn.parent);
var above = this.state.line > -1 ? line === this.state.line ? this.state.above : line > this.state.line : false;
var widget = cm.addLineWidget(line, parent, {
noHScroll: true,
above: above
});
this.setState({
widget: widget,
line: line,
above: above,
text: widget.line.text,
notDeletable: (0, _isNotDeletableLine.default)(cm.getLine(line)) // 削除できるかどうか
});
}
}, {
key: "render",
value: function render() {
var _this$state3 = this.state,
widget = _this$state3.widget,
clipboard = _this$state3.clipboard,
text = _this$state3.text;
if (!this.props.show) return null;
var node = widget ? widget.node : dummyNode;
var dcn = getCn(this.props, this.state);
var chipText = clipboard || text;
return _reactDom.default.createPortal(_react.default.createElement(_react.default.Fragment, null, !clipboard ? _react.default.createElement(_core.Button, {
variant: "text",
size: "small",
className: dcn.button,
onClick: this.handleLineCopyClick,
disabled: !text || this.state.notDeletable
}, _react.default.createElement(_SubdirectoryArrowRight.default, {
className: dcn.copy,
fontSize: "small"
}), this.props.localization.editorCard.copyLine) : _react.default.createElement(_core.Button, {
variant: "text",
size: "small",
className: dcn.button,
onClick: this.handleLinePasteClick
}, _react.default.createElement(_SubdirectoryArrowRight.default, {
className: dcn.paste,
fontSize: "small"
}), this.props.localization.editorCard.pasteLine), chipText && _react.default.createElement("div", {
className: dcn.clipboard
}, clipboard ? _react.default.createElement(_Cancel.default, {
className: dcn.cancel,
onClick: this.clearClipboard
}) : null, chipText), _react.default.createElement("div", {
className: cn.blank
}), _react.default.createElement(_core.Button, {
variant: "text",
size: "small",
className: dcn.button,
onClick: this.handleLineDeleteClick,
disabled: this.state.notDeletable
}, _react.default.createElement(_Backspace.default, {
fontSize: "small"
}), this.props.localization.editorCard.deleteLine)), node);
}
}]);
return LineWidget;
}(_react.default.Component), (0, _defineProperty2.default)(_class2, "propTypes", {
show: _propTypes.default.bool.isRequired,
codemirror: _propTypes.default.object.isRequired,
runApp: _propTypes.default.func.isRequired,
localization: _propTypes.default.object.isRequired
}), _temp)) || _class);
exports.default = LineWidget;