Repository: echosoar/medit
Branch: master
Commit: 25af04b5140d
Files: 8
Total size: 65.0 KB
Directory structure:
gitextract_t_m94g0a/
├── .gitignore
├── README.md
├── package.json
├── src/
│ ├── medit.css
│ └── medit.js
├── test/
│ ├── ajaxImageUpload.html
│ └── contentEditableFocus.html
└── webpack.config.dev.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
node_modules
demo
================================================
FILE: README.md
================================================

# Medit v2.0.0
***
medit新版本正在daily/3.0.0分支上进行开发,如有问题或者3.0版本开发建议可以提交issue
***
A creative WYSIWYG rich text editor for mobile device by javascript.
一个创新型的移动端所见即所得富文本编辑器。
Website Address : [https://medit.js.org](https://medit.js.org)
Demo: [Medit Demo](https://medit.js.org/demo.html)
##### 为了更专注做一个更具价值和体验的移动端富文本编辑器,所以Medit目前不支持Pc端使用,仅支持移动端。
***
### Medit2.0.0 较上一版本更新内容
1. 更易用的内容选择方式,目前已支持选取内容块后手势左右滑动选择、通过手机原生自带长按选择进行编辑操作。
2. 优化编辑器样式,把原有的图标、弹层和编辑器内部标识都进行了优化。
3. 开放功能扩展接口Medit.extend,可以通过这个接口来扩展更加丰富的内容。
4. 开放内置功能配置接口Medit.nativeSetting,开放内置弹层调用接口Medit.settingPage。
5. 工具条目前不在限制于页面顶部,用户可以对工具条进行自定义配置。
***
### 如何使用:
+ 第一步,引入medit.js文件,如果不下载使用icon包的话可能会导致部分功能性icon无法显示,icon存放于 __github/medit/build/images__ 下
```html
<script src="https://medit.js.org/build/medit.min.js"></script>
```
> 在第一步和第二步之间可以选择性的引入medit插件,也可以自己来书写medit插件,medit提供了两个方法,一个是 __medit.extend__ 方法来配置扩展插件,另外还有一个 __medit.nativeSetting__ 方法来配置内部功能,详情请看下面的 medit类方法。
+ 第二步,创建medit实例
```html
<script>
/*
* var meditObj = medit(editerContainerNode [, toolBarContainer]);
*
* 这里的medit方法内部实现了自动new,所以可以使用new medit,也可以直接使用medit。
*
* editerContainerNode:这是必须的,代表的是编辑框的node结点。
* toolBarContainer: 这是可选的参数,可以传入一个node结点来配置工具条位置,如果不传入那么就会固定在页面顶部。
*
* 下面是一个实例
*/
var meditObj = medit(document.getElementById("medit"), document.getElementById("meditToolBar"));
</script>
```
+ 经过上面两步之后一个medit富文本编辑器就可以使用了。
***
### Medit实例方法
通过上面创建好的medit实例meditObj可以调用medit的方法来实现你想要的功能。
+ meditObj.getContent()
获取medit编辑器中所编辑的内容结果。
+ meditObj.clear()
清除medit编辑器的内容和自动保存在客户端浏览器中的内容。
+ meditObj.autoSave(name, callBack(content, time))
配置medit自动保存,需要传入两个参数:
+ name:为了保证在同一页面引入两个编辑器后自动保存的效果,所以需要手动传入一个自动保存的字段名称,需要在页面中保持唯一性。
+ callBack(content, time):这是自动保存的回调函数,每次medit自动保存后都会调用这个回调函数,并传入当前保存的编辑器内容content和当前时间戳time。
+ meditObj.image(option) || meditObj.imageUpload(option)
medit图片上传配置,option是配置参数
```javascript
{ // 默认图片上传设置
path:'https://sm.ms/api/upload', // 图片上传路径
name:'smfile', // 图片上传文件参数
size:0, // 大小限制,0为不限制大小
timeout:0, // 上传超时时间,0为不限制
ext:["jpg","jpeg","png","gif","bmp"], // 上传文件格式限制
success:function(){}, // 上传成功回调
error:function(){} // 上传失败回调
}
```
***
### medit类方法
目前有三个medit类方法,所谓类方法就是直接通过medit类进行调用而不是通过medit实例进行调用。
+ medit.extend(config)
功能扩展方法,可以通过这个方法实现medit插件和功能扩展。
config是一个对象,其中必须包括 __图标: icon__ 、 __其它类型模块转换为此类型模块时动作: doWhat__ 、 __模块得到焦点时动作: focus__ 、__模块失去焦点时动作: blur__ 和 __模块名称: name__ 这五个属性。其中icon可以是远程url,也可以是dataURL;name必须保持唯一,不能与内置功能名称产生冲突。
下面是一个功能模块的完整配置属性:
```javscript
/*
icon: [String] 类型选择icon url
name: [String] 类型名称
isMerge: [Bollean] 是否开启相同内容自动合并
notDisplay: [Bollean] 在选择模式的时候不显示,
emptyNotDelete: [Bollean] 如果当前块只存在一个子节点并且这个子节点要删除的时候是否开启递归删除
doWhat: [Function] 转换到此类型时会自动做哪些转换
focus:[Function] 点击或此模块获取焦点时自动触发的函数
blur:[Function] 此模块失去焦点时自动触发的函数
empty: [Function] 什么时候当前模块为空
selecting:[Function] 选择当前模块并且手指在屏幕上移动时触发的操作
selected:[Function] 手指移动结束执行的操作
setting: [Array(Object)] 当前模块可以进行哪些操作
-- name: [String] 操作名称
-- icon: [String] 操作按钮icon url
-- doWhat: [Function/Array] 点击此操作按钮执行什么,或者是存在更深层次操作
*/
```
+ medit.nativeSetting(callBack(config, name))
内部功能配置方法,会循环调用callBack,然后把内置功能的配置和名称传入,返回值应该是一个修改后的config,然后medit就会应用这个config,如果没有返回值那么medit也就不会做任何改动。
+ medit.settingPage(title, contentHTML, callBack)
打开medit内置弹层,title是配置弹层顶部Title,contentHTML可以传入一段html文本作为弹层的内容,callBack是在弹层的ok按钮点击之后触发。
下面是一段应用medit类方法的实例:
```html
<script>
medit.extend({
name: 'time',
icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAClklEQVRYR8WXjW0VQQyExxUAHUAFJBWQVACpgFABoQJCBZAKgAqSVECogKQCSAVABUZf8B73s393QXorPa2ebs87Httjn2nHy3Z8v1YBcPfHkp5JeiHpYfzw4Vf8LiR9NbMfvY51AXD3A0lvJbH3rCtJ78yMvbqqANwdL99LOh5ZuZGEp3PjgIOZp6OznHtlZjCUXUUA7r4n6aMkdtZnSactegP0B0kv473rAMG+WFkAcfmXiPEtnplZ1kDJs7DxKRiBgcOcjQWA8IDL8Ry6D0oURlKqxErYIlSEBQcAMQlHDgCooQ/P92rxc3eHATOrhZI8SiAuzOxozNrkxaDtWxzYb9HeAwBbM7uwMCTwHABZ+5yEM7Nx5mdD3QsgQCRmr8zsMBkcAES8fsaDJ61sD6PNEKSLIl++x/9HKbRjAHhM2d2YWSq9qoisYSAAk4gkJNoAI/+k2N2p3dehYKd1/fr7dAMA7KKoQ4jHDJAY6PyArgViAwCU8jz6xZ2s5wBMsrQGIgFAITPnqHc8Heo+egoac21m+/8TQAnnGzMjtClkeA0AOmaRgclLDQYoW4SmtI7H1eTu1RCkJDwzs5NW/Lc8d/dqEqYyHOKz5ZIGY9UyhMpVQrQGYFOIoq6TXC6axprLcmfdPdm+NDNy4W7NewEzX5LL7nJsgZs1o4nM59pxSkbql47YPWAWPCe0OMW+aHKlgWQ8RBxtBdEz3JRGMtDi+YMYtwHRnHDHDITqIbvY+h3DzYLN3kkG24gOIlUNSWQ7DSfNE4x1zJTZ93rGcsSDLpkWhgDDngZV2jcJTHazp3UWk/T6sXxGJ0YBkkbtVuJ3jfCLMmxZjaSiieDx/CuJHIERRq6ix/M7uj7NWsDu83znAP4A8SpJMGG4znIAAAAASUVORK5CYII=',
doWhat: function(node) {
node.innerHTML = "this is time node";
return node;
},
setting: [{
name: 'time',
icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAClklEQVRYR8WXjW0VQQyExxUAHUAFJBWQVACpgFABoQJCBZAKgAqSVECogKQCSAVABUZf8B73s393QXorPa2ebs87Httjn2nHy3Z8v1YBcPfHkp5JeiHpYfzw4Vf8LiR9NbMfvY51AXD3A0lvJbH3rCtJ78yMvbqqANwdL99LOh5ZuZGEp3PjgIOZp6OznHtlZjCUXUUA7r4n6aMkdtZnSactegP0B0kv473rAMG+WFkAcfmXiPEtnplZ1kDJs7DxKRiBgcOcjQWA8IDL8Ry6D0oURlKqxErYIlSEBQcAMQlHDgCooQ/P92rxc3eHATOrhZI8SiAuzOxozNrkxaDtWxzYb9HeAwBbM7uwMCTwHABZ+5yEM7Nx5mdD3QsgQCRmr8zsMBkcAES8fsaDJ61sD6PNEKSLIl++x/9HKbRjAHhM2d2YWSq9qoisYSAAk4gkJNoAI/+k2N2p3dehYKd1/fr7dAMA7KKoQ4jHDJAY6PyArgViAwCU8jz6xZ2s5wBMsrQGIgFAITPnqHc8Heo+egoac21m+/8TQAnnGzMjtClkeA0AOmaRgclLDQYoW4SmtI7H1eTu1RCkJDwzs5NW/Lc8d/dqEqYyHOKz5ZIGY9UyhMpVQrQGYFOIoq6TXC6axprLcmfdPdm+NDNy4W7NewEzX5LL7nJsgZs1o4nM59pxSkbql47YPWAWPCe0OMW+aHKlgWQ8RBxtBdEz3JRGMtDi+YMYtwHRnHDHDITqIbvY+h3DzYLN3kkG24gOIlUNSWQ7DSfNE4x1zJTZ93rGcsSDLpkWhgDDngZV2jcJTHazp3UWk/T6sXxGJ0YBkkbtVuJ3jfCLMmxZjaSiieDx/CuJHIERRq6ix/M7uj7NWsDu83znAP4A8SpJMGG4znIAAAAASUVORK5CYII=',
doWhat: function(node){
medit.settingPage("时间插件测试","Time test",function(){ console.log("ok点击了")});
}
}],
focus: function(node){
node.setAttribute("class","medit-editing");
},
blur: function(node) {
node.removeAttribute("class");
}
})
medit.nativeSetting(function(mode, modeName){
console.log(mode, modeName);
});
</script>
```
***
© MIT License
================================================
FILE: package.json
================================================
{
"name": "medit",
"version": "1.0.0",
"description": "A creative WYSIWYG rich text editor for mobile device.",
"main": "medit.js",
"scripts": {
"dev": "webpack --config webpack.config.dev.js --watch",
"build": "webpack --config webpack.config.min.js"
},
"repository": {
"type": "git",
"url": "https://github.com/echosoar/medit.git"
},
"keywords": [
"WYSIWYG",
"mobile",
"rich",
"text",
"editor"
],
"author": "echosoar",
"license": "ISC",
"bugs": {
"url": "https://github.com/echosoar/medit/issues"
},
"homepage": "https://medit.js.org",
"devDependencies": {
"babel-plugin-transform-es2015-classes": "^6.18.0",
"copy-webpack-plugin": "^4.0.1",
"eslint": "~3.4.0",
"eslint-plugin-babel": "^3.2.0",
"eslint-plugin-react": "~4.2.3",
"optimist": "^0.6.1",
"resolve-url-loader": "^1.6.1",
"url-loader": "~0.5.7",
"webpack": "~1.12.14"
},
"dependencies": {
"autoprefixer": "~6.3.4",
"babel-core": "^6.14.0",
"babel-eslint": "^6.1.2",
"babel-loader": "~6.2.4",
"babel-plugin-transform-object-rest-spread": "~6.6.5",
"babel-polyfill": "^6.3.14",
"babel-preset-es2015": "^6.14.0",
"css-loader": "~0.23.1",
"file-loader": "~0.8.5",
"less": "~2.6.1",
"less-loader": "~2.2.2",
"loader-utils": "~0.2.12",
"md5": "~2.0.0",
"node-sass": "^3.6.0",
"postcss-loader": "~0.8.2",
"precss": "~1.4.0",
"sass-loader": "^3.2.0",
"style-loader": "~0.13.0"
}
}
================================================
FILE: src/medit.css
================================================
#medit {
font-family:微软雅黑,黑体,Helvetica,华文黑体;
font-size: 14px;
word-break:break-all;
}
#medit * {
outline:none;
}
#medit span {
position: relative;
outline:none;
}
.medit-editing{
outline:none;
padding: 0 20px;
background: #eeddff;
}
#medit-tool {
position:fixed;
display: none;
z-index:100;
width:100%;
left: 0;
top: 0;
height:40px;
white-space: nowrap;
overflow:auto;
background:#428bca;
text-align: left;
font-family:微软雅黑,黑体,Helvetica,华文黑体;
}
#medit-tool.medit-tool-inner {
position:relative;
}
#medit [data-meditMode=br] {
height: 14px;
width: 20px;
margin:10px 0;
border-radius: 3px;
background:url("./images/icon-br.png") no-repeat center;
background-size: 14px;
}
.medit-tool-button {
width:40px;
display:inline-block;
height:40px;
line-height: 40px;
text-align:center;
font-size:13px;
cursor: pointer;
color:#fff;
font-weight:bold;
}
.medit-tool-addLeft {
background:url("./images/add-left.png") no-repeat center center;
background-size: 24px;
}
.medit-tool-addRight {
background:url("./images/add-right.png") no-repeat center center;
background-size: 24px;
}
.medit-tool-delete {
background:url("./images/close.png") no-repeat center center;
background-size: 24px;
}
.medit-tool-mode {
background:url("./images/mode.png") no-repeat center center;
background-size: 24px;
}
.medit-tool-ok {
background:url("./images/ok.png") no-repeat center center;
background-size: 24px;
}
.medit-tool-return {
background:url("./images/return.png") no-repeat center center;
background-size: 24px;
}
.medit-tool-button{
border-right: 1px solid #357ebd;
background-color: #428bca;
}
/* text */
.medit-text-select {
position:relative;
background:#9cf;
}
/* Link */
.medit-link {
background: #def;
border-bottom:1px dashed #709;
}
#medit a {
position: relative;
outline:none;
padding: 0 20px;
}
#medit a:before {
content: " ";
position: absolute;
left: 0;
top: 0;
width: 20px;
height:20px;
background:url("./images/link/link-left.png") no-repeat center center;
background-size: 20px;
}
#medit a:after {
content: " ";
position: absolute;
bottom: 0;
width: 20px;
height:12px;
background:url("./images/link/link-right.png") no-repeat center center;
background-size: 20px;
}
/* setting page */
#medit-settingPage{
display: none;
position:fixed;
z-index:101;
top:0;
left:0;
width:100%;
height:100%;
background:rgba(0,0,0,.6);
font-size:14px;
font-family:微软雅黑,黑体,Helvetica,华文黑体;
}
#medit-settingPage input {
font-family:微软雅黑,黑体,Helvetica,华文黑体;
}
#medit-settingPage-main{
position:absolute;
top:50%;
left:10%;
transform:translateY(-50%);
width:80%;
background:#fff;
border-radius:3px;
border:1px solid #666;
}
#medit-settingPage-title {
padding:0 10px;
font-size:12px;
color:#000;
height:36px;
line-height:36px;
border-bottom:1px solid #ddd;
}
#medit-settingPage-content {
border-radius: 3px;
}
#medit-settingPage-content .medit-list-mode-style-innerTitle{
padding: 0 5px;
font-size:12px;
margin:10px;
border-left: 3px solid #f96;
}
#medit-settingPage-content input[type=text] {
width:100%;
box-sizing:border-box;
padding:0 10px;
height:40px;
line-height:40px;
margin-top:15px;
border:1px solid #eee;
border-left:0;
border-right:0;
outline:none;
margin-bottom:15px;
font-size:12px;
}
#medit-settingPage-content .medit-settingPage-image-dataInfo {
}
#medit-settingPage-content .medit-settingPage-image-dataInfo span {
display:block;
font-size:12px;
padding:15px;
}
#medit-settingPage-content .medit-settingPage-image-dataInfo input[type=text] {
display:block;
margin:0;
}
#medit-settingPage-content label{
display:block;
margin-left:10px;
}
#medit-settingPage-content input[type=radio], #medit-settingPage-content input[type=checkbox] {
display:none;
}
#medit-settingPage-content input[type=radio] + span, #medit-settingPage-content input[type=checkbox] + span {
position:relative;
display:inline-block;
height:24px;
line-height:24px;
padding-left:30px;
font-size:12px;
}
#medit-settingPage-content input[type=radio] + span:before, #medit-settingPage-content input[type=checkbox] + span:before{
content:' ';
position:absolute;
left:0;
top:4px;
width:16px;
height:16px;
background:#fff;
border-radius:100%;
border:2px solid #9cf;
}
#medit-settingPage-content input[type=radio]:checked + span:before, #medit-settingPage-content input[type=checkbox]:checked + span:before {
background:#39f url("./images/ok.png") no-repeat center center;
background-size: 16px;
border:2px solid #39f;
}
#medit-settingPage-button{
height:36px;
margin-top:15px;
}
#medit-settingPage-button-ok {
display: block;
font-style:normal;
height:36px;
line-height:36px;
text-align:center;
color:#fff;
overflow:hidden;
background:#69f;
}
#medit-settingPage-button-cancel {
background:#69f url("./images/close2.png") no-repeat center center;
background-size: 24px;
position:absolute;
top:-15px;
right:-15px;
width:30px;
height:30px;
border-radius:50%;
}
.medit-image{
position:relative;
}
img:after {
content:" ";
position:absolute;
width:200px;
height:200px;
right:0;
bottom:0;
color:#fff;
background:#333;
}
#medit [data-meditMode=image] {
background-color:#e5e5e5;
}
#medit-image-upload-select-btn {
width:70%;
overflow:hidden;
white-space:nowrap;
padding: 0 5%;
margin:20px auto;
height:32px;
line-height:32px;
color:#fff;
background:#3c9;
border-radius:3px;
text-align:center;
}
#medit-image-upload-file {
position:absolute;
left:-500px;
width:200px;
}
#medit-settingPage-content-img-uploading{
padding: 20px 10px;
line-height:24px;
}
#medit-settingPage-content-img-uploading-progress {
display:block;
height:4px;
background:#c33;
border-radius:2px;
margin:10px 0;
}
#medit ul, #medit ol {
position:relative;
padding: 5px 0;
margin:5px 0;
border-left:20px solid #eee;
min-height:30px;
}
#medit ul:before, #medit ol:before {
content: "Li st";
position:absolute;
height:12px;
line-height:12px;
left:-17px;
color:#333;
width:15px;
font-size: 10px;
top:2px;
}
.medit-list {
background:#ddd;
}
#medit li {
position:relative;
margin:0;
padding:0;
list-style:none;
padding:5px;
min-height:20px;
margin:3px;
border-left:20px solid #eee;
}
#medit li:before{
content: "li";
position:absolute;
height:20px;
line-height:20px;
left:-20px;
color:#333;
text-align:center;
width:20px;
font-size: 10px;
top:0px;
}
================================================
FILE: src/medit.js
================================================
require("./medit.css");
var obj = window;
var meditToolImage = obj.meditToolImage || "./";// 工具条图片位置
var meditId = null;
var container = [];
var regNodeId = /medit\-(\d+)\-(\d+)$/;
var regContent = /\s(class|id|contenteditable)(=".*?")?/g; // 获得内容时去除id,class和可编辑状态
var regIsNotContentEmpty = /^<.*?>$/; // 获得内容时检测是否是纯文本
var regNormalStyle = /(font\-style\s*:\s*normal\s*;)|(font\-weight\s*:\s*normal\s*;)|(color:\s*rgb\(0,\s*0,\s*0\);)|(\s*)/ig; // 正常的样式需要剔除
var selectTextReg = /<span class="medit\-text\-select">(.*?)<\/span>/i;
var isToolMove = false;
var toolBarCatch = null;
var isContainMove = false;
var mainTouchPoint = {};
var nowNode = null; // 当前选择的可编辑结点
var nodeFocusTimeout = null; // nodeFocus延时
var globalSelectionContent = null; // 缓存长按选择区域
var globalSelectionHandle = null;
var commonImageType = {
"jpeg":"image/jpeg",
"jpg":"image/jpeg",
"gif":"image/gif",
"png":"image/png",
"bmp":"image/bmp"
}
var getNodeById = function(id){
return document.getElementById(id);
}
var fun_deep_clone = function (parent, child) {
child = child || {};
for(var i in parent) {
if(parent.hasOwnProperty(i)) {
if(typeof parent[i] === "object") {
child[i] = (Object.prototype.toString.call(parent[i]) === "[object Array]") ? [] : {};
fun_deep_clone(parent[i], child[i]);
} else {
child[i] = parent[i];
}
}
}
return child;
}
var returnButtonHtml = function(from){
return '<span id="medit-tool-button-'+from+'" class="medit-tool-button medit-tool-return" data-meditToolStyle="return" data-meditToolDegree="1"> </span>';
}
var toArray = function(obj){
return [].slice.call(obj);
}
var getXhr = function(){
if(window.XMLHttpRequest){
var xhr=new XMLHttpRequest();
}else{
try{
var xhr=new ActiveXObject("Msxml2.XMLHTTP");
}catch(e){
try{
var xhr=new ActiveXObject("Microsoft.XMLHTTP");
}catch(e){
throw new TypeError('Unsupport XMLHttpRequest');
}
}
}
return xhr;
}
var mainButton = ["addLeft","delete","setting","mode","ok","addRight"];
var nowMode = "text";
/*
mode 属性:
icon: [String] 类型选择icon url
isMerge: [Bollean] 是否开启相同内容自动合并
notDisplay: [Bollean] 在选择模式的时候不显示,
emptyNotDelete: [Bollean] 如果当前块只存在一个子节点并且这个子节点要删除的时候是否开启递归删除
doWhat: [Function] 转换到此类型时会自动做哪些转换
focus:[Function] 点击或此模块获取焦点时自动触发的函数
blur:[Function] 此模块失去焦点时自动触发的函数
empty: [Function] 什么时候当前模块为空
selecting:[Function] 选择当前模块并且手指在屏幕上移动时触发的操作
selected:[Function] 手指移动结束执行的操作
setting: [Array(Object)] 当前模块可以进行哪些操作
-- name: [String] 操作名称
-- icon: [String] 操作按钮icon url
-- doWhat: [Function/Array] 点击此操作按钮执行什么,或者是存在更深层次操作
*/
var nativeMode = ["text", "br", "link", "image", "list", "li"];
var mode = {
"text": {
icon: meditToolImage + 'images/mode/text.png',
doWhat: function(node){
mode[node.getAttribute("data-meditmode")].blur(node);
var temNode = document.createElement("span");
temNode.setAttribute("data-medit", "true");
temNode.setAttribute("data-meditmode", "text");
node.parentNode.insertBefore(temNode,node);
node.parentNode.removeChild(node);
mode["text"].focus(temNode);
nodeFocus(temNode);
nowNode = temNode;
toolBarModeSetting("text",mode["text"].setting);
container[meditId].updateId();
nowMode = "text";
},
isMerge: true,
focus:function(node) {
node.setAttribute("contentEditable","true");
node.setAttribute("class","medit-editing");
},
blur:function(node) {
node.innerHTML = node.innerHTML.replace(selectTextReg,"$1");
node.removeAttribute("contentEditable");
node.removeAttribute("class");
},
empty:function(node) {
return node.innerHTML == "";
},
setting:[
{
name:"bold",
icon: meditToolImage + "images/text/bold.png",
doWhat:function(node){
var style = node.getAttribute("style");
var reg = /font\-weight\s*:\s*(.*?)\s*;/i;
if(reg.test(style)){
var regRes = reg.exec(style);
if(regRes[1] == "bold"){
node.style.fontWeight = "normal";
return;
}
}
node.style.fontWeight = "bold";
}
},
{
name:"italic",
icon: meditToolImage + "images/text/italic.png",
doWhat:function(node){
var style = node.getAttribute("style");
var reg = /font\-style\s*:\s*(.*?)\s*;/i;
if(reg.test(style)){
var regRes = reg.exec(style);
if(regRes[1] == "italic"){
node.style.fontStyle = "normal";
return;
}
}
node.style.fontStyle = "italic";
}
},
{
name:"underline",
icon: meditToolImage + "images/text/underline.png",
doWhat:function(node){
var style = node.getAttribute("style");
var reg = /text\-decoration\s*:\s*(.*?)\s*;/i;
if(reg.test(style)){
var regRes = reg.exec(style);
if(regRes[1] == "underline"){
node.style.textDecoration = "none";
return;
}
}
node.style.textDecoration = "underline";
}
},
{
name:"size",
icon: meditToolImage + "images/text/size.png",
doWhat:[
{
name: "fontSizeBig",
icon: meditToolImage + "images/text/sizeBigger.png",
doWhat: function(node) {
var style = node.getAttribute("style");
var displaySize = getNodeById("medit-tool-button-text-setting-3-doWhat-1");
var reg = /font\-size\s*:\s*(\d*)\s*(?:.*?)\s*;/i;
var size = 15;
if(reg.test(style)){
var regRes = reg.exec(style);
size = ++regRes[1];
}
if(displaySize){
displaySize.innerHTML = size;
}
node.style.fontSize = size + "px";
}
},
{
name: "fontSizeValue",
icon: "",
defaultValue: "size"
},
{
name: "fontSizeSmall",
icon: meditToolImage + "images/text/sizeSmaller.png",
doWhat: function(node) {
var style = node.getAttribute("style");
var displaySize = getNodeById("medit-tool-button-text-setting-3-doWhat-1");
var reg = /font\-size\s*:\s*(\d*)\s*(?:.*?)\s*;/i;
var size = 13;
if(reg.test(style)){
var regRes = reg.exec(style);
size = --regRes[1];
if(size<12)size=12;
}
if(displaySize){
displaySize.innerHTML = size;
}
node.style.fontSize = size + "px";
}
}
]
},
{
name: "color",
icon: meditToolImage + "images/text/color.png",
doWhat:[
{
name: "black",
icon: meditToolImage + "images/text/colorBlack.png",
doWhat:function(node){
node.style.color = "#000000";
}
},
{
name: "red",
icon: meditToolImage + "images/text/colorRed.png",
doWhat:function(node){
node.style.color = "#ff0000";
}
},
{
name: "green",
icon: meditToolImage + "images/text/colorGreen.png",
doWhat:function(node){
node.style.color = "#00ff00";
}
},
{
name: "blue",
icon: meditToolImage + "images/text/colorBlue.png",
doWhat:function(node){
node.style.color = "#0000ff";
}
},
{
name: "yellow",
icon: meditToolImage + "images/text/colorYellow.png",
doWhat:function(node){
node.style.color = "#ffff00";
}
},
{
name: "pink",
icon: meditToolImage + "images/text/colorPink.png",
doWhat:function(node){
node.style.color = "#ff00ff";
}
}
]
}
],
selecting : function(node, isAdd){
var selectReg = selectTextReg;
if(selectReg.test(node.innerHTML)){
var regRes = node.innerHTML.split(selectReg);
if(isAdd){
if(regRes[1].length>1){
if(/^ |^<(.*?)\s(.*?)>(.*?)<\/(.*?)>/.test(regRes[1])){
var innerTagReg = /^ |^<(.*?)\s(.*?)>(.*?)<\/(.*?)>/.exec(regRes[1]);
var replaceHTML = innerTagReg[0];
regRes[0] += replaceHTML;
regRes[1] = regRes[1].replace(/^ |^<(.*?)\s(.*?)>(.*?)<\/(.*?)>/, "");
}else{
regRes[0] = regRes[0] + regRes[1].slice(0, 1);
regRes[1] = regRes[1].slice(1);
}
}
}else{
if(regRes[1].length>1){
if(/<(.*?)\s(.*?)>(.*?)<\/(.*?)>$| $/.test(regRes[1])){
var innerTagReg = /<(.*?)\s(.*?)>(.*?)<\/(.*?)>$| $/.exec(regRes[1]);
var replaceHTML = innerTagReg[0];
regRes[2] = replaceHTML + regRes[2];
regRes[1] = regRes[1].replace(/<(.*?)\s(.*?)>(.*?)<\/(.*?)>$| $/, "");
}else{
regRes[2] = regRes[1].slice(-1) + regRes[2];
regRes[1] = regRes[1].slice(0, -1);
}
}
}
node.innerHTML = regRes[0] + '<span class="medit-text-select">' + regRes[1] + '</span>' + regRes[2];
}else{
node.innerHTML = '<span class="medit-text-select">' + node.innerHTML + '</span>';
}
},
selected: function(thisNode){
var selectReg = selectTextReg;
var newNode;
var contain = container[meditId];
if(selectReg.test(thisNode.innerHTML)) {
var thisId = regNodeId.exec(thisNode.getAttribute("id"))[1];
var regRes = thisNode.innerHTML.split(selectReg);
var style = thisNode.getAttribute("style");
if(regRes[0]!==''){
var spanPre =document.createElement("span");
spanPre.setAttribute("data-medit","true");
spanPre.setAttribute("data-meditMode","text");
spanPre.setAttribute("id","medit-" + thisId + "-" + meditId );
spanPre.setAttribute("style",style);
spanPre.innerHTML = regRes[0];
thisNode.parentNode.insertBefore(spanPre, thisNode);
thisId++;
}
if(regRes[2]!==''){
thisNode.innerHTML = regRes[2];
var span =document.createElement("span");
span.setAttribute("data-medit","true");
span.setAttribute("data-meditMode","text");
span.setAttribute("id","medit-" + thisId + "-" + meditId );
span.setAttribute("contentEditable","true");
span.setAttribute("class","medit-editing");
span.setAttribute("style",style);
span.innerHTML = regRes[1];
this.blur(thisNode);
thisNode.parentNode.insertBefore(span, thisNode);
newNode = thisNode.previousSibling;
}else{
thisNode.innerHTML = regRes[1];
newNode = thisNode;
}
contain.updateId();
contain.nowNodeId = thisId;
nodeFocus(newNode);
}else{
newNode = thisNode;
}
return newNode;
}
},
"br":{
icon: meditToolImage + 'images/mode/br.png',
doWhat: function(node) {
mode[node.getAttribute("data-meditmode")].blur(node);
var temNode = document.createElement("span");
temNode.style.display = "block";
temNode.innerHTML = " ";
temNode.setAttribute("data-medit", "true");
temNode.setAttribute("data-meditmode", "br");
node.parentNode.insertBefore(temNode,node);
node.parentNode.removeChild(node);
mode["br"].focus(temNode);
nodeFocus(temNode);
nowNode = temNode;
toolBarModeSetting("br",[]);
container[meditId].updateId();
nowMode = "br";
},
focus:function(node) {
node.style.backgroundColor = "#e5e5e5";
},
blur:function(node) {
node.style.backgroundColor = "";
}
},
"link":{
icon: meditToolImage + 'images/mode/link.png',
doWhat: function(node) {
var parent = node;
while(parent.parentNode.getAttribute("data-medit")){
parent = parent.parentNode;
}
if(parent.nodeName.toLowerCase() == "a"){
return;
}
var linkNode = document.createElement("a");
linkNode.setAttribute("data-medit","true");
linkNode.setAttribute("data-meditmode","link");
mode[node.getAttribute("data-meditmode")].blur(node);
node.parentNode.insertBefore(linkNode,node);
node.parentNode.removeChild(node);
linkNode.appendChild(node);
toolBarModeSetting("link",mode['link'].setting);
mode["link"].focus(linkNode);
container[meditId].updateId();
container[meditId].nowNodeId = regNodeId.exec(linkNode.getAttribute("id"))[1];
nowMode = "link";
clearTimeout(nodeFocusTimeout);
nowNode = linkNode;
},
setting: [
{
name: "setting",
icon: meditToolImage + "images/link/setting.png",
doWhat: function(node){
var href = node.getAttribute("data-meditHref");
var hrefHtml = '';
if(href){
hrefHtml = ' value="'+href+'"';
}
var target = node.getAttribute("target");
if(target && target != "_blank"){
target = "";
}else{
target = " checked";
}
var html = '<input type="text" id="medit-settingPage-input-link"'+hrefHtml+' placeholder="链接地址 Link Address"/><label><input type="checkbox" id="medit-settingPage-check-link"'+target+'><span>新窗口打开 Open in a new window</span></label>';
settingPageDisplay('超链接设置 Link Setting',html,function(){
var href = getNodeById("medit-settingPage-input-link");
if(href){
node.setAttribute("data-meditHref", href.value);
}
var checkbox = getNodeById("medit-settingPage-check-link");
if(checkbox.checked){
node.setAttribute("target", "_blank");
}else{
node.removeAttribute("target");
}
settingPage.style.display = "none";
});
}
},
{
name: "cancellink",
icon: meditToolImage + "images/link/cancel-link.png",
doWhat: function(node){
var childs = toArray(node.children);
var temNode = childs[0];
var temMode = temNode.getAttribute("data-meditmode");
childs.forEach(function(child){
node.parentNode.insertBefore(child, node);
});
node.parentNode.removeChild(node);
container[meditId].updateId();
toolBarModeSetting(temMode,mode[temMode].setting);
mode[temMode].focus(temNode);
nowNode = temNode;
nodeFocus(temNode);
}
}
],
focus: function(node){
getNodeById("medit-tool-button-mode").style.display = "none";
node.setAttribute("class","medit-link");
},
blur:function(node){
node.removeAttribute("class");
}
},
"image":{
icon: meditToolImage + "images/mode/image.png",
doWhat:function(node){
mode[node.getAttribute("data-meditmode")].blur(node);
var temNode = document.createElement("img");
temNode.setAttribute("data-medit", "true");
temNode.setAttribute("data-meditmode", "image");
temNode.setAttribute("src", mode["image"].icon);
temNode.setAttribute("width","32");
temNode.setAttribute("height","32");
node.parentNode.insertBefore(temNode,node);
node.parentNode.removeChild(node);
mode["image"].focus(temNode);
nodeFocus(temNode);
nowNode = temNode;
toolBarModeSetting("image",mode["image"].setting);
container[meditId].updateId();
nowMode = "image";
},
focus: function(node){
node.setAttribute("class","medit-image");
},
blur:function(node){
node.removeAttribute("class");
},
setting:[
{
name:"setting",
icon: meditToolImage + "images/image/setting.png",
doWhat: function(node) {
var width = node.getAttribute("width");
var height = node.getAttribute("height");
var address = node.getAttribute("src");
var html = '<div class="medit-settingPage-image-dataInfo"><span>宽度 Width:</span><input type="text" id="medit-settingPage-image-width" value="'+width+'"><span>高度 Height:</span><input type="text" id="medit-settingPage-image-height" value="'+height+'"><span>图像地址 Address:</span><input type="text" id="medit-settingPage-image-address" value="'+address+'"><div>';
settingPageDisplay('图像设置 Image Setting',html,function(){
var width = getNodeById("medit-settingPage-image-width").value;
if(width && width>0){
node.setAttribute("width",width);
}
var height = getNodeById("medit-settingPage-image-height").value;
if(height && height>0){
node.setAttribute("height",height);
}
var newAddress = getNodeById("medit-settingPage-image-address").value;
if(address != newAddress){ // 传入网络图片需要进行宽高转换
getNodeById("medit-settingPage-button").style.display = "none";
getNodeById("medit-settingPage-content").innerHTML = "Loading Image...";
var newImg = new Image();
newImg.src = newAddress;
newImg.onload = function(){
var scale = newImg.width/ newImg.height;
if(newImg.width>100){
newImg.width = 100;
newImg.height = 100/scale;
}
settingPage.style.display = "none";
node.setAttribute("src",newAddress);
node.setAttribute("width",newImg.width);
node.setAttribute("height",newImg.height);
}
}else{
settingPage.style.display = "none";
}
});
}
},
{
name: "biger",
icon: meditToolImage + "images/image/biger.png",
doWhat: function(node){
var width = node.getAttribute("width");
var height = node.getAttribute("height");
node.setAttribute("width",Math.ceil(width*1.1));
node.setAttribute("height",Math.ceil(height*1.1));
}
},
{
name: "smaller",
icon: meditToolImage + "images/image/smaller.png",
doWhat: function(node){
var width = node.getAttribute("width");
var height = node.getAttribute("height");
node.setAttribute("width",Math.ceil(width/1.1));
node.setAttribute("height",Math.ceil(height/1.1));
}
},
{
name: "upload",
icon: meditToolImage + "images/image/upload.png",
doWhat: function(node){
var config = container[meditId].imageUpload;
var html = '<form enctype="multipart/form-data" method="post" id="medit-image-upload-form"><input type="file" name="'+config.name+'" id="medit-image-upload-file"/></form><div id="medit-image-upload-select-btn">选择图片 Select Image</div>';
settingPageDisplay('图像上传 Image upload',html,function(){
var files = getNodeById("medit-image-upload-file");
if(files.files.length <=0){
return;
}
var file = files.files[0];
var size = file.size;
var name = file.name;
var type = file.type;
var config = container[meditId].imageUpload;
var ext = {};
config.ext && config.ext.forEach(function(v){ ext[commonImageType[v]] = true; });
if(config.size == 0 || config.size>=size){
if(!config.ext || ext[type]){
var http = getXhr();
var form = new FormData(getNodeById("medit-image-upload-form"));
getNodeById("medit-settingPage-button").style.display = "none";
getNodeById("medit-settingPage-content").innerHTML = '<div id="medit-settingPage-content-img-uploading">图片上传中 Image uploading...</div>';
http.upload.onprogress = function(v){
var progress = Math.floor(100*v.loaded/v.total) + "%";
var success = "";
if(progress == "100%") success ="上传成功,请稍后...<br />upload success,please waiting...";
getNodeById("medit-settingPage-content").innerHTML = '<div id="medit-settingPage-content-img-uploading">图片上传中 Image uploading...'+ progress +'<br /><i id="medit-settingPage-content-img-uploading-progress" style="width:' + progress + ';"></i>'+success+'</div>';
}
Object.keys(config.params).map(function(key) {
form.append(key, config.params[key]);
});
http.open("POST",config.path);
http.send(form);
http.onreadystatechange = function(){
if(http.readyState === 4){
if(http.status === 200 || http.status>200 && http.status<400){
var res = JSON.parse(http.responseText);
if(res.code == "success"){
config.success(res);
var scale = res.data.width/ res.data.height;
if(res.data.width>100){
res.data.width = 100;
res.data.height = 100/scale;
}
settingPage.style.display = "none";
node.setAttribute("src",res.data.url);
node.setAttribute("width",res.data.width);
node.setAttribute("height",res.data.height);
}
}else{
config.error("http status " + http.status);
}
}
}
}else{ config.error("image type limit "+config.ext.join(",")); }
}else{ config.error("image size limit "+config.size); }
});
getNodeById("medit-settingPage-button-ok").innerHTML = "上传 Upload";
var btn = getNodeById("medit-image-upload-select-btn");
var fileInput = getNodeById("medit-image-upload-file");
btn.onclick = function(){
fileInput.click();
}
fileInput.onchange = function(e){
e = e || window.event;
var files=e.target.files||e.srcElement.files;
var file = files[0];
var size = file.size;
var name = file.name;
var type = file.type;
var ext = {};
config.ext && config.ext.forEach(function(v){ ext[commonImageType[v]] = true; });
if (config.size == 0 || config.size>=size){
if (!config.ext || ext[type]){
btn.innerHTML = name;
} else {
config.error("image type limit "+config.ext.join(","));
}
} else {
config.error("image size limit "+config.size);
}
}
}
},
{
name: 'verticalAlign',
icon: meditToolImage + 'images/image/vertical-align.png',
doWhat:[
{
name: 'top',
icon: meditToolImage + 'images/image/top-align.png',
doWhat:function(node){
node.style.verticalAlign = "top";
}
},
{
name: 'middle',
icon: meditToolImage + 'images/image/middle-align.png',
doWhat:function(node){
node.style.verticalAlign = "middle";
}
},
{
name: 'bottom',
icon: meditToolImage + 'images/image/bottom-align.png',
doWhat:function(node){
node.style.verticalAlign = "bottom";
}
}
]
}
]
},
"list":{
emptyNotDelete: true,
icon: meditToolImage + "images/mode/list.png",
focus:function(node){
node.setAttribute("class","medit-list");
getNodeById("medit-tool-button-mode").style.display = "none";
},
blur:function(node){
node.removeAttribute("class");
},
doWhat:function(node){
mode[node.getAttribute("data-meditmode")].blur(node);
var temNode = document.createElement("ul");
temNode.setAttribute("data-medit", "true");
temNode.setAttribute("data-meditmode", "list");
temNode.setAttribute("type", "disc");
node.parentNode.insertBefore(temNode,node);
node.parentNode.removeChild(node);
nodeFocus(temNode);
nowNode = temNode;
toolBarModeSetting("list",mode["list"].setting);
mode["list"].focus(temNode);
container[meditId].updateId();
nowMode = "list";
},
setting:[
{
name:"setting",
icon: meditToolImage + "images/list/setting.png",
doWhat:function(node){
var type = node.getAttribute("type").toLowerCase();
var nodeType = node.nodeName.toLowerCase();
var html = '<div class="medit-list-mode-style-innerTitle">无序列表 Unorder List:</div>'+
'<label><input type="radio" class="medit-list-mode-style-ul" value="disc" name="medit-list-mode-style"'+(type=="disc"?" checked":"")+'><span>disc 实心圆</span></label>'+
'<label><input type="radio" class="medit-list-mode-style-ul" value="circle" name="medit-list-mode-style"'+(type=="circle"?" checked":"")+'><span>circle 空心圆</span></label>'+
'<label><input type="radio" class="medit-list-mode-style-ul" value="square" name="medit-list-mode-style"'+(type=="square"?" checked":"")+'><span>square 实心方块</span></label>'+
'<div class="medit-list-mode-style-innerTitle">有序列表 Order List:</div>'+
'<label><input type="radio" class="medit-list-mode-style-ol" value="1" name="medit-list-mode-style"'+(type=="1"?" checked":"")+'><span>1、2、3、4</span></label>'+
'<label><input type="radio" class="medit-list-mode-style-ol" value="a" name="medit-list-mode-style"'+(type=="a"?" checked":"")+'><span>a、b、c、d</span></label>'+
'<label><input type="radio" class="medit-list-mode-style-ol" value="A" name="medit-list-mode-style"'+(type=="A"?" checked":"")+'><span>A、B、C、D</span></label>'+
'<label><input type="radio" value="i" class="medit-list-mode-style-ol" name="medit-list-mode-style"'+(type=="i"?" checked":"")+'><span>i, ii, iii, iv</span></label>'+
'<label><input type="radio" class="medit-list-mode-style-ol" value="I" name="medit-list-mode-style"'+(type=="I"?" checked":"")+'><span>I, II, III, IV</span></label>';
settingPageDisplay('列表类型 List Mode',html,function(){
var radio = getNodeById("medit-settingPage-content").getElementsByTagName("input");
var input = null;
for(var i = 0; i<radio.length; i++){
if(radio[i].checked){
input = radio[i];
break;
}
}
var newType = input.getAttribute("class").split("-").pop();
if(nodeType == newType){
node.setAttribute("type",input.value);
}else{
var temNode = document.createElement(newType);
temNode.setAttribute("data-medit", "true");
temNode.setAttribute("data-meditmode", "list");
temNode.setAttribute("type", input.value);
node.parentNode.insertBefore(temNode,node);
var childNode = toArray(node.children);
childNode.forEach(function(v){
temNode.appendChild(v);
});
node.parentNode.removeChild(node);
nodeFocus(temNode);
nowNode = temNode;
mode["list"].focus(temNode);
container[meditId].updateId();
}
settingPage.style.display = "none";
});
}
},
{
name:"newLi",
icon: meditToolImage + "images/list/newLi.png",
doWhat:function(node){
mode["list"].blur(node);
var temNode = document.createElement("li");
temNode.setAttribute("data-medit", "true");
temNode.setAttribute("data-meditmode", "li");
node.appendChild(temNode);
nodeFocus(temNode);
nowNode = temNode;
toolBarModeSetting("li",mode["li"].setting);
container[meditId].updateId();
nowMode = "li";
mode["li"].focus(temNode);
}
}
]
},
"li":{
notDisplay:true,
emptyNotDelete: true,
focus:function(node){
node.setAttribute("class","medit-list");
if(!node.children.length){
node.setAttribute("contentEditable",true);
}
getNodeById("medit-tool-button-mode").style.display = "none";
getNodeById("medit-tool-button-addLeft").style.display = "none";
getNodeById("medit-tool-button-addRight").style.display = "none";
},
blur:function(node){
node.removeAttribute("class");
node.removeAttribute("contentEditable");
if(!node.children.length){
if(!/^\s*$/.test(node.innerHTML.replace(/ /g,""))){
var span =document.createElement("span");
span.setAttribute("data-medit","true");
span.setAttribute("data-meditMode","text");
span.innerHTML = node.innerHTML;
node.innerHTML = "";
node.appendChild(span);
container[meditId].updateId();
container[meditId].nowNodeId++;
return span;
}else{
node.innerHTML = "";
return {exit:true};
}
}
},
setting:[
{
name:"addLeft",
icon: meditToolImage + "images/list/add-top.png",
doWhat:function(node){
mode["list"].blur(node);
var temNode = document.createElement("li");
temNode.setAttribute("data-medit", "true");
temNode.setAttribute("data-meditmode", "li");
node.parentNode.insertBefore(temNode, node);
nodeFocus(temNode);
nowNode = temNode;
container[meditId].updateId();
mode["li"].focus(temNode);
}
},
{
name:"addRight",
icon: meditToolImage + "images/list/add-bottom.png",
doWhat:function(node){
mode["list"].blur(node);
var temNode = document.createElement("li");
temNode.setAttribute("data-medit", "true");
temNode.setAttribute("data-meditmode", "li");
if(node.nextSibling){
node.parentNode.insertBefore(temNode, node.nextSibling);
}else{
node.parentNode.appendChild(temNode);
}
nodeFocus(temNode);
nowNode = temNode;
container[meditId].updateId();
mode["li"].focus(temNode);
}
}
]
}
}
var isType = function(ele, type){ // 输入一个对象和一个type值,返回这个对象是不是这种type
if(!ele || !type)return false;
return {}.toString.call(ele).slice(8, -1).toLowerCase() === type.toLowerCase();
}
var mergeStyleIsSimilar = function(styleA, styleB){ // 判断合并的两个模块样式是否相同
if(styleA){
styleA = styleA.replace(regNormalStyle, "");
}
if(styleB){
styleB = styleB.replace(regNormalStyle, "");
}
if(!styleA && !styleB) return true;
if(styleA && !styleB || !styleA && styleB) return false;
var styleArrA = styleA.split(";").sort();
var styleArrB = styleB.split(";").sort();
if(styleArrA.length != styleArrB.length) return false;
for(var i=0;i<styleArrA.length;i++){
if(styleArrA[i]!==styleArrB[i])return false;
}
return true;
}
var mergeSimilarNextNode = function(node, notFocus){ // 向后合并相似模块结点
var nowMode = node.getAttribute("data-meditMode");
var nowStyle = node.getAttribute("style");
var nextNode = node.nextSibling;
if(!nextNode){
if(!notFocus)nodeFocus(node);
return node;
}
var nextMode = nextNode.getAttribute("data-meditMode");
if(nowMode==nextMode && nextNode && mode[nowMode].isMerge){
var nodeMode = nextNode.getAttribute("data-meditMode");
var nextStyle = nextNode.getAttribute("style");
if(mergeStyleIsSimilar(nowStyle, nextStyle) && !!node.innerHTML && !!nextNode.innerHTML){
node.innerHTML = node.innerHTML + nextNode.innerHTML;
node.parentNode.removeChild(nextNode);
container[meditId].updateId();
if(!notFocus)nodeFocus(node);
if(node.nextSibling){
return mergeSimilarNextNode(node);
}
}
}
return node;
}
var mergeSimilarPreNode = function(node, notFocus){ // 向前合并相似模块结点
var nowMode = node.getAttribute("data-meditMode");
var nowStyle = node.getAttribute("style");
var previousNode = node.previousSibling;
if(!previousNode){
if(!notFocus)nodeFocus(node);
return node;
}
var previousMode = previousNode.getAttribute("data-meditMode");
if(previousMode==nowMode && previousNode && mode[nowMode].isMerge){
var nodeMode = previousNode.getAttribute("data-meditMode");
var previousStyle = previousNode.getAttribute("style");
if(mergeStyleIsSimilar(nowStyle, previousStyle)){
var nowId = regNodeId.exec(previousNode.getAttribute("id"))[1];
previousNode.innerHTML = previousNode.innerHTML + node.innerHTML;
previousNode.parentNode.removeChild(node);
container[meditId].updateId();
if(!notFocus)nodeFocus(previousNode);
node = previousNode;
if(node.previousSibling){
return mergeSimilarPreNode(node, notFocus);
}
}
}
return node;
}
var gevent = function (ele,event,func){ // 通用事件处理模块
if(isType(event, "array")){
event.forEach(function(v){
gevent(ele, v, func);
});
}else{
if(window.addEventListener){
ele.addEventListener(event,func,false);
}else if(window.attachEvent){
ele.attachEvent("on"+event,func);
}else{
ele["on"+event]=func;
}
}
}
var initFromData = function(target){ // 如果原来容器内有数据的话,那么根据原来数据进行初始化
var contain = target.parentNode; // 获取容器对象
meditId = contain.getAttribute("data-meditid"); // 获取容器 meditID
contain = container[meditId]; // 由于所有容器对象均存放于container中,通过此ID进行获取
contain.updateId();
}
var toolBar = (function(){
var temTool = document.createElement("div");
temTool.setAttribute("id","medit-tool");
document.body.appendChild(temTool);
var tool = getNodeById("medit-tool");
gevent(tool, ["touchmove"], function(e){
isToolMove = true;
});
gevent(tool, ["touchend"], function(e){
if(isToolMove){
isToolMove=false;
return;
}
e = e || window.event;
var target = e.target || e.srcElement;
var type = target.getAttribute("data-meditToolStyle");
if(!type) return false;
var degree = target.getAttribute("data-meditToolDegree");
mainDo(degree, type, target);
});
return tool;
})();
var settingPage = (function(){
var temSettingPage = document.createElement("div");
temSettingPage.setAttribute("id","medit-settingPage");
temSettingPage.innerHTML = '<div id="medit-settingPage-main"></div>';
document.body.appendChild(temSettingPage);
var setingObj = getNodeById("medit-settingPage");
gevent(setingObj, ["touchmove"], function(e){
e = e || window.event;
e.preventDefault();
e.stopPropagation();
});
gevent(setingObj, ["touchend"], function(e){
e = e || window.event;
var target = e.target || e.srcElement;
var targetId = target.getAttribute("id");
if(targetId === "medit-settingPage-button-cancel"){
e.preventDefault();
e.stopPropagation();
settingPageOk = null;
settingPage.style.display = "none";
return;
}
if(targetId === "medit-settingPage-button-ok"){
e.preventDefault();
e.stopPropagation();
settingPageOk();
return;
}
if(mode[nowMode].settingPage){
mode[nowMode].settingPage(target);
}
});
return setingObj;
})();
var settingPageOk = null;
var settingPageDisplay = function(title,content,okCallBack) {
var html = [];
html.push(title?'<div id="medit-settingPage-title">'+title+'</div>':'');
html.push('<i id="medit-settingPage-button-cancel"></i>');
html.push('<div id="medit-settingPage-content">'+content+'</div>');
html.push('<div id="medit-settingPage-button"><i id="medit-settingPage-button-ok">确定 Ok</i></div>');
getNodeById("medit-settingPage-main").innerHTML = html.join("");
settingPageOk = okCallBack;
settingPage.style.display = "block";
}
var mainDo = function(degree, type, target) {
var contain = container[meditId];
var thisNode = getNodeById("medit-" + contain.nowNodeId + "-" + meditId); // 这里有个已经修复的bug,比如在超链接中,是在当前结点外部包了一层,那么thisNode需要更新到外层结点
nowMode = thisNode.getAttribute("data-meditMode");
if( mode[nowMode].selected ){
if(globalSelectionContent && globalSelectionContent.node == thisNode && globalSelectionContent.end!=globalSelectionContent.start ){ // 原生自带文本选择处理
var html = globalSelectionContent.node.innerHTML.split("");
html.splice(globalSelectionContent.end,0,'</span>');
html.splice(globalSelectionContent.start,0,'<span class="medit-text-select">');
globalSelectionContent.node.innerHTML = html.join("");
}
}
if(degree == 1) {
switch(type){
case 'delete':
if(mode[nowMode].blur){
mode[nowMode].blur(thisNode);
}
while(thisNode.parentNode.getAttribute("data-medit") && thisNode.parentNode.children.length === 1 && !mode[thisNode.parentNode.getAttribute("data-meditMode")].emptyNotDelete){
thisNode = thisNode.parentNode;
}
thisNode.parentNode.removeChild(thisNode);
contain.updateId();
toolBarHidden();
break;
case 'ok':
if(mode[nowMode].blur){
mode[nowMode].blur(thisNode);
}
if(mode[nowMode].empty && mode[nowMode].empty(thisNode)) thisNode.parentNode.removeChild(thisNode);
toolBarHidden();
contain.nodeCount++;
thisNode = mergeSimilarNextNode(thisNode);
mergeSimilarPreNode(thisNode);
break;
case 'addLeft':
if(mode[nowMode].empty && mode[nowMode].empty(thisNode)){
return;
}
if(mode[nowMode].blur){
mode[nowMode].blur(thisNode);
}
contain.createSpan(contain.nowNodeId, thisNode, false, true);
break;
case 'addRight':
if(mode[nowMode].empty && mode[nowMode].empty(thisNode)){
return;
}
if(mode[nowMode].blur){
mode[nowMode].blur(thisNode);
}
contain.createSpan(contain.nowNodeId, thisNode, true, true);
break;
case 'mode':
var toolBarRes = [];
toolBarRes.push(returnButtonHtml(nowMode + "-setting-1"));
for(var modeType in mode){
if(mode.hasOwnProperty(modeType) && modeType != nowMode && !mode[modeType].notDisplay){
var style = mode[modeType].icon?' style="background:#428bca url('+ mode[modeType].icon+') no-repeat center center;background-size: 24px;"':'';
toolBarRes.push('<span id="medit-tool-button-'+modeType+'" class="medit-tool-button" data-meditToolStyle="'+modeType+'"'+style+' data-meditToolDegree="2"> </span>');
}
}
toolBar.innerHTML = toolBarRes.join("");
break;
case 'return':
var path = target.getAttribute("id").replace("medit-tool-button-","");
var nodePath = path.split("-");
var doWhat = mode;
var pathMode = null;
nodePath.pop();
path = path.replace(/\-[a-zA-Z]*\-\d*$/,'');
while(pathMode = nodePath.shift()){
doWhat = doWhat[pathMode];
}
toolBarModeSetting(path, doWhat);
break;
}
}else{
if( mode[nowMode].selected ){
thisNode = mode[nowMode].selected(thisNode);
}
var pathRes = target.getAttribute("id").replace("medit-tool-button-","");
var pathArr = pathRes.split("-");
var pathMode = null;
var doWhat = mode;
while(pathMode = pathArr.shift()){
doWhat = doWhat[pathMode];
}
doWhat = doWhat.doWhat;
if(isType(doWhat, "array")){
toolBarModeSetting(pathRes, doWhat);
}else{
doWhat(thisNode);
}
}
if(!contain.node.children.length) contain.node.innerHTML = contain.preHTML || "Medit";
}
var toolBarModeSetting = function(path, list){
var pathRes = path.split("-");
var toolBarRes = [];
if(pathRes.length === 1){
mainButton.forEach(function(v,index){
if(v === "setting"){
if(list){
list.forEach(function(listv, listIndex){
var defaultValue = listv.defaultValue || " ";
var style = listv.icon?' style="background:#428bca url('+listv.icon+') no-repeat center center;background-size: 24px;"':'';
toolBarRes.push('<span id="medit-tool-button-'+path+'-setting-'+listIndex+'" class="medit-tool-button" data-meditToolStyle="'+path+"-setting-"+listIndex+'"'+style+' data-meditToolDegree="2">'+defaultValue+'</span>');
});
}
}else{
toolBarRes.push('<span id="medit-tool-button-'+v+'" class="medit-tool-button medit-tool-'+v+'" data-meditToolStyle="'+v+'" data-meditToolDegree="1"> </span>');
}
});
}else{
toolBarRes.push(returnButtonHtml(path));
if(!!list.length){
list.forEach(function(listv, listIndex){
var defaultValue = listv.defaultValue || " ";
var style = listv.icon?' style="background:#428bca url('+listv.icon+') no-repeat center center;background-size: 24px;"':' style="background:#428bca;"';
toolBarRes.push('<span id="medit-tool-button-'+path+'-doWhat-'+listIndex+'" class="medit-tool-button" data-meditToolStyle="'+path+"-doWhat-"+listIndex+'"'+style+' data-meditToolDegree="2">'+defaultValue+'</span>');
});
}
}
toolBar.innerHTML = toolBarRes.join("");
}
var toolBarDisplay = function() {
if(toolBarCatch)
toolBar.innerHTML = toolBarCatch;
toolBar.style.display = "block";
}
var toolBarHidden = function() {
nowNode = null;
toolBar.style.display = "none";
}
var toBr = function(node){
node.setAttribute("style","display:block");
node.setAttribute("data-meditMode","br");
node.setAttribute("contentEditable","false");
node.setAttribute("class","");
node.innerHTML = " ";
}
var nodeFocus = function(node){ // 使模块自动获取焦点 使用了很多方法,最后发现这个方法是在移动端最好的
nodeFocusTimeout = setTimeout(function() {
node.focus();
container[meditId].nowNodeId = regNodeId.exec(node.getAttribute("id"))[1];
}, 10);
}
var selectModeContent = function(isAdd){
if(nowNode){
var nodeMode = nowNode.getAttribute("data-meditmode");
var nodeModeObj = mode[nodeMode];
if(nodeModeObj.selecting){
nodeModeObj.selecting(nowNode, isAdd);
}
}
}
var medit = function(node, toolBarContainer) {
if(!(this instanceof medit)) return new medit(node, toolBarContainer);
if(!node || node.nodeType != 1)return false;
if(toolBarContainer && toolBarContainer.nodeType == 1) {
toolBar.parentNode.removeChild(toolBar);
toolBar.setAttribute("class", "medit-tool-inner");
toolBarContainer.appendChild(toolBar);
}
this.node = node;
this.nodeCount = 0; // 容器所有子元素数目
this.nowNodeId = 0; // 容器当前子元素ID
this.getContent = medit.prototype.getContent;
this.node.setAttribute("data-meditId",container.length);
this.imageUpload = { // 默认图片上传设置,由于是文件上传,所以在跨域方法仅支持CORS
path:'https://sm.ms/api/upload',
params: {},
name:'smfile',
size:0,
timeout:0,
ext:["jpg","jpeg","png","gif","bmp"],
success:function(){},
error:function(){}
}
container.push(this);
gevent(this.node, ["touchstart"], function(e){
mainTouchPoint = e.targetTouches[0];
if(window.getSelection){ // 原生手势长按选择
if(globalSelectionHandle)clearTimeout(globalSelectionHandle);
var selectionHandle = window.getSelection();
var selectionCheckTimeout = function(){
if(selectionHandle && selectionHandle.anchorNode && selectionHandle.anchorNode == selectionHandle.focusNode && selectionHandle.anchorNode.parentNode==nowNode){
globalSelectionContent = {
handle: selectionHandle,
node: selectionHandle.anchorNode.parentNode,
start: selectionHandle.anchorOffset<selectionHandle.focusOffset?selectionHandle.anchorOffset:selectionHandle.focusOffset,
end: selectionHandle.anchorOffset>selectionHandle.focusOffset?selectionHandle.anchorOffset:selectionHandle.focusOffset
}
globalSelectionHandle = setTimeout(selectionCheckTimeout, 100);
}else{
if(globalSelectionContent){
globalSelectionContent.handle.removeAllRanges();
globalSelectionContent = null;
}
if(globalSelectionHandle)clearTimeout(globalSelectionHandle);
}
}
selectionCheckTimeout();
}
});
gevent(this.node, ["touchmove"], function(e){
e = e || window.event;
var distance = e.targetTouches[0].clientX - mainTouchPoint.clientX;
if(Math.abs(distance) > 50){
var isAdd = distance > 0? true: false;
selectModeContent(isAdd);
mainTouchPoint = e.targetTouches[0];
}
isContainMove = true;
});
gevent(this.node, ["touchend"], this.editContainFocus);
gevent(this.node, ["keydown"], function(e){
e = e || window.event;
if(e.keyCode == 13){
e.preventDefault();
var contain = container[meditId];
var thisNode = getNodeById("medit-" + contain.nowNodeId + "-" + meditId);
nowMode = thisNode.getAttribute("data-meditMode");
if(mode[nowMode].blur){
var newNode = mode[nowMode].blur(thisNode); // 如果当前按下回车按钮的块需要对内容进行处理,或者是结点进行改变了
if(newNode){
if(newNode.exit) return; // 不需要继续创建新的结点了
thisNode = newNode;
}
}
contain.createSpan(contain.nowNodeId, thisNode, true, true);
var brNode = getNodeById("medit-" + contain.nowNodeId + "-" + meditId);
toBr(brNode);
contain.createSpan(contain.nowNodeId, brNode, true, true);
}
});
}
var returnNextNodeId = function(node){
var child = node.children;
if(child.length) return returnNextNodeId(child[child.length-1]);
return Number(regNodeId.exec(node.getAttribute("id"))[1])+1;
}
medit.prototype.createSpan = function(nodeId, fromNode, isAfter, isAutoFocus){ // 因为在内部创建span的时候不会自动focus,需要调用一下focus方法
var span =document.createElement("span");
span.setAttribute("data-medit","true");
span.setAttribute("data-meditMode","text");
span.setAttribute("id","medit-" + nodeId + "-" + meditId );
span.setAttribute("contentEditable","true");
span.setAttribute("class","medit-editing");
if(fromNode){
if(!isAfter){
this.nowNodeId = nodeId;
fromNode.parentNode.insertBefore(span, fromNode);
}else{
this.nowNodeId = returnNextNodeId(fromNode);
if(!fromNode.nextSibling){
fromNode.parentNode.appendChild(span);
}else{
fromNode.parentNode.insertBefore(span, fromNode.nextSibling);
}
}
this.updateId();
}else{
this.node.appendChild(span);
}
var editor = getNodeById("medit-" + this.nowNodeId + "-" + meditId);
if(nowNode){ // 当创建新的标签的时候把之前/之后的相似结点进行合并
if(!isAfter){
mergeSimilarNextNode(nowNode, true);
}else{
mergeSimilarPreNode(nowNode, true);
}
}
this.nowNodeId = Number(regNodeId.exec(editor.id)[1]); // 因为合并结点之后要重新更新id, 所以需要重新获取当前结点ID
nowNode = editor;
toolBarModeSetting("text", mode["text"].setting);
if(isAutoFocus){
nodeFocus(editor);
}
}
medit.prototype.updateId = function(nodeId, list) {
var child = list || toArray(this.node.children);
var index = nodeId || 0;
child.forEach(function(v){
if(v.getAttribute("href")){ // 防止超链接在内部触发
v.setAttribute("data-meditHref",v.getAttribute("href"));
v.removeAttribute("href");
}
v.setAttribute("id","medit-" + (index++) + "-" + meditId );
var secondChild = toArray(v.children);
if(secondChild.length){
index = container[meditId].updateId(index, secondChild);
}
});
return index;
}
medit.prototype.getContent = function(isEdit){
isEdit = isEdit || false;
if(!isEdit && toolBar.style.display == "block"){
mainDo(1, "ok");
}
var html = this.node.innerHTML;
if(regIsNotContentEmpty.test(html)){
html = html.replace(/\sdata\-meditHref="(.*?)"/ig," href=\"$1\"");
html = html.replace(selectTextReg,"$1");
return html.replace(regContent, " ");
}
return "";
}
medit.prototype.autoSave = function(appId, callBack){// 自动保存 callBack(data, timeStamp),自动恢复已保存数据
if(window.localStorage){
this.appId = appId;
var oldData = localStorage.getItem("meditAutosave"+appId); // repair bug: id is need not exits '-'
var temData = this.getContent(true);
if(!regIsNotContentEmpty.test(temData) && oldData){
meditId = this.node.getAttribute("data-meditid");
this.node.innerHTML = oldData;
this.updateId();
}
clearInterval(this.autoSaveInterval);
var _this = this;
this.autoSaveInterval = setInterval(function(){
var nowData = _this.getContent(true);
localStorage.setItem("meditAutosave"+appId,nowData);
callBack(nowData, (new Date())-0);
},1000);
}
}
medit.prototype.image = medit.prototype.imageUpload = function(option){ // 图片上传设置
var meditId = this.node.getAttribute("data-meditid") - 0;
var contain = container[meditId];
for(var item in option){
if(contain.imageUpload[item] != null){
contain.imageUpload[item] = option[item];
}
}
}
medit.prototype.clear = function(data){
data = data||"";
clearInterval(this.autoSaveInterval);
this.node.innerHTML = data;
if(this.appId!=null){
localStorage.removeItem("meditAutosave"+this.appId);
}
}
medit.prototype.editContainFocus = function(e) {
e = e || window.event;
var target = e.target || e.srcElement;
if(isContainMove){
e.preventDefault();
e.stopPropagation();
isContainMove = false;
return;
}
toolBarDisplay();
if(meditId != null) { // 在已经选择某个区块的时候选择其它的,会先调用这个区块的blur
var temObj = container[meditId];
var temNode = getNodeById("medit-" + temObj.nowNodeId + "-" + meditId);
if(temNode){
var temNodeMode = temNode.getAttribute("data-meditMode");
if(mode[temNodeMode].empty && mode[temNodeMode].empty(temNode) && temNode != target){
temNode.parentNode.removeChild(temNode);
temObj.updateId();
}else{
if(mode[temNodeMode].blur){
mode[temNodeMode].blur(temNode);
}
}
}
}
var type = target.getAttribute("data-medit");
if(!type && target.getAttribute("data-meditId")){ // target is container
meditId = target.getAttribute("data-meditId"); // 全局存贮当前medit容器ID
var meditObj = container[ meditId];
var child = target.children;
if(!child.length){ // 如果点击了容器发现没有结点,那么就保存原有内容,并且创建新的span
meditObj.preHTML = target.innerHTML;
target.innerHTML = "";
meditObj.createSpan(0);
target = false;
}else{
var temTarget = child[child.length-1];
var temTargetMode = temTarget.getAttribute("data-meditMode");
if(!mode[temTargetMode].empty || !mode[temTargetMode].empty(temTarget)){
meditObj.createSpan(child.length-1,temTarget, true);
target = false;
}else{
target = temTarget;
nowNode = target;
}
}
}else{ // target is 内部包含结点
while(!target.getAttribute("data-medit")){
target = target.parentNode;
}
nowNode = target;
}
if(target){
if(!target.id) {
var parentNode = target.parentNode;
while(!parentNode.getAttribute("data-meditid")){
parentNode = parentNode.parentNode;
}
meditId = parentNode.getAttribute("data-meditid");
container[meditId].updateId();
}
var idExecRes = regNodeId.exec(target.id);
meditId = Number(idExecRes[2]);
var meditObj = container[ meditId];
meditObj.nowNodeId = Number(idExecRes[1]);
var meditNodeMode = target.getAttribute("data-meditMode");
toolBarModeSetting(meditNodeMode, mode[meditNodeMode].setting);
if(mode[meditNodeMode].focus){
mode[meditNodeMode].focus(target);
}
}
}
medit.settingPage = function(title, content, callBack) {
settingPageDisplay(title, content, function(){
callBack();
settingPage.style.display = "none";
})
}
medit.extend = function(obj) { // 扩展方法 会向doWhat方法中传入当前结点,然后需要返回一个新的结点
if(obj && obj.icon && obj.doWhat && obj.focus && obj.blur && obj.name){
if(!mode[obj.name]){
mode[obj.name] = fun_deep_clone(obj);
mode[obj.name].doWhat = function(node){
mode[node.getAttribute("data-meditmode")].blur(node);
var newNode = obj.doWhat(node);
if(newNode) {
newNode.setAttribute("data-meditmode", obj.name);
newNode.setAttribute("data-medit", "true");
mode[obj.name].focus(newNode);
nodeFocus(newNode);
nowNode = newNode;
toolBarModeSetting(obj.name,obj.setting||[]);
container[meditId].updateId();
nowMode = obj.name;
}
}
}else{
throw new Error(obj.name + ' has already exist!');
}
}
}
medit.nativeSetting = function(execFun){ // 原生自带功能配置接口
for(var i =0; i<nativeMode.length; i++) {
var res = execFun(fun_deep_clone(mode[nativeMode[i]]), nativeMode[i] );
if(res){
mode[nativeMode[i]] = res;
}
}
}
obj.Medit = obj.medit = medit;
module.exports = medit;
================================================
FILE: test/ajaxImageUpload.html
================================================
<form enctype="multipart/form-data" method="post" name="fileinfo">
<input type="file" id="file" name="smfile"/>
</form>
<script>
var xhr = function(){
if(window.XMLHttpRequest){
var xhr=new XMLHttpRequest();
}else{
try{
var xhr=new ActiveXObject("Msxml2.XMLHTTP");
}catch(e){
try{
var xhr=new ActiveXObject("Microsoft.XMLHTTP");
}catch(e){
throw new TypeError('Unsupport XMLHttpRequest');
}
}
}
return xhr;
}
var fileinput = document.getElementById("file");
fileinput.onchange = function(e){
e = e || window.event;
var files=e.target.files||e.srcElement.files;
var file = files[0];
var form = new FormData(document.forms.namedItem("fileinfo"));
var http = xhr();
http.upload.onprogress = function(v){
console.log(Math.floor(100*v.loaded/v.total) + "%");
}
http.open("POST","https://sm.ms/api/upload");
http.send(form);
http.onreadystatechange = function(){
if(http.readyState === 4){
if(http.status === 200){
console.log(JSON.parse(http.responseText))
}
}
}
}
</script>
================================================
FILE: test/contentEditableFocus.html
================================================
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no, minimal-ui" />
<style>
#editable{
display:inline-block;
width:300px;
border:1px solid #ccc;
}
</style>
<span id="editable" contenteditable="true"></span>
<span onClick="contentfocus(document.getElementById('editable'))">Focus</span>
<script>
function contentfocus(node){
node.onfocus = function() {
window.setTimeout(function() {
var sel, range;
if (window.getSelection && document.createRange) {
range = document.createRange();
range.selectNodeContents(node);
range.collapse(true);
sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
} else if (document.body.createTextRange) {
range = document.body.createTextRange();
range.moveToElementText(node);
range.collapse(true);
range.select();
}
}, 1);
};
node.focus();
}
</script>
================================================
FILE: webpack.config.dev.js
================================================
var path = require('path')
var webpack = require('webpack')
var autoprefixer = require('autoprefixer')
var precss = require('precss')
var CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = {
entry: {
"medit.min": './src/medit.js'
},
output: {
path: path.join(__dirname, 'build'),
filename: '[name].js'
},
plugins: [],
resolve: {
alias: {
medit: path.resolve(__dirname, 'src')
},
extensions: ['', '.js', '.jsx']
},
module: {
loaders: [
{
test: /\.jsx?$/,
loader: 'babel',
include: [
path.resolve(__dirname, 'src')
]
},
{ test : /\.css$/, loaders: ['style-loader', 'css-loader', 'resolve-url-loader']},
{ test: /\.scss$/, loaders: ['style-loader', 'css-loader?modules&localIdentName=[local]-[hash:base64:5]', 'postcss-loader', 'sass-loader'] },
{ test: /\.(ttf|eot|woff|woff2|otf|svg)/, loader: 'file-loader?name=./font/[name].[ext]' },
{ test: /\.json$/, loader: 'file-loader?name=./json/[name].json' },
{ test: /\.(png|jpg|jpeg|gif)$/, loader: 'url-loader?limit=100000&name=./images/[name].[ext]' }
]
},
postcss: function () {
return [autoprefixer({ browsers: ['> 1%', 'IE 9'] }), precss]
},
plugins: [
new CopyWebpackPlugin([{context:'./src/images/', from:'**/*', to:'images'}])
]
}
gitextract_t_m94g0a/ ├── .gitignore ├── README.md ├── package.json ├── src/ │ ├── medit.css │ └── medit.js ├── test/ │ ├── ajaxImageUpload.html │ └── contentEditableFocus.html └── webpack.config.dev.js
Condensed preview — 8 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (81K chars).
[
{
"path": ".gitignore",
"chars": 17,
"preview": "node_modules\ndemo"
},
{
"path": "README.md",
"chars": 5970,
"preview": "\n# Medit v2.0.0\n\n***\n\nmedit新版本正在daily/3.0.0分支上进行开发,如有问题或者3.0版本开发建议可以提交issue\n\n***\n\nA creative W"
},
{
"path": "package.json",
"chars": 1521,
"preview": "{\n \"name\": \"medit\",\n \"version\": \"1.0.0\",\n \"description\": \"A creative WYSIWYG rich text editor for mobile device.\",\n "
},
{
"path": "src/medit.css",
"chars": 6407,
"preview": "#medit {\n\tfont-family:微软雅黑,黑体,Helvetica,华文黑体;\n\tfont-size: 14px;\n\tword-break:break-all;\n}\n#medit * {\n\toutline:none;\n}\n#me"
},
{
"path": "src/medit.js",
"chars": 49370,
"preview": "require(\"./medit.css\");\n\nvar obj = window;\n\nvar meditToolImage = obj.meditToolImage || \"./\";// 工具条图片位置\n\nvar meditId = nu"
},
{
"path": "test/ajaxImageUpload.html",
"chars": 1055,
"preview": "<form enctype=\"multipart/form-data\" method=\"post\" name=\"fileinfo\">\n<input type=\"file\" id=\"file\" name=\"smfile\"/>\n</form>\n"
},
{
"path": "test/contentEditableFocus.html",
"chars": 903,
"preview": "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no, minimal-ui\" />\n\n<style>\n#editable{"
},
{
"path": "webpack.config.dev.js",
"chars": 1356,
"preview": "var path = require('path')\nvar webpack = require('webpack')\nvar autoprefixer = require('autoprefixer')\nvar precss = requ"
}
]
About this extraction
This page contains the full source code of the echosoar/medit GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 8 files (65.0 KB), approximately 20.3k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.