1 import React, { Component } from 'react'
  2 import PubSub from 'pubsub'
  3 import GlobalVars from 'globalVars'
  4 import styles from './main.css'
  5
  6 // globalVars.runMode
  7 class Text extends Component{
  8     static defaultProps = {
  9         text: '文案内容'
 10
 11     };
 12     constructor(props, context) {
 13         super(props)
 14         this.state = {
 15                 'content' : props.content
 16                ,'Styles' : props.Styles
 17                ,'editMode' : false
 18             }
 19
 20         PubSub.subscribe('textEditorBar' , (evt) => {
 21             var workingEditor = evt.data
 22             if (workingEditor != this.editorID){
 23                 this.hideEditor()
 24             }
 25         })
 26     }
 27     componentWillReceiveProps(nextProps){
 28         this.setState({'Styles' : nextProps.Styles})
 29     }
 30
 31     emitChange(evt ){
 32         //https://github.com/sstur/react-rte/blob/master/src/SimpleRichTextEditor.js
 33         var new_content = this.textInput.innerHTML
 34         if (new_content != this.state.content){
 35             this.setState({'content' : new_content})
 36         }
 37     }
 38
 39     showEditor(evt){
 40         evt.preventDefault()
 41         this.setState({'editMode' : {'palette' : false}})
 42     }
 43     hideEditor(evt){
 44        this.setState({'editMode' : false})
 45     }
 46     saveSelection() {
 47         //https://github.com/mindmup/bootstrap-wysiwyg/blob/master/bootstrap-wysiwyg.js
 48
 49         var sel = window.getSelection()
 50         if (sel.getRangeAt && sel.rangeCount) {
 51             this.selectedRange = sel.getRangeAt(0)
 52         }
 53     }
 54     updateToolbar() {
 55         var btns = document.querySelectorAll('.' + styles.textEditor + ' li[data-tag]')
 56
 57         for (var i=0;i< btns.length;i++){
 58             var tag = btns[i].dataset.tag
 59
 60             if (document.queryCommandState(tag)){
 61                 btns[i].classList.add(styles.editActive)
 62             }else {
 63                 btns[i].classList.remove(styles.editActive)
 64             }
 65         }
 66     }
 67     emitKeyUp() {
 68         this.saveSelection()
 69         this.updateToolbar()
 70     }
 71     emitPaste(evt) {
 72         evt.preventDefault()
 73         var content = this.formatContent(evt.clipboardData.getData('Text') , {'nl2br':true})
 74         this.restoreSelection()
 75         document.execCommand('insertHTML', false, content)
 76         this.saveSelection()
 77     }
 78     formatContent(content , opt){
 79         opt = opt || {}
 80         if (!content) return ''
 81         if (opt.nl2br){
 82             //content = content.replace(/<(?:.|\n)*?>/gm, '').replace(/\n/g,'</br/>')
 83             content = content.replace(/\n/g,'</br/>')
 84         }
 85         return content
 86     }
 87
 88     restoreSelection() {
 89         var selection = window.getSelection()
 90         if (this.selectedRange) {
 91             try {
 92                 selection.removeAllRanges()
 93             } catch (ex) {
 94                 document.body.createTextRange().select()
 95                 document.selection.empty()
 96             }
 97
 98             selection.addRange(this.selectedRange)
 99         }
100     }
101
102
103     setStyles(tag ,new_val){
104         this.restoreSelection()
105         document.execCommand(tag ,false , new_val || null)
106         this.saveSelection()
107         this.updateToolbar()
108     }
109     getSelectionHtml(){
110         var userSelection
111         if (window.getSelection) {
112             // W3C Ranges
113             userSelection = window.getSelection()
114             // Get the range:
115             if (userSelection.getRangeAt){
116                 var range = userSelection.getRangeAt(0)
117                 var container = range.commonAncestorContainer
118                 if (container.nodeType == 3) {
119                     container = container.parentNode
120                     return container.outerHTML
121                 }
122                 //if (container.nodeName === "A") {alert ("Yes, it's an anchor!");}
123                 var clonedSelection = range.cloneContents()
124                 var div = document.createElement('div')
125                 div.appendChild(clonedSelection)
126                 return div.innerHTML
127             }
128         } else if (document.selection) {
129             // Explorer selection, return the HTML
130             userSelection = document.selection.createRange()
131             return userSelection.htmlText
132         } else {
133             return ''
134         }
135     }
136     setLink(){
137         this.restoreSelection()
138         var wSelf = this
139         var tmp = document.createElement('div')
140         tmp.innerHTML = this.getSelectionHtml()
141         var link = tmp.getElementsByTagName('a')
142         PubSub.publish(
143                 'widgetEditLink'
144                 , {'link' : link[0]
145                     ,'cbk' : (new_val) => {
146                         this.restoreSelection()
147                         var sText = window.getSelection()
148                         if (new_val.link){
149                             document.execCommand('createlink', false, new_val.link)
150                             //document.execCommand('insertHTML', false, '<a href="' + new_val.link + '" target="' + (new_val.target || '_blank') + '">' + sText + '</a>')
151                         }else{
152                             var range = window.getSelection().getRangeAt(0)
153                             var container = range.commonAncestorContainer
154                             if (container.nodeType == 3) {
155                                 container = container.parentNode
156                             }
157                             if (container.nodeName === "A") {
158                                 container.outerHTML = container.innerHTML
159                             }
160
161                         }
162                         this.saveSelection()
163                     }
164                 }
165         ,this)
166
167     }
168     setWholeStyles(tag , val){
169         var Styles = {...this.state.Styles }|| {}
170         if (val){
171             Styles[tag] = val
172         } else {
173             delete Styles[tag]
174         }
175         this.setState({'Styles' : Styles})
176     }
177     shouldComponentUpdate(newProps, newState){
178         if (this.props.setProps) {
179             var state_clone = {...newState}
180             delete state_clone.editMode
181             this.props.setProps(state_clone)
182         }
183         return true
184     }
185     setFontSize(evt){
186         this.setWholeStyles('fontSize' , evt.target.value)
187     }
188     setForeColor(evt){
189         this.setWholeStyles('color' , evt.target.dataset.color)
190     }
191     palette(){
192         var {editMode} = this.state || {}
193         this.setState({'editMode' : {'palette': !editMode.palette}})
194     }
195
196     render(){
197         var {content ,Styles ,editMode}  = this.state
198         Styles = Styles || {}
199         content = this.formatContent(content)
200
201         var fontsize_options = {
202             's' : styles.textSmall
203             ,'n' : styles.textNormal
204             , 'l' : styles.textLarge
205         }
206         var fontsize_state = (Styles.fontSize in fontsize_options) ? Styles.fontSize :'n'
207         var wrapper_cls = styles.textWrapper
208         var fontsize_cls = fontsize_options[fontsize_state]
209         if (fontsize_cls) wrapper_cls += ' ' + fontsize_cls
210
211
212         var StylesClone = {...Styles}
213         delete StylesClone.fontSize
214
215         if ('edit' == GlobalVars.runMode){
216             if (editMode) {
217                 editMode = editMode || {}
218                 //fontSize foreColor
219                 var size_options = []
220                 ;[{'txt' :'小' ,'val' : 's'}
221                 ,{'txt' :'普通' ,'val' : 'n'}
222                 ,{'txt' : '大' ,'val' : 'l'}].forEach((item , i) => {
223                     size_options.push(<option key={i} value={item.val}>{item.txt}</option>)
224                 })
225
226                 var color_options = []
227                 ;['#f00','#ccc' , '#0ff','#f69'].forEach((color , i) => {
228                     color_options.push(<li key={i} onClick={this.setForeColor.bind(this)} data-color={color} style={{'color':color}}>{color}</li>)
229
230                 })
231
232                 var palette_style = {}
233                 if (editMode.palette) {
234                     palette_style.display = 'block'
235                 }
236                 var edit_btn = (
237                     <ul className={styles.textEditor}>
238                         <li data-tag='bold'  onClick={this.setStyles.bind(this,'bold')}>B</li>
239                         <li data-tag='italic'  onClick={this.setStyles.bind(this,'italic')}>I</li>
240                         <li data-tag='underline'  onClick={this.setStyles.bind(this,'underline')}>U</li>
241
242                         <li data-tag='justifyLeft' onClick={this.setStyles.bind(this,'justifyLeft')}>L</li>
243                         <li data-tag='justifyCenter' onClick={this.setStyles.bind(this,'justifyCenter')}>C</li>
244                         <li data-tag='justifyRight'  onClick={this.setStyles.bind(this,'justifyRight')}>R</li>
245                         <li data-tag='justifyFull' onClick={this.setStyles.bind(this,'justifyFull')}>F</li>
246
247
248                         <li onClick={this.setLink.bind(this)}>Link</li>
249
250                         <li onClick={this.palette.bind(this)} className={styles.textColorEditor}>
251                             Color
252                             <ul style={palette_style}>
253                                 <li  onClick={this.setForeColor.bind(this)} data-color='' style={{'color':'grey'}}>默认</li>
254                                 {color_options}
255                             </ul>
256                         </li>
257                         <li>
258                         <select value={fontsize_state}  onChange={this.setFontSize.bind(this)}>
259                             {size_options}
260                        </select>
261                         </li>
262                     </ul>)
263             }
264             var holder_cls = `${styles.textHolder} textEditorHolder`
265             this.editorID = uuid()
266             return (
267                 <div className={holder_cls} data-editorid={this.editorID}>
268                     <div
269                         contentEditable
270                         suppressContentEditableWarning
271                         ref={(input) => this.textInput = input}
272                         onInput={this.emitChange.bind(this)}
273                         onBlur={this.emitChange.bind(this )}
274                         onClick={this.showEditor.bind(this)}
275                         onKeyUp={this.emitKeyUp.bind(this)}
276                         onMouseUp={this.emitKeyUp.bind(this)}
277                         onPaste={this.emitPaste.bind(this)}
278                         style={StylesClone}
279                         className={wrapper_cls}
280                         dangerouslySetInnerHTML={{__html:content}}
281                     ></div>
282                     {edit_btn}
283                 </div>
284             )
285
286         }else {
287             return (
288                 <div style={StylesClone} className={wrapper_cls}>{content}</div>
289             )
290         }
291     }
292 }
293 export default Text

