Bootstrap

javaweb以html方式集成富文本编辑器TinyMce

前言:
单一的批量图片上传按钮,禁用tinymce编辑器,但是还可以操作图片编辑;
多元化格式的富文本编辑要求;
采用tinymce实现。

附:
tinymce中文手册网站:
http://tinymce.ax-z.cn/download-all.php
tinymce下载地址:
社区版: http://download.tiny.cloud/tinymce/community/tinymce_5.10.0.zip
开发版:http://download.tiny.cloud/tinymce/community/tinymce_5.10.0_dev.zip
auxipimage批量图片插件下载地址:
百度风盘链接:链接: https://pan.baidu.com/s/1w4RE_an7Xi8KLLAVm6kf4A 提取码: ivjj
参考项目代码:
https://gitee.com/tonyjoba_deen/ssm_-shiro_-tiny-mce/tree/feature

效果
请添加图片描述

核心代码:(引入了网上大佬们无私奉献的tinymce批量上传图片插件,感谢,注意插件的plugin.js或者plugin.min.js里面的base路径需要根据实际的项目目录更改。另外,我这里时集成了EasyUi,通过dialog弹框的形式使用富文本编辑器,部分的css样式不能加载,只能采用skin_url的形式。如果有更好的操作,欢迎评论发言)。


