UNPKG

feeles-ide

Version:

The hackable and serializable IDE to make learning material

1,124 lines (957 loc) 42.1 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 = exports.pathToInstall = void 0; var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator")); var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator")); var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray")); var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray")); 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 _styles = require("@material-ui/core/styles"); var _propTypes = _interopRequireDefault(require("prop-types")); var _typestyle = require("typestyle"); var _core = require("@material-ui/core"); var _icons = require("@material-ui/icons"); var _colorManipulator = require("@material-ui/core/styles/colorManipulator"); var _codemirror = require("codemirror"); var _lodash = require("lodash"); var _reactResizeDetector = _interopRequireDefault(require("react-resize-detector")); var _keywords = require("../../utils/keywords"); var _replaceExistConsts = _interopRequireDefault(require("../../utils/replaceExistConsts")); var _AssetButton = _interopRequireDefault(require("./AssetButton")); var _SourceFile = _interopRequireDefault(require("../../File/SourceFile")); var _extractAssetNames = _interopRequireDefault(require("./extractAssetNames")); var _AssetLink = _interopRequireWildcard(require("./AssetLink")); var _dec, _class, _class2, _temp; var paneHeight = 80; // % var pathToInstall = 'modules'; // 後方互換性のために変更しない (TODO: feelesrc で上書きできるように) exports.pathToInstall = pathToInstall; var pathToAutoload = 'autoload.js'; // 後方互換性のために変更しない (TODO: feelesrc で上書きできるように) var cn = { in: (0, _typestyle.style)({ top: "".concat(100 - paneHeight, "vh") }), out: (0, _typestyle.style)({ top: '100vh' }), label: (0, _typestyle.style)({ flex: '0 0 100%', color: 'white', textAlign: 'center', marginTop: 16, fontWeight: 600 }), wrapper: (0, _typestyle.style)({ display: 'flex', flexWrap: 'wrap', justifyContent: 'center' }), assetLinkContainerClasses: { wrapperInner: (0, _typestyle.style)({ width: '100%', display: 'flex', paddingRight: 64 }) }, assetLinkButton: (0, _typestyle.style)({ margin: 4, marginRight: 0, width: _AssetLink.assetLinkWidth, minWidth: _AssetLink.assetLinkWidth // ButtonBase の minWidth を打ち消す }) }; var getCn = function getCn(_ref) { var theme = _ref.theme; return { root: (0, _typestyle.style)({ position: 'fixed', width: '100%', height: "".concat(paneHeight, "vh"), padding: theme.spacing.unit, boxSizing: 'border-box', zIndex: theme.zIndex.modal - 1, left: 0, transition: theme.transitions.create('top'), display: 'flex', flexDirection: 'column', backgroundColor: (0, _colorManipulator.fade)(theme.palette.text.primary, 0.75) }), scroller: (0, _typestyle.style)({ flex: 1, overflowX: 'auto', overflowY: 'scroll', boxSizing: 'border-box', paddingBottom: 24, borderTopLeftRadius: 0, borderTopRightRadius: 0 }), scopeWrapper: (0, _typestyle.style)({ color: theme.palette.common.white, paddingLeft: theme.spacing.unit * 10, paddingRight: theme.spacing.unit * 10, paddingBottom: theme.spacing.unit * 4, fontWeight: 600 }), scope: (0, _typestyle.style)({ padding: theme.spacing.unit, marginRight: theme.spacing.unit, color: theme.palette.getContrastText(theme.palette.primary.main), backgroundColor: theme.palette.primary.main, borderRadius: theme.shape.borderRadius }), closer: (0, _typestyle.style)({ position: 'absolute', top: theme.spacing.unit, right: theme.spacing.unit, color: theme.palette.common.white }), categoryWrapper: (0, _typestyle.style)({ display: 'flex', flexWrap: 'nowrap', paddingLeft: theme.spacing.unit * 10, paddingRight: theme.spacing.unit * 10, paddingBottom: theme.spacing.unit * 4, paddingTop: theme.spacing.unit * 4 }), category: (0, _typestyle.style)({ flex: 1, fontWeight: 600, cursor: 'pointer', color: theme.palette.grey[600], borderBottom: "4px solid ".concat(theme.palette.grey[600]), display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'space-around', $nest: { '&>img': { maxWidth: 48, height: 48 } } }), active: (0, _typestyle.style)({ color: theme.palette.common.white, borderBottomColor: theme.palette.common.white }), previousLinkButton: (0, _typestyle.style)({ borderColor: theme.palette.primary.main }) }; }; var AssetPane = (_dec = (0, _styles.withTheme)(), _dec(_class = (_temp = _class2 = /*#__PURE__*/ function (_PureComponent) { (0, _inherits2.default)(AssetPane, _PureComponent); function AssetPane() { var _getPrototypeOf2; var _this; (0, _classCallCheck2.default)(this, AssetPane); 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)(AssetPane)).call.apply(_getPrototypeOf2, [this].concat(args))); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "state", { show: false, assetLineNumber: 0, activeCategoryIndex: -1, scopeIndexes: [], assetNamesOfLinks: [], linkOnly: false, // 全てのアセットを表示するモード.全ての色を一画面に表示.「中に入れる」ボタンはない previousLabel: '', // リンクで移動する前の label を保持する (Home='') // オートインストール installingFileNames: null, // インストール中のモジュール名 callback: { // インストール後の挙動 type: '', // insertAsset | openFile | runApp payload: null // callback に必要な payload } }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "_widgets", new Map()); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "_pendingInstallModule", []); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "insertAsset", function (_ref2) { var insertCode = _ref2.insertCode; var cm = _this.props.codemirror; var assetLineNumber = _this.state.assetLineNumber; // バーが常に上に来るよう, 下に挿入 var pos = new _codemirror.Pos(assetLineNumber + 1, 0); var end = new _codemirror.Pos(pos.line + insertCode.split('\n').length, 0); insertCode = '\n' + insertCode; cm.replaceRange(insertCode, pos, pos, 'asset'); // スクロール cm.scrollIntoView({ from: pos, to: end }, 10); // カーソル (挿入直後に undo したときスクロールが上に戻るのを防ぐ) cm.focus(); cm.setCursor(new _codemirror.Pos(end.line - 1, 0)); // Pane をとじる _this.handleClose(); // 新しいアセットが更新された可能性が高いので, アセットのリンクを更新 _this.updateAssetLink(cm); // 実行 _this.props.runApp(); }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "updateAssetLink", function (cm) { // ソースコードに含まれるキーワードを抜き出して Scrapbox 風のリンクを表示する var asset = _this.props.asset; var assetNamesOfLinks = (0, _extractAssetNames.default)(cm.getValue()).filter(function (assetName) { return Boolean(asset.module[assetName]); }); _this.setState({ assetNamesOfLinks: assetNamesOfLinks }); }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "handleUpdateWidget", function (cm) { _this._widgets.clear(); var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = cm.getValue().split('\n').entries()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var _step$value = (0, _slicedToArray2.default)(_step.value, 2), line = _step$value[0], text = _step$value[1]; _this.updateWidget(cm, line, text); } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return != null) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "updateWidget", function (cm, line, text) { var asset = _this.props.asset; // Syntax: /*+ モンスター アイテム */ var tokens = _keywords.assetRegExp.exec(text); if (tokens) { var _tokens$map = tokens.map(function (t) { return t.replace(/\t/g, ' '); }), _tokens$map2 = (0, _slicedToArray2.default)(_tokens$map, 5), _prefix = _tokens$map2[1], _left = _tokens$map2[2], _label = _tokens$map2[3], _right = _tokens$map2[4]; var prefix = document.createElement('span'); prefix.textContent = _prefix; prefix.classList.add('Feeles-asset-blank'); var left = document.createElement('span'); left.textContent = _left; left.classList.add('Feeles-asset-blank'); var label = document.createElement('span'); label.textContent = _label; var right = document.createElement('span'); right.textContent = _right; right.classList.add('Feeles-asset-blank'); var button = document.createElement('span'); button.classList.add('Feeles-asset-button'); button.onclick = function (event) { var scopeIndexes = []; var activeCategoryIndex = -1; // バーに書かれた文字列の中に scope.name があれば選択 (0, _lodash.forEach)(asset.scopes, function (scope, index) { if ((0, _lodash.includes)(_label, scope.name)) { scopeIndexes.push(index); // 先頭のスコープで, 初期表示カテゴリを決める if (activeCategoryIndex < 0) { activeCategoryIndex = scope.defaultActiveCategory; } } }); _this.setState({ show: true, scopeIndexes: scopeIndexes, activeCategoryIndex: activeCategoryIndex, assetLineNumber: line }); event.stopPropagation(); }; button.appendChild(left); button.appendChild(label); button.appendChild(right); var parent = document.createElement('div'); parent.classList.add('Feeles-widget', 'Feeles-asset'); parent.appendChild(prefix); parent.appendChild(button); _this._widgets.set(line, parent); } }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "handleRenderWidget", function (cm) { // remove old widgets var _arr = (0, _toConsumableArray2.default)(document.querySelectorAll('.Feeles-asset')); for (var _i = 0; _i < _arr.length; _i++) { var widget = _arr[_i]; if (widget.parentNode) { widget.parentNode.removeChild(widget); } } // render new widgets var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for (var _iterator2 = _this._widgets.entries()[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { var _step2$value = (0, _slicedToArray2.default)(_step2.value, 2), i = _step2$value[0], element = _step2$value[1]; // fold されていないかを確認 var lineHandle = cm.getLineHandle(i); if (lineHandle.height > 0) { cm.addWidget(new _codemirror.Pos(i, 0), element); } } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2.return != null) { _iterator2.return(); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "handleIndexReplacement", function (cm, change) { if (!(0, _lodash.includes)(['asset', 'paste'], change.origin)) return; var code = cm.getValue('\n'); var sourceText = change.text.join('\n'); var replacedText = (0, _replaceExistConsts.default)(code, sourceText); if (sourceText !== replacedText) { change.update(change.from, change.to, replacedText.split('\n')); } }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "handleIndentLine", function (cm, change) { if (!(0, _lodash.includes)(['asset', 'paste'], change.origin)) return; var from = change.from; var to = new _codemirror.Pos(from.line + change.text.length, 0); // インデント for (var line = from.line; line < to.line; line++) { cm.indentLine(line); } }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "handleClose", function () { _this.setState({ show: false, linkOnly: false }); }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "openFile", /*#__PURE__*/ function () { var _ref4 = (0, _asyncToGenerator2.default)( /*#__PURE__*/ _regenerator.default.mark(function _callee(_ref3) { var filePath, label, iconUrl; return _regenerator.default.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: filePath = _ref3.filePath, label = _ref3.label, iconUrl = _ref3.iconUrl; if (filePath) { _context.next = 3; break; } return _context.abrupt("return"); case 3: _context.next = 5; return _this.props.saveFileIfNeeded(); case 5: // リンクで移動する前に変更を保存する _this.props.globalEvent.emit('message.editor', { data: { value: filePath, options: { showBackButton: Boolean(label), // アセットのコードを閉じて以前のファイルに戻るボタンを表示する label: label, // ↑そのボタンを、この名前で「${label}の改造をおわる」と表示 iconUrl: iconUrl } } }); _this.handleClose(); // Pane をとじる case 7: case "end": return _context.stop(); } } }, _callee, this); })); return function (_x) { return _ref4.apply(this, arguments); }; }()); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "installAssetModules", function (assetNames, callback) { if (_this.state.installingFileNames) { // すでに別のモジュールをインストール中 _this._pendingInstallModule.push([assetNames, callback]); // 前回コールされた installModule の終了を待ってから実行する return; } var _this$props = _this.props, asset = _this$props.asset, files = _this$props.files; // module が存在するかどうか var _iteratorNormalCompletion3 = true; var _didIteratorError3 = false; var _iteratorError3 = undefined; try { for (var _iterator3 = assetNames[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { var assetName = _step3.value; var mod = asset.module[assetName]; if (!mod) throw new Error("".concat(assetName, " is not exist in asset.module")); // TODO: 例外処理 } } catch (err) { _didIteratorError3 = true; _iteratorError3 = err; } finally { try { if (!_iteratorNormalCompletion3 && _iterator3.return != null) { _iterator3.return(); } } finally { if (_didIteratorError3) { throw _iteratorError3; } } } var toPath = function toPath(name) { return "".concat(pathToInstall, "/").concat(name, ".js"); }; var notInstalled = (0, _lodash.differenceWith)(assetNames, files, function (assetName, file) { return toPath(assetName) === file.name; }); if (notInstalled.length === 0) { // すでに全部インストールされている _this.executeCallback(callback); return; } // まずコールバックを設定してからファイルをコピー var installingFileNames = assetNames.map(toPath); _this.setState({ installingFileNames: installingFileNames, callback: callback }, /*#__PURE__*/ (0, _asyncToGenerator2.default)( /*#__PURE__*/ _regenerator.default.mark(function _callee2() { var autoload, text, _iteratorNormalCompletion4, _didIteratorError4, _iteratorError4, _iterator4, _step4, assetName, _iteratorNormalCompletion5, _didIteratorError5, _iteratorError5, _iterator5, _step5, _assetName, mod; return _regenerator.default.wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: autoload = _this.props.files.find(function (file) { return file.name === pathToAutoload; }); if (autoload) { _context2.next = 3; break; } throw new Error("".concat(pathToAutoload, " is not found")); case 3: // autoload.js の更新 text = autoload.text; if (text && text.substr(-1) !== '\n') text += '\n'; _iteratorNormalCompletion4 = true; _didIteratorError4 = false; _iteratorError4 = undefined; _context2.prev = 8; for (_iterator4 = notInstalled[Symbol.iterator](); !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { assetName = _step4.value; text += "import '".concat(pathToInstall, "/").concat(assetName, "'\n"); } _context2.next = 16; break; case 12: _context2.prev = 12; _context2.t0 = _context2["catch"](8); _didIteratorError4 = true; _iteratorError4 = _context2.t0; case 16: _context2.prev = 16; _context2.prev = 17; if (!_iteratorNormalCompletion4 && _iterator4.return != null) { _iterator4.return(); } case 19: _context2.prev = 19; if (!_didIteratorError4) { _context2.next = 22; break; } throw _iteratorError4; case 22: return _context2.finish(19); case 23: return _context2.finish(16); case 24: _context2.next = 26; return _this.props.putFile(autoload, new _SourceFile.default({ type: autoload.type, name: autoload.name, text: text })); case 26: // ファイルのコピー _iteratorNormalCompletion5 = true; _didIteratorError5 = false; _iteratorError5 = undefined; _context2.prev = 29; _iterator5 = assetNames[Symbol.iterator](); case 31: if (_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done) { _context2.next = 39; break; } _assetName = _step5.value; mod = asset.module[_assetName]; _context2.next = 36; return _this.props.putFile(new _SourceFile.default({ type: 'text/javascript', name: toPath(_assetName), text: mod.code })); case 36: _iteratorNormalCompletion5 = true; _context2.next = 31; break; case 39: _context2.next = 45; break; case 41: _context2.prev = 41; _context2.t1 = _context2["catch"](29); _didIteratorError5 = true; _iteratorError5 = _context2.t1; case 45: _context2.prev = 45; _context2.prev = 46; if (!_iteratorNormalCompletion5 && _iterator5.return != null) { _iterator5.return(); } case 48: _context2.prev = 48; if (!_didIteratorError5) { _context2.next = 51; break; } throw _iteratorError5; case 51: return _context2.finish(48); case 52: return _context2.finish(45); case 53: case "end": return _context2.stop(); } } }, _callee2, this, [[8, 12, 16, 24], [17,, 19, 23], [29, 41, 45, 53], [46,, 48, 52]]); }))); }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "getDependencies", function (name) { var _ignoreList = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; var mod = _this.props.asset.module[name]; if (!mod) return _ignoreList; _ignoreList.push(name); var _iteratorNormalCompletion6 = true; var _didIteratorError6 = false; var _iteratorError6 = undefined; try { for (var _iterator6 = (0, _extractAssetNames.default)(mod.code)[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) { var dependency = _step6.value; if (!(0, _lodash.includes)(_ignoreList, dependency)) { // 新しいアセットが見つかったら, 再帰的に依存アセットを探す _this.getDependencies(dependency, _ignoreList); } } } catch (err) { _didIteratorError6 = true; _iteratorError6 = err; } finally { try { if (!_iteratorNormalCompletion6 && _iterator6.return != null) { _iterator6.return(); } } finally { if (_didIteratorError6) { throw _iteratorError6; } } } return _ignoreList; }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "executeCallback", function (_ref6) { var type = _ref6.type, payload = _ref6.payload; switch (type) { case 'insertAsset': _this.insertAsset(payload); break; case 'openFile': _this.openFile(payload); break; case 'runApp': _this.props.runApp(); break; } // pending 状態のインストールを実行 var next = _this._pendingInstallModule.shift(); if (next) { _this.installAssetModules.apply((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), next); } }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "_pendingAssetsToInstall", []); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "handleInstallMessage", function (event) { var name = event.data.value; var asset = _this.props.asset; // module が存在するなら先に install var mod = asset.module[name]; if (mod) { _this._pendingAssetsToInstall.push(name); // ここでは pending list に入れるだけ _this.installAssetsFromMessage(); // この関数でインストールする } else {// そもそもアセットの名前を間違えているかも知れない } }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "installAssetsFromMessage", (0, _lodash.debounce)(function () { // install message を一定時間 debounce して, 一度にインストール var length = _this._pendingAssetsToInstall.length; if (length <= 0) return; // ない var assetNames = (0, _lodash.uniq)((0, _lodash.flatten)(_this._pendingAssetsToInstall.splice(0, length) // pending list から削除 .map(function (assetName) { return _this.getDependencies(assetName); }) // 依存アセットもここで同時にインストール )); // インストール後に runApp _this.installAssetModules(assetNames, { type: 'runApp' }); }.bind((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this))), 16)); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "handleInsertAsset", function (_ref7) { var name = _ref7.name, insertCode = _ref7.insertCode; var asset = _this.props.asset; // module が存在するなら先に install var mod = asset.module[name]; if (mod) { // 依存アセットもここで同時にインストール var dependencies = _this.getDependencies(name); // インストール後に insertAsset _this.installAssetModules(dependencies, { type: 'insertAsset', payload: { insertCode: insertCode } }); } else { _this.insertAsset({ insertCode: insertCode }); } }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "handleOpenFile", function (_ref8) { var name = _ref8.name, filePath = _ref8.filePath, iconUrl = _ref8.iconUrl; var asset = _this.props.asset; // module が存在するなら先に install var mod = asset.module[name]; if (mod) { // インストール後に openFile _this.installAssetModules([name], { type: 'openFile', payload: { filePath: filePath, label: name, iconUrl: iconUrl } }); } else { // 開けるかどうか試す _this.openFile({ filePath: filePath, label: name, iconUrl: iconUrl }); } }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "handleAssetLinkClick", function (_ref9) { var name = _ref9.name, iconUrl = _ref9.iconUrl; // もしそのアセットがインストールされていなければ、インストールしてから開く _this.handleOpenFile({ name: name, filePath: "".concat(pathToInstall, "/").concat(name, ".js"), iconUrl: iconUrl }); }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "handleBackButtonClick", function () { _this.openFile({ filePath: _this.props.filePathToBack }); }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "handleMoreButtonClick", function () { return _this.setState({ show: true, linkOnly: true, activeCategoryIndex: 0 }); }); return _this; } (0, _createClass2.default)(AssetPane, [{ key: "componentDidMount", value: function componentDidMount() { var cm = this.props.codemirror; cm.on('change', this.handleUpdateWidget); cm.on('swapDoc', this.handleUpdateWidget); cm.on('update', this.handleRenderWidget); cm.on('beforeChange', this.handleIndexReplacement); cm.on('change', this.handleIndentLine); cm.on('swapDoc', this.updateAssetLink); this.handleUpdateWidget(cm); this.handleRenderWidget(cm); this.updateAssetLink(cm); this.props.globalEvent.on('message.install', this.handleInstallMessage); } }, { key: "componentWillUnmount", value: function componentWillUnmount() { this.props.globalEvent.off('message.install', this.handleInstallMessage); } }, { key: "componentDidUpdate", value: function componentDidUpdate(prevProps) { var _this2 = this; var _this$props2 = this.props, files = _this$props2.files, label = _this$props2.label; var _this$state = this.state, installingFileNames = _this$state.installingFileNames, callback = _this$state.callback; // オートインストールの完了待ち if (installingFileNames && prevProps.files !== this.props.files) { var all = files.map(function (file) { return file.name; }); if (installingFileNames.every(function (filePath) { return (0, _lodash.includes)(all, filePath); })) { // 全てのファイルが含まれているので, 待ち状態を初期化してコールバックを実行 this.setState({ installingFileNames: null, callback: { type: '', payload: null } }, function () { return _this2.executeCallback(callback); }); } } // previousLabel: ラベルが変わったとき, 前回の label を保持 if (label !== prevProps.label) { var wasInHome = prevProps.filePath === prevProps.filePathToBack; this.setState({ previousLabel: wasInHome ? '' : prevProps.label }); } } }, { key: "renderAssetButtons", value: function renderAssetButtons(assetButtons) { var _this3 = this; var linkOnly = this.state.linkOnly; if (linkOnly) { // 全てのバリエーションを並べる return assetButtons.map(function (assetButton) { return assetButton.variations ? _react.default.createElement(_react.Fragment, { key: assetButton.name + '-container' }, _this3.renderAssetButtons(assetButton.variations)) : _react.default.createElement(_AssetButton.default, { key: assetButton.name, name: assetButton.name, description: assetButton.description, iconUrl: assetButton.iconUrl, insertCode: assetButton.insertCode, moduleCode: assetButton.moduleCode, filePath: assetButton.filePath, insertAsset: _this3.handleInsertAsset, openFile: _this3.handleOpenFile, findFile: _this3.props.findFile, localization: _this3.props.localization, globalEvent: _this3.props.globalEvent, asset: _this3.props.asset, linkOnly: linkOnly }); }); } else { // クリックでバリエーションを展開する return assetButtons.map(function (assetButton) { return _react.default.createElement(_AssetButton.default, { key: assetButton.name, name: assetButton.name, description: assetButton.description, iconUrl: assetButton.iconUrl, insertCode: assetButton.insertCode, moduleCode: assetButton.moduleCode, filePath: assetButton.filePath, variations: assetButton.variations, insertAsset: _this3.handleInsertAsset, openFile: _this3.handleOpenFile, findFile: _this3.props.findFile, localization: _this3.props.localization, globalEvent: _this3.props.globalEvent, asset: _this3.props.asset, linkOnly: linkOnly }); }); } } }, { key: "render", value: function render() { var _this4 = this; var dcn = getCn(this.props); var _this$props3 = this.props, localization = _this$props3.localization, _this$props3$asset = _this$props3.asset, scopes = _this$props3$asset.scopes, categories = _this$props3$asset.categories, buttons = _this$props3$asset.buttons, filePath = _this$props3.filePath, filePathToBack = _this$props3.filePathToBack; var _this$state2 = this.state, show = _this$state2.show, activeCategoryIndex = _this$state2.activeCategoryIndex, scopeIndexes = _this$state2.scopeIndexes, assetNamesOfLinks = _this$state2.assetNamesOfLinks, linkOnly = _this$state2.linkOnly, previousLabel = _this$state2.previousLabel; var showingScopes = scopes.filter(function (_, i) { return (0, _lodash.includes)(scopeIndexes, i); }); var _showingButtons = buttons.filter(function (b) { return b.category === activeCategoryIndex; }); var showingButtons = linkOnly ? (0, _lodash.uniqBy)(_showingButtons, function (assetButton) { return assetButton.name; }).filter(function (assetButton) { return Boolean(_this4.props.asset.module[assetButton.name]); }) // リンクのみ表示の場合, スコープを無視するが, 代わりにアセット名で一意にする : _showingButtons.filter(function (b) { return b.scopes === null || (0, _lodash.intersection)(b.scopes, scopeIndexes).length; }); // スコープが被っているものに絞る var showBackButton = filePath !== filePathToBack; var showLinkAssets = assetNamesOfLinks.length > 0 || showBackButton; // アセットがあれば表示 (=> 古いキットでは出てこない) || アセットがなくても, Home にいなければ表示 (=> もどるボタンは常に使える) // アセットリンクの表示限界個数を求める var calcMaxLength = function calcMaxLength(width) { return Math.floor((width - 64) / _AssetLink.assetLinkWidth - ( // slaask の分だけ引いた全体 width / リンク1個分の width previousLabel ? 2 : 1) // 直前のアセットへのリンクと, Home or More リンクの分を引く ); }; return _react.default.createElement(_react.default.Fragment, null, _react.default.createElement(_core.Collapse, { in: showLinkAssets, classes: cn.assetLinkContainerClasses, mountOnEnter: true, unmountOnExit: true }, showBackButton ? _react.default.createElement(_core.Tooltip, { title: this.props.localization.editorCard.stopEditing(this.props.label) }, _react.default.createElement(_core.Button, { variant: "contained", color: "primary", className: cn.assetLinkButton, onClick: this.handleBackButtonClick }, _react.default.createElement(_icons.Home, { fontSize: "large", className: cn.assetLinkButtonIcon }))) : null, previousLabel ? _react.default.createElement(_AssetLink.default, { key: previousLabel, name: previousLabel, asset: this.props.asset, className: (0, _typestyle.classes)(cn.assetLinkButton, dcn.previousLinkButton), onClick: this.handleAssetLinkClick, localization: this.props.localization }) : null, _react.default.createElement(_reactResizeDetector.default, { handleWidth: true, refreshMode: "throttle", refreshRate: 500 }, function (width) { return _react.default.createElement(_react.default.Fragment, null, (0, _lodash.without)(assetNamesOfLinks, previousLabel).slice(0, calcMaxLength(width)) // 表示限界を計算 .map(function (assetName) { return _react.default.createElement(_AssetLink.default, { key: assetName, name: assetName, asset: _this4.props.asset, className: cn.assetLinkButton, onClick: _this4.handleAssetLinkClick, localization: _this4.props.localization }); })); }), showBackButton ? null : _react.default.createElement(_core.Button, { variant: "outlined", className: cn.assetLinkButton, onClick: this.handleMoreButtonClick }, _react.default.createElement(_icons.MoreHoriz, { fontSize: "large", className: cn.assetLinkButtonIcon }))), _react.default.createElement("div", { className: (0, _typestyle.classes)(dcn.root, show ? cn.in : cn.out) }, categories.length ? _react.default.createElement("div", { className: dcn.categoryWrapper }, categories.map(function (cat, i) { return _react.default.createElement("div", { key: i, className: (0, _typestyle.classes)(dcn.category, i === activeCategoryIndex && dcn.active), onClick: function onClick() { return _this4.setState({ activeCategoryIndex: i }); } }, _react.default.createElement("span", null, cat.name), _react.default.createElement("img", { src: cat.iconUrl, alt: "" })); })) : null, linkOnly ? null : _react.default.createElement("div", { className: dcn.scopeWrapper }, _react.default.createElement("span", { className: dcn.scope }, '+ ' + showingScopes.map(function (scope) { return scope.name; }).join(' ')), _react.default.createElement("span", null, localization.editorCard.selectedScope)), _react.default.createElement(_core.IconButton, { "aria-label": "Close", className: dcn.closer, onClick: this.handleClose }, _react.default.createElement(_icons.Close, { fontSize: "large" })), _react.default.createElement("div", { className: dcn.scroller }, _react.default.createElement("div", { className: cn.wrapper }, this.renderAssetButtons(showingButtons))))); } }]); return AssetPane; }(_react.PureComponent), (0, _defineProperty2.default)(_class2, "propTypes", { label: _propTypes.default.string.isRequired, codemirror: _propTypes.default.object.isRequired, theme: _propTypes.default.object.isRequired, runApp: _propTypes.default.func.isRequired, files: _propTypes.default.array.isRequired, findFile: _propTypes.default.func.isRequired, putFile: _propTypes.default.func.isRequired, localization: _propTypes.default.object.isRequired, globalEvent: _propTypes.default.object.isRequired, asset: _propTypes.default.object.isRequired, filePath: _propTypes.default.string.isRequired, filePathToBack: _propTypes.default.string.isRequired, isExpandingEditorCard: _propTypes.default.bool.isRequired, saveFileIfNeeded: _propTypes.default.func.isRequired }), _temp)) || _class); exports.default = AssetPane;