feeles-ide
Version:
The hackable and serializable IDE to make learning material
405 lines (311 loc) • 11.5 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
var _screen = _interopRequireDefault(require("../../lib/screen"));
var _runtime = _interopRequireDefault(require("raw-loader!regenerator-runtime/runtime"));
/**
* @param html:String
* @param findFile:Function
* @param env:Object
* @return Promise<String>
*
* iframe にユーザーが入力したHTMLに、次の操作を加える
* 0. window.feeles と 環境変数 env のエクスポート
* 1. headタグの一番上に screenJs を埋め込む
* 2. src 属性を BinaryFile の Data URL に差し替える
* REMOVED: 3. screenJs のすぐ下で、全てのスクリプトを define する
* 4. スクリプトタグの src 属性を requirejs を Data URL に差し替える
* 5. a 要素の href 属性を feeles.replace の Data URL に差し替える
* 6. regeneratorRuntime
*/
var _default =
/*#__PURE__*/
function () {
var _ref = (0, _asyncToGenerator2.default)(
/*#__PURE__*/
_regenerator.default.mark(function _callee(html, findFile, env) {
var parser, doc, appendScript, binaries, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, node, file, dataURL, _arr, _i, _node, _file, replaced, _arr2, _i2, _node2, _file2, _dataURL, _arr3, _i3, _node3, href;
return _regenerator.default.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
parser = new DOMParser();
doc = parser.parseFromString(html, 'text/html');
appendScript = function (lastNode) {
return function (text) {
var script = doc.createElement('script');
script.type = 'text/javascript';
script.text = text;
doc.head.insertBefore(script, lastNode && lastNode.nextSibling);
lastNode = script;
};
}(doc.head.firstChild); // 0. window.feeles と 環境変数 env のエクスポート
appendScript("window.feeles = { env: ".concat(JSON.stringify(env), " };")); // 1. headタグの一番上に screenJs を埋め込む
appendScript((0, _screen.default)(env.MODULE)); // 2. src 属性を BinaryFile の Data URL に差し替える
binaries = (0, _toConsumableArray2.default)(doc.images);
_iteratorNormalCompletion = true;
_didIteratorError = false;
_iteratorError = undefined;
_context.prev = 9;
_iterator = binaries[Symbol.iterator]();
case 11:
if (_iteratorNormalCompletion = (_step = _iterator.next()).done) {
_context.next = 23;
break;
}
node = _step.value;
file = findFile(node.getAttribute('src'));
if (file) {
_context.next = 16;
break;
}
return _context.abrupt("continue", 20);
case 16:
_context.next = 18;
return file.toDataURL();
case 18:
dataURL = _context.sent;
node.setAttribute('src', dataURL);
case 20:
_iteratorNormalCompletion = true;
_context.next = 11;
break;
case 23:
_context.next = 29;
break;
case 25:
_context.prev = 25;
_context.t0 = _context["catch"](9);
_didIteratorError = true;
_iteratorError = _context.t0;
case 29:
_context.prev = 29;
_context.prev = 30;
if (!_iteratorNormalCompletion && _iterator.return != null) {
_iterator.return();
}
case 32:
_context.prev = 32;
if (!_didIteratorError) {
_context.next = 35;
break;
}
throw _iteratorError;
case 35:
return _context.finish(32);
case 36:
return _context.finish(29);
case 37:
// 2.1 link 要素の href 属性を Data URL に差し替える
_arr = (0, _toConsumableArray2.default)(doc.querySelectorAll('link'));
_i = 0;
case 39:
if (!(_i < _arr.length)) {
_context.next = 66;
break;
}
_node = _arr[_i];
_file = findFile(_node.getAttribute('href'));
if (_file) {
_context.next = 44;
break;
}
return _context.abrupt("continue", 63);
case 44:
if (!(_file.is('css') && _file.text.indexOf('url') >= 0)) {
_context.next = 58;
break;
}
_context.t1 = _file;
_context.next = 48;
return replaceUrls(_file.text, findFile);
case 48:
_context.t2 = _context.sent;
_context.t3 = {
text: _context.t2
};
replaced = _context.t1.set.call(_context.t1, _context.t3);
_context.t4 = _node;
_context.next = 54;
return replaced.toDataURL();
case 54:
_context.t5 = _context.sent;
_context.t4.setAttribute.call(_context.t4, 'href', _context.t5);
_context.next = 63;
break;
case 58:
_context.t6 = _node;
_context.next = 61;
return _file.toDataURL();
case 61:
_context.t7 = _context.sent;
_context.t6.setAttribute.call(_context.t6, 'href', _context.t7);
case 63:
_i++;
_context.next = 39;
break;
case 66:
// 4. スクリプトタグの src 属性を requirejs を Data URL に差し替える
_arr2 = (0, _toConsumableArray2.default)(doc.scripts);
_i2 = 0;
case 68:
if (!(_i2 < _arr2.length)) {
_context.next = 79;
break;
}
_node2 = _arr2[_i2];
if (!(_node2.type && _node2.type !== 'text/javascript')) {
_context.next = 72;
break;
}
return _context.abrupt("continue", 76);
case 72:
_file2 = findFile(_node2.getAttribute('src'));
if (_file2) {
_context.next = 75;
break;
}
return _context.abrupt("continue", 76);
case 75:
if (env.MODULE) {
_dataURL = 'data:text/javascript;charset=UTF-8,' + encodeURIComponent(requireTemplate(_file2.moduleName));
_node2.setAttribute('src', _dataURL);
} else {
_node2.text = _file2.text;
_node2.removeAttribute('src');
}
case 76:
_i2++;
_context.next = 68;
break;
case 79:
// 5. a 要素の href 属性を feeles.replace に差し替える
_arr3 = (0, _toConsumableArray2.default)(doc.links);
_i3 = 0;
case 81:
if (!(_i3 < _arr3.length)) {
_context.next = 91;
break;
}
_node3 = _arr3[_i3];
if (!(_node3.getAttribute('target') === '_blank')) {
_context.next = 85;
break;
}
return _context.abrupt("continue", 88);
case 85:
href = _node3.getAttribute('href') || '';
_node3.setAttribute('href', '#');
_node3.setAttribute('onclick', "feeles.replace('".concat(href, "')"));
case 88:
_i3++;
_context.next = 81;
break;
case 91:
// 6. regeneratorRuntime
appendScript(_runtime.default);
return _context.abrupt("return", doc.documentElement.outerHTML);
case 93:
case "end":
return _context.stop();
}
}
}, _callee, this, [[9, 25, 29, 37], [30,, 32, 36]]);
}));
return function (_x, _x2, _x3) {
return _ref.apply(this, arguments);
};
}();
exports.default = _default;
var requireTemplate = function requireTemplate(src) {
return "requirejs(['".concat(src, "'])");
};
var replaceUrls =
/*#__PURE__*/
function () {
var _ref2 = (0, _asyncToGenerator2.default)(
/*#__PURE__*/
_regenerator.default.mark(function _callee2(text, findFile) {
var regExp, matches, _iteratorNormalCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, token, path, file, dataURL;
return _regenerator.default.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
regExp = /url\(.*\)/g;
matches = text.match(regExp);
if (matches) {
_context2.next = 4;
break;
}
return _context2.abrupt("return", text);
case 4:
_iteratorNormalCompletion2 = true;
_didIteratorError2 = false;
_iteratorError2 = undefined;
_context2.prev = 7;
_iterator2 = matches[Symbol.iterator]();
case 9:
if (_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done) {
_context2.next = 21;
break;
}
token = _step2.value;
path = token.substr(4, token.length - 5);
file = findFile(path);
if (!file) {
_context2.next = 18;
break;
}
_context2.next = 16;
return file.toDataURL();
case 16:
dataURL = _context2.sent;
text = text.replace(token, "url(".concat(dataURL, ")"));
case 18:
_iteratorNormalCompletion2 = true;
_context2.next = 9;
break;
case 21:
_context2.next = 27;
break;
case 23:
_context2.prev = 23;
_context2.t0 = _context2["catch"](7);
_didIteratorError2 = true;
_iteratorError2 = _context2.t0;
case 27:
_context2.prev = 27;
_context2.prev = 28;
if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
_iterator2.return();
}
case 30:
_context2.prev = 30;
if (!_didIteratorError2) {
_context2.next = 33;
break;
}
throw _iteratorError2;
case 33:
return _context2.finish(30);
case 34:
return _context2.finish(27);
case 35:
return _context2.abrupt("return", text);
case 36:
case "end":
return _context2.stop();
}
}
}, _callee2, this, [[7, 23, 27, 35], [28,, 30, 34]]);
}));
return function replaceUrls(_x4, _x5) {
return _ref2.apply(this, arguments);
};
}();