reactjs simple text editor
import React, { Component } from 'react'
import PubSub from 'pubsub'
import GlobalVars from 'globalVars'
import styles from './main.css'
// globalVars.runMode
class Text extends Component{
static defaultProps = {
text: '文案内容'
};
constructor(props, context) {
super(props)
this.state = {
'content' : props.content
,'Styles' : props.Styles
,'editMode' : false
}
PubSub.subscribe('textEditorBar' , (evt) => {
var workingEditor = evt.data
if (workingEditor != this.editorID){
this.hideEditor()
}
})
}
componentWillReceiveProps(nextProps){
this.setState({'Styles' : nextProps.Styles})
}
emitChange(evt ){
//https://github.com/sstur/react-rte/blob/master/src/SimpleRichTextEditor.js
var new_content = this.textInput.innerHTML
if (new_content != this.state.content){
this.setState({'content' : new_content})
}
}
showEditor(evt){
evt.preventDefault()
this.setState({'editMode' : {'palette' : false}})
}
hideEditor(evt){
this.setState({'editMode' : false})
}
saveSelection() {
//https://github.com/mindmup/bootstrap-wysiwyg/blob/master/bootstrap-wysiwyg.js
var sel = window.getSelection()
if (sel.getRangeAt && sel.rangeCount) {
this.selectedRange = sel.getRangeAt()
}
}
updateToolbar() {
var btns = document.querySelectorAll('.' + styles.textEditor + ' li[data-tag]')
for (var i=;i< btns.length;i++){
var tag = btns[i].dataset.tag
if (document.queryCommandState(tag)){
btns[i].classList.add(styles.editActive)
}else {
btns[i].classList.remove(styles.editActive)
}
}
}
emitKeyUp() {
this.saveSelection()
this.updateToolbar()
}
emitPaste(evt) {
evt.preventDefault()
var content = this.formatContent(evt.clipboardData.getData('Text') , {'nl2br':true})
this.restoreSelection()
document.execCommand('insertHTML', false, content)
this.saveSelection()
}
formatContent(content , opt){
opt = opt || {}
if (!content) return ''
if (opt.nl2br){
//content = content.replace(/<(?:.|\n)*?>/gm, '').replace(/\n/g,'</br/>')
content = content.replace(/\n/g,'</br/>')
}
return content
}
restoreSelection() {
var selection = window.getSelection()
if (this.selectedRange) {
try {
selection.removeAllRanges()
} catch (ex) {
document.body.createTextRange().select()
document.selection.empty()
}
selection.addRange(this.selectedRange)
}
}
setStyles(tag ,new_val){
this.restoreSelection()
document.execCommand(tag ,false , new_val || null)
this.saveSelection()
this.updateToolbar()
}
getSelectionHtml(){
var userSelection
if (window.getSelection) {
// W3C Ranges
userSelection = window.getSelection()
// Get the range:
if (userSelection.getRangeAt){
var range = userSelection.getRangeAt()
var container = range.commonAncestorContainer
if (container.nodeType == ) {
container = container.parentNode
return container.outerHTML
}
//if (container.nodeName === "A") {alert ("Yes, it's an anchor!");}
var clonedSelection = range.cloneContents()
var div = document.createElement('div')
div.appendChild(clonedSelection)
return div.innerHTML
}
} else if (document.selection) {
// Explorer selection, return the HTML
userSelection = document.selection.createRange()
return userSelection.htmlText
} else {
return ''
}
}
setLink(){
this.restoreSelection()
var wSelf = this
var tmp = document.createElement('div')
tmp.innerHTML = this.getSelectionHtml()
var link = tmp.getElementsByTagName('a')
PubSub.publish(
'widgetEditLink'
, {'link' : link[]
,'cbk' : (new_val) => {
this.restoreSelection()
var sText = window.getSelection()
if (new_val.link){
document.execCommand('createlink', false, new_val.link)
//document.execCommand('insertHTML', false, '<a href="' + new_val.link + '" target="' + (new_val.target || '_blank') + '">' + sText + '</a>')
}else{
var range = window.getSelection().getRangeAt()
var container = range.commonAncestorContainer
if (container.nodeType == ) {
container = container.parentNode
}
if (container.nodeName === "A") {
container.outerHTML = container.innerHTML
}
}
this.saveSelection()
}
}
,this)
}
setWholeStyles(tag , val){
var Styles = {...this.state.Styles }|| {}
if (val){
Styles[tag] = val
} else {
delete Styles[tag]
}
this.setState({'Styles' : Styles})
}
shouldComponentUpdate(newProps, newState){
if (this.props.setProps) {
var state_clone = {...newState}
delete state_clone.editMode
this.props.setProps(state_clone)
}
return true
}
setFontSize(evt){
this.setWholeStyles('fontSize' , evt.target.value)
}
setForeColor(evt){
this.setWholeStyles('color' , evt.target.dataset.color)
}
palette(){
var {editMode} = this.state || {}
this.setState({'editMode' : {'palette': !editMode.palette}})
}
render(){
var {content ,Styles ,editMode} = this.state
Styles = Styles || {}
content = this.formatContent(content)
var fontsize_options = {
's' : styles.textSmall
,'n' : styles.textNormal
, 'l' : styles.textLarge
}
var fontsize_state = (Styles.fontSize in fontsize_options) ? Styles.fontSize :'n'
var wrapper_cls = styles.textWrapper
var fontsize_cls = fontsize_options[fontsize_state]
if (fontsize_cls) wrapper_cls += ' ' + fontsize_cls
var StylesClone = {...Styles}
delete StylesClone.fontSize
if ('edit' == GlobalVars.runMode){
if (editMode) {
editMode = editMode || {}
//fontSize foreColor
var size_options = []
;[{'txt' :'小' ,'val' : 's'}
,{'txt' :'普通' ,'val' : 'n'}
,{'txt' : '大' ,'val' : 'l'}].forEach((item , i) => {
size_options.push(<option key={i} value={item.val}>{item.txt}</option>)
})
var color_options = []
;['#f00','#ccc' , '#0ff','#f69'].forEach((color , i) => {
color_options.push(<li key={i} onClick={this.setForeColor.bind(this)} data-color={color} style={{'color':color}}>{color}</li>)
})
var palette_style = {}
if (editMode.palette) {
palette_style.display = 'block'
}
var edit_btn = (
<ul className={styles.textEditor}>
<li data-tag='bold' onClick={this.setStyles.bind(this,'bold')}>B</li>
<li data-tag='italic' onClick={this.setStyles.bind(this,'italic')}>I</li>
<li data-tag='underline' onClick={this.setStyles.bind(this,'underline')}>U</li>
<li data-tag='justifyLeft' onClick={this.setStyles.bind(this,'justifyLeft')}>L</li>
<li data-tag='justifyCenter' onClick={this.setStyles.bind(this,'justifyCenter')}>C</li>
<li data-tag='justifyRight' onClick={this.setStyles.bind(this,'justifyRight')}>R</li>
<li data-tag='justifyFull' onClick={this.setStyles.bind(this,'justifyFull')}>F</li>
<li onClick={this.setLink.bind(this)}>Link</li>
<li onClick={this.palette.bind(this)} className={styles.textColorEditor}>
Color
<ul style={palette_style}>
<li onClick={this.setForeColor.bind(this)} data-color='' style={{'color':'grey'}}>默认</li>
{color_options}
</ul>
</li>
<li>
<select value={fontsize_state} onChange={this.setFontSize.bind(this)}>
{size_options}
</select>
</li>
</ul>)
}
var holder_cls = `${styles.textHolder} textEditorHolder`
this.editorID = uuid()
return (
<div className={holder_cls} data-editorid={this.editorID}>
<div
contentEditable
suppressContentEditableWarning
ref={(input) => this.textInput = input}
onInput={this.emitChange.bind(this)}
onBlur={this.emitChange.bind(this )}
onClick={this.showEditor.bind(this)}
onKeyUp={this.emitKeyUp.bind(this)}
onMouseUp={this.emitKeyUp.bind(this)}
onPaste={this.emitPaste.bind(this)}
style={StylesClone}
className={wrapper_cls}
dangerouslySetInnerHTML={{__html:content}}
></div>
{edit_btn}
</div>
)
}else {
return (
<div style={StylesClone} className={wrapper_cls}>{content}</div>
)
}
}
}
export default Text
reactjs simple text editor的更多相关文章
- CSU1019: Simple Line Editor
1019: Simple Line Editor Submit Page Summary Time Limit: 1 Sec Memory Limit: 128 Mb Subm ...
- Rich Text Editor for MVC
在网站开发中难免会用到富文本编辑器,本文将介绍一款富文本编辑器(在线HTML编辑器) Rich Text Editor ,简要说明一下其在MVC中的使用. 具体使用情况和下载地址请参考:http:// ...
- Android开展:ADT+Eclipse使用错误:Text editor does not have a document provider
Eclipse参加Android sdk源代码 正在使用Eclipse进行Android开发时间,我们经常需要导入sdk源代码来Eclipse中,方便api阅读和查询,详细操作为:ctrl+鼠标左键. ...
- web & Rich Text Editor
web & Rich Text Editor 富文本编辑器 http://www.wangeditor.com/ https://github.com/wangfupeng1988/wangE ...
- DevExpress ASP.NET Core v19.1版本亮点:Rich Text Editor
行业领先的.NET界面控件DevExpress 发布了v19.1版本,本文将以系列文章的方式为大家介绍DevExpress ASP.NET Core Controls v19.1中新增的一些控件及增强 ...
- Download EditPlus Text Editor
突然发现EditPlus还是很强大的,很好用,破解也很方便,有个牛人做了在线生成验证码,只能说服!! 下边把官网的最新下载地址贴出,当然还有在线生成验证码喽. EditPlus Text Editor ...
- CHtmlEditCtrl(1) : Use CHtmlEditCtrl to Create a Simple HTML Editor
I needed a lightweight HTML editor to generate "rich text" emails, so I decided to explore ...
- CHtmlEditCtrl (2): Add a Source Text Editor to Your HTML Editor
In a previous article, I described how to create an HTML editor using the MFC CHtmlEditCtrl class in ...
- 中南大学2018年ACM暑期集训前期训练题集(入门题) Q: Simple Line Editor
数据有毒,一个一个读字符是错,整个字符串读入,一次就A了. 总之,数据总是没有错的,还是对c++了解地不够深刻,还有,在比赛中,一定要有勇气重构代码 错误代码: #include<iostrea ...
随机推荐
- 【POJ 3700】 Missile Defence System
[题目链接] http://poj.org/problem?id=3700 [算法] 对于每一枚导弹,有4种决策 : 1.新建一套递增的系统拦截它 2.新建一套递减的系统拦截它 3.在已经建好的递增拦 ...
- 原生mysql读出来数据有乱码
加入这个后mysql_query("set names utf8");,可以将读出来的数据变成utf8的格式,可能是解决问题的一个好方法.
- 单元测试之Mock
为什么需要Mock. 真实对象具有不确定的行为.所以会产生不可预测的结果. 真实对象很难被创建. 真实对象的某些行为很难被触发(如网络错误). 真实对象令程序的运行速度很慢. 真实对象有(或者是)用户 ...
- 微信小程序video组件出现无法播放或卡顿
微信小程序使用video组件播放视频的时候,会出现卡顿或者无法播放的问题,加一个custom-cache=”true“即可解决,这个属性文档上没有,是从小程序开发社区中get到的.
- js原生_获取url键值对
思路: 1.先对url进行处理,获取 ?后的字符串 postid=10457794&actiontip=保存修改成功') 2. 字符串通过&标识,不同参数转为数组 ["pos ...
- Paint、Canvas.2
1:使用Cavans画个简单图形 2:过程 2.1:绘制最外部的圆 /*** 初始化 paint */ Paint paint; paint = new Paint(); paint.setColor ...
- hdu4009 Transfer water 最小树形图
每一户人家水的来源有两种打井和从别家接水,每户人家都可能向外输送水. 打井和接水两种的付出代价都接边.设一个超级源点,每家每户打井的代价就是从该点(0)到该户人家(1~n)的边的权值.接水有两种可能, ...
- 【SQL】分析函数功能-排序
1:排名,不考虑并列问题 row_number() 2:排名,有并列,并列后的排名不连续 rank() 3:排名,有并列,并列后的排名连续 dense_rank() 测试: SQL> creat ...
- Python学习笔记基础篇-(1)Python周边
一.系统命令 1.Ctrl+D 退出Python IDLE input方法中输入EOF字符,键入Ctrl+D 2.命令行选项: -d 提供调试输出 -O 生成优化的字节码(.pyo文件) -S 不 ...
- 04--C语言文件操作函数大全(超详细)
fopen(打开文件)相关函数 open,fclose表头文件 #include<stdio.h>定义函数 FILE * fopen(const char * path,const cha ...