<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ include file="../../page/common/head.jsp" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
	<style lang="scss">
		/* 在el-dialog中使用tinymce  z-index被遮挡 */
		.tox-editor-container{
			z-index: 9999 !important;
		}
		.tox-tinymce-aux {
			z-index: 9999 !important;
		}
		/*隐藏文本输入框*/
		.tox-sidebar-wrap{

		}
	</style>

	<script src="${ctx}/tinymce/tinymce.min.js"></script>
	<script src="${ctx}/tinymce/themes/silver/theme.min.js"></script>
	<script src="${ctx}/tinymce/models/dom/model.min.js"></script>
	<script src="${ctx}/tinymce/icons/default/icons.min.js"></script>
	<script src="${ctx}/tinymce/plugins/image/plugin.min.js"></script>
	<script src="${ctx}/tinymce/plugins/axupimgs/plugin.min.js"></script>
	<script src="${ctx}/tinymce/plugins/quickbars/plugin.min.js"></script>
	<script src="${ctx}/tinymce/langs/zh-Hans.js"></script>
	<script type="text/javascript">
			/*获取每个tinyEditor的输入值,tinymce.get('my-tinymce-editor').getContent()*/
			tinymce.init(
				{
					selector: '#myfeel',
					skin: 'oxide-dark',
					language:'zh-Hans',
					/*inline:true,
					toolbar_persist:true,*/
					placeholder:"再次输入感受内容!",
					skin_url:'${ctx}/tinymce/skins/ui/oxide-dark',
					content_css:
							'${ctx}/tinymce/skins/content/default/content.min.css',
					statusbar:true,/*隐藏状态栏,就是下方的tinmce的官网链接行*/
					promotion: false,/*去除upgrade标识*/
					branding:false,/*去掉广告标tiny*/
					plugins: "image axupimgs",
					toolbar: "undo redo newdocument bold italic underline strikethrough subscript superscript | removeformat | selectall cut copy paste | image axupimgs",
					images_upload_handler: (blobInfo, progress) => new Promise((resolve, reject) => {
						const xhr = new XMLHttpRequest();
						xhr.withCredentials = false;
						xhr.open('POST', 'uploadFile');
						xhr.upload.onprogress = (e) => {
							progress(e.loaded / e.total * 100);
						};
						xhr.onload = () => {
							if (xhr.status === 403) {
								reject({ message: 'HTTP Error: ' + xhr.status, remove: true });
								return;
							}
							if (xhr.status < 200 || xhr.status >= 300) {
								reject('HTTP Error: ' + xhr.status);
								return;
							}
							const json = JSON.parse(xhr.responseText);
							if (!json || typeof json.location != 'string') {
								reject('Invalid JSON: ' + xhr.responseText);
								return;
							}
							resolve(json.location);
						};
						xhr.onerror = () => {
							reject('Image upload failed due to a XHR Transport error. Code: ' + xhr.status);
						};

						const formData = new FormData();
						formData.append('file', blobInfo.blob(), blobInfo.filename());

						xhr.send(formData);
					})
				});
	</script>
	<script>
		tinymce.init(
				{
					selector: '#mytinydemo',
					language:'zh-Hans',
					height:200,
					placeholder:"点击上方按钮上传图片,上传成功后点击保存至此处!",
					skin_url:'${ctx}/tinymce/skins/ui/oxide',
					content_css:
							'${ctx}/tinymce/skins/content/default/content.min.css',
					// ...其他TinyMCE配置
					plugins: "image axupimgs",
					toolbar: "axupimgs",
					menubar:false, /*隐藏菜单栏*/
					statusbar:true,/*隐藏状态栏,就是下方的tinmce的官网链接行*/
					promotion: false,/*去除upgrade标识*/
					branding:false,/*去掉广告标tiny*/
					//images_upload_url: 'uploadFile',//指定一个接受上传文件的后端处理程序地址
					//如果返回的地址是相对路径,还有一个参数images_upload_base_path,可以给相对路径指定它所相对的基本路径
					// images_upload_base_path: '/demo',
					images_upload_handler: function (blobInfo, succFun, failFun) {
						var xhr, formData;
						var file = blobInfo.blob();//转化为易于理解的file对象
						xhr = new XMLHttpRequest();
						xhr.withCredentials = false;
						xhr.open('POST', 'uploadFile');
						xhr.onload = function() {
							//上传完成回调
							var json;
							if (xhr.status != 200) {
								failFun('HTTP Error: ' + xhr.status);
								return;
							}
							json = JSON.parse(xhr.responseText);
							if (!json || typeof json.location != 'string') {
								failFun('Invalid JSON: ' + xhr.responseText);
								return;
							}
							succFun(json.location);
						};
						formData = new FormData();
						formData.append('file', file, file.name );//此处与源文档不一样
						xhr.send(formData);
					},
					//  添加`keydown`和`keydown`事件,实现编辑器的禁用
					setup: function (ed) {
						var tempVal = "";
						/*禁用编辑按钮,实现只负责文件图片的处理*/
						ed.on('keydown', function (e) {
							if(e.key=='Backspace' || e.key=="Delete"){
							}else{
								e.preventDefault();
								return false;
							}
						});
						ed.on('keyup', function (e) {
							if(e.key=='backspace'){
							}else{
								e.preventDefault();
								return false;
							}
						});
						ed.on('copy',function(e){
							return false;
						});
						ed.on('cut',function(e){
							return false;
						});
						ed.on('paste',function(e){
							return false;
						});
						ed.on('compositionstart',function(e){
							tempVal = tinymce.get('mytinydemo').getContent();
						});
						ed.on('compositionend',function(e){
							tinymce.get('mytinydemo').setContent(tempVal);
						});
					},
					file_picker_callback: function(callback, value, meta) {
						//文件上传,注意插件是link
						//文件分类
						var filetype='.pdf, .txt, .zip, .rar, .7z, .doc, .docx, .xls, .xlsx, .ppt, .pptx, .mp3, .mp4';
						//后端接收上传文件的地址
						var upurl='uploadFile';
						//为不同插件指定文件类型及后端地址
						switch(meta.filetype){
							case 'image':
								filetype='.jpg, .jpeg, .png, .gif';
								upurl='upimg.php';
								break;
							case 'media':
								filetype='.mp3, .mp4';
								upurl='upfile.php';
								break;
							case 'file':
							default:
						}
						//模拟出一个input用于添加本地文件
						var input = document.createElement('input');
						input.setAttribute('type', 'file');
						input.setAttribute('accept', filetype);
						input.click();
						input.onchange = function() {
							var file = this.files[0];

							var xhr, formData;
							console.log(file.name);
							xhr = new XMLHttpRequest();
							xhr.withCredentials = false;
							xhr.open('POST', upurl);
							xhr.onload = function() {
								var json;
								if (xhr.status != 200) {
									failure('HTTP Error: ' + xhr.status);
									return;
								}
								json = JSON.parse(xhr.responseText);
								if (!json || typeof json.location != 'string') {
									failure('Invalid JSON: ' + xhr.responseText);
									return;
								}
								callback(json.location);
							};
							formData = new FormData();
							formData.append('file', file, file.name );
							xhr.send(formData);
						}
					}

				});
		$("#feel_edit_submit").click(function(){
			$('#feel_edit_form').form('submit', {
				url:"user/submitUserInfo123123123223123",
				onSubmit: function(){
					$.messager.progress();	// 显示进度条
					var isValid = $(this).form('validate');
					if (!isValid){
						$.messager.progress('close');	// 如果表单是无效的则隐藏进度条
					}
					return isValid;	// 返回false终止表单提交
				},
				success:function(data){
					$.messager.progress('close');	// 如果提交成功则隐藏进度条
					if(data==1){
						$.messager.show({
							title:'系统消息',
							msg:'修改成功',
							timeout:3000,
							showType:'slide'
						});
						//弹出框关闭
						$("#role_dialog").dialog("close");
						$('#role_table').datagrid('reload');
					}else{
						$.messager.alert("系统信息","修改失败,请重新修改");
					}
				}
			});
		})
	</script>
</head>
<body>

<div  style="padding:10px;">
论坛管理 >> 文章管理
<hr/>
<form action="" method="post" id="feel_edit_form">
<input type="hidden" name="id"/>
<table width="800px">
	<tr>
		<td>标题:</td>
		<td><input type="text" name="title"/> </td>
	</tr>
	<tr>
		<td>图片:</td>
		<td>
			<div  id="mytinydemo" ></div>
        </td>
	</tr>
	<tr>
		<td>正文:</td>
		<td><textarea id="myfeel" type="text" name="remark"/> </td>
	</tr>
	<tr>
		<td colspan="2">
		<a id="feel_edit_submit" href="#" class="easyui-linkbutton"
		   data-options="iconCls:'icon-search'">发布</a>
		</td>
	</tr>
</table>
</form>
</div>
</body>
</html>

;