UNPKG

graft-react

Version:

react admin and helper components for graft-db

340 lines (339 loc) 16.4 kB
"use strict"; var __extends = (this && this.__extends) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t; return { next: verb(0), "throw": verb(1), "return": verb(2) }; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [0, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; var React = require("react"); ; var debounce = require("lodash.debounce"); var utils_1 = require("../utils"); var graft_db_1 = require("graft-db"); var WithClient_1 = require("./WithClient"); var modal_1 = require("../modal"); var draft_js_1 = require("draft-js"); var Immutable = require("immutable"); var Buttons_1 = require("react-md/lib/Buttons"); var MenuButton_1 = require("react-md/lib/Menus/MenuButton"); var FontIcons_1 = require("react-md/lib/FontIcons"); var Toolbars_1 = require("react-md/lib/Toolbars"); var SelectFields_1 = require("react-md/lib/SelectFields"); var ListItem_1 = require("react-md/lib/Lists/ListItem"); var Link = function (_a) { var entityKey = _a.entityKey, children = _a.children; var url = draft_js_1.Entity.get(entityKey).getData().url; return React.createElement("a", { href: url }, children); }; var NodeLink = function (_a) { var entityKey = _a.entityKey, children = _a.children; var id = draft_js_1.Entity.get(entityKey).getData().id; return React.createElement("a", { href: "#node:" + id }, children); }; function isType() { var types = []; for (var _i = 0; _i < arguments.length; _i++) { types[_i] = arguments[_i]; } return function (contentBlock, callback) { contentBlock.findEntityRanges(function (character) { var key = character.getEntity(); if (key === null) { return false; } var entity = draft_js_1.Entity.get(key); if (!entity) { return false; } return !!utils_1.find(types, function (t) { return t == entity.getType(); }); }, callback); }; } var decorator = new draft_js_1.CompositeDecorator([ { strategy: isType('NODE_LINK'), component: NodeLink, }, { strategy: isType('LINK'), component: Link, }, ]); var BLOCK_TYPES = [ { name: 'Normal', type: 'unstyled', className: 'editor-normal' }, { name: 'Heading', type: 'header-one', className: 'editor-heading-one' }, { name: 'Subheading', type: 'header-two', className: 'editor-heading-two' }, { name: 'Small', type: 'small', className: 'editor-small' }, { name: 'Quote', type: 'blockquote', className: 'editor-quote' }, { name: 'List', type: 'unordered-list-item', className: 'editor-list-item' }, ]; var MediaBlock = function (props) { var entity = draft_js_1.Entity.get(props.block.getEntityAt(0)); var _a = entity.getData(), src = _a.src, id = _a.id; var type = entity.getType(); var media; if (type === 'IMAGE') { media = React.createElement("img", { id: id, src: src, width: '100', height: '100' }); } else if (type === 'VIDEO') { media = React.createElement("span", null, "[VIDEO]"); } else { media = React.createElement("span", null, "[", type, ":ATOM]"); } return media; }; var blockRenderMap = draft_js_1.DefaultDraftBlockRenderMap.merge(Immutable.Map({ 'small': { element: 'div' } })); function blockRendererFn(block) { if (block.getType() === 'atomic') { return { component: MediaBlock, editable: false, }; } return null; } function getClassNameForBlock(contentBlock) { var type = contentBlock.getType(); var blockType = utils_1.find(BLOCK_TYPES, function (b) { return b.type == type; }); if (blockType) { return blockType.className; } return ''; } var RichTextProperty = (function (_super) { __extends(RichTextProperty, _super); function RichTextProperty() { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } var _this = _super.apply(this, args) || this; _this.save = debounce(function () { return __awaiter(_this, void 0, void 0, function () { var client, _a, object, property, value, editorState, v, args; return __generator(this, function (_b) { switch (_b.label) { case 0: client = this.context.client; _a = this.props, object = _a.object, property = _a.property, value = _a.value; editorState = this.state.editorState; if (!editorState) { return [2 /*return*/]; } v = JSON.stringify(draft_js_1.convertToRaw(editorState.getCurrentContent())); return [4 /*yield*/, client.storeValue({ id: value ? value.id : null, owner: object.id, property: property.id, }, v)]; case 1: args = _b.sent(); return [4 /*yield*/, client.setValue(args)]; case 2: _b.sent(); return [2 /*return*/]; } }); }); }, 750); _this.setEditorState = function (editorState) { var oldValue = JSON.stringify(draft_js_1.convertToRaw(_this.getEditorState().getCurrentContent())); var newValue = JSON.stringify(draft_js_1.convertToRaw(editorState.getCurrentContent())); _this.setState({ editorState: editorState }, function () { if (newValue == oldValue) { return; } _this.save(); _this.focus(); }); }; _this.resetEditorState = function () { var editorState = draft_js_1.EditorState.createEmpty(decorator); _this.setState({ editorState: editorState }); }; _this.onClickBold = function (e) { e.preventDefault(); var editorState = _this.getEditorState(); _this.setEditorState(draft_js_1.RichUtils.toggleInlineStyle(editorState, 'BOLD')); }; _this.onClickItalic = function (e) { e.preventDefault(); var editorState = _this.getEditorState(); _this.setEditorState(draft_js_1.RichUtils.toggleInlineStyle(editorState, 'ITALIC')); }; _this.changeBlockStyle = function (type) { console.log(type); var editorState = _this.getEditorState(); _this.setEditorState(draft_js_1.RichUtils.toggleBlockType(editorState, type)); }; _this.focus = function () { if (!_this.ref) { return; } _this.ref.focus(0); }; _this.setLink = function () { return __awaiter(_this, void 0, void 0, function () { var url, key, editorState; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, modal_1.prompt('Enter URL')]; case 1: url = _a.sent(); if (!url) { return [2 /*return*/]; } key = draft_js_1.Entity.create('LINK', 'MUTABLE', { url: url }); editorState = this.getEditorState(); this.setEditorState(draft_js_1.RichUtils.toggleLink(editorState, editorState.getSelection(), key)); return [2 /*return*/]; } }); }); }; _this.setImg = function () { return __awaiter(_this, void 0, void 0, function () { var src, editorState, entityKey; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, modal_1.prompt('Enter image url:')]; case 1: src = _a.sent(); editorState = this.getEditorState(); entityKey = draft_js_1.Entity.create('IMAGE', 'IMMUTABLE', { src: src }); this.setEditorState(draft_js_1.AtomicBlockUtils.insertAtomicBlock(editorState, entityKey, ' ')); return [2 /*return*/]; } }); }); }; _this.handleKeyCommand = function (command) { var editorState = _this.getEditorState(); var newState = draft_js_1.RichUtils.handleKeyCommand(editorState, command); if (newState) { _this.setEditorState(newState); return true; } return false; }; _this.keyBindings = function (e) { return draft_js_1.getDefaultKeyBinding(e); }; _this.onTab = function (e) { e.preventDefault(); var editorState = _this.getEditorState(); _this.setEditorState(draft_js_1.RichUtils.onTab(e, editorState, 2)); }; _this.setRef = function (ref) { _this.ref = ref; }; _this.raise = function (raised) { _this.setState({ raised: raised }); }; _this.state = { editorState: null, raised: false, }; return _this; } RichTextProperty.prototype.getEditorState = function () { var editorState = this.state.editorState; if (editorState) { return editorState; } var value = this.props.value; if (value && value.jsonValue) { try { return draft_js_1.EditorState.createWithContent(draft_js_1.convertFromRaw(JSON.parse(value.jsonValue)), decorator); } catch (err) { console.warn('bad rich text value', err); } } return draft_js_1.EditorState.createEmpty(decorator); }; RichTextProperty.prototype.renderEditor = function () { var editorState = this.getEditorState(); var selection = editorState.getSelection(); var blockType = editorState .getCurrentContent() .getBlockForKey(selection.getStartKey()) .getType(); var blockItem = utils_1.find(BLOCK_TYPES, function (t) { return t.type == blockType; }); var property = this.props.property; var raised = this.state.raised; var nav = React.createElement(Buttons_1.default, { icon: true, disabled: true }, utils_1.propertyIconName(graft_db_1.PropertyType.RichText)); var actions = [ React.createElement(SelectFields_1.default, { id: 'block-types', itemLabel: 'name', itemValue: 'type', menuItems: BLOCK_TYPES.map(function (_a) { var name = _a.name, type = _a.type; return ({ name: name, type: type }); }), position: SelectFields_1.default.Positions.BELOW, onChange: this.changeBlockStyle, value: blockItem ? blockItem.type : 'unstyled' }), React.createElement(MenuButton_1.default, { id: 'more-btn', buttonChildren: 'more_vert', icon: true, onClick: this.focus, onMenuToggle: this.raise }, React.createElement(ListItem_1.default, { onClick: this.onClickBold, primaryText: 'Bold', leftIcon: React.createElement(FontIcons_1.default, null, "format_bold") }), React.createElement(ListItem_1.default, { onClick: this.onClickItalic, primaryText: 'Italic', leftIcon: React.createElement(FontIcons_1.default, null, "format_italic") }), React.createElement(ListItem_1.default, { onClick: this.setImg, primaryText: 'Insert Image', leftIcon: React.createElement(FontIcons_1.default, null, "insert_photo") }), React.createElement(ListItem_1.default, { onClick: this.setLink, primaryText: 'Insert Link', leftIcon: React.createElement(FontIcons_1.default, null, "link") }), React.createElement(ListItem_1.default, { primaryText: "Clear Formatting", leftIcon: React.createElement(FontIcons_1.default, null, "format_clear") })), React.createElement(Buttons_1.default, { icon: true, tooltipLabel: property.hint, tooltipPosition: 'left' }, "help"), ]; return (React.createElement("div", { className: 'md-cell md-cell--12' }, React.createElement("div", null, React.createElement(Toolbars_1.default, { singleColor: true, themed: true, nav: nav, title: property.name, actions: actions, className: 'property-toolbar', style: { zIndex: raised ? 20 : null } }), React.createElement("div", { className: 'property-field' }, React.createElement(draft_js_1.Editor, { ref: this.setRef, stripPastedStyles: true, spellCheck: true, editorState: editorState, onChange: this.setEditorState, handleKeyCommand: this.handleKeyCommand, blockStyleFn: getClassNameForBlock, blockRenderMap: blockRenderMap, blockRendererFn: blockRendererFn, keyBindingFn: this.keyBindings, onTab: this.onTab }))))); }; RichTextProperty.prototype.renderResetMessage = function () { return React.createElement("div", null, React.createElement("div", null, "The rich text content is corrupt."), React.createElement("div", null, "An error was raised while attempting to draw the content:"), React.createElement(Buttons_1.default, { raised: true, label: 'reset data', onClick: this.resetEditorState }), React.createElement("div", { className: 'editor-small' }, "Resetting data will lose any content you have")); }; RichTextProperty.prototype.render = function () { try { return this.renderEditor(); } catch (e) { return this.renderResetMessage(); } }; return RichTextProperty; }(React.Component)); RichTextProperty.contextTypes = WithClient_1.clientContextTypes; exports.RichTextProperty = RichTextProperty;