├── .babelrc ├── .eslintrc ├── .flowconfig ├── .gitignore ├── .jsbeautifyrc ├── LICENSE ├── README.cn.md ├── README.md ├── build ├── 244e07c1f99aeefcb66fe01d003258a1.ttf ├── 57a86336bae65701daadc7cd36eb7bf5.eot ├── 61dd1f869f150b36c5946f1f9b631ce7.woff ├── 9e74c39d82e9adee5e6424efc94c3e18.svg ├── bundle.js ├── f0e15ca006c92aecf8c223729df02105.svg └── index.html ├── java_demo └── getQiniuUptoken.java ├── package.json ├── publish ├── .DS_Store ├── README.md ├── editor │ ├── components.css │ ├── config │ │ └── colorStyleMap.js │ ├── decorators │ │ ├── AudioDecorator.js │ │ ├── AudioSpan.js │ │ ├── ImageDecorator.js │ │ ├── ImageSpan.js │ │ ├── LinkDecorator.js │ │ ├── VideoDecorator.js │ │ ├── VideoSpan.js │ │ ├── decoratorStyle.css │ │ └── index.js │ ├── helpers │ │ ├── combineOrderedStyles.js │ │ ├── normalizeAttributes.js │ │ └── styleToCSS.js │ ├── index.js │ ├── toolBar │ │ ├── alignmentControls.js │ │ ├── autoSave.js │ │ ├── autoSaveList.js │ │ ├── blockSelectorControls.js │ │ ├── blockStyleControls.js │ │ ├── colorButton.js │ │ ├── colorControls.js │ │ ├── cookieControls.js │ │ ├── index.js │ │ ├── inlineStyleControls.js │ │ ├── mediaImageUploader.js │ │ ├── medioAudioUploader.js │ │ ├── medioVideoUploader.js │ │ ├── pasteNoStyleControls.js │ │ ├── removeStyleControls.js │ │ ├── styleButton.js │ │ ├── undoredoControls.js │ │ └── urlControls.js │ └── utils │ │ ├── ExtendedRichUtils.js │ │ ├── colorConfig.js │ │ ├── getCurrentlySelectedBlock.js │ │ ├── index.js │ │ ├── stateFromElement │ │ ├── main.js │ │ └── replaceTextWithMeta.js │ │ ├── stateFromHTML │ │ ├── main.js │ │ └── parseHTML.js │ │ ├── stateFromMD │ │ ├── MarkdownParser.js │ │ └── main.js │ │ ├── stateToHTML │ │ └── main.js │ │ ├── stateToMD │ │ └── main.js │ │ └── stateUtils │ │ ├── Constants.js │ │ ├── callModifierForSelectedBlocks.js │ │ ├── combineOrderedStyles.js │ │ ├── getEntityRanges.js │ │ ├── getSelectedBlocks.js │ │ ├── main.js │ │ ├── normalizeAttributes.js │ │ ├── selectionContainsEntity.js │ │ └── styleToCSS.js ├── global │ ├── components │ │ ├── businessComponents.js │ │ └── businessComponents │ │ │ ├── GroupUpload.js │ │ │ └── UploadImage.js │ ├── i18n.js │ └── supports │ │ ├── datas │ │ ├── base.js │ │ └── url.js │ │ ├── methods │ │ ├── Request.js │ │ ├── common.js │ │ └── public.js │ │ ├── publicDatas.js │ │ └── resources │ │ ├── blur.svg │ │ ├── custom.css │ │ ├── default.less │ │ ├── default │ │ ├── demo.css │ │ ├── demo_fontclass.html │ │ ├── demo_symbol.html │ │ ├── demo_unicode.html │ │ ├── iconfont.css │ │ ├── iconfont.eot │ │ ├── iconfont.js │ │ ├── iconfont.svg │ │ ├── iconfont.ttf │ │ └── iconfont.woff │ │ ├── iconfont.css │ │ ├── system.css │ │ └── system.less ├── index.js ├── main.js ├── package.json └── test.js ├── src ├── editor │ ├── components.css │ ├── config │ │ └── colorStyleMap.jsx │ ├── decorators │ │ ├── AudioDecorator.jsx │ │ ├── AudioSpan.jsx │ │ ├── ImageDecorator.jsx │ │ ├── ImageSpan.jsx │ │ ├── LinkDecorator.jsx │ │ ├── VideoDecorator.jsx │ │ ├── VideoSpan.jsx │ │ ├── decoratorStyle.css │ │ └── index.js │ ├── helpers │ │ ├── combineOrderedStyles.js │ │ ├── normalizeAttributes.js │ │ └── styleToCSS.js │ ├── index.jsx │ ├── toolBar │ │ ├── alignmentControls.jsx │ │ ├── autoSave.jsx │ │ ├── autoSaveList.jsx │ │ ├── blockSelectorControls.jsx │ │ ├── blockStyleControls.jsx │ │ ├── colorButton.jsx │ │ ├── colorControls.jsx │ │ ├── cookieControls.jsx │ │ ├── index.js │ │ ├── inlineStyleControls.jsx │ │ ├── mediaImageUploader.jsx │ │ ├── medioAudioUploader.jsx │ │ ├── medioVideoUploader.jsx │ │ ├── pasteNoStyleControls.jsx │ │ ├── removeStyleControls.jsx │ │ ├── styleButton.jsx │ │ ├── undoredoControls.jsx │ │ └── urlControls.jsx │ └── utils │ │ ├── ExtendedRichUtils.js │ │ ├── colorConfig.js │ │ ├── getCurrentlySelectedBlock.js │ │ ├── index.js │ │ ├── stateFromElement │ │ ├── main.js │ │ └── replaceTextWithMeta.js │ │ ├── stateFromHTML │ │ ├── main.js │ │ └── parseHTML.js │ │ ├── stateFromMD │ │ ├── MarkdownParser.js │ │ └── main.js │ │ ├── stateToHTML │ │ └── main.js │ │ ├── stateToMD │ │ └── main.js │ │ └── stateUtils │ │ ├── Constants.js │ │ ├── callModifierForSelectedBlocks.js │ │ ├── combineOrderedStyles.js │ │ ├── getEntityRanges.js │ │ ├── getSelectedBlocks.js │ │ ├── main.js │ │ ├── normalizeAttributes.js │ │ ├── selectionContainsEntity.js │ │ └── styleToCSS.js ├── global │ ├── components │ │ ├── businessComponents.js │ │ └── businessComponents │ │ │ ├── GroupUpload.jsx │ │ │ └── UploadImage.jsx │ ├── i18n.js │ └── supports │ │ ├── datas │ │ ├── base.js │ │ └── url.jsx │ │ ├── methods │ │ ├── Request.jsx │ │ ├── common.jsx │ │ └── public.jsx │ │ ├── publicDatas.js │ │ └── resources │ │ ├── blur.svg │ │ ├── custom.css │ │ ├── customiconfont.less │ │ ├── default │ │ ├── iconfont.css │ │ ├── iconfont.eot │ │ ├── iconfont.js │ │ ├── iconfont.svg │ │ ├── iconfont.ttf │ │ └── iconfont.woff │ │ ├── iconfont.css │ │ ├── system.css │ │ └── system.less ├── index.js ├── main.js └── test.jsx ├── webpack.config.js ├── webpack.release.config.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "react-hot-loader/babel", 4 | "transform-class-properties" 5 | ], 6 | "presets": [ 7 | ["es2015", {"loose" : true}], 8 | "stage-2", 9 | "react" 10 | ], 11 | "env": { 12 | "development": { 13 | "plugins": [ 14 | ["react-transform", { 15 | "transforms": [{ 16 | "transform": "react-transform-hmr", 17 | "imports": ["react"], 18 | "locals": ["module"] 19 | }, { 20 | "transform": "react-transform-catch-errors", 21 | "imports": ["react", "redbox-react"] 22 | }] 23 | }] 24 | ] 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": [ 4 | "airbnb" 5 | ], 6 | "globals": { 7 | "_": false, 8 | "enquire": false, 9 | "Raven": false 10 | }, 11 | "env": { 12 | "browser": true, 13 | "node": true 14 | }, 15 | "rules": { 16 | "comma-dangle": 0, 17 | "max-len": 0, 18 | "jsx-quotes": [2, "prefer-single"], 19 | "generator-star-spacing": 0, 20 | "no-plusplus": ["error", { "allowForLoopAfterthoughts": true }], 21 | "import/no-dynamic-require": 0, 22 | "class-methods-use-this": 0, 23 | "function-paren-newline": 0, 24 | "react/jsx-no-bind": 0, 25 | "react/prefer-stateless-function": 0, 26 | "react/jsx-filename-extension": 0, 27 | "react/forbid-prop-types": 0, 28 | "jsx-a11y/anchor-is-valid": 0, 29 | "react/sort-comp": 0, 30 | "prefer-destructuring": 0, 31 | "react/require-default-props": 0, 32 | "import/no-extraneous-dependencies": 0, 33 | "import/extensions": 0, 34 | "import/no-unresolved": 0 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | .*/node_modules/ 3 | .*/build/.* 4 | .*/.idea/.* 5 | .*/.git/.* 6 | .*/.global/.* 7 | 8 | [include] 9 | ./src/editor/utils 10 | 11 | [libs] 12 | ./node_modules/flow-bin/ 13 | 14 | [options] 15 | module.system=haste 16 | esproposal.class_static_fields=enable 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | dist/* 3 | release/* 4 | node_modules/* 5 | npm-debug.log 6 | npm-debug.log.* 7 | *.ts 8 | -------------------------------------------------------------------------------- /.jsbeautifyrc: -------------------------------------------------------------------------------- 1 | { 2 | "html": { 3 | "allowed_file_extensions": ["htm", "html", "xhtml", "shtml", "xml", "svg"], 4 | "brace_style": "collapse", 5 | "end_with_newline": false, 6 | "indent_char": " ", 7 | "indent_handlebars": false, 8 | "indent_inner_html": false, 9 | "indent_scripts": "keep", 10 | "indent_size": 2, 11 | "max_preserve_newlines": 0, 12 | "preserve_newlines": true, 13 | "unformatted": ["a", "span", "img", "code", "pre", "sub", "sup", "em", "strong", "b", "i", "u", "strike", "big", 14 | "small", "pre", "h1", "h2", "h3", "h4", "h5", "h6"], 15 | "wrap_line_length": 120 16 | }, 17 | "css": { 18 | "allowed_file_extensions": ["css", "scss", "sass", "less"], 19 | "end_with_newline": false, 20 | "indent_char": " ", 21 | "indent_size": 2, 22 | "newline_between_rules": true, 23 | "selector_separator_newline": true 24 | }, 25 | "js": { 26 | "allowed_file_extensions": ["js", "jsx", "json", "eslintrc", "jsbeautifyrc"], 27 | "brace_style": "collapse", 28 | "break_chained_methods": false, 29 | "comma_first": false, 30 | "e4x": false, 31 | "end_with_newline": false, 32 | "indent_char": " ", 33 | "indent_level": 0, 34 | "indent_size": 2, 35 | "jslint_happy": false, 36 | "keep_array_indentation": false, 37 | "keep_function_indentation": false, 38 | "max_preserve_newlines": 0, 39 | "preserve_newlines": true, 40 | "space_after_anon_function": false, 41 | "space_before_conditional": false, 42 | "space_in_empty_paren": false, 43 | "space_in_paren": false, 44 | "unescape_strings": false, 45 | "wrap_line_length": 120 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Li Zhen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /build/244e07c1f99aeefcb66fe01d003258a1.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaen/react-lz-editor/5097a8a57ac919afab3da11ad10e076bfdf4be24/build/244e07c1f99aeefcb66fe01d003258a1.ttf -------------------------------------------------------------------------------- /build/57a86336bae65701daadc7cd36eb7bf5.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaen/react-lz-editor/5097a8a57ac919afab3da11ad10e076bfdf4be24/build/57a86336bae65701daadc7cd36eb7bf5.eot -------------------------------------------------------------------------------- /build/61dd1f869f150b36c5946f1f9b631ce7.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaen/react-lz-editor/5097a8a57ac919afab3da11ad10e076bfdf4be24/build/61dd1f869f150b36c5946f1f9b631ce7.woff -------------------------------------------------------------------------------- /build/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | react-lz-editor demo page 8 | 9 | 10 |
11 | https://github.com/leejaen/react-lz-editor 12 |
13 | 14 |
15 |
16 |

react-lz-editor

17 |

An open source rich react editor based on draft-Js and ant design, good support for HTML, markdown and Draft Raw format.

18 |

一款支持 HTML\ markdown\ draft Raw 格式的 react 富文本编辑器,基于 draft-Js 和 ant-design 实现。

19 |

Install

20 |

npm install react-lz-editor --save

21 |

Git

22 |

git+ssh://git@github.com/leejaen/react-lz-editor.git

23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-lz-editor", 3 | "version": "1.0.3", 4 | "description": "An open source react editor based on draft-Js and ant design, good support HTML, markdown and Draft Raw format.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "build": "webpack", 9 | "typecheck": "flow", 10 | "dev": "webpack-dev-server --port 4000 --devtool eval --progress --colors --hot --content-base build && lessc src/global/supports/resources/system.less src/global/supports/resources/system.css", 11 | "release": "webpack -p --progress --colors --config webpack.release.config.js", 12 | "publish": "babel -d publish/ src/ --no-comments && lessc src/global/supports/resources/system.less publish/global/supports/resources/system.css" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "git+ssh://git@github.com/leejaen/react-lz-editor.git" 17 | }, 18 | "keywords": [ 19 | "react-editor", 20 | "draft-js", 21 | "draftjs", 22 | "react-rich-editor", 23 | "react-text-editor", 24 | "react-lz-editor", 25 | "contenteditable", 26 | "richtext", 27 | "editor" 28 | ], 29 | "author": "leejaen@gmail.com", 30 | "license": "ISC", 31 | "bugs": { 32 | "url": "https://github.com/leejaen/react-lz-editor/issues" 33 | }, 34 | "homepage": "https://github.com/leejaen/react-lz-editor#readme", 35 | "devDependencies": { 36 | "babel-cli": "^6.6.5", 37 | "babel-loader": "^6.2.4", 38 | "babel-plugin-import": "^1.1.1", 39 | "babel-plugin-transform-class-properties": "^6.19.0", 40 | "babel-preset-es2015": "^6.6.0", 41 | "babel-preset-react": "^6.16.0", 42 | "babel-preset-stage-2": "^6.18.0", 43 | "css-loader": "^0.23.1", 44 | "eslint": "^3.12.2", 45 | "eslint-plugin-react": "^6.8.0", 46 | "file-loader": "^0.8.5", 47 | "flow-bin": "^0.37.4", 48 | "less": "^2.7.2", 49 | "less-loader": "^2.2.3", 50 | "style-loader": "^0.13.1", 51 | "url-loader": "^0.5.7", 52 | "webpack": "^1.12.14", 53 | "webpack-dev-server": "^1.14.1", 54 | "hmacsha1": "^1.0.0", 55 | "md5": "^2.2.1" 56 | }, 57 | "dependencies": { 58 | "antd": "^2.8.3", 59 | "draft-js": "^0.10.0", 60 | "immutable": "^3.8.1", 61 | "js-base64": "^2.1.9", 62 | "lodash": "^4.17.3", 63 | "react": "^15.4.2", 64 | "react-dom": "^15.4.2", 65 | "synthetic-dom": "^0.2.1", 66 | "whatwg-fetch": "^2.0.3" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /publish/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaen/react-lz-editor/5097a8a57ac919afab3da11ad10e076bfdf4be24/publish/.DS_Store -------------------------------------------------------------------------------- /publish/README.md: -------------------------------------------------------------------------------- 1 | [中文](https://github.com/leejaen/react-lz-editor/blob/master/README.cn.md) 2 | 3 | # react-lz-editor 4 | 5 | An open source react rich-text editor ( mordern react editor includes media support such as texts, images, videos, audios, links etc. ), development based on Draft-Js and Ant-design, good support html, markdown, draft-raw mode. It's supports multiple languages well(English, Chinese and Russian for now) and welcome you add your language supports. 6 | 7 | ## Live demo 8 | 9 | [react-lz-editor:](https://leejaen.github.io/react-lz-editor/index.html) https://leejaen.github.io/react-lz-editor/index.html 10 | 11 | Disabled media insert feature on demo page, because of there was no online API support for the time being, here is [The server side API demo in java](https://github.com/leejaen/react-lz-editor/blob/master/java_demo/getQiniuUptoken.java) you may want. 12 | 13 | # Install 14 | ``` 15 | npm install react-lz-editor --save 16 | OR 17 | yarn add react-lz-editor 18 | ``` 19 | 20 | Version note: React 15.4.2+ and react-dom 15.4.2+ is required. Antd version at least from 2.8.3 in your project is recommended. 21 | 22 | # Git 23 | git+ssh://git@github.com/leejaen/react-lz-editor.git 24 | 25 | # Usage & Examples 26 | 27 | [clicking to code example](https://github.com/leejaen/react-lz-editor/blob/master/src/test.jsx) 28 | 29 | ``` js 30 | import React from 'react'; 31 | import ReactDOM from 'react-dom'; 32 | import LzEditor from './editor/index.jsx' 33 | class Test extends React.Component { 34 | constructor(props) { 35 | super(props); 36 | this.state = { 37 | htmlContent: `

Yankees, Peeking at the Red Sox, Will Soon Get an Eyeful

38 |

Whenever Girardi stole a glance, there was rarely any good news for the Yankees. While Girardi’s charges were clawing their way to a split of their four-game series against the formidable Indians, the Boston Red Sox were plowing past the rebuilding Chicago White Sox, sweeping four games at Fenway Park.

`, 39 | markdownContent: "## HEAD 2 \n markdown examples \n ``` welcome ```" 40 | responseList: [] 41 | } 42 | this.receiveHtml=this.receiveHtml.bind(this); 43 | } 44 | receiveHtml(content) { 45 | console.log("recieved HTML content", content); 46 | this.setState({responseList:[]}); 47 | } 48 | render() { 49 | let policy = ""; 50 | const uploadProps = { 51 | action: "http://v0.api.upyun.com/devopee", 52 | onChange: this.onChange, 53 | listType: 'picture', 54 | fileList: this.state.responseList, 55 | data: (file) => { 56 | 57 | }, 58 | multiple: true, 59 | beforeUpload: this.beforeUpload, 60 | showUploadList: true 61 | } 62 | return ( 63 |
64 |
Editor demo 1 (use default html format ): 65 |
66 | 68 |
69 |
Editor demo 2 (use markdown format ): 70 |
71 | 79 |
80 | ); 81 | } 82 | } 83 | 84 | ReactDOM.render( 85 | , document.getElementById('test')); 86 | 87 | ``` 88 | 89 | ![screenshot](https://image.qiluyidian.mobi/54541628992197066868.png) 90 | 91 | # API 92 | | props | type | default | description | 93 | | -- | -- | -- | -- | 94 | | active | bool | false | Is reloading content after changing | 95 | | importContent | string | "" | Editor content value, default to "" | 96 | | lang | string | "" | Editor using language, default to your browser language settings | 97 | | cbReceiver | function | null | `Callback` function, the changed value will be sent to its parameter. | 98 | | undoRedo | bool | true | Enabled `undo and redo` feature, default to true | 99 | | removeStyle | bool | true | Enabled `remove style` feature, default to true | 100 | | pasteNoStyle | bool | true | Enabled `paste plan text` feature, default to true | 101 | | blockStyle | bool | true | Enabled `block style (H1,ol,pre etc.)` feature, default to true | 102 | | alignment | bool | true | Enabled `text alignment` feature, default to true | 103 | | inlineStyle | bool | true | Enabled `inline style (bold, italic, underline etc.)` feature, default to true | 104 | | color | bool | true | Enabled `color text` feature, default to true | 105 | | image | bool | true | Enabled `insert image` feature, default to true | 106 | | video | bool | true | Enabled `insert video` feature, default to true | 107 | | audio | bool | true | Enabled `insert audio` feature, default to true | 108 | | urls | bool | true | Enabled `add hyper link` feature, default to true | 109 | | autoSave | bool | true | Enabled `auto save to draft-box` feature, default to true | 110 | | fullScreen | bool | true | Enabled `full screen` feature, default to true | 111 | | convertFormat | string | "html" | Set support format `(html, markdown, raw)`, default to "html" | 112 | | disabled | bool | false | Disabled editor or not | 113 | | uploadProps | object | null | Customize uploading settings. [API: Antd.Upload](https://ant.design/components/upload/) | 114 | -------------------------------------------------------------------------------- /publish/editor/components.css: -------------------------------------------------------------------------------- 1 | 2 | .editorHidden{ 3 | z-index: 10; 4 | overflow: hidden; 5 | position: relative; 6 | } 7 | .editor_container { 8 | border: 1px solid #E9E9E9; 9 | background-color: #F9F9F9; 10 | padding: 5px; 11 | } 12 | 13 | .editor_top { 14 | height: 30px; 15 | width: 100%; 16 | } 17 | 18 | .editor_middle { 19 | background-color: #FFF; 20 | border: 1px solid #E9E9E9; 21 | box-shadow: 3px 3px 5px #AAA inset; 22 | } 23 | 24 | .editor_bottom { 25 | height: 30px; 26 | width: 100%; 27 | } 28 | 29 | .superFancyBlockquote { 30 | color: #999; 31 | font-style: italic; 32 | text-align: center; 33 | } 34 | 35 | .RichEditor-root { 36 | background: #FFF; 37 | border: 1px solid #DDD; 38 | font-size: 14px; 39 | padding: 15px; 40 | } 41 | 42 | .RichEditor-editor { 43 | border-top: 1px solid #DDD; 44 | cursor: text; 45 | font-size: 16px; 46 | } 47 | 48 | .public-DraftStyleDefault-ul { 49 | list-style: disc; 50 | padding-left: 2.0rem 51 | } 52 | 53 | .public-DraftStyleDefault-ol { 54 | padding-left: 2.0rem; 55 | list-style-type: decimal; 56 | counter-reset: ol-counter; 57 | } 58 | 59 | .public-DraftStyleDefault-ol:before { 60 | content: counter(ol-counter); 61 | counter-increment: ol-counter; 62 | } 63 | 64 | .RichEditor-editor .public-DraftEditorPlaceholder-root, 65 | .RichEditor-editor .public-DraftEditor-content { 66 | margin: 0 -15px -15px; 67 | padding: 15px; 68 | } 69 | 70 | .RichEditor-editor .public-DraftEditor-content { 71 | min-height: 400px; 72 | line-height: initial; 73 | } 74 | 75 | .public-DraftEditor-content>div>* { 76 | margin: 10px 0; 77 | } 78 | 79 | .public-DraftEditor-content pre { 80 | white-space: pre-wrap; 81 | word-wrap: break-word; 82 | } 83 | 84 | .RichEditor-hidePlaceholder .public-DraftEditorPlaceholder-root { 85 | display: none; 86 | } 87 | 88 | .RichEditor-editor .RichEditor-blockquote { 89 | border-left: 5px solid #EEE; 90 | color: #666; 91 | font-family: 'Hoefler Text', 'Georgia', serif; 92 | font-style: italic; 93 | margin: 16px 0; 94 | padding: 10px 20px; 95 | } 96 | 97 | .RichEditor-editor .RichEditor-alignment-left { 98 | text-align: left; 99 | } 100 | 101 | .RichEditor-editor .RichEditor-alignment-center { 102 | text-align: center; 103 | } 104 | 105 | .RichEditor-editor .RichEditor-alignment-right { 106 | text-align: right; 107 | } 108 | 109 | .RichEditor-editor .RichEditor-alignment-justify { 110 | text-align: justify; 111 | } 112 | 113 | .RichEditor-editor .public-DraftStyleDefault-pre { 114 | background-color: rgba(0, 0, 0, 0.05); 115 | font-family: 'Inconsolata', 'Menlo', 'Consolas', monospace; 116 | font-size: 16px; 117 | padding: 20px; 118 | } 119 | 120 | .RichEditor-controls { 121 | font-family: 'Helvetica', sans-serif; 122 | font-size: 14px; 123 | margin-bottom: 5px; 124 | user-select: none; 125 | display: inline; 126 | border-left: 1px solid #EEE; 127 | } 128 | 129 | .RichEditor-controls-split { 130 | padding-right: 20px 131 | } 132 | 133 | .RichEditor-color span { 134 | margin: 0; 135 | width: 16px; 136 | line-height: 28px; 137 | } 138 | 139 | .RichEditor-styleButton { 140 | color: #999; 141 | cursor: pointer; 142 | margin: 0 8px; 143 | padding: 3px 5px !important; 144 | display: inline-block; 145 | position: relative; 146 | margin: 8px 5px; 147 | line-height: 20px; 148 | font-size: 16px; 149 | } 150 | .RichEditor-styleButton.ant-btn.ant-btn-primary.ant-btn-icon-only{ 151 | color: #fff; 152 | } 153 | 154 | .RichEditor-styleButton i.anticon { 155 | margin-left: 0px !important; 156 | } 157 | .RichEditor-activeButton { 158 | color: #fff; 159 | border-radius: 5px; 160 | } 161 | 162 | .RichEditor-color { 163 | display: inline-block; 164 | height: 16px; 165 | width: 16px; 166 | overflow: hidden; 167 | top: 3px; 168 | position: relative; 169 | border-radius: 3px; 170 | margin: 0px 5px; 171 | } 172 | 173 | .RichEditor-color-active {} 174 | 175 | .RichEditor-color:nth-child(2n+1) {} 176 | 177 | #text-editor-affix>.ant-affix{background-color:#fff!important;} 178 | .disabled-mask { 179 | background: rgba(200,200,200,0.5); 180 | width: 100%; 181 | height: 100%; 182 | top: 0; 183 | display: block; 184 | position: absolute; 185 | pointer-events: unset; 186 | cursor: not-allowed; 187 | left: 0; 188 | } 189 | .disabled-editor{ 190 | filter: grayscale(100%); 191 | } 192 | -------------------------------------------------------------------------------- /publish/editor/config/colorStyleMap.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var colorStyleMap = { 4 | grapeFruit1: { 5 | color: '#ED5565' 6 | }, 7 | grapeFruit2: { 8 | color: '#Da4453' 9 | }, 10 | bitterSweet1: { 11 | color: '#fc6e51' 12 | }, 13 | bitterSweet2: { 14 | color: '#e9573f' 15 | }, 16 | sunFlower1: { 17 | color: '#ffce54' 18 | }, 19 | sunFlower2: { 20 | color: '#f6bb42' 21 | }, 22 | grass1: { 23 | color: '#a0d468' 24 | }, 25 | grass2: { 26 | color: '#bcc152' 27 | }, 28 | mint1: { 29 | color: '#48cfad' 30 | }, 31 | mint2: { 32 | color: '#37bc9b' 33 | }, 34 | aqua1: { 35 | color: '#4fc1e9' 36 | }, 37 | aqua2: { 38 | color: '#38afda' 39 | }, 40 | blueJeans1: { 41 | color: '#5d9cec' 42 | }, 43 | blueJeans2: { 44 | color: '#4a89dc' 45 | }, 46 | lavander1: { 47 | color: '#ac92ec' 48 | }, 49 | lavander2: { 50 | color: '#967adc' 51 | }, 52 | mediumGray1: { 53 | color: '#ccd1d9' 54 | }, 55 | mediumGray2: { 56 | color: '#aab2bd' 57 | }, 58 | darkGray1: { 59 | color: '#656d78' 60 | }, 61 | darkGray2: { 62 | color: '#434a54' 63 | } 64 | }; 65 | 66 | module.exports = colorStyleMap; -------------------------------------------------------------------------------- /publish/editor/decorators/AudioDecorator.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _AudioSpan = require('./AudioSpan'); 8 | 9 | var _AudioSpan2 = _interopRequireDefault(_AudioSpan); 10 | 11 | var _draftJs = require('draft-js'); 12 | 13 | var _main = require('../utils/stateUtils/main'); 14 | 15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 16 | 17 | function findAudioEntities(contentBlock, callback) { 18 | 19 | contentBlock.findEntityRanges(function (character) { 20 | var entityKey = character.getEntity(); 21 | return entityKey != null && _draftJs.Entity.get(entityKey).getType() === _main.ENTITY_TYPE.AUDIO; 22 | }, callback); 23 | } 24 | 25 | exports.default = { 26 | strategy: findAudioEntities, 27 | component: _AudioSpan2.default 28 | }; -------------------------------------------------------------------------------- /publish/editor/decorators/AudioSpan.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 8 | 9 | var _react = require('react'); 10 | 11 | var _react2 = _interopRequireDefault(_react); 12 | 13 | var _draftJs = require('draft-js'); 14 | 15 | var _decoratorStyle = require('./decoratorStyle.css'); 16 | 17 | var _decoratorStyle2 = _interopRequireDefault(_decoratorStyle); 18 | 19 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 20 | 21 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 22 | 23 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 24 | 25 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 26 | 27 | var AudioSpan = function (_Component) { 28 | _inherits(AudioSpan, _Component); 29 | 30 | function AudioSpan(props) { 31 | _classCallCheck(this, AudioSpan); 32 | 33 | var _this = _possibleConstructorReturn(this, (AudioSpan.__proto__ || Object.getPrototypeOf(AudioSpan)).call(this, props)); 34 | 35 | var entity = _draftJs.Entity.get(_this.props.entityKey); 36 | 37 | var _entity$getData = entity.getData(), 38 | width = _entity$getData.width, 39 | height = _entity$getData.height; 40 | 41 | _this.state = { 42 | width: width, 43 | height: height 44 | }; 45 | return _this; 46 | } 47 | 48 | _createClass(AudioSpan, [{ 49 | key: 'componentDidMount', 50 | value: function componentDidMount() { 51 | var _this2 = this; 52 | 53 | var _state = this.state, 54 | width = _state.width, 55 | height = _state.height; 56 | 57 | var entity = _draftJs.Entity.get(this.props.entityKey); 58 | var audio = document.createElement('audio'); 59 | 60 | var _entity$getData2 = entity.getData(), 61 | src = _entity$getData2.src; 62 | 63 | audio.src = src; 64 | audio.onload = function () { 65 | if (width == null || height == null) { 66 | _this2.setState({ width: audio.width, height: audio.height }); 67 | _draftJs.Entity.mergeData(_this2.props.entityKey, { 68 | width: audio.width, 69 | height: audio.height, 70 | originalWidth: audio.width, 71 | originalHeight: audio.height 72 | }); 73 | } 74 | }; 75 | } 76 | }, { 77 | key: 'render', 78 | value: function render() { 79 | var _state2 = this.state, 80 | width = _state2.width, 81 | height = _state2.height; 82 | 83 | var entity = _draftJs.Entity.get(this.props.entityKey); 84 | 85 | var _entity$getData3 = entity.getData(), 86 | src = _entity$getData3.src; 87 | 88 | var audioStyle = { 89 | verticalAlign: 'bottom', 90 | backgroundImage: 'url("' + src + '")', 91 | backgroundSize: width + 'px ' + height + 'px', 92 | lineHeight: height + 'px', 93 | fontSize: height + 'px', 94 | width: width, 95 | height: height, 96 | letterSpacing: width 97 | }; 98 | 99 | return _react2.default.createElement( 100 | 'figure', 101 | { className: 'editor-inline-audio', onClick: this._onClick }, 102 | _react2.default.createElement('audio', { controls: true, src: '' + src, className: 'media-audio' }) 103 | ); 104 | } 105 | }, { 106 | key: '_onClick', 107 | value: function _onClick() {} 108 | }, { 109 | key: '_handleResize', 110 | value: function _handleResize(event, data) { 111 | var _data$size = data.size, 112 | width = _data$size.width, 113 | height = _data$size.height; 114 | 115 | this.setState({ width: width, height: height }); 116 | _draftJs.Entity.mergeData(this.props.entityKey, { width: width, height: height }); 117 | } 118 | }]); 119 | 120 | return AudioSpan; 121 | }(_react.Component); 122 | 123 | exports.default = AudioSpan; 124 | 125 | 126 | AudioSpan.defaultProps = { 127 | children: null, 128 | entityKey: "", 129 | className: "" 130 | }; -------------------------------------------------------------------------------- /publish/editor/decorators/ImageDecorator.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _ImageSpan = require('./ImageSpan'); 8 | 9 | var _ImageSpan2 = _interopRequireDefault(_ImageSpan); 10 | 11 | var _draftJs = require('draft-js'); 12 | 13 | var _main = require('../utils/stateUtils/main'); 14 | 15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 16 | 17 | function findImageEntities(contentBlock, callback) { 18 | contentBlock.findEntityRanges(function (character) { 19 | var entityKey = character.getEntity(); 20 | return entityKey != null && _draftJs.Entity.get(entityKey).getType() === _main.ENTITY_TYPE.IMAGE; 21 | }, callback); 22 | } 23 | 24 | exports.default = { 25 | strategy: findImageEntities, 26 | component: _ImageSpan2.default 27 | }; -------------------------------------------------------------------------------- /publish/editor/decorators/LinkDecorator.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _react = require('react'); 8 | 9 | var _react2 = _interopRequireDefault(_react); 10 | 11 | var _draftJs = require('draft-js'); 12 | 13 | var _main = require('../utils/stateUtils/main'); 14 | 15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 16 | 17 | function Link(props_) { 18 | var _Entity$get$getData = _draftJs.Entity.get(props_.entityKey).getData(), 19 | url = _Entity$get$getData.url; 20 | 21 | return _react2.default.createElement( 22 | 'a', 23 | { href: url }, 24 | props_.children 25 | ); 26 | } 27 | 28 | function findLinkEntities(contentBlock, callback) { 29 | contentBlock.findEntityRanges(function (character) { 30 | var entityKey = character.getEntity(); 31 | return entityKey != null && _draftJs.Entity.get(entityKey).getType() === _main.ENTITY_TYPE.LINK; 32 | }, callback); 33 | } 34 | 35 | exports.default = { 36 | strategy: findLinkEntities, 37 | component: Link 38 | }; -------------------------------------------------------------------------------- /publish/editor/decorators/VideoDecorator.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _VideoSpan = require('./VideoSpan'); 8 | 9 | var _VideoSpan2 = _interopRequireDefault(_VideoSpan); 10 | 11 | var _draftJs = require('draft-js'); 12 | 13 | var _main = require('../utils/stateUtils/main'); 14 | 15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 16 | 17 | function findVideoEntities(contentBlock, callback) { 18 | contentBlock.findEntityRanges(function (character) { 19 | var entityKey = character.getEntity(); 20 | return entityKey != null && _draftJs.Entity.get(entityKey).getType() === _main.ENTITY_TYPE.VIDEO; 21 | }, callback); 22 | } 23 | 24 | exports.default = { 25 | strategy: findVideoEntities, 26 | component: _VideoSpan2.default 27 | }; -------------------------------------------------------------------------------- /publish/editor/decorators/VideoSpan.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 8 | 9 | var _react = require('react'); 10 | 11 | var _react2 = _interopRequireDefault(_react); 12 | 13 | var _draftJs = require('draft-js'); 14 | 15 | var _decoratorStyle = require('./decoratorStyle.css'); 16 | 17 | var _decoratorStyle2 = _interopRequireDefault(_decoratorStyle); 18 | 19 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 20 | 21 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 22 | 23 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 24 | 25 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 26 | 27 | var VideoSpan = function (_Component) { 28 | _inherits(VideoSpan, _Component); 29 | 30 | function VideoSpan(props) { 31 | _classCallCheck(this, VideoSpan); 32 | 33 | var _this = _possibleConstructorReturn(this, (VideoSpan.__proto__ || Object.getPrototypeOf(VideoSpan)).call(this, props)); 34 | 35 | var entity = _draftJs.Entity.get(_this.props.entityKey); 36 | 37 | var _entity$getData = entity.getData(), 38 | width = _entity$getData.width, 39 | height = _entity$getData.height; 40 | 41 | _this.state = { 42 | width: width, 43 | height: height 44 | }; 45 | return _this; 46 | } 47 | 48 | _createClass(VideoSpan, [{ 49 | key: 'componentDidMount', 50 | value: function componentDidMount() { 51 | var _this2 = this; 52 | 53 | var _state = this.state, 54 | width = _state.width, 55 | height = _state.height; 56 | 57 | var entity = _draftJs.Entity.get(this.props.entityKey); 58 | var video = document.createElement('video'); 59 | 60 | var _entity$getData2 = entity.getData(), 61 | src = _entity$getData2.src; 62 | 63 | video.src = src; 64 | video.onload = function () { 65 | if (width == null || height == null) { 66 | _this2.setState({ width: video.width, height: video.height }); 67 | _draftJs.Entity.mergeData(_this2.props.entityKey, { 68 | width: video.width, 69 | height: video.height, 70 | originalWidth: video.width, 71 | originalHeight: video.height 72 | }); 73 | } 74 | }; 75 | } 76 | }, { 77 | key: 'render', 78 | value: function render() { 79 | var _state2 = this.state, 80 | width = _state2.width, 81 | height = _state2.height; 82 | 83 | var entity = _draftJs.Entity.get(this.props.entityKey); 84 | 85 | var _entity$getData3 = entity.getData(), 86 | src = _entity$getData3.src; 87 | 88 | var videoStyle = { 89 | verticalAlign: 'bottom', 90 | backgroundImage: 'url("' + src + '")', 91 | backgroundSize: width + 'px ' + height + 'px', 92 | lineHeight: height + 'px', 93 | fontSize: height + 'px', 94 | width: width, 95 | height: height, 96 | letterSpacing: width 97 | }; 98 | 99 | return _react2.default.createElement( 100 | 'figure', 101 | { className: 'editor-inline-video', onClick: this._onClick }, 102 | _react2.default.createElement('video', { controls: 'controls', src: '' + src, className: 'media-video' }) 103 | ); 104 | } 105 | }, { 106 | key: '_onClick', 107 | value: function _onClick() {} 108 | }, { 109 | key: '_handleResize', 110 | value: function _handleResize(event, data) { 111 | var _data$size = data.size, 112 | width = _data$size.width, 113 | height = _data$size.height; 114 | 115 | this.setState({ width: width, height: height }); 116 | _draftJs.Entity.mergeData(this.props.entityKey, { width: width, height: height }); 117 | } 118 | }]); 119 | 120 | return VideoSpan; 121 | }(_react.Component); 122 | 123 | exports.default = VideoSpan; 124 | 125 | 126 | VideoSpan.defaultProps = { 127 | children: null, 128 | entityKey: "", 129 | className: "" 130 | }; -------------------------------------------------------------------------------- /publish/editor/decorators/decoratorStyle.css: -------------------------------------------------------------------------------- 1 | .root { 2 | background-repeat: no-repeat; 3 | display: inline-block; 4 | overflow: hidden; 5 | cursor: pointer; 6 | } 7 | 8 | .resize { 9 | border: 1px dashed #78a300; 10 | position: relative; 11 | max-width: 100%; 12 | display: inline-block; 13 | line-height: 0; 14 | top: -1px; 15 | left: -1px 16 | } 17 | 18 | .resizeHandle { 19 | cursor: nwse-resize; 20 | position: absolute; 21 | z-index: 2; 22 | line-height: 1; 23 | bottom: -4px; 24 | right: -5px; 25 | border: 1px solid white; 26 | background-color: #78a300; 27 | width: 8px; 28 | height: 8px; 29 | } 30 | figure{ 31 | text-align: center; 32 | overflow: hidden; 33 | } 34 | figure video { 35 | max-width: 300px; 36 | min-width: 300px; 37 | max-height: 200px; 38 | min-height: 200px; 39 | } 40 | figure img, 41 | figure video, 42 | figure audio { 43 | display: block; 44 | margin: 0 auto; 45 | max-width: 100%; 46 | } 47 | 48 | .editor-inline-image, 49 | .editor-inline-video, 50 | .editor-inline-audio 51 | { 52 | display: inline-block; 53 | overflow: hidden; 54 | cursor: pointer; 55 | width: 100%!important; 56 | } 57 | .editor-inline-image:hover, 58 | .editor-inline-video:hover, 59 | .editor-inline-audio:hover{ 60 | background-color:#f7f7f7 61 | 62 | } 63 | .editor-inline-image span, 64 | .editor-inline-video span, 65 | .editor-inline-audio span { 66 | font-size: 0px; 67 | color: rgba(0, 0, 0, 0); 68 | position: absolute; 69 | left: -10000px 70 | } 71 | -------------------------------------------------------------------------------- /publish/editor/decorators/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = { 4 | LinkDecorator: require("./LinkDecorator"), 5 | ImageDecorator: require("./ImageDecorator"), 6 | VideoDecorator: require("./VideoDecorator"), 7 | AudioDecorator: require("./AudioDecorator") 8 | }; -------------------------------------------------------------------------------- /publish/editor/helpers/combineOrderedStyles.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; 8 | 9 | var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); 10 | 11 | function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } 12 | 13 | function combineOrderedStyles(customMap, defaults) { 14 | if (customMap == null) { 15 | return defaults; 16 | } 17 | 18 | var _defaults = _slicedToArray(defaults, 2), 19 | defaultStyleMap = _defaults[0], 20 | defaultStyleOrder = _defaults[1]; 21 | 22 | var styleMap = _extends({}, defaultStyleMap); 23 | var styleOrder = [].concat(_toConsumableArray(defaultStyleOrder)); 24 | var _iteratorNormalCompletion = true; 25 | var _didIteratorError = false; 26 | var _iteratorError = undefined; 27 | 28 | try { 29 | for (var _iterator = Object.keys(customMap)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { 30 | var _styleName = _step.value; 31 | 32 | if (defaultStyleMap.hasOwnProperty(_styleName)) { 33 | var defaultStyles = defaultStyleMap[_styleName]; 34 | styleMap[_styleName] = _extends({}, defaultStyles, customMap[_styleName]); 35 | } else { 36 | styleMap[_styleName] = customMap[_styleName]; 37 | styleOrder.push(_styleName); 38 | } 39 | } 40 | } catch (err) { 41 | _didIteratorError = true; 42 | _iteratorError = err; 43 | } finally { 44 | try { 45 | if (!_iteratorNormalCompletion && _iterator.return) { 46 | _iterator.return(); 47 | } 48 | } finally { 49 | if (_didIteratorError) { 50 | throw _iteratorError; 51 | } 52 | } 53 | } 54 | 55 | return [styleMap, styleOrder]; 56 | } 57 | 58 | exports.default = combineOrderedStyles; -------------------------------------------------------------------------------- /publish/editor/helpers/normalizeAttributes.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var ATTR_NAME_MAP = { 8 | acceptCharset: 'accept-charset', 9 | className: 'class', 10 | htmlFor: 'for', 11 | httpEquiv: 'http-equiv' 12 | }; 13 | 14 | function normalizeAttributes(attributes) { 15 | if (attributes == null) { 16 | return attributes; 17 | } 18 | var normalized = {}; 19 | var didNormalize = false; 20 | var _iteratorNormalCompletion = true; 21 | var _didIteratorError = false; 22 | var _iteratorError = undefined; 23 | 24 | try { 25 | for (var _iterator = Object.keys(attributes)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { 26 | var name = _step.value; 27 | 28 | var newName = name; 29 | if (ATTR_NAME_MAP.hasOwnProperty(name)) { 30 | newName = ATTR_NAME_MAP[name]; 31 | didNormalize = true; 32 | } 33 | normalized[newName] = attributes[name]; 34 | } 35 | } catch (err) { 36 | _didIteratorError = true; 37 | _iteratorError = err; 38 | } finally { 39 | try { 40 | if (!_iteratorNormalCompletion && _iterator.return) { 41 | _iterator.return(); 42 | } 43 | } finally { 44 | if (_didIteratorError) { 45 | throw _iteratorError; 46 | } 47 | } 48 | } 49 | 50 | return didNormalize ? normalized : attributes; 51 | } 52 | 53 | exports.default = normalizeAttributes; -------------------------------------------------------------------------------- /publish/editor/helpers/styleToCSS.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _CSSProperty = require('react-dom/lib/CSSProperty'); 8 | 9 | var VENDOR_PREFIX = /^(moz|ms|o|webkit)-/; 10 | var NUMERIC_STRING = /^\d+$/; 11 | var UPPERCASE_PATTERN = /([A-Z])/g; 12 | 13 | function processStyleName(name) { 14 | return name.replace(UPPERCASE_PATTERN, '-$1').toLowerCase().replace(VENDOR_PREFIX, '-$1-'); 15 | } 16 | 17 | function processStyleValue(name, value) { 18 | var isNumeric = void 0; 19 | if (typeof value === 'string') { 20 | isNumeric = NUMERIC_STRING.test(value); 21 | } else { 22 | isNumeric = true; 23 | value = String(value); 24 | } 25 | if (!isNumeric || value === '0' || _CSSProperty.isUnitlessNumber[name] === true) { 26 | return value; 27 | } else { 28 | return value + 'px'; 29 | } 30 | } 31 | 32 | function styleToCSS(styleDescr) { 33 | return Object.keys(styleDescr).map(function (name) { 34 | var styleValue = processStyleValue(name, styleDescr[name]); 35 | var styleName = processStyleName(name); 36 | return styleName + ': ' + styleValue; 37 | }).join('; '); 38 | } 39 | 40 | exports.default = styleToCSS; -------------------------------------------------------------------------------- /publish/editor/toolBar/alignmentControls.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _react = require("react"); 4 | 5 | var _react2 = _interopRequireDefault(_react); 6 | 7 | var _styleButton = require("./styleButton"); 8 | 9 | var _styleButton2 = _interopRequireDefault(_styleButton); 10 | 11 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 12 | 13 | var AlignmentControls = function AlignmentControls(props) { 14 | var editorState = props.editorState, 15 | lang = props.lang; 16 | 17 | var selection = editorState.getSelection(); 18 | var blockType = editorState.getCurrentContent().getBlockForKey(selection.getStartKey()).getType(); 19 | var BLOCK_TYPES = [{ 20 | text: lang.alignLeft, 21 | label: "editor_alignment_left", 22 | style: 'left' 23 | }, { 24 | text: lang.alignCenter, 25 | label: "editor_alignment_center", 26 | style: 'center' 27 | }, { 28 | text: lang.alignRight, 29 | label: "editor_alignment_right", 30 | style: 'right' 31 | }, { 32 | text: lang.alignJustify, 33 | label: "editor_alignment_justify", 34 | style: 'justify' 35 | }]; 36 | return _react2.default.createElement( 37 | "div", 38 | { className: "RichEditor-controls" }, 39 | BLOCK_TYPES.map(function (type, i) { 40 | var button = _react2.default.createElement(_styleButton2.default, { 41 | key: type.style, 42 | text: type.text, 43 | active: type.style === blockType, 44 | label: type.label, 45 | onToggle: props.onToggle, 46 | style: type.style }); 47 | return button; 48 | }) 49 | ); 50 | }; 51 | module.exports = AlignmentControls; -------------------------------------------------------------------------------- /publish/editor/toolBar/autoSave.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 4 | 5 | var _react = require("react"); 6 | 7 | var _react2 = _interopRequireDefault(_react); 8 | 9 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 10 | 11 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 12 | 13 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 14 | 15 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 16 | 17 | var AutoSave = function (_Component) { 18 | _inherits(AutoSave, _Component); 19 | 20 | function AutoSave(props) { 21 | _classCallCheck(this, AutoSave); 22 | 23 | return _possibleConstructorReturn(this, (AutoSave.__proto__ || Object.getPrototypeOf(AutoSave)).call(this, props)); 24 | } 25 | 26 | _createClass(AutoSave, [{ 27 | key: "render", 28 | value: function render() { 29 | return _react2.default.createElement( 30 | "div", 31 | { className: "RichEditor-controls" }, 32 | _react2.default.createElement( 33 | "span", 34 | { className: "RichEditor-styleButton", onClick: this.props.onToggle }, 35 | this.props.lang.autoSave 36 | ) 37 | ); 38 | } 39 | }]); 40 | 41 | return AutoSave; 42 | }(_react.Component); 43 | 44 | module.exports = AutoSave; -------------------------------------------------------------------------------- /publish/editor/toolBar/blockSelectorControls.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | 5 | var _icon = require('antd/lib/icon'); 6 | 7 | var _icon2 = _interopRequireDefault(_icon); 8 | 9 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 10 | 11 | var _react = require('react'); 12 | 13 | var _react2 = _interopRequireDefault(_react); 14 | 15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 16 | 17 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 18 | 19 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 20 | 21 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 22 | 23 | var RemoveStyleControls = function (_Component) { 24 | _inherits(RemoveStyleControls, _Component); 25 | 26 | function RemoveStyleControls(props) { 27 | _classCallCheck(this, RemoveStyleControls); 28 | 29 | return _possibleConstructorReturn(this, (RemoveStyleControls.__proto__ || Object.getPrototypeOf(RemoveStyleControls)).call(this, props)); 30 | } 31 | 32 | _createClass(RemoveStyleControls, [{ 33 | key: 'render', 34 | value: function render() { 35 | var className = 'RichEditor-styleButton'; 36 | return _react2.default.createElement( 37 | 'div', 38 | { className: 'RichEditor-controls' }, 39 | _react2.default.createElement( 40 | 'span', 41 | { className: className, onClick: this.props.onToggle }, 42 | _react2.default.createElement(_icon2.default, { key: 'empty_style', type: 'editor_select_block' }) 43 | ) 44 | ); 45 | } 46 | }]); 47 | 48 | return RemoveStyleControls; 49 | }(_react.Component); 50 | 51 | module.exports = RemoveStyleControls; -------------------------------------------------------------------------------- /publish/editor/toolBar/blockStyleControls.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _react = require("react"); 4 | 5 | var _react2 = _interopRequireDefault(_react); 6 | 7 | var _styleButton = require("./styleButton"); 8 | 9 | var _styleButton2 = _interopRequireDefault(_styleButton); 10 | 11 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 12 | 13 | var BlockStyleControls = function BlockStyleControls(props) { 14 | var editorState = props.editorState, 15 | lang = props.lang; 16 | 17 | var selection = editorState.getSelection(); 18 | var blockType = editorState.getCurrentContent().getBlockForKey(selection.getStartKey()).getType(); 19 | var BLOCK_TYPES = [{ 20 | text: lang.H1, 21 | label: "editor_H1", 22 | style: 'header-one' 23 | }, { 24 | text: lang.H2, 25 | label: "editor_H2", 26 | style: 'header-two' 27 | }, { 28 | text: lang.H3, 29 | label: "editor_H3", 30 | style: 'header-three' 31 | }, { 32 | text: lang.H4, 33 | label: "editor_H4", 34 | style: 'header-four' 35 | }, { 36 | text: lang.refs, 37 | label: "editor_refs", 38 | style: 'blockquote' 39 | }, { 40 | text: lang.ul, 41 | label: "editor_ul", 42 | style: 'unordered-list-item' 43 | }, { 44 | text: lang.ol, 45 | label: "editor_ol", 46 | style: 'ordered-list-item' 47 | }, { 48 | text: lang.pre, 49 | label: "editor_pre", 50 | style: 'code-block' 51 | }]; 52 | return _react2.default.createElement( 53 | "div", 54 | { className: "RichEditor-controls" }, 55 | BLOCK_TYPES.map(function (type, i) { 56 | var button = _react2.default.createElement(_styleButton2.default, { 57 | key: type.style, 58 | text: type.text, 59 | active: type.style === blockType, 60 | label: type.label, 61 | onToggle: props.onToggle, 62 | style: type.style }); 63 | return button; 64 | }) 65 | ); 66 | }; 67 | module.exports = BlockStyleControls; -------------------------------------------------------------------------------- /publish/editor/toolBar/colorButton.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 4 | 5 | var _react = require('react'); 6 | 7 | var _react2 = _interopRequireDefault(_react); 8 | 9 | var _colorStyleMap = require('../config/colorStyleMap'); 10 | 11 | var _colorStyleMap2 = _interopRequireDefault(_colorStyleMap); 12 | 13 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 14 | 15 | function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } 16 | 17 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 18 | 19 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 20 | 21 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 22 | 23 | var ColorButton = function (_Component) { 24 | _inherits(ColorButton, _Component); 25 | 26 | function ColorButton(props) { 27 | _classCallCheck(this, ColorButton); 28 | 29 | var _this = _possibleConstructorReturn(this, (ColorButton.__proto__ || Object.getPrototypeOf(ColorButton)).call(this, props)); 30 | 31 | _this.onToggle = function (e) { 32 | e.preventDefault(); 33 | _this.props.onToggle(_this.props.style); 34 | }; 35 | return _this; 36 | } 37 | 38 | _createClass(ColorButton, [{ 39 | key: 'render', 40 | value: function render() { 41 | var _styles, 42 | _this2 = this; 43 | 44 | var styles = (_styles = { 45 | editor: { 46 | borderTop: '1px solid #ddd', 47 | cursor: 'text', 48 | fontSize: 16, 49 | marginTop: 20, 50 | minHeight: 400, 51 | paddingTop: 20 52 | }, 53 | controls: { 54 | fontFamily: '\'Helvetica\', sans-serif', 55 | fontSize: 14, 56 | marginBottom: 10, 57 | userSelect: 'none' 58 | }, 59 | ColorButton: { 60 | color: '#999', 61 | cursor: 'pointer', 62 | marginRight: 16, 63 | padding: '2px 0' 64 | }, 65 | root: { 66 | fontFamily: '\'Georgia\', serif', 67 | padding: 20, 68 | width: 600 69 | }, 70 | buttons: { 71 | marginBottom: 10 72 | }, 73 | urlInputContainer: { 74 | marginBottom: 10 75 | }, 76 | urlInput: { 77 | fontFamily: '\'Georgia\', serif', 78 | marginRight: 10, 79 | padding: 3 80 | } 81 | }, _defineProperty(_styles, 'editor', { 82 | border: '1px solid #ccc', 83 | cursor: 'text', 84 | minHeight: 80, 85 | padding: 10 86 | }), _defineProperty(_styles, 'button', { 87 | marginTop: 10, 88 | textAlign: 'center' 89 | }), _defineProperty(_styles, 'link', { 90 | color: 'blue', 91 | textDecoration: 'underline' 92 | }), _styles); 93 | 94 | var style = Object.assign({}, styles.ColorButton, this.props.active ? _colorStyleMap2.default[this.props.style] : {}); 95 | var className = 'RichEditor-styleButton'; 96 | return _react2.default.createElement( 97 | 'div', 98 | { className: 'RichEditor-color' }, 99 | _react2.default.createElement( 100 | 'span', 101 | { 102 | className: className, 103 | onClick: this.onToggle, 104 | style: { 105 | backgroundColor: _colorStyleMap2.default[this.props.style].color 106 | } }, 107 | this.props.label 108 | ), 109 | function () { 110 | if (!!_this2.props.split) { 111 | return _react2.default.createElement( 112 | 'span', 113 | { className: 'RichEditor-controls-split' }, 114 | _this2.props.split 115 | ); 116 | } 117 | }() 118 | ); 119 | } 120 | }]); 121 | 122 | return ColorButton; 123 | }(_react.Component); 124 | 125 | module.exports = ColorButton; -------------------------------------------------------------------------------- /publish/editor/toolBar/colorControls.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 4 | 5 | var _react = require("react"); 6 | 7 | var _react2 = _interopRequireDefault(_react); 8 | 9 | var _colorButton = require("./colorButton"); 10 | 11 | var _colorButton2 = _interopRequireDefault(_colorButton); 12 | 13 | var _colorConfig = require("../utils/colorConfig"); 14 | 15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 16 | 17 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 18 | 19 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 20 | 21 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 22 | 23 | var ColorControls = function (_Component) { 24 | _inherits(ColorControls, _Component); 25 | 26 | function ColorControls(props) { 27 | _classCallCheck(this, ColorControls); 28 | 29 | return _possibleConstructorReturn(this, (ColorControls.__proto__ || Object.getPrototypeOf(ColorControls)).call(this, props)); 30 | } 31 | 32 | _createClass(ColorControls, [{ 33 | key: "render", 34 | value: function render() { 35 | var _this2 = this; 36 | 37 | var currentStyle = this.props.editorState.getCurrentInlineStyle(); 38 | var COLORS = Object.keys(_colorConfig.colorStyleMap).map(function (item) { 39 | return { label: ' ', alias: item, style: item }; 40 | }); 41 | return _react2.default.createElement( 42 | "div", 43 | { className: "RichEditor-controls", style: { 44 | paddingRight: "20px" 45 | } }, 46 | COLORS.map(function (type, i) { 47 | return _react2.default.createElement(_colorButton2.default, { 48 | active: currentStyle.has(type.style), 49 | label: type.label, 50 | onToggle: _this2.props.onToggle, 51 | style: type.style, 52 | key: i, 53 | split: i == COLORS.length - 1 ? "|" : "" }); 54 | }) 55 | ); 56 | } 57 | }]); 58 | 59 | return ColorControls; 60 | }(_react.Component); 61 | 62 | module.exports = ColorControls; -------------------------------------------------------------------------------- /publish/editor/toolBar/cookieControls.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 4 | 5 | var _react = require("react"); 6 | 7 | var _react2 = _interopRequireDefault(_react); 8 | 9 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 10 | 11 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 12 | 13 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 14 | 15 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 16 | 17 | var OpenFull = function (_Component) { 18 | _inherits(OpenFull, _Component); 19 | 20 | function OpenFull(props) { 21 | _classCallCheck(this, OpenFull); 22 | 23 | return _possibleConstructorReturn(this, (OpenFull.__proto__ || Object.getPrototypeOf(OpenFull)).call(this, props)); 24 | } 25 | 26 | _createClass(OpenFull, [{ 27 | key: "render", 28 | value: function render() { 29 | return _react2.default.createElement( 30 | "div", 31 | { className: "RichEditor-controls" }, 32 | _react2.default.createElement( 33 | "span", 34 | { className: "RichEditor-styleButton", onClick: this.props.onToggle }, 35 | this.props.coverTitle 36 | ) 37 | ); 38 | } 39 | }]); 40 | 41 | return OpenFull; 42 | }(_react.Component); 43 | 44 | var AutoSave = function (_Component2) { 45 | _inherits(AutoSave, _Component2); 46 | 47 | function AutoSave(props) { 48 | _classCallCheck(this, AutoSave); 49 | 50 | return _possibleConstructorReturn(this, (AutoSave.__proto__ || Object.getPrototypeOf(AutoSave)).call(this, props)); 51 | } 52 | 53 | _createClass(AutoSave, [{ 54 | key: "render", 55 | value: function render() { 56 | return _react2.default.createElement( 57 | "div", 58 | { className: "RichEditor-controls" }, 59 | _react2.default.createElement( 60 | "span", 61 | { className: "RichEditor-styleButton", onClick: this.props.onToggle }, 62 | this.props.lang.autoSave 63 | ) 64 | ); 65 | } 66 | }]); 67 | 68 | return AutoSave; 69 | }(_react.Component); 70 | 71 | ; 72 | 73 | var SourceEditor = function (_Component3) { 74 | _inherits(SourceEditor, _Component3); 75 | 76 | function SourceEditor(props) { 77 | _classCallCheck(this, SourceEditor); 78 | 79 | return _possibleConstructorReturn(this, (SourceEditor.__proto__ || Object.getPrototypeOf(SourceEditor)).call(this, props)); 80 | } 81 | 82 | _createClass(SourceEditor, [{ 83 | key: "render", 84 | value: function render() { 85 | return _react2.default.createElement( 86 | "div", 87 | { className: "RichEditor-controls" }, 88 | _react2.default.createElement( 89 | "span", 90 | { className: "RichEditor-styleButton", onClick: this.props.onToggle }, 91 | this.props.coverTitle 92 | ) 93 | ); 94 | } 95 | }]); 96 | 97 | return SourceEditor; 98 | }(_react.Component); 99 | 100 | ; 101 | module.exports = { 102 | OpenFull: OpenFull, 103 | AutoSave: AutoSave, 104 | SourceEditor: SourceEditor 105 | }; -------------------------------------------------------------------------------- /publish/editor/toolBar/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = { 4 | ImgStyleControls: require("./mediaImageUploader"), 5 | VideoStyleControls: require("./medioVideoUploader"), 6 | AudioStyleControls: require("./medioAudioUploader"), 7 | AutoSaveControls: require("./autoSaveList"), 8 | BlockStyleControls: require("./BlockStyleControls"), 9 | RemoveStyleControls: require("./removeStyleControls"), 10 | InlineStyleControls: require("./inlineStyleControls"), 11 | ColorControls: require("./colorControls"), 12 | PasteNoStyleControls: require("./pasteNoStyleControls"), 13 | AutoSave: require("./autoSave") 14 | }; -------------------------------------------------------------------------------- /publish/editor/toolBar/inlineStyleControls.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 4 | 5 | var _react = require('react'); 6 | 7 | var _react2 = _interopRequireDefault(_react); 8 | 9 | var _styleButton = require('./styleButton'); 10 | 11 | var _styleButton2 = _interopRequireDefault(_styleButton); 12 | 13 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 14 | 15 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 16 | 17 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 18 | 19 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 20 | 21 | var InlineStyleControls = function (_Component) { 22 | _inherits(InlineStyleControls, _Component); 23 | 24 | function InlineStyleControls(props) { 25 | _classCallCheck(this, InlineStyleControls); 26 | 27 | return _possibleConstructorReturn(this, (InlineStyleControls.__proto__ || Object.getPrototypeOf(InlineStyleControls)).call(this, props)); 28 | } 29 | 30 | _createClass(InlineStyleControls, [{ 31 | key: 'render', 32 | value: function render() { 33 | var _props = this.props, 34 | editorState = _props.editorState, 35 | onToggle = _props.onToggle, 36 | lang = _props.lang; 37 | 38 | var INLINE_STYLES = [{ 39 | text: lang.textBold, 40 | style: 'BOLD', 41 | label: "editor_b" 42 | }, { 43 | text: lang.textItalic, 44 | style: 'ITALIC', 45 | label: "editor_i" 46 | }, { 47 | text: lang.textUnderline, 48 | style: 'UNDERLINE', 49 | label: "editor_u" 50 | }, { 51 | text: lang.textCode, 52 | style: 'CODE', 53 | label: "editor_e" 54 | }]; 55 | var currentStyle = editorState ? editorState.getCurrentInlineStyle() : {}; 56 | return _react2.default.createElement( 57 | 'div', 58 | { className: 'RichEditor-controls' }, 59 | INLINE_STYLES.map(function (type, i) { 60 | return _react2.default.createElement(_styleButton2.default, { 61 | key: type.style, 62 | text: type.text, 63 | active: currentStyle.has(type.style), 64 | label: type.label, 65 | onToggle: onToggle, 66 | style: type.style }); 67 | }) 68 | ); 69 | } 70 | }]); 71 | 72 | return InlineStyleControls; 73 | }(_react.Component); 74 | 75 | module.exports = InlineStyleControls; -------------------------------------------------------------------------------- /publish/editor/toolBar/removeStyleControls.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | 5 | var _popconfirm = require('antd/lib/popconfirm'); 6 | 7 | var _popconfirm2 = _interopRequireDefault(_popconfirm); 8 | 9 | 10 | 11 | var _icon = require('antd/lib/icon'); 12 | 13 | var _icon2 = _interopRequireDefault(_icon); 14 | 15 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 16 | 17 | var _react = require('react'); 18 | 19 | var _react2 = _interopRequireDefault(_react); 20 | 21 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 22 | 23 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 24 | 25 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 26 | 27 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 28 | 29 | var RemoveStyleControls = function (_Component) { 30 | _inherits(RemoveStyleControls, _Component); 31 | 32 | function RemoveStyleControls(props) { 33 | _classCallCheck(this, RemoveStyleControls); 34 | 35 | return _possibleConstructorReturn(this, (RemoveStyleControls.__proto__ || Object.getPrototypeOf(RemoveStyleControls)).call(this, props)); 36 | } 37 | 38 | _createClass(RemoveStyleControls, [{ 39 | key: 'render', 40 | value: function render() { 41 | var className = 'RichEditor-styleButton'; 42 | return _react2.default.createElement( 43 | 'div', 44 | { className: 'RichEditor-controls' }, 45 | _react2.default.createElement( 46 | _popconfirm2.default, 47 | { title: this.props.lang.confirmToRemove, onConfirm: this.props.onToggle, okText: this.props.lang.doRemove, cancelText: this.props.lang.doNotRemove }, 48 | _react2.default.createElement( 49 | 'span', 50 | { className: className }, 51 | _react2.default.createElement(_icon2.default, { key: 'empty_style', type: 'editor_empty_style' }) 52 | ) 53 | ) 54 | ); 55 | } 56 | }]); 57 | 58 | return RemoveStyleControls; 59 | }(_react.Component); 60 | 61 | module.exports = RemoveStyleControls; -------------------------------------------------------------------------------- /publish/editor/toolBar/styleButton.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | 5 | var _icon = require('antd/lib/icon'); 6 | 7 | var _icon2 = _interopRequireDefault(_icon); 8 | 9 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 10 | 11 | var _react = require('react'); 12 | 13 | var _react2 = _interopRequireDefault(_react); 14 | 15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 16 | 17 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 18 | 19 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 20 | 21 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 22 | 23 | var StyleButton = function (_React$Component) { 24 | _inherits(StyleButton, _React$Component); 25 | 26 | function StyleButton() { 27 | _classCallCheck(this, StyleButton); 28 | 29 | var _this = _possibleConstructorReturn(this, (StyleButton.__proto__ || Object.getPrototypeOf(StyleButton)).call(this)); 30 | 31 | _this.onToggle = function (e) { 32 | e.preventDefault(); 33 | _this.props.onToggle(_this.props.style); 34 | }; 35 | return _this; 36 | } 37 | 38 | _createClass(StyleButton, [{ 39 | key: 'render', 40 | value: function render() { 41 | var _this2 = this; 42 | 43 | var className = 'RichEditor-styleButton'; 44 | if (this.props.active) { 45 | className += ' RichEditor-activeButton ant-btn ant-btn-primary ant-btn-icon-only '; 46 | } 47 | 48 | return _react2.default.createElement( 49 | 'span', 50 | null, 51 | _react2.default.createElement( 52 | 'span', 53 | { className: className, onClick: this.onToggle, title: this.props.text }, 54 | _react2.default.createElement(_icon2.default, { type: '' + this.props.label }) 55 | ), 56 | function () { 57 | if (!!_this2.props.split) { 58 | return _react2.default.createElement( 59 | 'span', 60 | { className: 'RichEditor-controls-split' }, 61 | _this2.props.split 62 | ); 63 | } 64 | }() 65 | ); 66 | } 67 | }]); 68 | 69 | return StyleButton; 70 | }(_react2.default.Component); 71 | 72 | module.exports = StyleButton; -------------------------------------------------------------------------------- /publish/editor/toolBar/undoredoControls.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | 5 | var _icon = require('antd/lib/icon'); 6 | 7 | var _icon2 = _interopRequireDefault(_icon); 8 | 9 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 10 | 11 | var _react = require('react'); 12 | 13 | var _react2 = _interopRequireDefault(_react); 14 | 15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 16 | 17 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 18 | 19 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 20 | 21 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 22 | 23 | var undoRedo = function (_Component) { 24 | _inherits(undoRedo, _Component); 25 | 26 | function undoRedo(props) { 27 | _classCallCheck(this, undoRedo); 28 | 29 | return _possibleConstructorReturn(this, (undoRedo.__proto__ || Object.getPrototypeOf(undoRedo)).call(this, props)); 30 | } 31 | 32 | _createClass(undoRedo, [{ 33 | key: 'render', 34 | value: function render() { 35 | var _this2 = this; 36 | 37 | var className = 'RichEditor-styleButton'; 38 | return _react2.default.createElement( 39 | 'div', 40 | { className: 'RichEditor-controls' }, 41 | _react2.default.createElement( 42 | 'span', 43 | { className: 'RichEditor-styleButton', onClick: function onClick() { 44 | return _this2.props.onToggle("undo"); 45 | }, title: this.props.lang.undo }, 46 | _react2.default.createElement(_icon2.default, { key: '_undo', type: 'editor_undo' }) 47 | ), 48 | _react2.default.createElement( 49 | 'span', 50 | { className: 'RichEditor-styleButton', onClick: function onClick() { 51 | return _this2.props.onToggle("redo"); 52 | }, title: this.props.lang.redo }, 53 | _react2.default.createElement(_icon2.default, { key: '_redo', type: 'editor_redo' }) 54 | ) 55 | ); 56 | } 57 | }]); 58 | 59 | return undoRedo; 60 | }(_react.Component); 61 | 62 | ; 63 | module.exports = undoRedo; -------------------------------------------------------------------------------- /publish/editor/toolBar/urlControls.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | 4 | 5 | var _icon = require("antd/lib/icon"); 6 | 7 | var _icon2 = _interopRequireDefault(_icon); 8 | 9 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 10 | 11 | var _react = require("react"); 12 | 13 | var _react2 = _interopRequireDefault(_react); 14 | 15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 16 | 17 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 18 | 19 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 20 | 21 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 22 | 23 | var AddUrl = function (_Component) { 24 | _inherits(AddUrl, _Component); 25 | 26 | function AddUrl(props) { 27 | _classCallCheck(this, AddUrl); 28 | 29 | return _possibleConstructorReturn(this, (AddUrl.__proto__ || Object.getPrototypeOf(AddUrl)).call(this, props)); 30 | } 31 | 32 | _createClass(AddUrl, [{ 33 | key: "render", 34 | value: function render() { 35 | return _react2.default.createElement( 36 | "div", 37 | { className: "RichEditor-controls" }, 38 | _react2.default.createElement( 39 | "span", 40 | { className: "RichEditor-styleButton", onClick: this.props.onToggle, title: this.props.lang.addLink }, 41 | _react2.default.createElement(_icon2.default, { type: "editor_link" }) 42 | ) 43 | ); 44 | } 45 | }]); 46 | 47 | return AddUrl; 48 | }(_react.Component); 49 | 50 | var CloseUrl = function (_Component2) { 51 | _inherits(CloseUrl, _Component2); 52 | 53 | function CloseUrl(props) { 54 | _classCallCheck(this, CloseUrl); 55 | 56 | return _possibleConstructorReturn(this, (CloseUrl.__proto__ || Object.getPrototypeOf(CloseUrl)).call(this, props)); 57 | } 58 | 59 | _createClass(CloseUrl, [{ 60 | key: "render", 61 | value: function render() { 62 | return _react2.default.createElement( 63 | "div", 64 | { className: "RichEditor-controls" }, 65 | _react2.default.createElement( 66 | "span", 67 | { className: "RichEditor-styleButton", onClick: this.props.onToggle, title: this.props.lang.removeLink }, 68 | _react2.default.createElement(_icon2.default, { type: "editor_unlink" }) 69 | ) 70 | ); 71 | } 72 | }]); 73 | 74 | return CloseUrl; 75 | }(_react.Component); 76 | 77 | module.exports = { 78 | AddUrl: AddUrl, 79 | CloseUrl: CloseUrl 80 | }; -------------------------------------------------------------------------------- /publish/editor/utils/ExtendedRichUtils.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.ALIGNMENT_DATA_KEY = exports.ALIGNMENTS = undefined; 7 | 8 | var _draftJs = require('draft-js'); 9 | 10 | var _getCurrentlySelectedBlock = require('./getCurrentlySelectedBlock'); 11 | 12 | var _getCurrentlySelectedBlock2 = _interopRequireDefault(_getCurrentlySelectedBlock); 13 | 14 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 15 | 16 | var ALIGNMENTS = exports.ALIGNMENTS = { 17 | CENTER: 'center', 18 | JUSTIFY: 'justify', 19 | LEFT: 'left', 20 | RIGHT: 'right' 21 | }; 22 | 23 | var ALIGNMENT_DATA_KEY = exports.ALIGNMENT_DATA_KEY = 'textAlignment'; 24 | 25 | var ExtendedRichUtils = Object.assign({}, _draftJs.RichUtils, { 26 | toggleAlignment: function toggleAlignment(editorState, alignment) { 27 | var _getCurrentlySelected = (0, _getCurrentlySelectedBlock2.default)(editorState), 28 | content = _getCurrentlySelected.content, 29 | currentBlock = _getCurrentlySelected.currentBlock, 30 | hasAtomicBlock = _getCurrentlySelected.hasAtomicBlock, 31 | target = _getCurrentlySelected.target; 32 | 33 | if (hasAtomicBlock) { 34 | return editorState; 35 | } 36 | 37 | var blockData = currentBlock.getData(); 38 | 39 | var keyName = blockData.get(ALIGNMENT_DATA_KEY); 40 | 41 | var alignmentToSet = !!blockData && keyName === alignment ? undefined : alignment; 42 | 43 | var alignBlockData = new Map(); 44 | alignBlockData.set(ALIGNMENT_DATA_KEY, alignmentToSet); 45 | 46 | var newBlockData = _draftJs.Modifier.setBlockData(content, target, alignBlockData); 47 | 48 | return _draftJs.EditorState.push(editorState, newBlockData, 'change-block-type'); 49 | }, 50 | splitBlock: function splitBlock(editorState) { 51 | var contentState = _draftJs.Modifier.splitBlock(editorState.getCurrentContent(), editorState.getSelection()); 52 | var splitState = _draftJs.EditorState.push(editorState, contentState, 'split-block'); 53 | 54 | var _getCurrentlySelected2 = (0, _getCurrentlySelectedBlock2.default)(editorState), 55 | currentBlock = _getCurrentlySelected2.currentBlock; 56 | 57 | var alignment = currentBlock.getData().get(ALIGNMENT_DATA_KEY); 58 | if (alignment) { 59 | return ExtendedRichUtils.toggleAlignment(splitState, alignment); 60 | } else { 61 | return splitState; 62 | } 63 | } 64 | }); 65 | 66 | exports.default = ExtendedRichUtils; -------------------------------------------------------------------------------- /publish/editor/utils/colorConfig.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | colorStyleMap: { 5 | grapeFruit1: { 6 | color: '#ED5565' 7 | }, 8 | grapeFruit2: { 9 | color: '#Da4453' 10 | }, 11 | bitterSweet1: { 12 | color: '#fc6e51' 13 | }, 14 | bitterSweet2: { 15 | color: '#e9573f' 16 | }, 17 | sunFlower1: { 18 | color: '#ffce54' 19 | }, 20 | sunFlower2: { 21 | color: '#f6bb42' 22 | }, 23 | grass1: { 24 | color: '#a0d468' 25 | }, 26 | grass2: { 27 | color: '#bcc152' 28 | }, 29 | mint1: { 30 | color: '#48cfad' 31 | }, 32 | mint2: { 33 | color: '#37bc9b' 34 | }, 35 | aqua1: { 36 | color: '#4fc1e9' 37 | }, 38 | aqua2: { 39 | color: '#38afda' 40 | }, 41 | blueJeans1: { 42 | color: '#5d9cec' 43 | }, 44 | blueJeans2: { 45 | color: '#4a89dc' 46 | }, 47 | lavander1: { 48 | color: '#ac92ec' 49 | }, 50 | lavander2: { 51 | color: '#967adc' 52 | }, 53 | mediumGray1: { 54 | color: '#ccd1d9' 55 | }, 56 | mediumGray2: { 57 | color: '#aab2bd' 58 | }, 59 | darkGray1: { 60 | color: '#656d78' 61 | }, 62 | darkGray2: { 63 | color: '#434a54' 64 | } 65 | } 66 | }; -------------------------------------------------------------------------------- /publish/editor/utils/getCurrentlySelectedBlock.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | var getCurrentlySelectedBlock = function getCurrentlySelectedBlock(editorState) { 7 | var selection = editorState.getSelection(); 8 | var startKey = selection.getStartKey(); 9 | var endKey = selection.getEndKey(); 10 | var content = editorState.getCurrentContent(); 11 | var target = selection; 12 | 13 | if (startKey !== endKey && selection.getEndOffset() === 0) { 14 | var blockBefore = content.getBlockBefore(endKey); 15 | if (!blockBefore) { 16 | throw new Error('Got unexpected null or undefined'); 17 | } 18 | 19 | endKey = blockBefore.getKey(); 20 | target = target.merge({ 21 | anchorKey: startKey, 22 | anchorOffset: selection.getStartOffset(), 23 | focusKey: endKey, 24 | focusOffset: blockBefore.getLength(), 25 | isBackward: false 26 | }); 27 | } 28 | 29 | var hasAtomicBlock = content.getBlockMap().skipWhile(function (_, k) { 30 | return k !== startKey; 31 | }).takeWhile(function (_, k) { 32 | return k !== endKey; 33 | }).some(function (v) { 34 | return v.getType() === 'atomic'; 35 | }); 36 | 37 | var currentBlock = content.getBlockForKey(startKey); 38 | 39 | return { 40 | content: content, 41 | currentBlock: currentBlock, 42 | hasAtomicBlock: hasAtomicBlock, 43 | target: target 44 | }; 45 | }; 46 | 47 | exports.default = getCurrentlySelectedBlock; -------------------------------------------------------------------------------- /publish/editor/utils/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _main = require('./stateFromElement/main'); 8 | 9 | Object.defineProperty(exports, 'stateFromElement', { 10 | enumerable: true, 11 | get: function get() { 12 | return _interopRequireDefault(_main).default; 13 | } 14 | }); 15 | 16 | var _main2 = require('./stateFromHTML/main'); 17 | 18 | Object.defineProperty(exports, 'stateFromHTML', { 19 | enumerable: true, 20 | get: function get() { 21 | return _interopRequireDefault(_main2).default; 22 | } 23 | }); 24 | 25 | var _main3 = require('./stateToHTML/main'); 26 | 27 | Object.defineProperty(exports, 'stateToHTML', { 28 | enumerable: true, 29 | get: function get() { 30 | return _interopRequireDefault(_main3).default; 31 | } 32 | }); 33 | 34 | var _main4 = require('./stateFromMD/main'); 35 | 36 | Object.defineProperty(exports, 'stateFromMD', { 37 | enumerable: true, 38 | get: function get() { 39 | return _interopRequireDefault(_main4).default; 40 | } 41 | }); 42 | 43 | var _main5 = require('./stateToMD/main'); 44 | 45 | Object.defineProperty(exports, 'stateToMD', { 46 | enumerable: true, 47 | get: function get() { 48 | return _interopRequireDefault(_main5).default; 49 | } 50 | }); 51 | 52 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -------------------------------------------------------------------------------- /publish/editor/utils/stateFromElement/replaceTextWithMeta.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.default = replaceTextWithMeta; 7 | function replaceTextWithMeta(subject, searchText, replaceText) { 8 | var text = subject.text, 9 | characterMeta = subject.characterMeta; 10 | 11 | var searchTextLength = searchText.length; 12 | var replaceTextLength = replaceText.length; 13 | var resultTextParts = []; 14 | 15 | var resultCharMeta = characterMeta.slice(0, 0); 16 | var lastEndIndex = 0; 17 | var index = text.indexOf(searchText); 18 | while (index !== -1) { 19 | resultTextParts.push(text.slice(lastEndIndex, index) + replaceText); 20 | resultCharMeta = resultCharMeta.concat(characterMeta.slice(lastEndIndex, index), repeatSeq(characterMeta.slice(index, index + 1), replaceTextLength)); 21 | lastEndIndex = index + searchTextLength; 22 | index = text.indexOf(searchText, lastEndIndex); 23 | } 24 | resultTextParts.push(text.slice(lastEndIndex)); 25 | resultCharMeta = resultCharMeta.concat(characterMeta.slice(lastEndIndex)); 26 | return { text: resultTextParts.join(''), characterMeta: resultCharMeta }; 27 | } 28 | 29 | function repeatSeq(seq, count) { 30 | var result = seq.slice(0, 0); 31 | while (count-- > 0) { 32 | result = result.concat(seq); 33 | } 34 | return result; 35 | } -------------------------------------------------------------------------------- /publish/editor/utils/stateFromHTML/main.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.default = stateFromHTML; 7 | 8 | var _index = require('../index'); 9 | 10 | var _parseHTML = require('./parseHTML'); 11 | 12 | var _parseHTML2 = _interopRequireDefault(_parseHTML); 13 | 14 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 15 | 16 | function stateFromHTML(html, options) { 17 | var parser = options == null || options.parser == null ? _parseHTML2.default : options.parser; 18 | var element = parser(html); 19 | return (0, _index.stateFromElement)(element, options); 20 | } -------------------------------------------------------------------------------- /publish/editor/utils/stateFromHTML/parseHTML.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.default = parseHTML; 7 | function parseHTML(html) { 8 | var doc = void 0; 9 | if (typeof DOMParser !== 'undefined') { 10 | var parser = new DOMParser(); 11 | doc = parser.parseFromString(html, 'text/html'); 12 | } else { 13 | doc = document.implementation.createHTMLDocument(''); 14 | doc.documentElement.innerHTML = html; 15 | } 16 | return doc.body; 17 | } -------------------------------------------------------------------------------- /publish/editor/utils/stateFromMD/main.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.default = stateFromMarkdown; 7 | 8 | var _MarkdownParser = require('./MarkdownParser'); 9 | 10 | var _MarkdownParser2 = _interopRequireDefault(_MarkdownParser); 11 | 12 | var _index = require('../index'); 13 | 14 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 15 | 16 | function stateFromMarkdown(markdown) { 17 | var element = _MarkdownParser2.default.parse(markdown, { getAST: true }); 18 | return (0, _index.stateFromElement)(element); 19 | } -------------------------------------------------------------------------------- /publish/editor/utils/stateUtils/Constants.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | var BLOCK_TYPE = exports.BLOCK_TYPE = { 7 | UNSTYLED: 'unstyled', 8 | HEADER_ONE: 'header-one', 9 | HEADER_TWO: 'header-two', 10 | HEADER_THREE: 'header-three', 11 | HEADER_FOUR: 'header-four', 12 | HEADER_FIVE: 'header-five', 13 | HEADER_SIX: 'header-six', 14 | UNORDERED_LIST_ITEM: 'unordered-list-item', 15 | ORDERED_LIST_ITEM: 'ordered-list-item', 16 | BLOCKQUOTE: 'blockquote', 17 | PULLQUOTE: 'pullquote', 18 | CODE: 'code-block', 19 | ATOMIC: 'atomic' 20 | }; 21 | 22 | var ENTITY_TYPE = exports.ENTITY_TYPE = { 23 | LINK: 'LINK', 24 | IMAGE: 'IMAGE', 25 | VIDEO: 'VIDEO', 26 | AUDIO: 'AUDIO' 27 | }; 28 | 29 | var INLINE_STYLE = exports.INLINE_STYLE = { 30 | BOLD: 'BOLD', 31 | CODE: 'CODE', 32 | SPAN: 'SPAN', 33 | ITALIC: 'ITALIC', 34 | STRIKETHROUGH: 'STRIKETHROUGH', 35 | UNDERLINE: 'UNDERLINE' 36 | }; 37 | 38 | exports.default = { 39 | BLOCK_TYPE: BLOCK_TYPE, 40 | ENTITY_TYPE: ENTITY_TYPE, 41 | INLINE_STYLE: INLINE_STYLE 42 | }; -------------------------------------------------------------------------------- /publish/editor/utils/stateUtils/callModifierForSelectedBlocks.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _draftJs = require('draft-js'); 8 | 9 | var _getSelectedBlocks = require('./getSelectedBlocks'); 10 | 11 | var _getSelectedBlocks2 = _interopRequireDefault(_getSelectedBlocks); 12 | 13 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 14 | 15 | exports.default = function (editorState, modifier) { 16 | for (var _len = arguments.length, args = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) { 17 | args[_key - 2] = arguments[_key]; 18 | } 19 | 20 | var contentState = editorState.getCurrentContent(); 21 | var currentSelection = editorState.getSelection(); 22 | 23 | var startKey = currentSelection.getStartKey(); 24 | var endKey = currentSelection.getEndKey(); 25 | var startOffset = currentSelection.getStartOffset(); 26 | var endOffset = currentSelection.getEndOffset(); 27 | 28 | var isSameBlock = startKey === endKey; 29 | var selectedBlocks = (0, _getSelectedBlocks2.default)(contentState, startKey, endKey); 30 | 31 | var finalEditorState = editorState; 32 | selectedBlocks.forEach(function (block) { 33 | var currentBlockKey = block.getKey(); 34 | var selectionStart = startOffset; 35 | var selectionEnd = endOffset; 36 | 37 | if (currentBlockKey === startKey) { 38 | selectionStart = startOffset; 39 | selectionEnd = isSameBlock ? endOffset : block.getText().length; 40 | } else if (currentBlockKey === endKey) { 41 | selectionStart = isSameBlock ? startOffset : 0; 42 | selectionEnd = endOffset; 43 | } else { 44 | selectionStart = 0; 45 | selectionEnd = block.getText().length; 46 | } 47 | 48 | var selection = new _draftJs.SelectionState({ 49 | anchorKey: currentBlockKey, 50 | anchorOffset: selectionStart, 51 | focusKey: currentBlockKey, 52 | focusOffset: selectionEnd 53 | }); 54 | 55 | finalEditorState = modifier.apply(undefined, [finalEditorState, selection].concat(args)); 56 | }); 57 | 58 | return _draftJs.EditorState.forceSelection(finalEditorState, currentSelection); 59 | }; -------------------------------------------------------------------------------- /publish/editor/utils/stateUtils/combineOrderedStyles.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); 8 | 9 | function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } 10 | 11 | function combineOrderedStyles(customMap, defaults) { 12 | if (customMap == null) { 13 | return defaults; 14 | } 15 | 16 | var _defaults = _slicedToArray(defaults, 2), 17 | defaultStyleMap = _defaults[0], 18 | defaultStyleOrder = _defaults[1]; 19 | 20 | var styleMap = Object.assign({}, defaultStyleMap); 21 | var styleOrder = [].concat(_toConsumableArray(defaultStyleOrder)); 22 | var _iteratorNormalCompletion = true; 23 | var _didIteratorError = false; 24 | var _iteratorError = undefined; 25 | 26 | try { 27 | for (var _iterator = Object.keys(customMap)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { 28 | var _styleName = _step.value; 29 | 30 | if (defaultStyleMap.hasOwnProperty(_styleName)) { 31 | var defaultStyles = defaultStyleMap[_styleName]; 32 | styleMap[_styleName] = Object.assign({}, defaultStyles, customMap[_styleName]); 33 | } else { 34 | styleMap[_styleName] = customMap[_styleName]; 35 | styleOrder.push(_styleName); 36 | } 37 | } 38 | } catch (err) { 39 | _didIteratorError = true; 40 | _iteratorError = err; 41 | } finally { 42 | try { 43 | if (!_iteratorNormalCompletion && _iterator.return) { 44 | _iterator.return(); 45 | } 46 | } finally { 47 | if (_didIteratorError) { 48 | throw _iteratorError; 49 | } 50 | } 51 | } 52 | 53 | return [styleMap, styleOrder]; 54 | } 55 | 56 | exports.default = combineOrderedStyles; -------------------------------------------------------------------------------- /publish/editor/utils/stateUtils/getEntityRanges.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.EMPTY_SET = undefined; 7 | exports.default = getEntityRanges; 8 | 9 | var _immutable = require('immutable'); 10 | 11 | var EMPTY_SET = exports.EMPTY_SET = new _immutable.OrderedSet(); 12 | 13 | function getEntityRanges(text, charMetaList) { 14 | var charEntity = null; 15 | var prevCharEntity = null; 16 | var ranges = []; 17 | var rangeStart = 0; 18 | for (var i = 0, len = text.length; i < len; i++) { 19 | prevCharEntity = charEntity; 20 | var meta = charMetaList.get(i); 21 | charEntity = meta ? meta.getEntity() : null; 22 | if (i > 0 && charEntity !== prevCharEntity) { 23 | ranges.push([prevCharEntity, getStyleRanges(text.slice(rangeStart, i), charMetaList.slice(rangeStart, i))]); 24 | rangeStart = i; 25 | } 26 | } 27 | ranges.push([charEntity, getStyleRanges(text.slice(rangeStart), charMetaList.slice(rangeStart))]); 28 | return ranges; 29 | } 30 | 31 | function getStyleRanges(text, charMetaList) { 32 | var charStyle = EMPTY_SET; 33 | var prevCharStyle = EMPTY_SET; 34 | var ranges = []; 35 | var rangeStart = 0; 36 | for (var i = 0, len = text.length; i < len; i++) { 37 | prevCharStyle = charStyle; 38 | var meta = charMetaList.get(i); 39 | charStyle = meta ? meta.getStyle() : EMPTY_SET; 40 | if (i > 0 && !(0, _immutable.is)(charStyle, prevCharStyle)) { 41 | ranges.push([text.slice(rangeStart, i), prevCharStyle]); 42 | rangeStart = i; 43 | } 44 | } 45 | ranges.push([text.slice(rangeStart), charStyle]); 46 | return ranges; 47 | } -------------------------------------------------------------------------------- /publish/editor/utils/stateUtils/getSelectedBlocks.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | exports.default = function (contentState, anchorKey, focusKey) { 8 | var isSameBlock = anchorKey === focusKey; 9 | var startingBlock = contentState.getBlockForKey(anchorKey); 10 | 11 | if (!startingBlock) { 12 | return []; 13 | } 14 | 15 | var selectedBlocks = [startingBlock]; 16 | 17 | if (!isSameBlock) { 18 | var blockKey = anchorKey; 19 | 20 | while (blockKey !== focusKey) { 21 | var nextBlock = contentState.getBlockAfter(blockKey); 22 | 23 | if (!nextBlock) { 24 | selectedBlocks = []; 25 | break; 26 | } 27 | 28 | selectedBlocks.push(nextBlock); 29 | blockKey = nextBlock.getKey(); 30 | } 31 | } 32 | 33 | return selectedBlocks; 34 | }; -------------------------------------------------------------------------------- /publish/editor/utils/stateUtils/main.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _Constants = require('./Constants'); 8 | 9 | Object.keys(_Constants).forEach(function (key) { 10 | if (key === "default" || key === "__esModule") return; 11 | Object.defineProperty(exports, key, { 12 | enumerable: true, 13 | get: function get() { 14 | return _Constants[key]; 15 | } 16 | }); 17 | }); 18 | Object.defineProperty(exports, 'Constants', { 19 | enumerable: true, 20 | get: function get() { 21 | return _interopRequireDefault(_Constants).default; 22 | } 23 | }); 24 | 25 | var _getEntityRanges = require('./getEntityRanges'); 26 | 27 | Object.defineProperty(exports, 'getEntityRanges', { 28 | enumerable: true, 29 | get: function get() { 30 | return _interopRequireDefault(_getEntityRanges).default; 31 | } 32 | }); 33 | 34 | var _getSelectedBlocks = require('./getSelectedBlocks'); 35 | 36 | Object.defineProperty(exports, 'getSelectedBlocks', { 37 | enumerable: true, 38 | get: function get() { 39 | return _interopRequireDefault(_getSelectedBlocks).default; 40 | } 41 | }); 42 | 43 | var _selectionContainsEntity = require('./selectionContainsEntity'); 44 | 45 | Object.defineProperty(exports, 'selectionContainsEntity', { 46 | enumerable: true, 47 | get: function get() { 48 | return _interopRequireDefault(_selectionContainsEntity).default; 49 | } 50 | }); 51 | 52 | var _callModifierForSelectedBlocks = require('./callModifierForSelectedBlocks'); 53 | 54 | Object.defineProperty(exports, 'callModifierForSelectedBlocks', { 55 | enumerable: true, 56 | get: function get() { 57 | return _interopRequireDefault(_callModifierForSelectedBlocks).default; 58 | } 59 | }); 60 | 61 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -------------------------------------------------------------------------------- /publish/editor/utils/stateUtils/normalizeAttributes.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var ATTR_NAME_MAP = { 8 | acceptCharset: 'accept-charset', 9 | className: 'class', 10 | htmlFor: 'for', 11 | httpEquiv: 'http-equiv' 12 | }; 13 | 14 | function normalizeAttributes(attributes) { 15 | if (attributes == null) { 16 | return attributes; 17 | } 18 | var normalized = {}; 19 | var didNormalize = false; 20 | var _iteratorNormalCompletion = true; 21 | var _didIteratorError = false; 22 | var _iteratorError = undefined; 23 | 24 | try { 25 | for (var _iterator = Object.keys(attributes)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { 26 | var name = _step.value; 27 | 28 | var newName = name; 29 | if (ATTR_NAME_MAP.hasOwnProperty(name)) { 30 | newName = ATTR_NAME_MAP[name]; 31 | didNormalize = true; 32 | } 33 | normalized[newName] = attributes[name]; 34 | } 35 | } catch (err) { 36 | _didIteratorError = true; 37 | _iteratorError = err; 38 | } finally { 39 | try { 40 | if (!_iteratorNormalCompletion && _iterator.return) { 41 | _iterator.return(); 42 | } 43 | } finally { 44 | if (_didIteratorError) { 45 | throw _iteratorError; 46 | } 47 | } 48 | } 49 | 50 | return didNormalize ? normalized : attributes; 51 | } 52 | 53 | exports.default = normalizeAttributes; -------------------------------------------------------------------------------- /publish/editor/utils/stateUtils/selectionContainsEntity.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _getSelectedBlocks = require('./getSelectedBlocks'); 8 | 9 | var _getSelectedBlocks2 = _interopRequireDefault(_getSelectedBlocks); 10 | 11 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 12 | 13 | exports.default = function (strategy) { 14 | return function (editorState, selection) { 15 | var contentState = editorState.getCurrentContent(); 16 | var currentSelection = selection || editorState.getSelection(); 17 | var startKey = currentSelection.getStartKey(); 18 | var endKey = currentSelection.getEndKey(); 19 | var startOffset = currentSelection.getStartOffset(); 20 | var endOffset = currentSelection.getEndOffset(); 21 | 22 | var isSameBlock = startKey === endKey; 23 | var selectedBlocks = (0, _getSelectedBlocks2.default)(contentState, startKey, endKey); 24 | var entityFound = false; 25 | 26 | var finalStartOffset = startOffset + 1; 27 | var finalEndOffset = endOffset - 1; 28 | 29 | selectedBlocks.forEach(function (block) { 30 | strategy(block, function (start, end) { 31 | if (entityFound) { 32 | return; 33 | } 34 | 35 | var blockKey = block.getKey(); 36 | 37 | if (isSameBlock && (end < finalStartOffset || start > finalEndOffset)) { 38 | return; 39 | } else if (blockKey === startKey && end < finalStartOffset) { 40 | return; 41 | } else if (blockKey === endKey && start > finalEndOffset) { 42 | return; 43 | } 44 | 45 | entityFound = true; 46 | }); 47 | }); 48 | 49 | return entityFound; 50 | }; 51 | }; -------------------------------------------------------------------------------- /publish/editor/utils/stateUtils/styleToCSS.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _CSSProperty = require('react-dom/lib/CSSProperty'); 8 | 9 | var VENDOR_PREFIX = /^(moz|ms|o|webkit)-/; 10 | var NUMERIC_STRING = /^\d+$/; 11 | var UPPERCASE_PATTERN = /([A-Z])/g; 12 | 13 | function processStyleName(name) { 14 | return name.replace(UPPERCASE_PATTERN, '-$1').toLowerCase().replace(VENDOR_PREFIX, '-$1-'); 15 | } 16 | 17 | function processStyleValue(name, value) { 18 | var isNumeric = void 0; 19 | if (typeof value === 'string') { 20 | isNumeric = NUMERIC_STRING.test(value); 21 | } else { 22 | isNumeric = true; 23 | value = String(value); 24 | } 25 | if (!isNumeric || value === '0' || _CSSProperty.isUnitlessNumber[name] === true) { 26 | return value; 27 | } else { 28 | return value + 'px'; 29 | } 30 | } 31 | 32 | function styleToCSS(styleDescr) { 33 | return Object.keys(styleDescr).map(function (name) { 34 | var styleValue = processStyleValue(name, styleDescr[name]); 35 | var styleName = processStyleName(name); 36 | return styleName + ': ' + styleValue; 37 | }).join('; '); 38 | } 39 | 40 | exports.default = styleToCSS; -------------------------------------------------------------------------------- /publish/global/components/businessComponents.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | UploadImage: require('./businessComponents/UploadImage'), 5 | GroupUpload: require('./businessComponents/GroupUpload') 6 | }; -------------------------------------------------------------------------------- /publish/global/supports/datas/base.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = { 4 | Config: { 5 | version: "2.1.3 (Beta)", 6 | server: { 7 | ajax: 'http://114.55.148.57:8083/' }, 8 | watermarkImage: [{ 9 | type: "white_small", 10 | tip: "白色小图", 11 | value: "http://7xjl1j.com1.z0.glb.clouddn.com/white_small.png", 12 | valuebase64: "aHR0cDovLzd4amwxai5jb20xLnowLmdsYi5jbG91ZGRuLmNvbS93aGl0ZV9zbWFsbC5wbmc=" 13 | }, { 14 | type: "white_big", 15 | tip: "白色大图", 16 | value: "http://7xjl1j.com1.z0.glb.clouddn.com/white_big.png", 17 | valuebase64: "aHR0cDovLzd4amwxai5jb20xLnowLmdsYi5jbG91ZGRuLmNvbS93aGl0ZV9iaWcucG5n" 18 | }, { 19 | type: "gray_small", 20 | tip: "灰色小图", 21 | value: "http://7xjl1j.com1.z0.glb.clouddn.com/gray_small.png", 22 | valuebase64: "aHR0cDovLzd4amwxai5jb20xLnowLmdsYi5jbG91ZGRuLmNvbS9ncmF5X3NtYWxsLnBuZw==" 23 | }, { 24 | type: "gray_big", 25 | tip: "灰色大图", 26 | value: "http://7xjl1j.com1.z0.glb.clouddn.com/gray_big.png", 27 | valuebase64: "aHR0cDovLzd4amwxai5jb20xLnowLmdsYi5jbG91ZGRuLmNvbS9ncmF5X2JpZy5wbmc=" 28 | }, { 29 | type: "black_small", 30 | tip: "黑色小图", 31 | value: "http://7xjl1j.com1.z0.glb.clouddn.com/black_small.png", 32 | valuebase64: "aHR0cDovLzd4amwxai5jb20xLnowLmdsYi5jbG91ZGRuLmNvbS9ibGFja19zbWFsbC5wbmc=" 33 | }, { 34 | type: "black_big", 35 | tip: "黑色大图", 36 | value: "http://7xjl1j.com1.z0.glb.clouddn.com/black_big.png", 37 | valuebase64: "aHR0cDovLzd4amwxai5jb20xLnowLmdsYi5jbG91ZGRuLmNvbS9ibGFja19iaWcucG5n" 38 | }] 39 | } 40 | }; -------------------------------------------------------------------------------- /publish/global/supports/methods/public.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _Request = require('./Request'); 4 | 5 | var _url = require('../datas/url'); 6 | 7 | module.exports = { 8 | supportMime: { 9 | image: ["image/jpeg", "image/png", "image/jpg", "image/gif", "image/webp"], 10 | video: ["video/mp4"], 11 | audio: ["audio/mp4", "audio/mp3", "audio/mpeg"] 12 | }, 13 | makeGuid: function makeGuid() { 14 | var guid = ""; 15 | for (var i = 1; i <= 32; i++) { 16 | var n = Math.floor(Math.random() * 16.0).toString(16); 17 | guid += n; 18 | if (i == 8 || i == 12 || i == 16 || i == 20) guid += "-"; 19 | } 20 | return guid; 21 | }, 22 | 23 | nowTime: function nowTime() { 24 | var time = Date.parse(new Date()) / 1000; 25 | return time; 26 | }, 27 | 28 | checkQiniu: { 29 | 30 | checkQiniuImgToken: function checkQiniuImgToken(key) { 31 | 32 | var timestamp = Date.parse(new Date()) / 1000; 33 | var last_qiniu_token_time = localStorage.getItem("last_qiniu_token_time_" + key); 34 | var mark = false; 35 | 36 | if (last_qiniu_token_time) { 37 | if (timestamp - last_qiniu_token_time < 3500) { 38 | mark = true; 39 | } 40 | } 41 | var qiniu_token = ""; 42 | if (localStorage.getItem("qiniu_" + key + "_token") && mark) { 43 | qiniu_token = localStorage.getItem("qiniu_" + key + "_token"); 44 | } 45 | return qiniu_token; 46 | }, 47 | returnToken: function returnToken() { 48 | var uploadConfig = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; 49 | var key = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'image'; 50 | var params = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; 51 | 52 | if (Object.keys(uploadConfig).length == 0) { 53 | return false; 54 | } 55 | var token = this.checkQiniuImgToken(key); 56 | token = !!token == true ? token : this.getQiniuToken(uploadConfig, key, params); 57 | return token; 58 | }, 59 | getQiniuToken: function getQiniuToken(uploadConfig) { 60 | var type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'image'; 61 | var params = arguments[2]; 62 | 63 | var token = ""; 64 | var url = void 0; 65 | if (type == 'image') { 66 | url = uploadConfig.QINIU_IMG_TOKEN_URL; 67 | } else if (type == 'video') { 68 | url = uploadConfig.QINIU_VIDEO_TOKEN_URL; 69 | } else if (type == 'file') { 70 | url = uploadConfig.QINIU_FILE_TOKEN_URL; 71 | } else if (type == 'manage') { 72 | url = uploadConfig.QINIU_MANAGE_TOKEN_URL; 73 | } else { 74 | url = uploadConfig.QINIU_IMG_TOKEN_URL; 75 | } 76 | 77 | _Request.ajax.requestData({ 78 | url: url, 79 | method: 'post', 80 | isAsync: true, 81 | defaultData: {} 82 | }, params, function (data) { 83 | token = data.uptoken; 84 | 85 | localStorage.setItem("qiniu_" + type + "_token", token); 86 | localStorage.setItem("last_qiniu_token_time_" + type, Date.parse(new Date()) / 1000); 87 | }, function () { 88 | return false; 89 | }); 90 | return token; 91 | } 92 | } 93 | }; -------------------------------------------------------------------------------- /publish/global/supports/publicDatas.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | PRO_BASE: require('./datas/base'), 5 | PRO_URL: require('./datas/url'), 6 | PRO_REQUEST: require('./methods/Request'), 7 | PRO_COMMON: require('./methods/common'), 8 | PRO_QINIU: require('./methods/public') 9 | }; -------------------------------------------------------------------------------- /publish/global/supports/resources/blur.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /publish/global/supports/resources/custom.css: -------------------------------------------------------------------------------- 1 | .openFullAll { 2 | position: fixed; 3 | top: 0; 4 | right: 0; 5 | bottom: 0; 6 | left: 0; 7 | z-index: 999; 8 | overflow: auto; 9 | } 10 | 11 | .watermark_grid { 12 | display: block; 13 | position: absolute; 14 | top: 0; 15 | background-repeat: no-repeat; 16 | } 17 | 18 | .watermark_grid span { 19 | display: inline-block; 20 | border: 1px dashed rgba(255, 255, 255, .2); 21 | cursor: pointer; 22 | } 23 | 24 | .editor-inline-image tips { 25 | font-size: 12px; 26 | position: absolute; 27 | right: 0; 28 | color: #aaa; 29 | } 30 | 31 | .breakImages>div { 32 | width: 100px; 33 | height: 100px; 34 | overflow: hidden; 35 | display: inline-block; 36 | margin: 10px 10px 0 0; 37 | background-clip: content-box; 38 | background-size: cover; 39 | background-repeat: no-repeat; 40 | background-position: center; 41 | border: 1px solid #E9E9E9; 42 | border-radius: 3px; 43 | overflow: hidden; 44 | } 45 | -------------------------------------------------------------------------------- /publish/global/supports/resources/default/iconfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaen/react-lz-editor/5097a8a57ac919afab3da11ad10e076bfdf4be24/publish/global/supports/resources/default/iconfont.eot -------------------------------------------------------------------------------- /publish/global/supports/resources/default/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaen/react-lz-editor/5097a8a57ac919afab3da11ad10e076bfdf4be24/publish/global/supports/resources/default/iconfont.ttf -------------------------------------------------------------------------------- /publish/global/supports/resources/default/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaen/react-lz-editor/5097a8a57ac919afab3da11ad10e076bfdf4be24/publish/global/supports/resources/default/iconfont.woff -------------------------------------------------------------------------------- /publish/global/supports/resources/iconfont.css: -------------------------------------------------------------------------------- 1 | 2 | @font-face {font-family: "iconfont"; 3 | src: url('iconfont.eot?t=1479085947184'); /* IE9*/ 4 | src: url('iconfont.eot?t=1479085947184#iefix') format('embedded-opentype'), /* IE6-IE8 */ 5 | url('iconfont.woff?t=1479085947184') format('woff'), /* chrome, firefox */ 6 | url('iconfont.ttf?t=1479085947184') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/ 7 | url('iconfont.svg?t=1479085947184#iconfont') format('svg'); /* iOS 4.1- */ 8 | } 9 | 10 | .iconfont { 11 | font-family:"iconfont" !important; 12 | font-size:16px; 13 | font-style:normal; 14 | -webkit-font-smoothing: antialiased; 15 | -webkit-text-stroke-width: 0.2px; 16 | -moz-osx-font-smoothing: grayscale; 17 | } 18 | 19 | .icon-panorama_time:before { content: "\ea16"; } 20 | 21 | .icon-shangdian:before { content: "\ea01"; } 22 | 23 | .icon-yonghuzumingcheng:before { content: "\ea36"; } 24 | 25 | .icon-panorama_joinuser:before { content: "\ea18"; } 26 | 27 | .icon-panorama_joindevice:before { content: "\ea19"; } 28 | 29 | .icon-shangpin:before { content: "\e998"; } 30 | 31 | .icon-newsVerify:before { content: "\ea26"; } 32 | 33 | .icon-access_user:before { content: "\ea1d"; } 34 | 35 | .icon-xitong:before { content: "\ea1c"; } 36 | 37 | .icon-dropdown:before { content: "\ea0b"; } 38 | 39 | .icon-yidianhaoleibie:before { content: "\ea2e"; } 40 | 41 | .icon-unie60e:before { content: "\ea23"; } 42 | 43 | .icon-yidianhaowenzhang:before { content: "\ea30"; } 44 | 45 | .icon-empty:before { content: "\ea0d"; } 46 | 47 | .icon-lunbozutu:before { content: "\ea06"; } 48 | 49 | .icon-quanzi:before { content: "\e991"; } 50 | 51 | .icon-recycleNews:before { content: "\ea24"; } 52 | 53 | .icon-tiezi:before { content: "\e995"; } 54 | 55 | .icon-unie6672:before { content: "\e996"; } 56 | 57 | .icon-untitled22:before { content: "\e993"; } 58 | 59 | .icon-unie604:before { content: "\e932"; } 60 | 61 | .icon-untitled144:before { content: "\ea04"; } 62 | 63 | .icon-newsChannel1:before { content: "\ea27"; } 64 | 65 | .icon-quanziline:before { content: "\e992"; } 66 | 67 | .icon-piliangicon:before { content: "\ea08"; } 68 | 69 | .icon-yidianhaotiaomu:before { content: "\ea2f"; } 70 | 71 | .icon-huodong:before { content: "\e999"; } 72 | 73 | .icon-paixu:before { content: "\ea03"; } 74 | 75 | .icon-news:before { content: "\ea2a"; } 76 | 77 | .icon-jiangpai:before { content: "\ea1b"; } 78 | 79 | .icon-appclient:before { content: "\ea40"; } 80 | 81 | .icon-neirong:before { content: "\e994"; } 82 | 83 | .icon-paixu1:before { content: "\ea0e"; } 84 | 85 | .icon-newsComment:before { content: "\ea29"; } 86 | 87 | .icon-bumen:before { content: "\ea34"; } 88 | 89 | .icon-pinpai:before { content: "\ea02"; } 90 | 91 | .icon-newsChannel:before { content: "\ea28"; } 92 | 93 | .icon-yonghuxinxixian:before { content: "\ea07"; } 94 | 95 | .icon-panorama_app:before { content: "\ea1a"; } 96 | 97 | .icon-panorama_today:before { content: "\ea12"; } 98 | 99 | .icon-yaochi:before { content: "\ea09"; } 100 | 101 | .icon-gengxinupdated:before { content: "\ea21"; } 102 | 103 | .icon-panorama_version:before { content: "\ea14"; } 104 | 105 | .icon-wochuangjiande:before { content: "\ea38"; } 106 | 107 | .icon-ditu-copy-copy:before { content: "\e997"; } 108 | 109 | .icon-jingxuan-copy:before { content: "\ea05"; } 110 | 111 | .icon-yichu:before { content: "\ea0a"; } 112 | 113 | .icon-panorama_newboot:before { content: "\ea13"; } 114 | 115 | .icon-panorama:before { content: "\ea15"; } 116 | 117 | .icon-panorama_device:before { content: "\ea17"; } 118 | 119 | .icon-lunbotuzujian:before { content: "\ea39"; } 120 | 121 | .icon-order:before { content: "\ea0c"; } 122 | 123 | .icon-sort:before { content: "\ea10"; } 124 | 125 | .icon-zhanghuyuquanxian:before { content: "\ea32"; } 126 | 127 | .icon-panorama_action:before { content: "\ea11"; } 128 | 129 | .icon-yidianhaoshenhe:before { content: "\ea31"; } 130 | 131 | .icon-jiaosequanxian0101:before { content: "\ea1f"; } 132 | 133 | .icon-city:before { content: "\ea25"; } 134 | 135 | .icon-startpage:before { content: "\ea41"; } 136 | 137 | .icon-jiaosesheding:before { content: "\ea1e"; } 138 | 139 | .icon-chuangjianjiaose:before { content: "\ea22"; } 140 | 141 | .icon-yidianhao:before { content: "\ea2d"; } 142 | 143 | .icon-gongzuoxiang:before { content: "\ea20"; } 144 | 145 | .icon-grab:before { content: "\ea2c"; } 146 | 147 | .icon-draft:before { content: "\ea2b"; } 148 | 149 | .icon-channelpd-copy:before { content: "\ea33"; } 150 | 151 | .icon-bumen-copy:before { content: "\ea37"; } 152 | 153 | .icon-10106-copy:before { content: "\ea35"; } 154 | 155 | .icon-news_radar:before { content: "\ea49"; } 156 | 157 | .icon-news_radar_list:before { content: "\ea50"; } 158 | 159 | .icon-news_radar_comment:before { content: "\ea51"; } 160 | -------------------------------------------------------------------------------- /publish/global/supports/resources/system.less: -------------------------------------------------------------------------------- 1 | @import "custom.css"; 2 | @import "fonticon/default.less"; -------------------------------------------------------------------------------- /publish/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = require('./editor/index'); 4 | exports.LzEditor = require('./editor/index'); -------------------------------------------------------------------------------- /publish/main.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _test = require('./test.jsx'); 4 | 5 | var _test2 = _interopRequireDefault(_test); 6 | 7 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -------------------------------------------------------------------------------- /publish/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-lz-editor", 3 | "version": "0.12.1", 4 | "description": "An open source react rich-text editor (mordern react editor includes media support such as texts, images, videos, audios, links etc.), development based on Draft-Js and Ant-design, good support html, markdown, draft-raw mode.", 5 | "main": "index", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+ssh://git@github.com/leejaen/react-lz-editor.git" 12 | }, 13 | "keywords": [ 14 | "react editor", 15 | "draft-js", 16 | "react-rich-editor", 17 | "react-lz-editor" 18 | ], 19 | "devDependencies": { 20 | "babel-cli": "^6.6.5", 21 | "babel-loader": "^6.2.4", 22 | "babel-plugin-transform-class-properties": "^6.19.0", 23 | "babel-preset-es2015": "^6.6.0", 24 | "babel-preset-react": "^6.16.0", 25 | "babel-preset-stage-2": "^6.18.0", 26 | "css-loader": "^0.23.1", 27 | "eslint": "^3.12.2", 28 | "eslint-plugin-react": "^6.8.0", 29 | "file-loader": "^0.8.5", 30 | "flow-bin": "^0.37.4", 31 | "less": "^2.7.1", 32 | "less-loader": "^2.2.3", 33 | "react": "^0.14.8", 34 | "style-loader": "^0.13.1", 35 | "url-loader": "^0.5.7", 36 | "webpack": "^1.12.14", 37 | "webpack-dev-server": "^1.14.1" 38 | }, 39 | "dependencies": { 40 | "antd": "^2.8.3", 41 | "draft-js": "^0.10.0", 42 | "immutable": "^3.8.1", 43 | "js-base64": "^2.1.9", 44 | "lodash": "^4.17.3", 45 | "synthetic-dom": "^0.2.1" 46 | }, 47 | "author": "leejaen@gmail.com", 48 | "license": "ISC", 49 | "bugs": { 50 | "url": "https://github.com/leejaen/react-lz-editor/issues" 51 | }, 52 | "homepage": "https://github.com/leejaen/react-lz-editor#readme" 53 | } 54 | -------------------------------------------------------------------------------- /src/editor/components.css: -------------------------------------------------------------------------------- 1 | .editorHidden { 2 | z-index: 10; 3 | overflow: hidden; 4 | position: relative; 5 | } 6 | 7 | .editor_container { 8 | border: 1px solid #E9E9E9; 9 | background-color: #F9F9F9; 10 | padding: 5px; 11 | } 12 | 13 | .editor_top { 14 | height: 30px; 15 | width: 100%; 16 | } 17 | 18 | .editor_middle { 19 | background-color: #FFF; 20 | border: 1px solid #E9E9E9; 21 | box-shadow: 3px 3px 5px #AAA inset; 22 | } 23 | 24 | .editor_bottom { 25 | height: 30px; 26 | width: 100%; 27 | } 28 | 29 | .superFancyBlockquote { 30 | color: #999; 31 | font-style: italic; 32 | text-align: center; 33 | } 34 | /*.public-DraftEditor-content>div>div>div>div:before{content:"¶"}*/ 35 | .editor-inline-image img, 36 | .editor-inline-video video, 37 | .editor-inline-audio audio { 38 | padding: 0 5px; 39 | display: block; 40 | margin: 0 auto; 41 | max-width: 100%; 42 | } 43 | 44 | .RichEditor-root { 45 | background: #FFF; 46 | font-size: 14px; 47 | padding: 15px; 48 | } 49 | 50 | .RichEditor-editor { 51 | cursor: text; 52 | font-size: 16px; 53 | } 54 | 55 | .RichEditor-toolbar { 56 | border-bottom: 1px solid #DDD; 57 | } 58 | 59 | .public-DraftStyleDefault-ul { 60 | list-style: disc; 61 | padding-left: 2.0rem 62 | } 63 | 64 | .public-DraftStyleDefault-ol { 65 | padding-left: 2.0rem; 66 | list-style-type: decimal; 67 | } 68 | 69 | .RichEditor-editor .public-DraftEditorPlaceholder-root, 70 | .RichEditor-editor .public-DraftEditor-content { 71 | margin: 0 -15px -15px; 72 | padding: 15px; 73 | } 74 | 75 | .RichEditor-editor .public-DraftEditor-content { 76 | min-height: 100px; 77 | line-height: initial; 78 | } 79 | 80 | .RichEditor-editor .public-DraftEditor-content>div>* { 81 | margin: 10px 0; 82 | } 83 | 84 | .RichEditor-editor .public-DraftEditor-content pre { 85 | white-space: pre-wrap; 86 | word-wrap: break-word; 87 | } 88 | 89 | .RichEditor-hidePlaceholder .public-DraftEditorPlaceholder-root { 90 | display: none; 91 | } 92 | 93 | .RichEditor-editor .RichEditor-blockquote { 94 | border-left: 5px solid #EEE; 95 | color: #666; 96 | font-family: 'Hoefler Text', 'Georgia', serif; 97 | font-style: italic; 98 | margin: 16px 0; 99 | padding: 10px 20px; 100 | } 101 | 102 | .RichEditor-editor .RichEditor-alignment-left { 103 | text-align: left; 104 | } 105 | 106 | .RichEditor-editor .RichEditor-alignment-center { 107 | text-align: center; 108 | } 109 | 110 | .RichEditor-editor .RichEditor-alignment-right { 111 | text-align: right; 112 | } 113 | 114 | .RichEditor-editor .RichEditor-alignment-justify { 115 | text-align: justify; 116 | } 117 | 118 | .RichEditor-editor .public-DraftStyleDefault-pre { 119 | background-color: rgba(0, 0, 0, 0.05); 120 | font-family: 'Inconsolata', 'Menlo', 'Consolas', monospace; 121 | font-size: 16px; 122 | padding: 20px; 123 | } 124 | 125 | .RichEditor-controls { 126 | font-family: 'Helvetica', sans-serif; 127 | font-size: 14px; 128 | margin-bottom: 5px; 129 | user-select: none; 130 | display: inline; 131 | border-left: 1px solid #EEE; 132 | } 133 | .RichEditor-controls .ant-btn{ 134 | transition:none!important; 135 | -o-transition:none!important; 136 | -ms-transition:none!important; 137 | -moz-transition:none!important; 138 | -webkit-transition:none!important; 139 | } 140 | .RichEditor-controls-split { 141 | padding-right: 20px 142 | } 143 | 144 | .RichEditor-color span { 145 | margin: 0; 146 | width: 16px; 147 | line-height: 28px; 148 | } 149 | 150 | .RichEditor-styleButton { 151 | color: #999; 152 | cursor: pointer; 153 | margin: 0 8px; 154 | padding: 3px 5px !important; 155 | display: inline-block; 156 | position: relative; 157 | margin: 8px 5px; 158 | line-height: 20px; 159 | font-size: 16px; 160 | border: 1px solid transparent; 161 | } 162 | .RichEditor-styleButton.ant-btn.ant-btn-primary.ant-btn-icon-only{ 163 | color: #fff; 164 | } 165 | 166 | .RichEditor-styleButton i.anticon { 167 | margin-left: 0px !important; 168 | } 169 | 170 | .RichEditor-activeButton { 171 | color: #fff; 172 | border-radius: 5px; 173 | /*Can not use the default color, otherwise it will replace the custom theme color*/ 174 | } 175 | 176 | .RichEditor-color { 177 | display: inline-block; 178 | height: 16px; 179 | width: 16px; 180 | overflow: hidden; 181 | top: 3px; 182 | position: relative; 183 | border-radius: 3px; 184 | margin: 0px 5px; 185 | } 186 | 187 | .RichEditor-color-active {} 188 | 189 | .RichEditor-color:nth-child(2n+1) {} 190 | #text-editor-affix>.ant-affix{background-color:#fff!important;} 191 | .disabled-mask { 192 | background: rgba(200,200,200,0.5); 193 | width: 100%; 194 | height: 100%; 195 | top: 0; 196 | display: block; 197 | position: absolute; 198 | pointer-events: unset; 199 | cursor: not-allowed; 200 | left: 0; 201 | } 202 | .disabled-editor{ 203 | filter: grayscale(100%); 204 | } 205 | -------------------------------------------------------------------------------- /src/editor/config/colorStyleMap.jsx: -------------------------------------------------------------------------------- 1 | 2 | // This object provides the styling information for our custom color styles. 3 | const colorStyleMap = { 4 | grapeFruit1: { 5 | color: '#ED5565' 6 | }, 7 | grapeFruit2: { 8 | color: '#Da4453' 9 | }, 10 | bitterSweet1: { 11 | color: '#fc6e51' 12 | }, 13 | bitterSweet2: { 14 | color: '#e9573f' 15 | }, 16 | sunFlower1: { 17 | color: '#ffce54' 18 | }, 19 | sunFlower2: { 20 | color: '#f6bb42' 21 | }, 22 | grass1: { 23 | color: '#a0d468' 24 | }, 25 | grass2: { 26 | color: '#bcc152' 27 | }, 28 | mint1: { 29 | color: '#48cfad' 30 | }, 31 | mint2: { 32 | color: '#37bc9b' 33 | }, 34 | aqua1: { 35 | color: '#4fc1e9' 36 | }, 37 | aqua2: { 38 | color: '#38afda' 39 | }, 40 | blueJeans1: { 41 | color: '#5d9cec' 42 | }, 43 | blueJeans2: { 44 | color: '#4a89dc' 45 | }, 46 | lavander1: { 47 | color: '#ac92ec' 48 | }, 49 | lavander2: { 50 | color: '#967adc' 51 | }, 52 | mediumGray1: { 53 | color: '#ccd1d9' 54 | }, 55 | mediumGray2: { 56 | color: '#aab2bd' 57 | }, 58 | darkGray1: { 59 | color: '#656d78' 60 | }, 61 | darkGray2: { 62 | color: '#434a54' 63 | } 64 | }; 65 | 66 | module.exports=colorStyleMap; 67 | -------------------------------------------------------------------------------- /src/editor/decorators/AudioDecorator.jsx: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | import AudioSpan from './AudioSpan'; 3 | import {Entity} from 'draft-js'; 4 | import {ENTITY_TYPE} from '../utils/stateUtils/main'; 5 | 6 | import type {ContentBlock} from 'draft-js'; 7 | // import {ContentBlock} from 'draft-js'; 8 | type EntityRangeCallback = (start: number, end: number) => void; 9 | function findAudioEntities(contentBlock: ContentBlock, callback: EntityRangeCallback) { 10 | // function findAudioEntities(contentBlock: ContentBlock, callback) { 11 | 12 | contentBlock.findEntityRanges((character) => { 13 | const entityKey = character.getEntity(); 14 | return ( 15 | entityKey != null && 16 | Entity.get(entityKey).getType() === ENTITY_TYPE.AUDIO 17 | ); 18 | }, callback); 19 | } 20 | 21 | export default { 22 | strategy: findAudioEntities, 23 | component: AudioSpan, 24 | }; 25 | -------------------------------------------------------------------------------- /src/editor/decorators/AudioSpan.jsx: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | // import autobind from 'class-autobind'; 4 | import React, {Component} from 'react'; 5 | import {Entity} from 'draft-js'; 6 | 7 | // $FlowIssue - Flow doesn't understand CSS Modules 8 | import styles from './decoratorStyle.css'; 9 | 10 | export default class AudioSpan extends Component { 11 | constructor(props : Props) { 12 | super(props); 13 | // autobind(this); 14 | const entity = Entity.get(this.props.entityKey); 15 | const {width, height} = entity.getData(); 16 | this.state = { 17 | width, 18 | height 19 | }; 20 | } 21 | 22 | componentDidMount() { 23 | const {width 24 | , height} = this.state; 25 | const entity = Entity.get(this.props.entityKey); 26 | const audio = document.createElement('audio'); 27 | const {src} = entity.getData(); 28 | audio.src = src; 29 | audio.onload = () => { 30 | if (width == null || height == null) { 31 | // TODO: isMounted? 32 | this.setState({width: audio.width, height: audio.height}); 33 | Entity.mergeData(this.props.entityKey, { 34 | width: audio.width, 35 | height: audio.height, 36 | originalWidth: audio.width, 37 | originalHeight: audio.height 38 | }); 39 | } 40 | }; 41 | } 42 | 43 | render() { 44 | const {width, height} = this.state; 45 | //let {className} = this.props; 46 | const entity = Entity.get(this.props.entityKey); 47 | const {src} = entity.getData(); 48 | //console.log("styles.root: ", styles.root); className = cx(className, styles.root); 49 | const audioStyle = { 50 | verticalAlign: 'bottom', 51 | backgroundImage: `url("${src}")`, 52 | backgroundSize: `${width}px ${height}px`, 53 | lineHeight: `${height}px`, 54 | fontSize: `${height}px`, 55 | width, 56 | height, 57 | letterSpacing: width 58 | }; 59 | 60 | // return ( {this.props.children} ); 62 | return ( 63 |
64 | 65 |
66 | ); 67 | } 68 | 69 | _onClick() { 70 | //console.log('audio click'); 71 | } 72 | 73 | _handleResize(event : Object, data : Object) { 74 | const {width, height} = data.size; 75 | this.setState({width, height}); 76 | Entity.mergeData(this.props.entityKey, {width, height}); 77 | } 78 | } 79 | //AudioSpan.propTypes={ children: React.PropTypes, entityKey: string, className?: string } 80 | 81 | AudioSpan.defaultProps = { 82 | children: null, 83 | entityKey: "", 84 | className: "" 85 | } 86 | -------------------------------------------------------------------------------- /src/editor/decorators/ImageDecorator.jsx: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | import ImageSpan from './ImageSpan'; 3 | import {Entity} from 'draft-js'; 4 | import {ENTITY_TYPE} from '../utils/stateUtils/main'; 5 | 6 | import type {ContentBlock} from 'draft-js'; 7 | 8 | type EntityRangeCallback = (start: number, end: number) => void; 9 | 10 | function findImageEntities(contentBlock: ContentBlock, callback: EntityRangeCallback) { 11 | contentBlock.findEntityRanges((character) => { 12 | const entityKey = character.getEntity(); 13 | return ( 14 | entityKey != null && 15 | Entity.get(entityKey).getType() === ENTITY_TYPE.IMAGE 16 | ); 17 | }, callback); 18 | } 19 | 20 | export default { 21 | strategy: findImageEntities, 22 | component: ImageSpan, 23 | }; 24 | -------------------------------------------------------------------------------- /src/editor/decorators/ImageSpan.jsx: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | // import autobind from 'class-autobind'; 4 | import React, {Component} from 'react'; 5 | import ReactDom from 'react-dom'; 6 | import {Entity,EditorState} from 'draft-js'; 7 | import {message} from 'antd'; 8 | 9 | // $FlowIssue - Flow doesn't understand CSS Modules 10 | import styles from './decoratorStyle.css'; 11 | 12 | export default class ImageSpan extends Component { 13 | constructor(props : Props) { 14 | super(props); 15 | // autobind(this); 16 | const entity = Entity.get(this.props.entityKey); 17 | const {width, height} = entity.getData(); 18 | this.state = { 19 | width, 20 | height, 21 | imageSrc:'' 22 | }; 23 | this.onImageClick=this._onImageClick.bind(this); 24 | this.onDoubleClick=this._onDoubleClick.bind(this); 25 | } 26 | 27 | componentDidMount() { 28 | const {width, height} = this.state; 29 | const entity = Entity.get(this.props.entityKey); 30 | const image = new Image(); 31 | let {src} = entity.getData(); 32 | src=src.replace(/[?#&].*$/g,""); 33 | this.setState({imageSrc:src}); 34 | image.src = this.state.imageSrc; 35 | image.onload = () => { 36 | if (width == null || height == null) { 37 | // TODO: isMounted? 38 | this.setState({width: image.width, height: image.height}); 39 | Entity.mergeData(this.props.entityKey, { 40 | width: image.width, 41 | height: image.height, 42 | originalWidth: image.width, 43 | originalHeight: image.height 44 | }); 45 | } 46 | }; 47 | } 48 | 49 | render() { 50 | const {width, height} = this.state; 51 | //let {className} = this.props; 52 | let key=this.props.entityKey; 53 | const entity = Entity.get(key); 54 | const {src} = entity.getData(); 55 | // this.setState({imageSrc:src}); 56 | //console.log("styles.root: ", styles.root); className = cx(className, styles.root); 57 | const imageStyle = { 58 | verticalAlign: 'bottom', 59 | backgroundImage: `url("${this.state.imageSrc}")`, 60 | backgroundSize: `${width}px ${height}px`, 61 | lineHeight: `${height}px`, 62 | fontSize: `${height}px`, 63 | width, 64 | height, 65 | letterSpacing: width 66 | }; 67 | 68 | // return ( {this.props.children} ); 70 | // {imageStyle.width&&imageStyle.height?`Width ${imageStyle.width}px Height ${imageStyle.height}px`:""} 71 | return ( 72 |
73 | {this.onImageClick(event,key);event.stopPropagation();}} onDoubleClick={this.onDoubleClick}/> 74 |
75 | ); 76 | } 77 | 78 | _onDoubleClick() { 79 | //Popup a modal to edit 80 | let currentPicture=ReactDom.findDOMNode(this).querySelector("img"); 81 | let pictureWidth=currentPicture.naturalWidth; 82 | let pictureSrc=currentPicture.src; 83 | // console.log("pictureSrc",pictureSrc); 84 | // currentPicture.src="http://www.cbinews.com/article/image/20161027/20161027091805_674.png" 85 | } 86 | _onImageClick(e:any,key){ 87 | let currentPicture=ReactDom.findDOMNode(this).querySelector("img"); 88 | // console.log("currentPicture:",currentPicture.src); 89 | let pictureWidth=currentPicture.naturalWidth; 90 | // console.log("this",this); 91 | // console.log("this.props.children[0].key",this.props.children[0].key); 92 | // console.log("this.state.editorState",EditorState); 93 | // console.log("key",key); 94 | // console.log("pictureWidth:",pictureWidth); 95 | 96 | const editorState=EditorState.createEmpty(); 97 | const selection = editorState.getSelection(); 98 | // console.log("selection",selection); 99 | const blockTree = editorState.getBlockTree(this.props.children[0].key); 100 | // console.log("blockTree",blockTree); 101 | // this.setState({imageSrc:"https://image.qiluyidian.mobi/87928142151028397142qn1d609U291dGhFYXN0.jpg"}); 102 | if (pictureWidth==0) { 103 | message.error("图片地址错误!"); 104 | }else if(pictureWidth>650) { 105 | message.error("图片尺寸过大将会导致用户流量浪费!请调整至最大650px。",10); 106 | } 107 | } 108 | 109 | _handleResize(event : Object, data : Object) { 110 | const {width, height} = data.size; 111 | this.setState({width, height}); 112 | Entity.mergeData(this.props.entityKey, {width, height}); 113 | } 114 | } 115 | //ImageSpan.propTypes={ children: React.PropTypes, entityKey: string, className?: string } 116 | 117 | ImageSpan.defaultProps = { 118 | children: null, 119 | entityKey: "", 120 | className: "" 121 | } 122 | -------------------------------------------------------------------------------- /src/editor/decorators/LinkDecorator.jsx: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | import React from 'react'; 3 | import {Entity} from 'draft-js'; 4 | import {ENTITY_TYPE} from '../utils/stateUtils/main'; 5 | 6 | import type {ContentBlock} from 'draft-js'; 7 | 8 | // TODO: Use a more specific type here. 9 | type ReactNode = any; 10 | 11 | type Props = { 12 | children: ReactNode, 13 | entityKey: string, 14 | }; 15 | 16 | type EntityRangeCallback = (start: number, end: number) => void; 17 | 18 | function Link(props_: Props): React.Element { 19 | const {url} = Entity.get(props_.entityKey).getData(); 20 | return ( 21 | {props_.children} 22 | ); 23 | 24 | 25 | 26 | // const {url} = Entity.get(props.entityKey).getData(); 27 | // let currentStyle = props.editorState 28 | // ? props.editorState.getCurrentInlineStyle() 29 | // : {}; 30 | // return ( 31 | // 34 | // {props.children} 35 | // 36 | // ); 37 | } 38 | 39 | function findLinkEntities(contentBlock: ContentBlock, callback: EntityRangeCallback) { 40 | contentBlock.findEntityRanges((character) => { 41 | const entityKey = character.getEntity(); 42 | return ( 43 | entityKey != null && 44 | Entity.get(entityKey).getType() === ENTITY_TYPE.LINK 45 | ); 46 | }, callback); 47 | } 48 | 49 | export default { 50 | strategy: findLinkEntities, 51 | component: Link, 52 | }; 53 | -------------------------------------------------------------------------------- /src/editor/decorators/VideoDecorator.jsx: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | import VideoSpan from './VideoSpan'; 3 | import {Entity} from 'draft-js'; 4 | import {ENTITY_TYPE} from '../utils/stateUtils/main'; 5 | 6 | import type {ContentBlock} from 'draft-js'; 7 | 8 | type EntityRangeCallback = (start: number, end: number) => void; 9 | 10 | function findVideoEntities(contentBlock: ContentBlock, callback: EntityRangeCallback) { 11 | contentBlock.findEntityRanges((character) => { 12 | const entityKey = character.getEntity(); 13 | return ( 14 | entityKey != null && 15 | Entity.get(entityKey).getType() === ENTITY_TYPE.VIDEO 16 | ); 17 | }, callback); 18 | } 19 | 20 | export default { 21 | strategy: findVideoEntities, 22 | component: VideoSpan, 23 | }; 24 | -------------------------------------------------------------------------------- /src/editor/decorators/VideoSpan.jsx: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | // import autobind from 'class-autobind'; 4 | import React, {Component} from 'react'; 5 | import {Entity} from 'draft-js'; 6 | 7 | // $FlowIssue - Flow doesn't understand CSS Modules 8 | import styles from './decoratorStyle.css'; 9 | 10 | export default class VideoSpan extends Component { 11 | constructor(props : Props) { 12 | super(props); 13 | // autobind(this); 14 | const entity = Entity.get(this.props.entityKey); 15 | const {width, height} = entity.getData(); 16 | this.state = { 17 | width, 18 | height 19 | }; 20 | } 21 | 22 | componentDidMount() { 23 | const {width 24 | , height} = this.state; 25 | const entity = Entity.get(this.props.entityKey); 26 | const video = document.createElement('video'); 27 | const {src} = entity.getData(); 28 | video.src = src; 29 | video.onload = () => { 30 | if (width == null || height == null) { 31 | // TODO: isMounted? 32 | this.setState({width: video.width, height: video.height}); 33 | Entity.mergeData(this.props.entityKey, { 34 | width: video.width, 35 | height: video.height, 36 | originalWidth: video.width, 37 | originalHeight: video.height 38 | }); 39 | } 40 | }; 41 | } 42 | 43 | render() { 44 | const {width, height} = this.state; 45 | //let {className} = this.props; 46 | const entity = Entity.get(this.props.entityKey); 47 | const {src} = entity.getData(); 48 | //console.log("styles.root: ", styles.root); className = cx(className, styles.root); 49 | const videoStyle = { 50 | verticalAlign: 'bottom', 51 | backgroundImage: `url("${src}")`, 52 | backgroundSize: `${width}px ${height}px`, 53 | lineHeight: `${height}px`, 54 | fontSize: `${height}px`, 55 | width, 56 | height, 57 | letterSpacing: width 58 | }; 59 | 60 | // return ( {this.props.children} ); 62 | return ( 63 |
64 | 65 |
66 | ); 67 | } 68 | 69 | _onClick() { 70 | //console.log('video click'); 71 | } 72 | 73 | _handleResize(event : Object, data : Object) { 74 | const {width, height} = data.size; 75 | this.setState({width, height}); 76 | Entity.mergeData(this.props.entityKey, {width, height}); 77 | } 78 | } 79 | //VideoSpan.propTypes={ children: React.PropTypes, entityKey: string, className?: string } 80 | 81 | VideoSpan.defaultProps = { 82 | children: null, 83 | entityKey: "", 84 | className: "" 85 | } 86 | -------------------------------------------------------------------------------- /src/editor/decorators/decoratorStyle.css: -------------------------------------------------------------------------------- 1 | .root { 2 | background-repeat: no-repeat; 3 | display: inline-block; 4 | overflow: hidden; 5 | cursor: pointer; 6 | } 7 | 8 | .resize { 9 | border: 1px dashed #78a300; 10 | position: relative; 11 | max-width: 100%; 12 | display: inline-block; 13 | line-height: 0; 14 | top: -1px; 15 | left: -1px 16 | } 17 | 18 | .resizeHandle { 19 | cursor: nwse-resize; 20 | position: absolute; 21 | z-index: 2; 22 | line-height: 1; 23 | bottom: -4px; 24 | right: -5px; 25 | border: 1px solid white; 26 | background-color: #78a300; 27 | width: 8px; 28 | height: 8px; 29 | } 30 | figure{ 31 | text-align: center; 32 | overflow: hidden; 33 | } 34 | figure video { 35 | max-width: 300px; 36 | min-width: 300px; 37 | max-height: 200px; 38 | min-height: 200px; 39 | } 40 | figure img, 41 | figure video, 42 | figure audio { 43 | display: block; 44 | margin: 0 auto; 45 | max-width: 100%; 46 | } 47 | 48 | .editor-inline-image, 49 | .editor-inline-video, 50 | .editor-inline-audio 51 | { 52 | display: inline-block; 53 | overflow: hidden; 54 | cursor: pointer; 55 | width: 100%!important; 56 | } 57 | .editor-inline-image:hover, 58 | .editor-inline-video:hover, 59 | .editor-inline-audio:hover{ 60 | background-color:#f7f7f7 61 | 62 | } 63 | .editor-inline-image span, 64 | .editor-inline-video span, 65 | .editor-inline-audio span { 66 | font-size: 100px; 67 | /*color: rgba(0, 0, 0, 0);*/ 68 | position: absolute; 69 | left: -10px 70 | } 71 | -------------------------------------------------------------------------------- /src/editor/decorators/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | LinkDecorator :require ("./LinkDecorator"), 3 | ImageDecorator :require ("./ImageDecorator"), 4 | VideoDecorator :require ("./VideoDecorator"), 5 | AudioDecorator :require ("./AudioDecorator") 6 | }; 7 | -------------------------------------------------------------------------------- /src/editor/helpers/combineOrderedStyles.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | type Attributes = {[key: string]: string}; 4 | type StyleDescr = {[key: string]: number | string}; 5 | type RenderConfig = { 6 | element?: string; 7 | attributes?: Attributes; 8 | style?: StyleDescr; 9 | }; 10 | type StyleMap = {[styleName: string]: RenderConfig}; 11 | type StyleOrder = Array; 12 | type OrderedStyleMap = [StyleMap, StyleOrder]; 13 | 14 | function combineOrderedStyles( 15 | customMap: ?StyleMap, 16 | defaults: OrderedStyleMap, 17 | ): OrderedStyleMap { 18 | if (customMap == null) { 19 | return defaults; 20 | } 21 | let [defaultStyleMap, defaultStyleOrder] = defaults; 22 | let styleMap = {...defaultStyleMap}; 23 | let styleOrder = [...defaultStyleOrder]; 24 | for (let styleName of Object.keys(customMap)) { 25 | if (defaultStyleMap.hasOwnProperty(styleName)) { 26 | let defaultStyles = defaultStyleMap[styleName]; 27 | styleMap[styleName] = {...defaultStyles, ...customMap[styleName]}; 28 | } else { 29 | styleMap[styleName] = customMap[styleName]; 30 | styleOrder.push(styleName); 31 | } 32 | } 33 | return [styleMap, styleOrder]; 34 | } 35 | 36 | export default combineOrderedStyles; 37 | -------------------------------------------------------------------------------- /src/editor/helpers/normalizeAttributes.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | type Attributes = {[key: string]: string}; 4 | type StringMap = {[key: string]: string}; 5 | 6 | // Lifted from: https://github.com/facebook/react/blob/master/src/renderers/dom/shared/HTMLDOMPropertyConfig.js 7 | const ATTR_NAME_MAP: StringMap = { 8 | acceptCharset: 'accept-charset', 9 | className: 'class', 10 | htmlFor: 'for', 11 | httpEquiv: 'http-equiv', 12 | }; 13 | 14 | function normalizeAttributes(attributes: ?Attributes) { 15 | if (attributes == null) { 16 | return attributes; 17 | } 18 | let normalized = {}; 19 | let didNormalize = false; 20 | for (let name of Object.keys(attributes)) { 21 | let newName = name; 22 | if (ATTR_NAME_MAP.hasOwnProperty(name)) { 23 | newName = ATTR_NAME_MAP[name]; 24 | didNormalize = true; 25 | } 26 | normalized[newName] = attributes[name]; 27 | } 28 | return didNormalize ? normalized : attributes; 29 | } 30 | 31 | export default normalizeAttributes; 32 | -------------------------------------------------------------------------------- /src/editor/helpers/styleToCSS.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import {isUnitlessNumber} from 'react-dom/lib/CSSProperty'; 4 | 5 | type StyleDescr = {[key: string]: number | string}; 6 | 7 | const VENDOR_PREFIX = /^(moz|ms|o|webkit)-/; 8 | const NUMERIC_STRING = /^\d+$/; 9 | const UPPERCASE_PATTERN = /([A-Z])/g; 10 | 11 | // Lifted from: https://github.com/facebook/react/blob/master/src/renderers/dom/shared/CSSPropertyOperations.js 12 | function processStyleName(name: string): string { 13 | return name 14 | .replace(UPPERCASE_PATTERN, '-$1') 15 | .toLowerCase() 16 | .replace(VENDOR_PREFIX, '-$1-'); 17 | } 18 | 19 | // Lifted from: https://github.com/facebook/react/blob/master/src/renderers/dom/shared/dangerousStyleValue.js 20 | function processStyleValue(name: string, value: number | string): string { 21 | let isNumeric; 22 | if (typeof value === 'string') { 23 | isNumeric = NUMERIC_STRING.test(value); 24 | } else { 25 | isNumeric = true; 26 | value = String(value); 27 | } 28 | if (!isNumeric || value === '0' || isUnitlessNumber[name] === true) { 29 | return value; 30 | } else { 31 | return value + 'px'; 32 | } 33 | } 34 | 35 | function styleToCSS(styleDescr: StyleDescr): string { 36 | return Object.keys(styleDescr).map((name) => { 37 | let styleValue = processStyleValue(name, styleDescr[name]); 38 | let styleName = processStyleName(name); 39 | return `${styleName}: ${styleValue}`; 40 | }).join('; '); 41 | } 42 | 43 | export default styleToCSS; 44 | -------------------------------------------------------------------------------- /src/editor/toolBar/alignmentControls.jsx: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import StyleButton from "./styleButton" 3 | const AlignmentControls = (props) => { 4 | const {editorState,lang} = props; 5 | const selection = editorState.getSelection(); 6 | const blockType = editorState.getCurrentContent().getBlockForKey(selection.getStartKey()).getType(); 7 | const BLOCK_TYPES = [ 8 | { 9 | text:lang.alignLeft, 10 | label: "editor_alignment_left", 11 | style: 'left' 12 | }, { 13 | text:lang.alignCenter, 14 | label: "editor_alignment_center", 15 | style: 'center' 16 | }, { 17 | text:lang.alignRight, 18 | label: "editor_alignment_right", 19 | style: 'right' 20 | }, { 21 | text:lang.alignJustify, 22 | label: "editor_alignment_justify", 23 | style: 'justify' 24 | } 25 | ]; 26 | return ( 27 |
28 | {BLOCK_TYPES.map((type, i) => { 29 | let button = 36 | return button; 37 | })} 38 |
39 | ); 40 | }; 41 | module.exports = AlignmentControls; 42 | -------------------------------------------------------------------------------- /src/editor/toolBar/autoSave.jsx: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | class AutoSave extends Component { 3 | constructor(props) { 4 | super(props); 5 | } 6 | render() { 7 | return ( 8 |
9 | 10 | {this.props.lang.autoSave} 11 | 12 |
13 | ) 14 | } 15 | } 16 | module.exports = AutoSave; 17 | -------------------------------------------------------------------------------- /src/editor/toolBar/autoSaveList.jsx: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import { 3 | Modal, 4 | Button, 5 | Popconfirm, 6 | message, 7 | Table, 8 | Icon 9 | } from 'antd'; 10 | import {PRO_COMMON} from '../../global/supports/publicDatas'; 11 | import find from "lodash/find"; 12 | class AutoSaveControls extends Component { 13 | constructor(props) { 14 | super(props); 15 | this.state = { 16 | visible: false, 17 | list: [], 18 | selectedRowKeys: [], 19 | selectedKeyName: "" 20 | }, 21 | this.onAutoSaveToggle = this.onAutoSaveToggle.bind(this); 22 | this.handleCancel = this.handleCancel.bind(this); 23 | this.sendSavedItemToEditor = this.sendSavedItemToEditor.bind(this); 24 | this.doDelete = this.doDelete.bind(this); 25 | this.selectRow = this.selectRow.bind(this); 26 | } 27 | 28 | onAutoSaveToggle() { 29 | this.setState({visible: true, list: []}); 30 | this.componentDidMount(); 31 | } 32 | doDelete(text) { 33 | window.localStorage.removeItem("$d" + text); 34 | let currItem=find(this.state.list,item=>item.keyName==text) 35 | if (currItem.key===this.state.selectedRowKeys[0]) { 36 | this.state.selectedRowKeys=[]; 37 | this.forceUpdate(); 38 | } 39 | this.componentDidMount(); 40 | } 41 | handleCancel(e) { 42 | // console.log(e); 43 | this.setState({visible: false}); 44 | this.state.list = []; 45 | this.forceUpdate(); 46 | } 47 | sendSavedItemToEditor() { 48 | this.setState({visible: false}); 49 | let list = this.state.list.map((item) => { 50 | return item; 51 | }); 52 | let content=PRO_COMMON.localDB.getter("$d"+this.state.selectedKeyName);//window.localStorage.getItem("$d"+this.state.selectedKeyName); 53 | //console.log("content",content) 54 | this.props.receiveSavedItem(content); 55 | this.state.list = []; 56 | this.forceUpdate(); 57 | } 58 | componentDidMount() { 59 | //console.log("componentDidMount!"); 60 | let itemList = []; 61 | for (var i = 0; i < localStorage.length; i++) { 62 | let keyName = localStorage.key(i); 63 | if (!~ keyName.lastIndexOf("$d")) { 64 | continue; 65 | } 66 | //console.log(keyName); 67 | itemList.push({keyName: keyName.replace("$d","")}) 68 | } 69 | 70 | PRO_COMMON.obj.refsKeyTo(itemList) 71 | if (!!itemList.length) { 72 | //console.log("itemList", itemList); 73 | this.setState({list: itemList}); 74 | } else { 75 | this.setState({list: []}); 76 | } 77 | } 78 | selectRow(record, index) { 79 | //console.log("selectRow!",record, index) 80 | this.state.selectedRowKeys = [this.state.list[index].key]; 81 | this.state.selectedKeyName = this.state.list[index].keyName; 82 | this.forceUpdate(); 83 | } 84 | render() { 85 | let className = 'RichEditor-styleButton'; 86 | let that = this; 87 | 88 | const columns = [ 89 | { 90 | title: this.props.lang.previewMsg, 91 | dataIndex: 'keyName', 92 | key: 'keyName', 93 | render: (text, record, index) => (text + "...") 94 | }, { 95 | title: '', 96 | key: 'operation', 97 | render: (text, record) => ( 98 | this.doDelete(record.keyName)}>{this.props.lang.deleteDraftItem} 99 | ) 100 | } 101 | ]; 102 | 103 | const rowSelection = { 104 | selectedRowKeys: that.state.selectedRowKeys, 105 | onChange: (selectedRowKeys, selectedRows) => { 106 | //console.log("onChange", selectedRowKeys); 107 | that.state.selectedRowKeys = selectedRowKeys; 108 | that.forceUpdate(); 109 | }, 110 | onSelect: function(record, selected, selectedRows) { 111 | //console.log("onSelect", record.keyName); 112 | that.state.selectedKeyName = record.keyName; 113 | }, 114 | type: "radio" 115 | }; 116 | return ( 117 |
118 | 119 | 120 | 121 | 122 | {this.props.lang.cancelText} < /Button>, 130 | 131 |      132 | ]}> 133 | {this.props.lang.draftCautionMsg} 140 | 141 | 142 | ) 143 | } 144 | } 145 | module.exports = AutoSaveControls; 146 | -------------------------------------------------------------------------------- /src/editor/toolBar/blockSelectorControls.jsx: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import {Popconfirm,Icon} from 'antd'; 3 | class RemoveStyleControls extends Component { 4 | constructor(props) { 5 | super(props); 6 | } 7 | render() { 8 | let className = 'RichEditor-styleButton'; 9 | return ( 10 |
11 | 12 | 13 | 14 |
15 | ) 16 | } 17 | } 18 | module.exports = RemoveStyleControls; 19 | -------------------------------------------------------------------------------- /src/editor/toolBar/blockStyleControls.jsx: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import StyleButton from "./styleButton" 3 | const BlockStyleControls = (props) => { 4 | const {editorState,lang} = props; 5 | const selection = editorState.getSelection(); 6 | const blockType = editorState.getCurrentContent().getBlockForKey(selection.getStartKey()).getType(); 7 | const BLOCK_TYPES = [ 8 | { 9 | text:lang.H1, 10 | label: "editor_H1", 11 | style: 'header-one' 12 | }, { 13 | text:lang.H2, 14 | label: "editor_H2", 15 | style: 'header-two' 16 | }, { 17 | text:lang.H3, 18 | label: "editor_H3", 19 | style: 'header-three' 20 | }, { 21 | text:lang.H4, 22 | label: "editor_H4", 23 | style: 'header-four' 24 | }, { 25 | text:lang.refs, 26 | label: "editor_refs", 27 | style: 'blockquote' 28 | }, { 29 | text:lang.ul, 30 | label: "editor_ul", 31 | style: 'unordered-list-item' 32 | }, { 33 | text:lang.ol, 34 | label: "editor_ol", 35 | style: 'ordered-list-item' 36 | }, { 37 | text:lang.pre, 38 | label: "editor_pre", 39 | style: 'code-block' 40 | } 41 | ]; 42 | return ( 43 |
44 | {BLOCK_TYPES.map((type, i) => { 45 | let button = 52 | return button; 53 | })} 54 |
55 | ); 56 | }; 57 | module.exports = BlockStyleControls; 58 | -------------------------------------------------------------------------------- /src/editor/toolBar/colorButton.jsx: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | 3 | import colorStyleMap from "../config/colorStyleMap" 4 | 5 | class ColorButton extends Component { 6 | constructor(props) { 7 | super(props); 8 | this.onToggle = (e) => { 9 | e.preventDefault(); 10 | this.props.onToggle(this.props.style); 11 | }; 12 | } 13 | 14 | render() { 15 | const styles = { 16 | editor: { 17 | borderTop: '1px solid #ddd', 18 | cursor: 'text', 19 | fontSize: 16, 20 | marginTop: 20, 21 | minHeight: 400, 22 | paddingTop: 20 23 | }, 24 | controls: { 25 | fontFamily: '\'Helvetica\', sans-serif', 26 | fontSize: 14, 27 | marginBottom: 10, 28 | userSelect: 'none' 29 | }, 30 | ColorButton: { 31 | color: '#999', 32 | cursor: 'pointer', 33 | marginRight: 16, 34 | padding: '2px 0' 35 | }, 36 | root: { 37 | fontFamily: '\'Georgia\', serif', 38 | padding: 20, 39 | width: 600 40 | }, 41 | buttons: { 42 | marginBottom: 10 43 | }, 44 | urlInputContainer: { 45 | marginBottom: 10 46 | }, 47 | urlInput: { 48 | fontFamily: '\'Georgia\', serif', 49 | marginRight: 10, 50 | padding: 3 51 | }, 52 | editor: { 53 | border: '1px solid #ccc', 54 | cursor: 'text', 55 | minHeight: 80, 56 | padding: 10 57 | }, 58 | button: { 59 | marginTop: 10, 60 | textAlign: 'center' 61 | }, 62 | link: { 63 | color: 'blue', 64 | textDecoration: 'underline' 65 | } 66 | }; 67 | 68 | let style = Object.assign({}, styles.ColorButton, (this.props.active 69 | ? colorStyleMap[this.props.style] 70 | : {})); 71 | let className = 'RichEditor-styleButton'; 72 | return ( 73 |
74 | 80 | {this.props.label} 81 | 82 | {(() => { 83 | if (!!this.props.split) { 84 | return {this.props.split}; 85 | } 86 | })()} 87 |
88 | ) 89 | }; 90 | } 91 | module.exports = ColorButton; 92 | -------------------------------------------------------------------------------- /src/editor/toolBar/colorControls.jsx: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import ColorButton from "./colorButton" 3 | import {colorStyleMap} from "../utils/colorConfig" 4 | class ColorControls extends Component { 5 | constructor(props) { 6 | super(props); 7 | } 8 | render() { 9 | let currentStyle = this.props.editorState.getCurrentInlineStyle(); 10 | let COLORS = Object.keys(colorStyleMap).map(item => { 11 | return {label: ' ', alias: item, style: item} 12 | }); 13 | return ( 14 |
17 | {COLORS.map((type, i) => )} 26 |
27 | ); 28 | } 29 | } 30 | module.exports = ColorControls; 31 | -------------------------------------------------------------------------------- /src/editor/toolBar/cookieControls.jsx: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import {Icon} from "antd" 3 | 4 | class OpenFull extends Component { 5 | constructor(props) { 6 | super(props); 7 | } 8 | render() { 9 | return ( 10 |
11 | 12 | {this.props.coverTitle} 13 | 14 |
15 | ) 16 | } 17 | } 18 | class AutoSave extends Component { 19 | constructor(props) { 20 | super(props); 21 | } 22 | render() { 23 | return ( 24 |
25 | 26 | {this.props.lang.autoSave} 27 | 28 |
29 | ) 30 | } 31 | }; 32 | class SourceEditor extends Component { 33 | constructor(props) { 34 | super(props); 35 | } 36 | render() { 37 | return ( 38 |
39 | 40 | {this.props.coverTitle} 41 | 42 |
43 | ) 44 | } 45 | }; 46 | module.exports = { 47 | OpenFull, 48 | AutoSave, 49 | SourceEditor 50 | }; 51 | -------------------------------------------------------------------------------- /src/editor/toolBar/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ImgStyleControls :require ("./mediaImageUploader"), 3 | VideoStyleControls :require ("./medioVideoUploader"), 4 | AudioStyleControls :require ("./medioAudioUploader"), 5 | AutoSaveControls :require ("./autoSaveList"), 6 | BlockStyleControls :require ("./BlockStyleControls"), 7 | RemoveStyleControls :require ("./removeStyleControls"), 8 | InlineStyleControls :require ("./inlineStyleControls"), 9 | ColorControls :require ("./colorControls"), 10 | PasteNoStyleControls :require ("./pasteNoStyleControls"), 11 | AutoSave :require ("./autoSave") 12 | }; 13 | -------------------------------------------------------------------------------- /src/editor/toolBar/inlineStyleControls.jsx: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import StyleButton from "./styleButton" 3 | class InlineStyleControls extends Component { 4 | constructor(props) { 5 | super(props); 6 | } 7 | render() { 8 | const {editorState,onToggle,lang} = this.props; 9 | const INLINE_STYLES = [ 10 | { 11 | text: lang.textBold, 12 | style: 'BOLD', 13 | label: "editor_b" 14 | }, { 15 | text: lang.textItalic, 16 | style: 'ITALIC', 17 | label: "editor_i" 18 | }, { 19 | text: lang.textUnderline, 20 | style: 'UNDERLINE', 21 | label: "editor_u" 22 | }, { 23 | text: lang.textCode, 24 | style: 'CODE', 25 | label: "editor_e" 26 | } 27 | ]; 28 | let currentStyle = editorState 29 | ? editorState.getCurrentInlineStyle() 30 | : {}; 31 | return ( 32 |
33 | {INLINE_STYLES.map((type, i) => )} 40 |
41 | ) 42 | } 43 | } 44 | module.exports = InlineStyleControls; 45 | -------------------------------------------------------------------------------- /src/editor/toolBar/medioAudioUploader.jsx: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import { 3 | Upload, 4 | Modal, 5 | Button, 6 | Popconfirm, 7 | Form, 8 | Input, 9 | message, 10 | Icon 11 | } from 'antd'; 12 | import {UploadImage} from '../../global/components/businessComponents'; 13 | class AudioStyleControls extends Component { 14 | constructor(props) { 15 | super(props); 16 | this.state = { 17 | visible: false, 18 | audios: [] 19 | }, 20 | this.onAudioToggle = this.onAudioToggle.bind(this); 21 | this.sendAudioToEditor = this.sendAudioToEditor.bind(this); 22 | this.handleCancel = this.handleCancel.bind(this); 23 | this.getAudioObject = this.getAudioObject.bind(this); 24 | } 25 | 26 | getAudioObject(fileObj) { 27 | this.state.audios = this.state.audios.concat(fileObj); 28 | if (!!this.state.audios) { 29 | this.setState({disabled: false}); 30 | } 31 | this.forceUpdate(); 32 | } 33 | 34 | onAudioToggle() { 35 | this.setState({visible: true, disabled: true,audios : []}) 36 | } 37 | 38 | sendAudioToEditor() { 39 | this.setState({visible: false}); 40 | let audios = this.state.audios.map((item) => { 41 | return item; 42 | }); 43 | this.props.receiveAudio(audios); 44 | this.state.audios = []; 45 | this.forceUpdate(); 46 | } 47 | 48 | handleCancel(e) { 49 | // console.log(e); 50 | this.setState({visible: false}); 51 | this.state.audios = []; 52 | this.forceUpdate(); 53 | } 54 | 55 | render() { 56 | let className = 'RichEditor-styleButton'; 57 | let that = this; 58 | return ( 59 |
60 | 61 | 62 | 63 | {this.props.lang.cancelText} < /Button>, ]}> 70 | 79 | 80 |
81 | ) 82 | } 83 | } 84 | module.exports = AudioStyleControls; 85 | -------------------------------------------------------------------------------- /src/editor/toolBar/medioVideoUploader.jsx: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import { 3 | Upload, 4 | Modal, 5 | Button, 6 | Popconfirm, 7 | Form, 8 | Input, 9 | message, 10 | Icon 11 | } from 'antd'; 12 | import {UploadImage} from '../../global/components/businessComponents'; 13 | class VideoStyleControls extends Component { 14 | constructor(props) { 15 | super(props); 16 | this.state = { 17 | visible: false, 18 | videos: [] 19 | }; 20 | this.onVideoToggle = this.onVideoToggle.bind(this); 21 | 22 | this.handleCancel = this.handleCancel.bind(this); 23 | this.getVideoObject = this.getVideoObject.bind(this); 24 | this.sendVideoToEditor = this.sendVideoToEditor.bind(this); 25 | } 26 | 27 | getVideoObject(fileObj) { 28 | this.state.videos = this.state.videos.concat(fileObj); 29 | if (!!this.state.videos) { 30 | this.setState({disabled: false}) 31 | } 32 | this.forceUpdate(); 33 | } 34 | 35 | sendVideoToEditor() { 36 | this.setState({visible: false}); 37 | let videos = this.state.videos.map((item) => { 38 | return item; 39 | }); 40 | this.props.receiveVideo(videos); 41 | this.state.videos = []; 42 | this.forceUpdate(); 43 | } 44 | 45 | onVideoToggle() { 46 | this.setState({visible: true, disabled: true,videos : []}) 47 | } 48 | 49 | handleCancel(e) { 50 | // console.log(e); 51 | this.setState({visible: false}); 52 | this.state.videos = []; 53 | this.forceUpdate(); 54 | } 55 | 56 | render() { 57 | let className = 'RichEditor-styleButton'; 58 | let that = this; 59 | return ( 60 |
61 | 62 | 63 | 64 | {this.props.lang.cancelText} , ]}> 71 | 80 | 81 |
82 | ) 83 | } 84 | } 85 | 86 | module.exports = VideoStyleControls; 87 | -------------------------------------------------------------------------------- /src/editor/toolBar/pasteNoStyleControls.jsx: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import ReactDom from 'react-dom'; 3 | import { 4 | Modal, 5 | Button, 6 | Input, 7 | Icon 8 | } from 'antd'; 9 | class PasteNoStyleControls extends Component { 10 | constructor(props) { 11 | super(props); 12 | this.state = { 13 | visible: false, 14 | plantext: "" 15 | }; 16 | this.onTextToggle = this.onTextToggle.bind(this); 17 | this.pasteContent = this.pasteContent.bind(this); 18 | this.handleCancel = this.handleCancel.bind(this); 19 | this.sendTextToEditor = this.sendTextToEditor.bind(this); 20 | } 21 | pasteContent(e){ 22 | this.state.plantext = e.target.value; 23 | this.forceUpdate(); 24 | setTimeout(() => { 25 | if (!!this.state.plantext) { 26 | this.setState({disabled: false}) 27 | } 28 | }, 100); 29 | } 30 | sendTextToEditor() { 31 | let text=this.state.plantext+""; 32 | this.props.receiveText(text); 33 | this.setState({visible: false,plantext: ""}) 34 | } 35 | 36 | onTextToggle() { 37 | this.setState({visible: true, disabled: true,plantext : ""}) 38 | // let that=this; 39 | // setTimeout(()=>{ 40 | // console.log("this.refs.nostyletext",that.refs.noStyleText) 41 | // ReactDom.findDOMNode(that.refs.noStyleText).focus(); 42 | // },1000); 43 | } 44 | 45 | handleCancel(e) { 46 | // console.log(e); 47 | this.setState({visible: false}); 48 | this.state.plantext = ""; 49 | this.forceUpdate(); 50 | } 51 | componentDidMount(){ 52 | } 53 | render() { 54 | let className = 'RichEditor-styleButton'; 55 | let that = this; 56 | return ( 57 |
58 | 59 | 60 | 61 | 62 | 63 | {that.props.lang.cancelText} < /Button>, ]}> 71 | 72 | 73 |
74 | ) 75 | } 76 | } 77 | 78 | module.exports = PasteNoStyleControls; 79 | -------------------------------------------------------------------------------- /src/editor/toolBar/removeStyleControls.jsx: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import {Popconfirm,Icon} from 'antd'; 3 | class RemoveStyleControls extends Component { 4 | constructor(props) { 5 | super(props); 6 | } 7 | render() { 8 | let className = 'RichEditor-styleButton'; 9 | return ( 10 |
11 | 12 | 13 | 14 | 15 | 16 |
17 | ) 18 | } 19 | } 20 | module.exports = RemoveStyleControls; 21 | -------------------------------------------------------------------------------- /src/editor/toolBar/styleButton.jsx: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import {Icon} from "antd" 3 | class StyleButton extends React.Component { 4 | constructor() { 5 | super(); 6 | this.onToggle = (e) => { 7 | e.preventDefault(); 8 | this.props.onToggle(this.props.style); 9 | }; 10 | } 11 | 12 | render() { 13 | let className = 'RichEditor-styleButton'; 14 | if (this.props.active) { 15 | className += ' RichEditor-activeButton ant-btn ant-btn-primary ant-btn-icon-only '; 16 | } 17 | 18 | return ( 19 | 20 | 21 | 22 | 23 | {(() => { 24 | if (!!this.props.split) { 25 | return {this.props.split}; 26 | } 27 | })()} 28 | 29 | ); 30 | } 31 | } 32 | module.exports = StyleButton; 33 | -------------------------------------------------------------------------------- /src/editor/toolBar/undoredoControls.jsx: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import {Icon} from "antd" 3 | 4 | class undoRedo extends Component { 5 | constructor(props) { 6 | super(props); 7 | } 8 | render() { 9 | let className = 'RichEditor-styleButton'; 10 | return ( 11 |
12 | this.props.onToggle("undo")} title={this.props.lang.undo}> 13 | 14 | 15 | this.props.onToggle("redo")} title={this.props.lang.redo}> 16 | 17 | 18 |
19 | ) 20 | } 21 | }; 22 | module.exports = undoRedo; 23 | -------------------------------------------------------------------------------- /src/editor/toolBar/urlControls.jsx: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import {Tooltip, Icon} from "antd" 3 | class AddUrl extends Component { 4 | constructor(props) { 5 | super(props); 6 | } 7 | render() { 8 | return ( 9 |
10 | 11 | 12 | 13 |
14 | ) 15 | } 16 | } 17 | 18 | class CloseUrl extends Component { 19 | constructor(props) { 20 | super(props); 21 | } 22 | render() { 23 | return ( 24 |
25 | 26 | 27 | 28 |
29 | ) 30 | } 31 | } 32 | 33 | module.exports = { 34 | AddUrl, 35 | CloseUrl 36 | }; 37 | -------------------------------------------------------------------------------- /src/editor/utils/ExtendedRichUtils.js: -------------------------------------------------------------------------------- 1 | import { Modifier, EditorState, RichUtils } from 'draft-js'; 2 | import getCurrentlySelectedBlock from './getCurrentlySelectedBlock'; 3 | 4 | export const ALIGNMENTS = { 5 | CENTER: 'center', 6 | JUSTIFY: 'justify', 7 | LEFT: 'left', 8 | RIGHT: 'right' 9 | }; 10 | 11 | export const ALIGNMENT_DATA_KEY = 'textAlignment'; 12 | 13 | const ExtendedRichUtils = Object.assign({}, RichUtils, { 14 | // Largely copied from RichUtils' `toggleBlockType` 15 | toggleAlignment(editorState, alignment) { 16 | const { content, currentBlock, hasAtomicBlock, target } = getCurrentlySelectedBlock(editorState); 17 | // console.log("ExtendedRichUtils content, currentBlock, hasAtomicBlock, target",content, currentBlock, hasAtomicBlock, target) 18 | if (hasAtomicBlock) { 19 | return editorState; 20 | } 21 | 22 | const blockData = currentBlock.getData(); 23 | // console.log("ExtendedRichUtils blockData,alignment",blockData,alignment) 24 | let keyName=blockData.get(ALIGNMENT_DATA_KEY); 25 | // console.log("ExtendedRichUtils blockData.get,keyName",ALIGNMENT_DATA_KEY,keyName) 26 | const alignmentToSet = ((!!blockData) && (keyName === alignment)) ? 27 | undefined : 28 | alignment; 29 | // console.log("ExtendedRichUtils alignmentToSet",alignmentToSet) 30 | // console.log("ExtendedRichUtils content",content) 31 | // console.log("ExtendedRichUtils target",target) 32 | // console.log("ExtendedRichUtils ALIGNMENT_DATA_KEY",ALIGNMENT_DATA_KEY) 33 | // console.log("ExtendedRichUtils alignmentToSet",alignmentToSet) 34 | let alignBlockData=new Map(); 35 | alignBlockData.set(ALIGNMENT_DATA_KEY,alignmentToSet); 36 | // console.log("ExtendedRichUtils alignBlockData",alignBlockData); 37 | // let newBlockData=Modifier.mergeBlockData(content, target,alignBlockData ); 38 | let newBlockData=Modifier.setBlockData(content, target,alignBlockData ); 39 | // console.log("ExtendedRichUtils newBlockData",newBlockData); 40 | return EditorState.push( 41 | editorState, 42 | newBlockData, 43 | 'change-block-type' 44 | ); 45 | }, 46 | 47 | /* 48 | * An extension of the default split block functionality, originally pulled from 49 | * https://github.com/facebook/draft-js/blob/master/src/component/handlers/edit/commands/keyCommandInsertNewline.js 50 | * 51 | * This version ensures that the text alignment is copied from the previously selected block. 52 | */ 53 | splitBlock(editorState) { 54 | // Original split logic 55 | const contentState = Modifier.splitBlock( 56 | editorState.getCurrentContent(), 57 | editorState.getSelection() 58 | ); 59 | const splitState = EditorState.push(editorState, contentState, 'split-block'); 60 | 61 | // Assign alignment if previous block has alignment. Note that `currentBlock` is the block that was selected 62 | // before the split. 63 | const { currentBlock } = getCurrentlySelectedBlock(editorState); 64 | const alignment = currentBlock.getData().get(ALIGNMENT_DATA_KEY); 65 | if (alignment) { 66 | return ExtendedRichUtils.toggleAlignment(splitState, alignment); 67 | } else { 68 | return splitState; 69 | } 70 | } 71 | }); 72 | 73 | export default ExtendedRichUtils; 74 | -------------------------------------------------------------------------------- /src/editor/utils/colorConfig.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | colorStyleMap: { 3 | grapeFruit1: { 4 | color: '#ED5565' 5 | }, 6 | grapeFruit2: { 7 | color: '#Da4453' 8 | }, 9 | bitterSweet1: { 10 | color: '#fc6e51' 11 | }, 12 | bitterSweet2: { 13 | color: '#e9573f' 14 | }, 15 | sunFlower1: { 16 | color: '#ffce54' 17 | }, 18 | sunFlower2: { 19 | color: '#f6bb42' 20 | }, 21 | grass1: { 22 | color: '#a0d468' 23 | }, 24 | grass2: { 25 | color: '#bcc152' 26 | }, 27 | mint1: { 28 | color: '#48cfad' 29 | }, 30 | mint2: { 31 | color: '#37bc9b' 32 | }, 33 | aqua1: { 34 | color: '#4fc1e9' 35 | }, 36 | aqua2: { 37 | color: '#38afda' 38 | }, 39 | blueJeans1: { 40 | color: '#5d9cec' 41 | }, 42 | blueJeans2: { 43 | color: '#4a89dc' 44 | }, 45 | lavander1: { 46 | color: '#ac92ec' 47 | }, 48 | lavander2: { 49 | color: '#967adc' 50 | }, 51 | mediumGray1: { 52 | color: '#ccd1d9' 53 | }, 54 | mediumGray2: { 55 | color: '#aab2bd' 56 | }, 57 | darkGray1: { 58 | color: '#656d78' 59 | }, 60 | darkGray2: { 61 | color: '#434a54' 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/editor/utils/getCurrentlySelectedBlock.js: -------------------------------------------------------------------------------- 1 | const getCurrentlySelectedBlock = (editorState) => { 2 | const selection = editorState.getSelection(); 3 | const startKey = selection.getStartKey(); 4 | let endKey = selection.getEndKey(); 5 | const content = editorState.getCurrentContent(); 6 | let target = selection; 7 | 8 | // Triple-click can lead to a selection that includes offset 0 of the 9 | // following block. The `SelectionState` for this case is accurate, but 10 | // we should avoid toggling block type for the trailing block because it 11 | // is a confusing interaction. 12 | if (startKey !== endKey && selection.getEndOffset() === 0) { 13 | const blockBefore = content.getBlockBefore(endKey); 14 | if (!blockBefore) { 15 | throw new Error('Got unexpected null or undefined'); 16 | } 17 | 18 | endKey = blockBefore.getKey(); 19 | target = target.merge({ 20 | anchorKey: startKey, 21 | anchorOffset: selection.getStartOffset(), 22 | focusKey: endKey, 23 | focusOffset: blockBefore.getLength(), 24 | isBackward: false 25 | }); 26 | } 27 | 28 | const hasAtomicBlock = content.getBlockMap() 29 | .skipWhile((_, k) => k !== startKey) 30 | .takeWhile((_, k) => k !== endKey) 31 | .some(v => v.getType() === 'atomic'); 32 | 33 | const currentBlock = content.getBlockForKey(startKey); 34 | 35 | return { 36 | content, 37 | currentBlock, 38 | hasAtomicBlock, 39 | target 40 | }; 41 | }; 42 | 43 | export default getCurrentlySelectedBlock; -------------------------------------------------------------------------------- /src/editor/utils/index.js: -------------------------------------------------------------------------------- 1 | export {default as stateFromElement} from './stateFromElement/main';//https://github.com/sstur/draft-js-import-element/blob/9a989ed7d2f7a8453cc6ca1cfbab9754740e6e18/src/stateFromElement.js 2 | export {default as stateFromHTML} from './stateFromHTML/main'; 3 | export {default as stateToHTML} from './stateToHTML/main';//note:from https://github.com/sstur/draft-js-export-html/blob/d41aa2f1ff633889b1bd361c5d60c7a5d7b1e531/src/stateToHTML.js 4 | export {default as stateFromMD} from './stateFromMD/main'; 5 | export {default as stateToMD} from './stateToMD/main'; 6 | -------------------------------------------------------------------------------- /src/editor/utils/stateFromElement/replaceTextWithMeta.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import type {IndexedSeq} from 'immutable'; 4 | 5 | type TextFragment = { 6 | text: string; 7 | characterMeta: IndexedSeq; 8 | }; 9 | 10 | export default function replaceTextWithMeta( 11 | subject: TextFragment, 12 | searchText: string, 13 | replaceText: string 14 | ): TextFragment { 15 | let {text, characterMeta} = subject; 16 | let searchTextLength = searchText.length; 17 | let replaceTextLength = replaceText.length; 18 | let resultTextParts: Array = []; 19 | // Get empty set of same kind as characterMeta. 20 | let resultCharMeta = characterMeta.slice(0, 0); 21 | let lastEndIndex = 0; 22 | let index = text.indexOf(searchText); 23 | while (index !== -1) { 24 | resultTextParts.push( 25 | text.slice(lastEndIndex, index) + replaceText 26 | ); 27 | resultCharMeta = resultCharMeta.concat( 28 | characterMeta.slice(lastEndIndex, index), 29 | // Use the metadata of the first char we are replacing. 30 | repeatSeq(characterMeta.slice(index, index + 1), replaceTextLength) 31 | ); 32 | lastEndIndex = index + searchTextLength; 33 | index = text.indexOf(searchText, lastEndIndex); 34 | } 35 | resultTextParts.push( 36 | text.slice(lastEndIndex) 37 | ); 38 | resultCharMeta = resultCharMeta.concat( 39 | characterMeta.slice(lastEndIndex) 40 | ); 41 | return {text: resultTextParts.join(''), characterMeta: resultCharMeta}; 42 | } 43 | 44 | function repeatSeq(seq: IndexedSeq, count: number): IndexedSeq { 45 | let result = seq.slice(0, 0); 46 | while (count-- > 0) { 47 | result = result.concat(seq); 48 | } 49 | return result; 50 | } 51 | -------------------------------------------------------------------------------- /src/editor/utils/stateFromHTML/main.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import {stateFromElement} from '../index'; 4 | import parseHTML from './parseHTML'; 5 | 6 | import type {ContentState} from 'draft-js'; 7 | 8 | type Options = { 9 | parser?: (html: string) => Element; 10 | }; 11 | 12 | export default function stateFromHTML(html: string, options?: Options): ContentState { 13 | let parser = (options == null || options.parser == null) ? parseHTML : options.parser; 14 | let element = parser(html); 15 | return stateFromElement(element, options); 16 | } 17 | -------------------------------------------------------------------------------- /src/editor/utils/stateFromHTML/parseHTML.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export default function parseHTML(html: string): Element { 4 | let doc; 5 | if (typeof DOMParser !== 'undefined') { 6 | let parser = new DOMParser(); 7 | doc = parser.parseFromString(html, 'text/html'); 8 | } else { 9 | doc = document.implementation.createHTMLDocument(''); 10 | doc.documentElement.innerHTML = html; 11 | } 12 | return doc.body; 13 | } 14 | -------------------------------------------------------------------------------- /src/editor/utils/stateFromMD/main.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import MarkdownParser from './MarkdownParser'; 4 | import {stateFromElement} from '../index'; 5 | 6 | import type {ContentState} from 'draft-js'; 7 | 8 | export default function stateFromMarkdown(markdown: string): ContentState { 9 | // console.log("MarkdownParser:",stateFromMarkdown); 10 | let element = MarkdownParser.parse(markdown, {getAST: true}); 11 | return stateFromElement(element); 12 | } 13 | -------------------------------------------------------------------------------- /src/editor/utils/stateUtils/Constants.js: -------------------------------------------------------------------------------- 1 | export const BLOCK_TYPE = { 2 | // This is used to represent a normal text block (paragraph). 3 | UNSTYLED: 'unstyled', 4 | HEADER_ONE: 'header-one', 5 | HEADER_TWO: 'header-two', 6 | HEADER_THREE: 'header-three', 7 | HEADER_FOUR: 'header-four', 8 | HEADER_FIVE: 'header-five', 9 | HEADER_SIX: 'header-six', 10 | UNORDERED_LIST_ITEM: 'unordered-list-item', 11 | ORDERED_LIST_ITEM: 'ordered-list-item', 12 | BLOCKQUOTE: 'blockquote', 13 | PULLQUOTE: 'pullquote', 14 | CODE: 'code-block', 15 | ATOMIC: 'atomic', 16 | }; 17 | 18 | export const ENTITY_TYPE = { 19 | LINK: 'LINK', 20 | IMAGE: 'IMAGE', 21 | VIDEO: 'VIDEO', 22 | AUDIO: 'AUDIO' 23 | }; 24 | 25 | export const INLINE_STYLE = { 26 | BOLD: 'BOLD', 27 | CODE: 'CODE', 28 | SPAN: 'SPAN', 29 | ITALIC: 'ITALIC', 30 | STRIKETHROUGH: 'STRIKETHROUGH', 31 | UNDERLINE: 'UNDERLINE', 32 | }; 33 | 34 | export default { 35 | BLOCK_TYPE, 36 | ENTITY_TYPE, 37 | INLINE_STYLE, 38 | }; 39 | -------------------------------------------------------------------------------- /src/editor/utils/stateUtils/callModifierForSelectedBlocks.js: -------------------------------------------------------------------------------- 1 | import {EditorState, SelectionState} from 'draft-js'; 2 | 3 | import getSelectedBlocks from './getSelectedBlocks'; 4 | 5 | /** 6 | * Calls a provided `modifier` function with a selection for each 7 | * selected block in the current editor selection. Passes through additional 8 | * arguments to the modifier. 9 | * 10 | * Note: At the moment it will retain the original selection and override 11 | * possible selection changes from modifiers 12 | * 13 | * @param {object} editorState The current draft.js editor state object 14 | * 15 | * @param {function} modifier A modifier function to be executed. 16 | * Must have the signature (editorState, selection, ...) 17 | * 18 | * @param {mixed} ...args Additional arguments to be passed through to the modifier 19 | * 20 | * @return {object} The new editor state 21 | */ 22 | export default (editorState, modifier, ...args) => { 23 | const contentState = editorState.getCurrentContent(); 24 | const currentSelection = editorState.getSelection(); 25 | 26 | const startKey = currentSelection.getStartKey(); 27 | const endKey = currentSelection.getEndKey(); 28 | const startOffset = currentSelection.getStartOffset(); 29 | const endOffset = currentSelection.getEndOffset(); 30 | 31 | const isSameBlock = startKey === endKey; 32 | const selectedBlocks = getSelectedBlocks(contentState, startKey, endKey); 33 | 34 | let finalEditorState = editorState; 35 | selectedBlocks.forEach((block) => { 36 | const currentBlockKey = block.getKey(); 37 | let selectionStart = startOffset; 38 | let selectionEnd = endOffset; 39 | 40 | if (currentBlockKey === startKey) { 41 | selectionStart = startOffset; 42 | selectionEnd = isSameBlock ? endOffset : block.getText().length; 43 | } else if (currentBlockKey === endKey) { 44 | selectionStart = isSameBlock ? startOffset : 0; 45 | selectionEnd = endOffset; 46 | } else { 47 | selectionStart = 0; 48 | selectionEnd = block.getText().length; 49 | } 50 | 51 | const selection = new SelectionState({ 52 | anchorKey: currentBlockKey, 53 | anchorOffset: selectionStart, 54 | focusKey: currentBlockKey, 55 | focusOffset: selectionEnd, 56 | }); 57 | 58 | finalEditorState = modifier(finalEditorState, selection, ...args); 59 | }); 60 | 61 | return EditorState.forceSelection(finalEditorState, currentSelection); 62 | }; 63 | -------------------------------------------------------------------------------- /src/editor/utils/stateUtils/combineOrderedStyles.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | type Attributes = {[key: string]: string}; 4 | type StyleDescr = {[key: string]: number | string}; 5 | type RenderConfig = { 6 | element?: string; 7 | attributes?: Attributes; 8 | style?: StyleDescr; 9 | }; 10 | type StyleMap = {[styleName: string]: RenderConfig}; 11 | type StyleOrder = Array; 12 | type OrderedStyleMap = [StyleMap, StyleOrder]; 13 | 14 | function combineOrderedStyles( 15 | customMap: ?StyleMap, 16 | defaults: OrderedStyleMap 17 | ): OrderedStyleMap { 18 | if (customMap == null) { 19 | return defaults; 20 | } 21 | let [defaultStyleMap, defaultStyleOrder] = defaults; 22 | let styleMap = Object.assign({},defaultStyleMap);//{...defaultStyleMap} 23 | let styleOrder = [...defaultStyleOrder]; 24 | for (let styleName of Object.keys(customMap)) { 25 | if (defaultStyleMap.hasOwnProperty(styleName)) { 26 | let defaultStyles = defaultStyleMap[styleName]; 27 | styleMap[styleName] =Object.assign({},defaultStyles,customMap[styleName]);// {...defaultStyles, ...customMap[styleName]}; 28 | } else { 29 | styleMap[styleName] = customMap[styleName]; 30 | styleOrder.push(styleName); 31 | } 32 | } 33 | return [styleMap, styleOrder]; 34 | } 35 | 36 | export default combineOrderedStyles; 37 | -------------------------------------------------------------------------------- /src/editor/utils/stateUtils/getEntityRanges.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | import {OrderedSet, is} from 'immutable'; 3 | 4 | import type {CharacterMetadata} from 'draft-js'; 5 | import type {List} from 'immutable'; 6 | 7 | type EntityKey = ?string; 8 | type Style = OrderedSet; 9 | type StyleRange = [string, Style]; 10 | type EntityRange = [EntityKey, Array]; 11 | export type CharacterMetaList = List; 12 | 13 | export const EMPTY_SET: Style = new OrderedSet(); 14 | 15 | export default function getEntityRanges( 16 | text: string, 17 | charMetaList: CharacterMetaList 18 | ): Array { 19 | let charEntity: ?string = null; 20 | let prevCharEntity: ?string = null; 21 | let ranges: Array = []; 22 | let rangeStart = 0; 23 | for (let i = 0, len = text.length; i < len; i++) { 24 | prevCharEntity = charEntity; 25 | let meta: CharacterMetadata = charMetaList.get(i); 26 | charEntity = meta ? meta.getEntity() : null; 27 | if (i > 0 && charEntity !== prevCharEntity) { 28 | ranges.push([ 29 | prevCharEntity, 30 | getStyleRanges( 31 | text.slice(rangeStart, i), 32 | charMetaList.slice(rangeStart, i) 33 | ), 34 | ]); 35 | rangeStart = i; 36 | } 37 | } 38 | ranges.push([ 39 | charEntity, 40 | getStyleRanges( 41 | text.slice(rangeStart), 42 | charMetaList.slice(rangeStart) 43 | ), 44 | ]); 45 | return ranges; 46 | } 47 | 48 | function getStyleRanges( 49 | text: string, 50 | charMetaList: CharacterMetaList 51 | ): Array { 52 | let charStyle = EMPTY_SET; 53 | let prevCharStyle = EMPTY_SET; 54 | let ranges = []; 55 | let rangeStart = 0; 56 | for (let i = 0, len = text.length; i < len; i++) { 57 | prevCharStyle = charStyle; 58 | let meta = charMetaList.get(i); 59 | charStyle = meta ? meta.getStyle() : EMPTY_SET; 60 | if (i > 0 && !is(charStyle, prevCharStyle)) { 61 | ranges.push([text.slice(rangeStart, i), prevCharStyle]); 62 | rangeStart = i; 63 | } 64 | } 65 | ranges.push([text.slice(rangeStart), charStyle]); 66 | return ranges; 67 | } 68 | -------------------------------------------------------------------------------- /src/editor/utils/stateUtils/getSelectedBlocks.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Returns an array of all `ContentBlock` instances within two block keys 3 | * 4 | * @param {object} contentState A draft.js `ContentState` instance 5 | * @param {string} anchorKey The block key to start searching from 6 | * @param {string} focusKey The block key until which to search 7 | * 8 | * @return {array} An array containing the found content blocks 9 | */ 10 | export default (contentState, anchorKey, focusKey) => { 11 | const isSameBlock = anchorKey === focusKey; 12 | const startingBlock = contentState.getBlockForKey(anchorKey); 13 | 14 | if (!startingBlock) { 15 | return []; 16 | } 17 | 18 | let selectedBlocks = [startingBlock]; 19 | 20 | if (!isSameBlock) { 21 | let blockKey = anchorKey; 22 | 23 | while (blockKey !== focusKey) { 24 | const nextBlock = contentState.getBlockAfter(blockKey); 25 | 26 | if (!nextBlock) { 27 | selectedBlocks = []; 28 | break; 29 | } 30 | 31 | selectedBlocks.push(nextBlock); 32 | blockKey = nextBlock.getKey(); 33 | } 34 | } 35 | 36 | return selectedBlocks; 37 | }; 38 | -------------------------------------------------------------------------------- /src/editor/utils/stateUtils/main.js: -------------------------------------------------------------------------------- 1 | export * from './Constants'; 2 | export {default as Constants} from './Constants'; 3 | 4 | export {default as getEntityRanges} from './getEntityRanges'; 5 | 6 | export type {CharacterMetaList} from './getEntityRanges'; 7 | 8 | export {default as getSelectedBlocks} from './getSelectedBlocks'; 9 | export {default as selectionContainsEntity} from './selectionContainsEntity'; 10 | export {default as callModifierForSelectedBlocks} from './callModifierForSelectedBlocks'; 11 | -------------------------------------------------------------------------------- /src/editor/utils/stateUtils/normalizeAttributes.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | type Attributes = {[key: string]: string}; 4 | type StringMap = {[key: string]: string}; 5 | 6 | // Lifted from: https://github.com/facebook/react/blob/master/src/renderers/dom/shared/HTMLDOMPropertyConfig.js 7 | const ATTR_NAME_MAP: StringMap = { 8 | acceptCharset: 'accept-charset', 9 | className: 'class', 10 | htmlFor: 'for', 11 | httpEquiv: 'http-equiv', 12 | }; 13 | 14 | function normalizeAttributes(attributes: ?Attributes) { 15 | if (attributes == null) { 16 | return attributes; 17 | } 18 | let normalized = {}; 19 | let didNormalize = false; 20 | for (let name of Object.keys(attributes)) { 21 | let newName = name; 22 | if (ATTR_NAME_MAP.hasOwnProperty(name)) { 23 | newName = ATTR_NAME_MAP[name]; 24 | didNormalize = true; 25 | } 26 | normalized[newName] = attributes[name]; 27 | } 28 | return didNormalize ? normalized : attributes; 29 | } 30 | 31 | export default normalizeAttributes; 32 | -------------------------------------------------------------------------------- /src/editor/utils/stateUtils/selectionContainsEntity.js: -------------------------------------------------------------------------------- 1 | import getSelectedBlocks from './getSelectedBlocks'; 2 | 3 | export default (strategy) => (editorState, selection) => { 4 | const contentState = editorState.getCurrentContent(); 5 | const currentSelection = selection || editorState.getSelection(); 6 | const startKey = currentSelection.getStartKey(); 7 | const endKey = currentSelection.getEndKey(); 8 | const startOffset = currentSelection.getStartOffset(); 9 | const endOffset = currentSelection.getEndOffset(); 10 | 11 | const isSameBlock = startKey === endKey; 12 | const selectedBlocks = getSelectedBlocks(contentState, startKey, endKey); 13 | let entityFound = false; 14 | 15 | // We have to shift the offset to not get false positives when selecting 16 | // a character just before or after an entity 17 | const finalStartOffset = startOffset + 1; 18 | const finalEndOffset = endOffset - 1; 19 | 20 | selectedBlocks.forEach((block) => { 21 | strategy( 22 | block, 23 | (start, end) => { 24 | if (entityFound) { 25 | return; 26 | } 27 | 28 | const blockKey = block.getKey(); 29 | 30 | if (isSameBlock && (end < finalStartOffset || start > finalEndOffset)) { 31 | return; 32 | } else if (blockKey === startKey && end < finalStartOffset) { 33 | return; 34 | } else if (blockKey === endKey && start > finalEndOffset) { 35 | return; 36 | } 37 | 38 | entityFound = true; 39 | } 40 | ); 41 | }); 42 | 43 | return entityFound; 44 | }; 45 | -------------------------------------------------------------------------------- /src/editor/utils/stateUtils/styleToCSS.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import {isUnitlessNumber} from 'react-dom/lib/CSSProperty'; 4 | 5 | type StyleDescr = {[key: string]: number | string}; 6 | 7 | const VENDOR_PREFIX = /^(moz|ms|o|webkit)-/; 8 | const NUMERIC_STRING = /^\d+$/; 9 | const UPPERCASE_PATTERN = /([A-Z])/g; 10 | 11 | // Lifted from: https://github.com/facebook/react/blob/master/src/renderers/dom/shared/CSSPropertyOperations.js 12 | function processStyleName(name: string): string { 13 | return name 14 | .replace(UPPERCASE_PATTERN, '-$1') 15 | .toLowerCase() 16 | .replace(VENDOR_PREFIX, '-$1-'); 17 | } 18 | 19 | // Lifted from: https://github.com/facebook/react/blob/master/src/renderers/dom/shared/dangerousStyleValue.js 20 | function processStyleValue(name: string, value: number | string): string { 21 | let isNumeric; 22 | if (typeof value === 'string') { 23 | isNumeric = NUMERIC_STRING.test(value); 24 | } else { 25 | isNumeric = true; 26 | value = String(value); 27 | } 28 | if (!isNumeric || value === '0' || isUnitlessNumber[name] === true) { 29 | return value; 30 | } else { 31 | return value + 'px'; 32 | } 33 | } 34 | 35 | function styleToCSS(styleDescr: StyleDescr): string { 36 | return Object.keys(styleDescr).map((name) => { 37 | let styleValue = processStyleValue(name, styleDescr[name]); 38 | let styleName = processStyleName(name); 39 | return `${styleName}: ${styleValue}`; 40 | }).join('; '); 41 | } 42 | 43 | export default styleToCSS; 44 | -------------------------------------------------------------------------------- /src/global/components/businessComponents.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by lizhen on 4/14/2016. 3 | */ 4 | module.exports = { 5 | UploadImage: require('./businessComponents/UploadImage'), 6 | GroupUpload:require('./businessComponents/GroupUpload') 7 | }; 8 | -------------------------------------------------------------------------------- /src/global/supports/datas/base.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Administrator on 2016/5/20. 3 | */ 4 | module.exports = { 5 | Config: { 6 | version: "2.1.3 (Beta)", 7 | server : { 8 | // ajax: 'http://192.168.110.239:8082/qlwb/' //测试服务器 9 | ajax: 'http://114.55.148.57:8083/' //正式(公网)服务器 10 | }, 11 | watermarkImage: [{ 12 | type: "white_small", 13 | tip: "白色小图", 14 | value: "http://7xjl1j.com1.z0.glb.clouddn.com/white_small.png", 15 | valuebase64: "aHR0cDovLzd4amwxai5jb20xLnowLmdsYi5jbG91ZGRuLmNvbS93aGl0ZV9zbWFsbC5wbmc=" 16 | }, { 17 | type: "white_big", 18 | tip: "白色大图", 19 | value: "http://7xjl1j.com1.z0.glb.clouddn.com/white_big.png", 20 | valuebase64: "aHR0cDovLzd4amwxai5jb20xLnowLmdsYi5jbG91ZGRuLmNvbS93aGl0ZV9iaWcucG5n" 21 | }, { 22 | type: "gray_small", 23 | tip: "灰色小图", 24 | value: "http://7xjl1j.com1.z0.glb.clouddn.com/gray_small.png", 25 | valuebase64: "aHR0cDovLzd4amwxai5jb20xLnowLmdsYi5jbG91ZGRuLmNvbS9ncmF5X3NtYWxsLnBuZw==" 26 | }, { 27 | type: "gray_big", 28 | tip: "灰色大图", 29 | value: "http://7xjl1j.com1.z0.glb.clouddn.com/gray_big.png", 30 | valuebase64: "aHR0cDovLzd4amwxai5jb20xLnowLmdsYi5jbG91ZGRuLmNvbS9ncmF5X2JpZy5wbmc=" 31 | }, { 32 | type: "black_small", 33 | tip: "黑色小图", 34 | value: "http://7xjl1j.com1.z0.glb.clouddn.com/black_small.png", 35 | valuebase64: "aHR0cDovLzd4amwxai5jb20xLnowLmdsYi5jbG91ZGRuLmNvbS9ibGFja19zbWFsbC5wbmc=" 36 | }, { 37 | type: "black_big", 38 | tip: "黑色大图", 39 | value: "http://7xjl1j.com1.z0.glb.clouddn.com/black_big.png", 40 | valuebase64: "aHR0cDovLzd4amwxai5jb20xLnowLmdsYi5jbG91ZGRuLmNvbS9ibGFja19iaWcucG5n" 41 | }] 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/global/supports/methods/public.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Administrator on 2016/5/5. 3 | * From Public function doing 4 | */ 5 | import {ajax as AJAX} from './Request'; 6 | import {QINIU_IMG_TOKEN_URL, QINIU_MANAGE_TOKEN_URL, QINIU_VIDEO_TOKEN_URL, QINIU_FILE_TOKEN_URL} from '../datas/url'; 7 | module.exports = { 8 | supportMime: { 9 | image: [ 10 | "image/jpeg", "image/png", "image/jpg", "image/gif", "image/webp" 11 | ], 12 | video: ["video/mp4"], 13 | audio: ["audio/mp4", "audio/mp3", "audio/mpeg"] 14 | }, 15 | makeGuid: function() { 16 | var guid = ""; 17 | for (var i = 1; i <= 32; i++) { 18 | var n = Math.floor(Math.random() * 16.0).toString(16); 19 | guid += n; 20 | if ((i == 8) || (i == 12) || (i == 16) || (i == 20)) 21 | guid += "-"; 22 | } 23 | return guid; 24 | }, 25 | 26 | nowTime: function() { 27 | let time = Date.parse(new Date()) / 1000; 28 | return time; 29 | }, 30 | 31 | checkQiniu: { 32 | 33 | checkQiniuImgToken: function(key) { 34 | 35 | let timestamp = Date.parse(new Date()) / 1000; 36 | let last_qiniu_token_time = localStorage.getItem("last_qiniu_token_time_" + key); 37 | let mark = false; 38 | 39 | if (last_qiniu_token_time) { 40 | if ((timestamp - last_qiniu_token_time) < 3500) { 41 | //console.log("time not out "); 42 | mark = true; 43 | } 44 | } 45 | let qiniu_token = ""; 46 | if (localStorage.getItem("qiniu_" + key + "_token") && mark) { 47 | qiniu_token = localStorage.getItem("qiniu_" + key + "_token"); 48 | } 49 | return qiniu_token; 50 | }, 51 | returnToken: function(uploadConfig={},key = 'image', params = {}) { 52 | if (Object.keys(uploadConfig).length==0) { 53 | return false; 54 | } 55 | let token = this.checkQiniuImgToken(key); 56 | token = !!token == true 57 | ? token 58 | : this.getQiniuToken(uploadConfig, key, params); 59 | return token; 60 | }, 61 | getQiniuToken: function(uploadConfig,type = 'image', params) { 62 | //console.log("getQiniuToken"); 63 | let token = ""; 64 | let url; 65 | if (type == 'image') { 66 | url = uploadConfig.QINIU_IMG_TOKEN_URL; 67 | } else if (type == 'video') { 68 | url = uploadConfig.QINIU_VIDEO_TOKEN_URL; 69 | } else if (type == 'file') { 70 | url = uploadConfig.QINIU_FILE_TOKEN_URL; 71 | } else if (type == 'manage') { 72 | url = uploadConfig.QINIU_MANAGE_TOKEN_URL; 73 | } else { 74 | url = uploadConfig.QINIU_IMG_TOKEN_URL; 75 | } 76 | //console.log("token_url",url); 77 | AJAX.requestData({ 78 | url: url, 79 | method: 'post', 80 | isAsync: true, 81 | defaultData: {} 82 | }, params, (data) => { 83 | //console.log(data); data = JSON.parse(data); 84 | token = data.uptoken; 85 | //console.log("token=", token); 86 | localStorage.setItem("qiniu_" + type + "_token", token); 87 | localStorage.setItem("last_qiniu_token_time_" + type, Date.parse(new Date()) / 1000); 88 | }, () => { 89 | //console.log("err:", err); 90 | return false; 91 | }); 92 | return token; 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/global/supports/publicDatas.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by lizhen on 4/14/2016. 3 | */ 4 | //import PRO_MENU from 'datas/menu'; 5 | //import PRO_RELEASE from 'datas/release'; 6 | //import PRO_URL from 'datas/url'; 7 | //import PRO_USER from 'datas/user'; 8 | //import PRO_DOM_HELPER from 'methods/domHelper'; 9 | //import PRO_REQUEST from 'methods/Request'; 10 | //import PRO_COMMON from 'methods/common'; 11 | //import PRO_QINIU from 'methods/public'; 12 | //module.exports = {PRO_RELEASE, PRO_MENU, PRO_URL, PRO_USER, PRO_DOM_HELPER, PRO_REQUEST, PRO_COMMON, PRO_QINIU}; 13 | module.exports = { 14 | PRO_BASE: require('./datas/base'), 15 | PRO_URL: require('./datas/url'), 16 | PRO_REQUEST: require('./methods/Request'), 17 | PRO_COMMON: require('./methods/common'), 18 | PRO_QINIU: require('./methods/public') 19 | }; 20 | -------------------------------------------------------------------------------- /src/global/supports/resources/blur.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/global/supports/resources/custom.css: -------------------------------------------------------------------------------- 1 | .openFullAll { 2 | position: fixed; 3 | top: 0; 4 | right: 0; 5 | bottom: 0; 6 | left: 0; 7 | z-index: 999; 8 | overflow: auto; 9 | } 10 | 11 | .watermark_grid { 12 | display: block; 13 | position: absolute; 14 | top: 0; 15 | background-repeat: no-repeat; 16 | } 17 | 18 | .watermark_grid span { 19 | display: inline-block; 20 | border: 1px dashed rgba(255, 255, 255, .2); 21 | cursor: pointer; 22 | } 23 | 24 | .editor-inline-image tips { 25 | font-size: 12px; 26 | position: absolute; 27 | right: 0; 28 | color: #aaa; 29 | } 30 | .uploadingImagies { 31 | text-align: center; 32 | } 33 | .uploadingImagies img{ 34 | max-width: 100%; 35 | } 36 | .uploadingImagies a { 37 | font-size: 20px; 38 | position: relative; 39 | display: inherit; 40 | margin: 0 auto; 41 | } 42 | .breakImages>div { 43 | width: 100px; 44 | height: 100px; 45 | overflow: hidden; 46 | display: inline-block; 47 | margin: 10px 10px 0 0; 48 | background-clip: content-box; 49 | background-size: cover; 50 | background-repeat: no-repeat; 51 | background-position: center; 52 | border: 1px solid #E9E9E9; 53 | border-radius: 3px; 54 | overflow: hidden; 55 | } 56 | -------------------------------------------------------------------------------- /src/global/supports/resources/default/iconfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaen/react-lz-editor/5097a8a57ac919afab3da11ad10e076bfdf4be24/src/global/supports/resources/default/iconfont.eot -------------------------------------------------------------------------------- /src/global/supports/resources/default/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaen/react-lz-editor/5097a8a57ac919afab3da11ad10e076bfdf4be24/src/global/supports/resources/default/iconfont.ttf -------------------------------------------------------------------------------- /src/global/supports/resources/default/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leejaen/react-lz-editor/5097a8a57ac919afab3da11ad10e076bfdf4be24/src/global/supports/resources/default/iconfont.woff -------------------------------------------------------------------------------- /src/global/supports/resources/iconfont.css: -------------------------------------------------------------------------------- 1 | 2 | @font-face {font-family: "iconfont"; 3 | src: url('iconfont.eot?t=1479085947184'); /* IE9*/ 4 | src: url('iconfont.eot?t=1479085947184#iefix') format('embedded-opentype'), /* IE6-IE8 */ 5 | url('iconfont.woff?t=1479085947184') format('woff'), /* chrome, firefox */ 6 | url('iconfont.ttf?t=1479085947184') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/ 7 | url('iconfont.svg?t=1479085947184#iconfont') format('svg'); /* iOS 4.1- */ 8 | } 9 | 10 | .iconfont { 11 | font-family:"iconfont" !important; 12 | font-size:16px; 13 | font-style:normal; 14 | -webkit-font-smoothing: antialiased; 15 | -webkit-text-stroke-width: 0.2px; 16 | -moz-osx-font-smoothing: grayscale; 17 | } 18 | 19 | .icon-panorama_time:before { content: "\ea16"; } 20 | 21 | .icon-shangdian:before { content: "\ea01"; } 22 | 23 | .icon-yonghuzumingcheng:before { content: "\ea36"; } 24 | 25 | .icon-panorama_joinuser:before { content: "\ea18"; } 26 | 27 | .icon-panorama_joindevice:before { content: "\ea19"; } 28 | 29 | .icon-shangpin:before { content: "\e998"; } 30 | 31 | .icon-newsVerify:before { content: "\ea26"; } 32 | 33 | .icon-access_user:before { content: "\ea1d"; } 34 | 35 | .icon-xitong:before { content: "\ea1c"; } 36 | 37 | .icon-dropdown:before { content: "\ea0b"; } 38 | 39 | .icon-yidianhaoleibie:before { content: "\ea2e"; } 40 | 41 | .icon-unie60e:before { content: "\ea23"; } 42 | 43 | .icon-yidianhaowenzhang:before { content: "\ea30"; } 44 | 45 | .icon-empty:before { content: "\ea0d"; } 46 | 47 | .icon-lunbozutu:before { content: "\ea06"; } 48 | 49 | .icon-quanzi:before { content: "\e991"; } 50 | 51 | .icon-recycleNews:before { content: "\ea24"; } 52 | 53 | .icon-tiezi:before { content: "\e995"; } 54 | 55 | .icon-unie6672:before { content: "\e996"; } 56 | 57 | .icon-untitled22:before { content: "\e993"; } 58 | 59 | .icon-unie604:before { content: "\e932"; } 60 | 61 | .icon-untitled144:before { content: "\ea04"; } 62 | 63 | .icon-newsChannel1:before { content: "\ea27"; } 64 | 65 | .icon-quanziline:before { content: "\e992"; } 66 | 67 | .icon-piliangicon:before { content: "\ea08"; } 68 | 69 | .icon-yidianhaotiaomu:before { content: "\ea2f"; } 70 | 71 | .icon-huodong:before { content: "\e999"; } 72 | 73 | .icon-paixu:before { content: "\ea03"; } 74 | 75 | .icon-news:before { content: "\ea2a"; } 76 | 77 | .icon-jiangpai:before { content: "\ea1b"; } 78 | 79 | .icon-appclient:before { content: "\ea40"; } 80 | 81 | .icon-neirong:before { content: "\e994"; } 82 | 83 | .icon-paixu1:before { content: "\ea0e"; } 84 | 85 | .icon-newsComment:before { content: "\ea29"; } 86 | 87 | .icon-bumen:before { content: "\ea34"; } 88 | 89 | .icon-pinpai:before { content: "\ea02"; } 90 | 91 | .icon-newsChannel:before { content: "\ea28"; } 92 | 93 | .icon-yonghuxinxixian:before { content: "\ea07"; } 94 | 95 | .icon-panorama_app:before { content: "\ea1a"; } 96 | 97 | .icon-panorama_today:before { content: "\ea12"; } 98 | 99 | .icon-yaochi:before { content: "\ea09"; } 100 | 101 | .icon-gengxinupdated:before { content: "\ea21"; } 102 | 103 | .icon-panorama_version:before { content: "\ea14"; } 104 | 105 | .icon-wochuangjiande:before { content: "\ea38"; } 106 | 107 | .icon-ditu-copy-copy:before { content: "\e997"; } 108 | 109 | .icon-jingxuan-copy:before { content: "\ea05"; } 110 | 111 | .icon-yichu:before { content: "\ea0a"; } 112 | 113 | .icon-panorama_newboot:before { content: "\ea13"; } 114 | 115 | .icon-panorama:before { content: "\ea15"; } 116 | 117 | .icon-panorama_device:before { content: "\ea17"; } 118 | 119 | .icon-lunbotuzujian:before { content: "\ea39"; } 120 | 121 | .icon-order:before { content: "\ea0c"; } 122 | 123 | .icon-sort:before { content: "\ea10"; } 124 | 125 | .icon-zhanghuyuquanxian:before { content: "\ea32"; } 126 | 127 | .icon-panorama_action:before { content: "\ea11"; } 128 | 129 | .icon-yidianhaoshenhe:before { content: "\ea31"; } 130 | 131 | .icon-jiaosequanxian0101:before { content: "\ea1f"; } 132 | 133 | .icon-city:before { content: "\ea25"; } 134 | 135 | .icon-startpage:before { content: "\ea41"; } 136 | 137 | .icon-jiaosesheding:before { content: "\ea1e"; } 138 | 139 | .icon-chuangjianjiaose:before { content: "\ea22"; } 140 | 141 | .icon-yidianhao:before { content: "\ea2d"; } 142 | 143 | .icon-gongzuoxiang:before { content: "\ea20"; } 144 | 145 | .icon-grab:before { content: "\ea2c"; } 146 | 147 | .icon-draft:before { content: "\ea2b"; } 148 | 149 | .icon-channelpd-copy:before { content: "\ea33"; } 150 | 151 | .icon-bumen-copy:before { content: "\ea37"; } 152 | 153 | .icon-10106-copy:before { content: "\ea35"; } 154 | 155 | .icon-news_radar:before { content: "\ea49"; } 156 | 157 | .icon-news_radar_list:before { content: "\ea50"; } 158 | 159 | .icon-news_radar_comment:before { content: "\ea51"; } 160 | -------------------------------------------------------------------------------- /src/global/supports/resources/system.less: -------------------------------------------------------------------------------- 1 | @import "custom.css"; 2 | @import "customiconfont.less"; 3 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = require('./editor/index'); 3 | exports.LzEditor = require('./editor/index'); 4 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Test from './test.jsx'; 2 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | module.exports = { 4 | //entry:path.resolve('','src/main.js'), 5 | resolve: { 6 | root: [ 7 | path.resolve('./src/global/components'), 8 | path.resolve('./src/global/supports'), 9 | ], 10 | extensions: ['', '.js', '.jsx'] 11 | }, 12 | entry: [ 13 | 'webpack/hot/dev-server', 14 | 'webpack-dev-server/client?http://localhost:8081', 15 | // path.resolve('', 'src/main.js')//for publish 16 | path.resolve('', 'src/test.jsx')//for text 17 | ], 18 | output: { 19 | path: path.resolve('', 'build'), 20 | filename: 'bundle.js' 21 | }, 22 | module: { 23 | loaders: [{ 24 | test: /.jsx?$/, 25 | loader: 'babel-loader', 26 | exclude: /node_modules/, 27 | query: { 28 | presets: ['es2015', 'react'] 29 | } 30 | }, { 31 | test: /.js$/, 32 | loader: 'babel-loader', 33 | exclude: /node_modules/, 34 | query: { 35 | presets: ['es2015', 'react'], 36 | //compact: false 37 | }, 38 | loaders: [ 39 | 'babel?presets[]=react,presets[]=es2015,presets[]=stage-2' 40 | ] 41 | }, { 42 | test: /\.(jpg|png)$/, 43 | loader: "url?limit=8192" 44 | }, { 45 | test: /\.less$/, 46 | loader: 'style!css!less' 47 | }, { 48 | test: /\.css$/, // Only .css files 49 | loader: 'style!css' // Run both loaders 50 | }, { 51 | test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, 52 | loader: "url-loader?limit=10000&mimetype=application/font-woff" 53 | }, { 54 | test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, 55 | loader: "file-loader" 56 | }] 57 | }, 58 | plugins: [ 59 | new webpack.DefinePlugin({ 60 | 'process.env.NODE_ENV': '"development"' 61 | }), 62 | new webpack.HotModuleReplacementPlugin() 63 | ] 64 | }; 65 | -------------------------------------------------------------------------------- /webpack.release.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | var CommonsChunkPlugin = require("webpack/lib/optimize/CommonsChunkPlugin"); 4 | module.exports = { 5 | resolve: { 6 | root: [ 7 | path.resolve('./src/global/components'), 8 | path.resolve('./src/global/supports'), 9 | ], 10 | extensions: ['', '.js', '.jsx'] 11 | }, 12 | entry: [ 13 | path.resolve('', 'src/test.jsx') 14 | ], 15 | output: { 16 | path: __dirname + '/release', 17 | filename: 'bundle.js', 18 | chunkFilename: '[id].[chunkhash:4].js' 19 | }, 20 | module: { 21 | loaders: [{ 22 | test: /.jsx?$/, 23 | loader: 'babel-loader', 24 | exclude: /node_modules/, 25 | query: { 26 | presets: ['es2015', 'react'] 27 | } 28 | }, { 29 | test: /.js$/, 30 | loader: 'babel-loader', 31 | exclude: /node_modules/, 32 | query: { 33 | presets: ['es2015', 'react'], 34 | }, 35 | loaders: [ 36 | 'babel?presets[]=react,presets[]=es2015,presets[]=stage-2' 37 | ] 38 | }, { 39 | test: /\.(jpg|png)$/, 40 | loader: "url?limit=8192" 41 | }, { 42 | test: /\.less$/, 43 | loader: 'style!css!less' 44 | }, { 45 | test: /\.css$/, // Only .css files 46 | loader: 'style!css' // Run both loaders 47 | }, { 48 | test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, 49 | loader: "url-loader?limit=10000&mimetype=application/font-woff" 50 | }, { 51 | test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, 52 | loader: "file-loader" 53 | }] 54 | }, 55 | plugins: [ 56 | new webpack.DefinePlugin({ 57 | 'process.env.NODE_ENV': JSON.stringify("production") //部署时用 58 | }), 59 | new webpack.optimize.DedupePlugin() //找相等或近似的模块,避免在最终生成的文件中出现重复的模块 60 | ] 61 | }; 62 | --------------------------------------------------------------------------------