转载于:https://www.cnblogs.com/vaal-water/p/6047809.html

reactjs simple text editor相关推荐

  1. html+txt+编辑器,txtPro Text Editor

    txtPro Text Editor是一款文本编辑器,也是一款多语言代码编辑器.html编辑器.多样化的编辑器,你可以选择需要的代码效果,选择你喜欢的字体编辑.txtPro还附带了键盘快捷方式,并正确 ...

  2. Java Code Geeks通过Twitter赠送了免费的Sublime Text Editor许可

    正在与您的重量级编辑斗争? 然后,我们特别为您准备了一些东西! 我们正在举办比赛,免费赠送 kick-ass Sublime Text Editor 许可证 . Sublime Text是用于代码,标 ...

  3. 【Python CheckiO 题解】Text Editor

    CheckiO 是面向初学者和高级程序员的编码游戏,使用 Python 和 JavaScript 解决棘手的挑战和有趣的任务,从而提高你的编码技能,本博客主要记录自己用 Python 在闯关时的做题思 ...

  4. sublime text_Sublime Text Editor赠品报告和获胜者

    sublime text We had Sublime Text Editor Giveaway going on here, now it's ended and we are here to pr ...

  5. HTML Text Editor

    2019独角兽企业重金招聘Python工程师标准>>> HTML Text Editor 实现了基于 WebView 上的 CKEditor 编辑器的功能. 转载:http://ww ...

  6. Dynamics 365 New Feature之Rich Text Editor Control

    在Dynamics 365(CRM)中富文本的编辑一直是刚需,之前都是通过自定义的方式引入富文本功能,现在MS已经引入了该控件. 该控件支持文本,当然因为single text字数有限,一般都会选择m ...

  7. Download EditPlus Text Editor

    突然发现EditPlus还是很强大的,很好用,破解也很方便,有个牛人做了在线生成验证码,只能说服!! 下边把官网的最新下载地址贴出,当然还有在线生成验证码喽. EditPlus Text Editor ...

  8. CodeForces - 253C:Text Editor(暴力枚举)

    Discription Vasya is pressing the keys on the keyboard reluctantly, squeezing out his ideas on the c ...

  9. Blender:下载并安装文本编辑器(Text Editor)代码自动补全插件

    参考网站: [Addon] Auto Completion in Blenders Text Editor Code Autocomplete Manual#Installation [Youtube ...

