richTextEditors.jsx 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. import React from 'react';
  2. import theme from 'react-quill/dist/quill.snow.css';
  3. import { message } from 'antd';
  4. import ReactQuill, { Quill } from 'react-quill';
  5. import ajax from 'jquery/src/ajax/xhr.js';
  6. import $ from 'jquery/src/ajax';
  7. import audioIcon from '../../image/audio.png';
  8. let BlockEmbed = Quill.import('blots/block/embed');
  9. class AppPanelEmbed extends BlockEmbed {
  10. static create(value) {
  11. const node = super.create(value);
  12. node.setAttribute('contenteditable', 'false');
  13. node.setAttribute('width', '100%');
  14. // 设置自定义html
  15. node.innerHTML = this.transformValue(value)
  16. return node;
  17. }
  18. static transformValue(value) {
  19. let handleArr = value.split('\n')
  20. handleArr = handleArr.map(e => e.replace(/^[\s]+/, '')
  21. .replace(/[\s]+$/, ''))
  22. return handleArr.join('')
  23. }
  24. // 返回节点自身的value值 用于撤销操作
  25. static value(node) {
  26. return node.innerHTML
  27. }
  28. }
  29. // blotName
  30. AppPanelEmbed.blotName = 'AppPanelEmbed';
  31. // class名将用于匹配blot名称
  32. AppPanelEmbed.className = 'embed-innerApp';
  33. // 标签类型自定义
  34. AppPanelEmbed.tagName = 'p';
  35. Quill.register(AppPanelEmbed);
  36. var RichTextUploadUrl, RichTextUploadSign, RichTextUploadId;
  37. //上传图片
  38. function uploadImg(s, _this) {
  39. let myform = new FormData()
  40. let file = document.getElementById(_this.props.id + "fileToUpload").files[0];
  41. if (!file) { return; };
  42. if (file.size > 52428800) {
  43. message.warning('图片大小不能超过50M');
  44. return
  45. }
  46. myform.append('file', file);
  47. myform.append('sign', RichTextUploadSign);
  48. myform.append('id', RichTextUploadId);
  49. $.ajax({
  50. method: "post",
  51. dataType: "json",
  52. url: location.origin + RichTextUploadUrl,
  53. data: myform,
  54. contentType: false,
  55. processData: false,
  56. success: function (data) {
  57. if (data.error && data.error.length) {
  58. message.warning(data.error[0].message);
  59. document.getElementById(_this.props.id + "fileToUpload").value = ''
  60. } else {
  61. const cursorPosition = s.quill.getSelection().index
  62. s.quill.insertEmbed(
  63. cursorPosition,
  64. 'AppPanelEmbed',
  65. `<img style="width: 100%" src="${globalConfig.avatarUploadHost + data.data}"/>`
  66. );
  67. s.quill.setSelection(cursorPosition + 1);
  68. document.getElementById(_this.props.id + "fileToUpload").value = ''
  69. };
  70. },
  71. error: function (XMLHttpRequest, textStatus, errorThrown) {
  72. //查看错误信息
  73. message("上传失败");
  74. document.getElementById(_this.props.id + "fileToUpload").value = ''
  75. }
  76. })
  77. }
  78. //图片文件选择
  79. function fileSelect() {
  80. let _this = this.options._this;
  81. let uploader = document.getElementById(_this.props.id + "fileToUpload");
  82. if (!uploader.onchange) {
  83. uploader.onchange = () => {
  84. uploadImg(this, _this)
  85. }
  86. }
  87. uploader.click();
  88. }
  89. //音频文件选择
  90. function fileSelectAudio() {
  91. let _this = this.options._this;
  92. let uploader = document.getElementById(_this.props.id + "fileToUploadAudio");
  93. if (!uploader.onchange) {
  94. uploader.onchange = () => {
  95. uploadAudio(this, _this)
  96. }
  97. }
  98. uploader.click();
  99. }
  100. //音频文件上传
  101. function uploadAudio(s, _this) {
  102. let myform = new FormData()
  103. let file = document.getElementById(_this.props.id + "fileToUploadAudio").files[0]
  104. if (!file) { return; };
  105. if (file.size > 52428800) {
  106. message.warning('音频大小不能超过50M');
  107. return
  108. }
  109. myform.append('file', file);
  110. myform.append('sign', RichTextUploadSign);
  111. myform.append('id', RichTextUploadId);
  112. $.ajax({
  113. method: "post",
  114. dataType: "json",
  115. url: location.origin + RichTextUploadUrl,
  116. data: myform,
  117. contentType: false,
  118. processData: false,
  119. success: function (data) {
  120. if (data.error && data.error.length) {
  121. message.warning(data.error[0].message);
  122. document.getElementById(_this.props.id + "fileToUploadAudio").value = ''
  123. } else {
  124. const cursorPosition = s.quill.getSelection().index
  125. s.quill.insertEmbed(
  126. cursorPosition,
  127. 'AppPanelEmbed',
  128. `<audio src="${globalConfig.avatarUploadHost + data.data}" controls="controls">Your browser does not support the audio element.</audio>`
  129. );
  130. s.quill.setSelection(cursorPosition + 1)
  131. document.getElementById(_this.props.id + "fileToUploadAudio").value = ''
  132. };
  133. },
  134. error: function (XMLHttpRequest, textStatus, errorThrown) {
  135. document.getElementById(_this.props.id + "fileToUploadAudio").value = ''
  136. //查看错误信息
  137. message("上传失败");
  138. }
  139. })
  140. }
  141. //视频文件选择
  142. function fileSelectVideo() {
  143. let _this = this.options._this;
  144. let uploader = document.getElementById(_this.props.id + "fileToUploadVideo");
  145. if (!uploader.onchange) {
  146. uploader.onchange = () => {
  147. uploadVideo(this, _this)
  148. }
  149. }
  150. uploader.click();
  151. }
  152. //视频文件上传
  153. function uploadVideo(s, _this) {
  154. let myform = new FormData()
  155. let file = document.getElementById(_this.props.id + "fileToUploadVideo").files[0]
  156. if (!file) { return; };
  157. if (file.size > 52428800) {
  158. message.warning('视频大小不能超过50M');
  159. return
  160. }
  161. myform.append('file', file);
  162. myform.append('sign', RichTextUploadSign);
  163. myform.append('id', RichTextUploadId);
  164. $.ajax({
  165. method: "post",
  166. dataType: "json",
  167. url: location.origin + RichTextUploadUrl,
  168. data: myform,
  169. contentType: false,
  170. processData: false,
  171. success: function (data) {
  172. if (data.error && data.error.length) {
  173. message.warning(data.error[0].message);
  174. document.getElementById(_this.props.id + "fileToUploadVideo").value = ''
  175. } else {
  176. const cursorPosition = s.quill.getSelection().index
  177. s.quill.insertEmbed(
  178. cursorPosition,
  179. 'AppPanelEmbed',
  180. `<video style="width:100%" controls="" autoPlay="" name="media">
  181. <source src=${globalConfig.avatarUploadHost + data.data} type="video/mp4">
  182. </video>`
  183. );
  184. s.quill.setSelection(cursorPosition + 1);
  185. document.getElementById(_this.props.id + "fileToUploadVideo").value = ''
  186. };
  187. },
  188. error: function (XMLHttpRequest, textStatus, errorThrown) {
  189. document.getElementById(_this.props.id + "fileToUploadVideo").value = ''
  190. //查看错误信息
  191. }
  192. })
  193. }
  194. const Editors = React.createClass({
  195. getInitialState() {
  196. return {
  197. value: null,
  198. theBool: true
  199. }
  200. },
  201. handleRichText(value) {
  202. this.setState({ value: value });
  203. this.props.handleRichText(value);
  204. // this.props.handleRichText(value.replace(/iframe/g, 'video'));
  205. },
  206. componentDidMount() {
  207. document.getElementsByClassName('ql-audio')[this.props.id || 0].style = `background: url(${audioIcon}) no-repeat;background-size: contain;`
  208. },
  209. componentWillMount() {
  210. RichTextUploadUrl = this.props.uploadUrl;
  211. RichTextUploadSign = this.props.uploadSign;
  212. },
  213. componentWillReceiveProps(nextProps) {
  214. RichTextUploadId = nextProps.uploadId;
  215. this.state.theBool = true;
  216. // if(nextProps.textContent){
  217. this.state.value = nextProps.textContent || '';
  218. // }
  219. },
  220. render() {
  221. const modules = {
  222. toolbar: {
  223. container: [
  224. [{ 'size': ['small', false, 'large', 'huge'] }], // custom dropdown
  225. [{ 'header': [1, 2, 3, false] }],
  226. ['bold', 'italic', 'underline', 'strike', 'blockquote'], // toggled buttons
  227. // [{ 'header': 1 }, { 'header': 2 }], // custom button values
  228. [{ 'list': 'ordered' }, { 'list': 'bullet' }],
  229. // [{ 'script': 'sub' }, { 'script': 'super' }], // superscript/subscript
  230. [{ 'indent': '-1' }, { 'indent': '+1' }], // outdent/indent
  231. // [{ 'direction': 'rtl' }], // text direction
  232. [{ 'color': [] }, { 'background': [] }], // dropdown with defaults from theme
  233. // [{ 'font': [] }],
  234. [{ 'align': [] }],
  235. ['link', 'image', 'video'],
  236. ['clean'],
  237. ['audio'],
  238. ],
  239. handlers: { 'image': fileSelect, 'video': fileSelectVideo, 'audio': fileSelectAudio },
  240. _this: this
  241. },
  242. };
  243. const formats = [
  244. 'size', 'header',
  245. 'bold', 'italic', 'underline', 'strike', 'blockquote',
  246. 'list', 'bullet', 'indent',
  247. 'color', 'background',
  248. 'align',
  249. 'link', 'image', 'video', 'AppPanelEmbed', 'clean'
  250. ];
  251. return (
  252. <div>
  253. <ReactQuill
  254. theme="snow"
  255. value={this.state.value}
  256. modules={modules}
  257. formats={formats}
  258. placeholder='请填写内容!'
  259. onChange={this.handleRichText}
  260. />
  261. <input accept="image/*" type="file" name={this.props.id + "fileToUpload"} id={this.props.id + "fileToUpload"} placeholder='请填写内容!' style={{ "display": "none" }} />
  262. <input accept="video/*" type="file" name={this.props.id + "fileToUploadVideo"} id={this.props.id + "fileToUploadVideo"} placeholder='请填写视频!' style={{ "display": "none" }} />
  263. <input accept="audio/*" type="file" name={this.props.id + "fileToUploadAudio"} id={this.props.id + "fileToUploadAudio"} placeholder='请选择音频!' style={{ "display": "none" }} />
  264. </div>
  265. )
  266. },
  267. });
  268. export default Editors;