feeles-ide
Version:
The hackable and serializable IDE to make learning material
1,124 lines (957 loc) • 42.1 kB
JavaScript
"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;