最新文章

  1. 用java数组模拟登录和注册功能
  2. 【转】JAVA 并发性和多线程 -- 读感 (二 线程间通讯,共享内存的机制)
  3. kafka 分区和副本以及kafaka 执行流程,以及消息的高可用
  4. couldn't connect to server 127.0.0.1:27017 src/mongo/
  5. jax-rs jax-ws_使用JAX-RS的HTTP缓存
  6. shell 文件内容替换 sed用法
  7. ListView嵌套ListView优化
  8. 通过js动态设置字体大小
  9. 批量抓取羊毛网站信息,定时自动发送到邮箱进行阅览
  10. 设计模式:设计模式经典总结
  11. iOS 3DTouch 开发
  12. 配置全局less变量;解决iphoneX、 iphone8 plus 键盘退下去仍占空间,导致无法点击;vue-photo-preview 配置正常,但无法触发图片的预览
  13. 【向生活低头】wps行间距问题
  14. 上海市新生婴儿户口登记(出生申报)
  15. 与小卡特一起学python 第18章 一种新的输入-事件
  16. 机器视觉系统——照明
  17. Nginx配置并使用SSI功能
  18. Matlab对科氏力建模,基于ADAMS和MATLAB的惯性组件联合仿真研究
  19. 禁止开机时软件自启动的三种方法
  20. centOS7下 安装nodejs+nginx+mongodb+pm2部署vue项目

热门文章

  1. 前端文字点击出现蓝底
  2. 关于CAN报文中ACK应答错误的检测原理
  3. 我的世界职业系统rpg服务器,我的世界1.8.X-1.10.X服务器七彩之风RPG混合生存群组服小游戏空岛海岛粘液丧尸世界职业...
  4. Python识别二维码获取电子发票基本信息
  5. 以太网电缆作为“传输天线”,黑客可从气隙系统窃取数据
  6. MySQL无法启动 系统发生1058错误
  7. pdf2htmlEX命令行参数大全
  8. 背包问题贪心算法求解
  9. 猫掉进山洞C语言随机数,《小猫出生在秘密山洞》读书心得最新范文五篇
  10. 数据分析-思维分析逻辑day02