首页 > 代码库 > reactjs simple text editor

reactjs simple text editor

  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 userSelection111         if (window.getSelection) {112             // W3C Ranges113             userSelection = window.getSelection()114             // Get the range:115             if (userSelection.getRangeAt){116                 var range = userSelection.getRangeAt(0)117                 var container = range.commonAncestorContainer118                 if (container.nodeType == 3) {119                     container = container.parentNode120                     return container.outerHTML121                 }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.innerHTML127             }128         } else if (document.selection) {129             // Explorer selection, return the HTML130             userSelection = document.selection.createRange()131             return userSelection.htmlText132         } else {133             return ‘‘134         }135     }136     setLink(){137         this.restoreSelection()138         var wSelf = this139         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="http://www.mamicode.com/‘ + new_val.link + ‘" target="‘ + (new_val.target || ‘_blank‘) + ‘">‘ + sText + ‘</a>‘)151                         }else{152                             var range = window.getSelection().getRangeAt(0)153                             var container = range.commonAncestorContainer154                             if (container.nodeType == 3) {155                                 container = container.parentNode156                             }157                             if (container.nodeName === "A") {158                                 container.outerHTML = container.innerHTML159                             }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] = val172         } 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.editMode181             this.props.setProps(state_clone) 182         }183         return true184     }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.state198         Styles = Styles || {}199         content = this.formatContent(content) 200 201         var fontsize_options = {202             s : styles.textSmall 203             ,n : styles.textNormal204             , l : styles.textLarge205         }206         var fontsize_state = (Styles.fontSize in fontsize_options) ? Styles.fontSize :n207         var wrapper_cls = styles.textWrapper208         var fontsize_cls = fontsize_options[fontsize_state] 209         if (fontsize_cls) wrapper_cls +=   + fontsize_cls210 211         212         var StylesClone = {...Styles}213         delete StylesClone.fontSize214 215         if (edit == GlobalVars.runMode){216             if (editMode) {217                 editMode = editMode || {}218                 //fontSize foreColor219                 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=http://www.mamicode.com/{item.val}>{item.txt})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 = block235                 } 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                             Color252                             <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=http://www.mamicode.com/{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                     <div269                         contentEditable270                         suppressContentEditableWarning271                         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                         onm ouseUp={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

 

reactjs simple text editor