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的更多相关文章

  1. CSU1019: Simple Line Editor

    1019: Simple Line Editor Submit Page   Summary   Time Limit: 1 Sec     Memory Limit: 128 Mb     Subm ...

  2. Rich Text Editor for MVC

    在网站开发中难免会用到富文本编辑器,本文将介绍一款富文本编辑器(在线HTML编辑器) Rich Text Editor ,简要说明一下其在MVC中的使用. 具体使用情况和下载地址请参考:http:// ...

  3. Android开展:ADT+Eclipse使用错误:Text editor does not have a document provider

    Eclipse参加Android sdk源代码 正在使用Eclipse进行Android开发时间,我们经常需要导入sdk源代码来Eclipse中,方便api阅读和查询,详细操作为:ctrl+鼠标左键. ...

  4. web & Rich Text Editor

    web & Rich Text Editor 富文本编辑器 http://www.wangeditor.com/ https://github.com/wangfupeng1988/wangE ...

  5. DevExpress ASP.NET Core v19.1版本亮点:Rich Text Editor

    行业领先的.NET界面控件DevExpress 发布了v19.1版本,本文将以系列文章的方式为大家介绍DevExpress ASP.NET Core Controls v19.1中新增的一些控件及增强 ...

  6. Download EditPlus Text Editor

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

  7. 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 ...

  8. 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 ...

  9. 中南大学2018年ACM暑期集训前期训练题集(入门题) Q: Simple Line Editor

    数据有毒,一个一个读字符是错,整个字符串读入,一次就A了. 总之,数据总是没有错的,还是对c++了解地不够深刻,还有,在比赛中,一定要有勇气重构代码 错误代码: #include<iostrea ...

随机推荐

  1. [Hacker] 端口大全

    一 .端口大全 端口:0 服务:Reserved 说明:通常用于分析操作系统.这一方法能够工作是因为在一些系统中“0”是无效端口,当你试图使用通常的闭合端口连接它时将产生不同的结果.一种典型的扫描,使 ...

  2. Dvwa安装,配置(Linux)

    文章演示使用系统:CenTOS7 一:搭建LAMP环境 使用XAMPP安装部署,下载地址:https://www.apachefriends.org/download.html 1.1:赋予账号对XA ...

  3. 原生JS通过勾股定理计算苹果菜单效果

    JS原生苹果菜单效果 知识点: 勾股定理 a²+b²=c² Event 是一个事件对象,当一个事件发生后,和当前事件发生相关的详细信息会被临时存储到一个指定的地方,也就是event对象,以方便我们在需 ...

  4. TYVJ 1941 BZOJ3038 上帝造题的七分钟2 并查集+树状数组

    背景 XLk觉得<上帝造题的七分钟>不太过瘾,于是有了第二部. 描述 "第一分钟,X说,要有数列,于是便给定了一个正整数数列. 第二分钟,L说,要能修改,于是便有了对一段数中每个 ...

  5. Android网络编程随想录(2)

    上篇文章介绍了传输层TCP协议的理论知识,本文主要介绍了TCP协议基础之上HTTP协议和HTTPS协议的理论知识. HTTP协议基于TCP协议定义了客户端向服务器请求数据的方式,它是面向事务的应用层协 ...

  6. Codeforces Round #455

    Generate Login 第二个单词肯定只取首字母 Solution Segments 从1开始的线段和在n结束的线段各自凑一凑,剩下的转化为规模为n-2的子问题. Solution Python ...

  7. javascript的基础知识及面向对象和原型属性

    自己总结一下javascript的基础知识,希望对大家有用,也希望大家来拍砖,毕竟是个人的理解啊 1.1 类型检查:typeof(验证数据类型是:string) var num = 123; cons ...

  8. Android Studio插件:Android Drawable Importer

    Android Drawable Importer 为了在不同分辨率的设备上更好的展示图片的效果,我们往往需要在 res/drawable 中添加不同分辨率的图片.有时我们可能手里只有一份分辨率的图片 ...

  9. C# 5.0新加特性

    1. 异步编程 在.Net 4.5中,通过async和await两个关键字,引入了一种新的基于任务的异步编程模型(TAP).在这种方式下,可以通过类似同步方式编写异步代码,极大简化了异步编程模型.如下 ...

  10. 前端web通过flask操作数据库-增删改查

    后端python代码: #coding:utf8 from flask import Flask,request,render_template import pymysql as mysql imp ...