feeles-ide
Version:
The hackable and serializable IDE to make learning material
602 lines (518 loc) • 19.5 kB
JavaScript
import _slicedToArray from 'babel-runtime/helpers/slicedToArray';
import _Object$entries from 'babel-runtime/core-js/object/entries';
import _getIterator from 'babel-runtime/core-js/get-iterator';
import _JSON$stringify from 'babel-runtime/core-js/json/stringify';
import _Object$keys from 'babel-runtime/core-js/object/keys';
import _regeneratorRuntime from 'babel-runtime/regenerator';
import _defineProperty from 'babel-runtime/helpers/defineProperty';
import _extends from 'babel-runtime/helpers/extends';
import _asyncToGenerator from 'babel-runtime/helpers/asyncToGenerator';
import _Object$getPrototypeOf from 'babel-runtime/core-js/object/get-prototype-of';
import _classCallCheck from 'babel-runtime/helpers/classCallCheck';
import _createClass from 'babel-runtime/helpers/createClass';
import _possibleConstructorReturn from 'babel-runtime/helpers/possibleConstructorReturn';
import _inherits from 'babel-runtime/helpers/inherits';
import _Promise from 'babel-runtime/core-js/promise';
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import md5 from 'md5';
import URLSearchParams from 'url-search-params';
import Card from '../CardWindow';
import { CardActions } from 'material-ui/Card';
import { GridList, GridTile } from 'material-ui/GridList';
import FlatButton from 'material-ui/FlatButton';
import ImagePhotoCamera from 'material-ui/svg-icons/image/photo-camera';
import ActionDelete from 'material-ui/svg-icons/action/delete';
import { emphasize, fade } from 'material-ui/utils/colorManipulator';
import organization from '../../organization';
import debugWindow from '../../utils/debugWindow';
import { SourceFile } from '../../File/';
import fetchPonyfill from 'fetch-ponyfill';
var fetch = window.fetch ||
// for IE11
fetchPonyfill({
// TODO: use babel-runtime to rewrite this into require("babel-runtime/core-js/promise")
Promise: _Promise
}).fetch;
var ScreenShotCard = function (_PureComponent) {
_inherits(ScreenShotCard, _PureComponent);
function ScreenShotCard() {
var _ref,
_this2 = this;
var _temp, _this, _ret;
_classCallCheck(this, ScreenShotCard);
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = ScreenShotCard.__proto__ || _Object$getPrototypeOf(ScreenShotCard)).call.apply(_ref, [this].concat(args))), _this), _this.state = {
cache: {},
selected: null,
uploading: null
}, _this.handleSelect = function (event) {
var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
event.stopPropagation();
if (_this.state.selected === selected) {
selected = null; // toggle
}
_this.setState({ selected: selected });
}, _this.handleCapture = function () {
var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(event) {
var value, uploading, cache, url;
return _regeneratorRuntime.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
value = event.data.value;
uploading = md5(value);
// キャッシュを確認
if (!(uploading in _this.state.cache)) {
_context2.next = 8;
break;
}
_context2.next = 5;
return _this.props.updateCard('ScreenShotCard', { visible: true });
case 5:
_this.props.cardPropsBag.scrollToCard('ScreenShotCard');
_this.setState({ selected: uploading });
return _context2.abrupt('return');
case 8:
// アップロードの前に仮の URL を挿入
cache = _extends({}, _this.state.cache, _defineProperty({}, uploading, [value]));
_this.setState({ cache: cache, uploading: uploading }, _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
return _regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
_context.next = 2;
return _this.props.updateCard('ScreenShotCard', { visible: true });
case 2:
_this.props.cardPropsBag.scrollToCard('ScreenShotCard');
case 3:
case 'end':
return _context.stop();
}
}
}, _callee, _this2);
})));
// サムネイルをアップロード
_context2.next = 12;
return _this.uploadThumbnail(value);
case 12:
url = _context2.sent;
_context2.next = 15;
return _this.setCache(uploading, url);
case 15:
_this.setState({ uploading: null });
// サムネイルをセット
_this.setState({ selected: uploading }, _this.handleThumbnailSet);
case 17:
case 'end':
return _context2.stop();
}
}
}, _callee2, _this2);
}));
return function (_x2) {
return _ref2.apply(this, arguments);
};
}(), _this.handleThumbnailSet = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
var _this$state, selected, uploading, cache, url, ogp;
return _regeneratorRuntime.wrap(function _callee3$(_context3) {
while (1) {
switch (_context3.prev = _context3.next) {
case 0:
_this$state = _this.state, selected = _this$state.selected, uploading = _this$state.uploading, cache = _this$state.cache;
if (!(selected === uploading)) {
_context3.next = 3;
break;
}
return _context3.abrupt('return');
case 3:
url = cache[selected];
ogp = _extends({}, _this.props.getConfig('ogp'), {
'og:image': url,
'twitter:image': url
});
_context3.next = 7;
return _this.props.setConfig('ogp', ogp);
case 7:
_this.props.showNotice({
message: _this.props.localization.screenShotCard.set
});
case 8:
case 'end':
return _context3.stop();
}
}
}, _callee3, _this2);
})), _this.handleThumbnailDelete = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee4() {
var selected, keys, index, next;
return _regeneratorRuntime.wrap(function _callee4$(_context4) {
while (1) {
switch (_context4.prev = _context4.next) {
case 0:
selected = _this.state.selected;
// 選択アイテムを削除
_context4.next = 3;
return _this.setCache(selected, undefined);
case 3:
// 選択アイテムをとなりに移動
keys = _Object$keys(_this.state.cache);
index = keys.indexOf(selected);
next = keys[index + 1] || keys[index - 1] || null;
_this.setState({ selected: next });
case 7:
case 'end':
return _context4.stop();
}
}
}, _callee4, _this2);
})), _temp), _possibleConstructorReturn(_this, _ret);
}
_createClass(ScreenShotCard, [{
key: 'componentWillMount',
value: function () {
var _ref6 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee5() {
var globalEvent;
return _regeneratorRuntime.wrap(function _callee5$(_context5) {
while (1) {
switch (_context5.prev = _context5.next) {
case 0:
globalEvent = this.props.globalEvent;
globalEvent.on('message.capture', this.handleCapture);
_context5.t0 = this;
_context5.next = 5;
return this.getCache();
case 5:
_context5.t1 = _context5.sent;
_context5.t2 = {
cache: _context5.t1
};
_context5.t0.setState.call(_context5.t0, _context5.t2);
case 8:
case 'end':
return _context5.stop();
}
}
}, _callee5, this);
}));
function componentWillMount() {
return _ref6.apply(this, arguments);
}
return componentWillMount;
}()
}, {
key: 'componentWillReceiveProps',
value: function () {
var _ref7 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee6(nextProps) {
return _regeneratorRuntime.wrap(function _callee6$(_context6) {
while (1) {
switch (_context6.prev = _context6.next) {
case 0:
if (!(this.props.files !== nextProps.files)) {
_context6.next = 7;
break;
}
_context6.t0 = this;
_context6.next = 4;
return this.getCache();
case 4:
_context6.t1 = _context6.sent;
_context6.t2 = {
cache: _context6.t1
};
_context6.t0.setState.call(_context6.t0, _context6.t2);
case 7:
case 'end':
return _context6.stop();
}
}
}, _callee6, this);
}));
function componentWillReceiveProps(_x3) {
return _ref7.apply(this, arguments);
}
return componentWillReceiveProps;
}()
}, {
key: 'getCache',
value: function () {
var _ref8 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee7() {
var file;
return _regeneratorRuntime.wrap(function _callee7$(_context7) {
while (1) {
switch (_context7.prev = _context7.next) {
case 0:
file = this.props.findFile(ScreenShotCard.fileName);
_context7.prev = 1;
return _context7.abrupt('return', JSON.parse(file.text));
case 5:
_context7.prev = 5;
_context7.t0 = _context7['catch'](1);
return _context7.abrupt('return', this.state.cache);
case 8:
case 'end':
return _context7.stop();
}
}
}, _callee7, this, [[1, 5]]);
}));
function getCache() {
return _ref8.apply(this, arguments);
}
return getCache;
}()
}, {
key: 'setCache',
value: function () {
var _ref9 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee8(hash, url) {
var prevFile, next, text, nextFile, _nextFile;
return _regeneratorRuntime.wrap(function _callee8$(_context8) {
while (1) {
switch (_context8.prev = _context8.next) {
case 0:
prevFile = this.props.findFile(ScreenShotCard.fileName);
next = void 0;
try {
next = JSON.parse(prevFile.text);
} catch (e) {
next = _extends({}, this.state.cache);
}
// update data
next[hash] = url;
text = _JSON$stringify(next);
// update file
if (!prevFile) {
_context8.next = 11;
break;
}
// file is exist. replace it
nextFile = prevFile.set({ text: text });
_context8.next = 9;
return this.props.putFile(prevFile, nextFile);
case 9:
_context8.next = 14;
break;
case 11:
// file is missing. insert it
_nextFile = new SourceFile({
type: 'application/json',
name: ScreenShotCard.fileName,
text: text
});
_context8.next = 14;
return this.props.addFile(_nextFile);
case 14:
return _context8.abrupt('return', next);
case 15:
case 'end':
return _context8.stop();
}
}
}, _callee8, this);
}));
function setCache(_x4, _x5) {
return _ref9.apply(this, arguments);
}
return setCache;
}()
// 'capture' message をうけとったとき
}, {
key: 'uploadThumbnail',
value: function () {
var _ref10 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee9(data_url) {
var body, response;
return _regeneratorRuntime.wrap(function _callee9$(_context9) {
while (1) {
switch (_context9.prev = _context9.next) {
case 0:
body = new URLSearchParams();
body.append('data_url', data_url);
_context9.next = 4;
return fetch(organization.api.thumbnail, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/x-www-form-urlencoded'
},
body: body.toString(),
mode: 'cors'
});
case 4:
response = _context9.sent;
if (!response.ok) {
_context9.next = 11;
break;
}
_context9.next = 8;
return response.text();
case 8:
return _context9.abrupt('return', _context9.sent);
case 11:
_context9.next = 13;
return debugWindow(response);
case 13:
throw new Error();
case 14:
case 'end':
return _context9.stop();
}
}
}, _callee9, this);
}));
function uploadThumbnail(_x6) {
return _ref10.apply(this, arguments);
}
return uploadThumbnail;
}()
}, {
key: 'render',
value: function render() {
var _this3 = this;
var _context$muiTheme = this.context.muiTheme,
palette = _context$muiTheme.palette,
paper = _context$muiTheme.paper,
transitions = _context$muiTheme.transitions;
var _state = this.state,
selected = _state.selected,
uploading = _state.uploading;
var localization = this.props.localization;
var styles = {
root: {
backgroundColor: fade(emphasize(palette.canvasColor, 1), 0.07),
maxHeight: '50vh',
overflowX: 'hidden',
overflowY: 'scroll',
padding: 8
},
action: {
display: 'flex'
},
blank: {
flex: '1 1 auto'
},
tile: function tile(hash) {
return {
zIndex: hash === selected ? 2 : 1,
filter: hash === uploading ? 'blur(1px)' : 'blur(0px)',
opacity: hash === uploading ? 0.5 : 1,
overflow: hash === selected ? 'visible' : 'hidden',
transition: transitions.easeOut()
};
},
image: function image(file) {
return {
boxShadow: file === selected ? paper.zDepthShadows[1] : 'none',
transition: transitions.easeOut()
};
}
};
var gridList = [];
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
var _loop = function _loop() {
var _step$value = _slicedToArray(_step.value, 2),
hash = _step$value[0],
url = _step$value[1];
gridList.push(React.createElement(
GridTile,
{
key: hash,
style: styles.tile(hash),
onClick: function onClick(e) {
return _this3.handleSelect(e, hash);
}
},
React.createElement('img', { style: styles.image(hash), src: url })
));
};
for (var _iterator = _getIterator(_Object$entries(this.state.cache)), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
_loop();
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
var alreadySetImage = this.props.getConfig('ogp')['og:image'] === this.state.cache[selected];
return React.createElement(
Card,
_extends({ icon: ScreenShotCard.icon() }, this.props.cardPropsBag),
React.createElement(
GridList,
{
cellHeight: 180,
style: styles.root,
onClick: function onClick(event) {
return _this3.handleSelect(event, null);
}
},
gridList
),
React.createElement(
CardActions,
{ style: styles.action },
React.createElement(FlatButton, {
label: localization.screenShotCard.coverImage,
disabled: !selected || alreadySetImage,
onClick: this.handleThumbnailSet
}),
React.createElement('div', { style: styles.blank }),
React.createElement(FlatButton, {
label: '',
icon: React.createElement(ActionDelete, null),
disabled: !selected,
onClick: this.handleThumbnailDelete
})
)
);
}
}, {
key: 'search',
get: function get() {
try {
var _ref11 = new URL(this.props.deployURL),
pathname = _ref11.pathname;
return pathname.split('/').pop();
} catch (e) {
return null;
}
}
}], [{
key: 'icon',
value: function icon() {
return React.createElement(ImagePhotoCamera, null);
}
}]);
return ScreenShotCard;
}(PureComponent);
ScreenShotCard.propTypes = {
cardPropsBag: PropTypes.object.isRequired,
files: PropTypes.array.isRequired,
findFile: PropTypes.func.isRequired,
getConfig: PropTypes.func.isRequired,
setConfig: PropTypes.func.isRequired,
showNotice: PropTypes.func.isRequired,
addFile: PropTypes.func.isRequired,
putFile: PropTypes.func.isRequired,
deployURL: PropTypes.string,
localization: PropTypes.object.isRequired,
updateCard: PropTypes.func.isRequired,
globalEvent: PropTypes.object.isRequired
};
ScreenShotCard.contextTypes = {
muiTheme: PropTypes.object.isRequired
};
ScreenShotCard.fileName = 'feeles/capture.json';
export default ScreenShotCard;