feeles-ide
Version:
The hackable and serializable IDE to make learning material
398 lines (302 loc) • 11.3 kB
JavaScript
import _regeneratorRuntime from 'babel-runtime/regenerator';
import _getIterator from 'babel-runtime/core-js/get-iterator';
import _toConsumableArray from 'babel-runtime/helpers/toConsumableArray';
import _JSON$stringify from 'babel-runtime/core-js/json/stringify';
import _asyncToGenerator from 'babel-runtime/helpers/asyncToGenerator';
var _this = this;
import screenJs from '../../lib/screen';
import regeneratorRuntimePolyfill from '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
*/
export default (function () {
var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.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 _regeneratorRuntime.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: ' + _JSON$stringify(env) + ' };');
// 1. headタグの一番上に screenJs を埋め込む
appendScript(screenJs(env.MODULE));
// 2. src 属性を BinaryFile の Data URL に差し替える
binaries = [].concat(_toConsumableArray(doc.images));
_iteratorNormalCompletion = true;
_didIteratorError = false;
_iteratorError = undefined;
_context.prev = 9;
_iterator = _getIterator(binaries);
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) {
_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 = [].concat(_toConsumableArray(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 = [].concat(_toConsumableArray(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 = [].concat(_toConsumableArray(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(\'' + href + '\')');
case 88:
_i3++;
_context.next = 81;
break;
case 91:
// 6. regeneratorRuntime
appendScript(regeneratorRuntimePolyfill);
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);
};
})();
var requireTemplate = function requireTemplate(src) {
return 'requirejs([\'' + src + '\'])';
};
var replaceUrls = function () {
var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(text, findFile) {
var regExp, matches, _iteratorNormalCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, token, path, file, dataURL;
return _regeneratorRuntime.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 = _getIterator(matches);
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(' + 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) {
_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);
};
}();