This repository has been archived on 2023-08-30. You can view files and clone it, but cannot push or open issues/pull-requests.
bytedo
/
wcui
Archived
1
0
Fork 0

修复layer组件的回调及对shift属性的优化;移植meditor到新的框架

old
宇天 2018-05-17 04:41:49 +08:00
parent 8be3b9c70a
commit d256f145cf
9 changed files with 900 additions and 760 deletions

View File

@ -4,7 +4,7 @@ $cpp: #651fff #7c4dff #6200ea;
$cb: #2196f3 #64b5f6 #1976d2; $cb: #2196f3 #64b5f6 #1976d2;
$cr: #ff5722 #ff7043 #e64a19; $cr: #ff5722 #ff7043 #e64a19;
$co: #ff9800 #ffa726 #f57c00; $co: #ff9800 #ffa726 #f57c00;
$cp: #e7e8eb #ecf0f1 #bdc3c7; $cp: #e7e8eb #ecf0f1 #d3d5db;
$cgr: #546e7a #607d8b #37474f; $cgr: #546e7a #607d8b #37474f;
@mixin ts($c: all, $t: .2s, $m: ease-in-out){ @mixin ts($c: all, $t: .2s, $m: ease-in-out){

View File

@ -182,8 +182,8 @@ class __layer__ {
} }
}, },
mounted: function() { mounted: function() {
if (typeof this.success === 'function') { if (typeof this.props.success === 'function') {
this.success(_id) this.props.success.call(this)
} }
} }
} }
@ -216,7 +216,9 @@ class __layer__ {
layBox.classList.add('__' + state.shift) layBox.classList.add('__' + state.shift)
} else { } else {
for (let k in state.shift) { for (let k in state.shift) {
layBox.style.cssText += `${k}: ${state.shift[k]};` let val = state.shift[k]
val += isFinite(val) ? 'px' : ''
layBox.style.cssText += `${k}: ${val};`
} }
} }

View File

@ -1,414 +1,438 @@
/** /**
* *
* @authors yutent (yutent@doui.cc) * @authors yutent (yutent@doui.cc)
* @date 2017-04-19 21:17:26 * @date 2017-04-19 21:17:26
* *
*/ */
"use strict"; 'use strict'
define(['lib/layer/base', 'css!./attach'], function() {
var Uploader = function(url) {
this.url = url || ''
this.init()
}
define([ Uploader.prototype = {
'lib/layer/base', init: function() {
'css!./attach' this.xhr = new XMLHttpRequest()
], function(){ this.form = new FormData()
return this
var Uploader = function(url){ },
this.url = url || '' field: function(key, val) {
this.init() if (typeof key === 'object') {
} for (var i in key) {
this.form.append(i, key[i])
Uploader.prototype = {
init: function(){
this.xhr = new XMLHttpRequest()
this.form = new FormData()
return this
},
field: function(key, val){
if(typeof key === 'object'){
for(var i in key){
this.form.append(i, key[i])
}
}else{
this.form.append(key, val)
}
return this
},
start: function(){
var _this = this
this.xhr.open('POST', this.url, true)
var startTime = Date.now()
this.xhr.upload.addEventListener('progress', function(evt){
if(evt.lengthComputable && _this.progress){
var res = Math.round(evt.loaded * 100 / evt.total)
_this.progress(res)
}
}, false)
this.xhr.onreadystatechange = function(){
if(_this.xhr.readyState === 4){
if(_this.xhr.status >= 200 && _this.xhr.status < 205){
var res = _this.xhr.responseText
try{
res = JSON.parse(res)
}catch(err){}
_this.end && _this.end(res)
}else{
console.error(_this.xhr)
}
}
}
this.xhr.send(this.form)
},
onProgress: function(fn){
this.progress = fn
return this
},
onEnd: function(fn){
this.end = fn
return this
} }
} else {
this.form.append(key, val)
}
return this
},
start: function() {
var _this = this
this.xhr.open('POST', this.url, true)
var startTime = Date.now()
this.xhr.upload.addEventListener(
'progress',
function(evt) {
if (evt.lengthComputable && _this.progress) {
var res = Math.round(evt.loaded * 100 / evt.total)
_this.progress(res)
}
},
false
)
this.xhr.onreadystatechange = function() {
if (_this.xhr.readyState === 4) {
if (_this.xhr.status >= 200 && _this.xhr.status < 205) {
var res = _this.xhr.responseText
try {
res = JSON.parse(res)
} catch (err) {}
_this.end && _this.end(res)
} else {
console.error(_this.xhr)
}
}
}
this.xhr.send(this.form)
},
onProgress: function(fn) {
this.progress = fn
return this
},
onEnd: function(fn) {
this.end = fn
return this
}
}
function uploadScreenshot(vm, blob) {
var upload = new Uploader(vm.uploadUrl || ME.uploadUrl)
if (ME.beforeUpload) {
ME.beforeUpload(Date.now().toString(16) + '.jpg', function(qn) {
upload
.field('file', blob)
.field('token', qn.token)
.field('key', qn.key)
.onEnd(function(json) {
ME.insert(vm.$editor, '![截图](' + qn.url + ')')
})
.start()
})
} else {
upload
.field('file', blob)
.onEnd(function(json) {
ME.insert(vm.$editor, '![截图](' + json.data.url + ')')
})
.start()
}
}
var $init = function(vm) {
if (!vm.uploadUrl && !ME.uploadUrl) {
console.error(
'使用附件上传,必须先设置uploadUrl;\n可以给vm增加uploadUrl属性,也可以通过ME.uploadUrl设置'
)
}
if (!vm.manageUrl && !ME.manageUrl) {
console.error(
'使用附件管理功能,必须先设置manageUrl;\n可以给vm增加manageUrl属性,也可以通过ME.manageUrl设置'
)
}
if (!ME.maxSize) {
ME.maxSize = 4194304
}
vm.$editor.addEventListener('paste', function(ev) {
var txt = ev.clipboardData.getData('text/plain').trim(),
html = ev.clipboardData.getData('text/html').trim()
//文本类型直接默认处理
if (txt || html) {
return
}
if (ev.clipboardData.items) {
var items = ev.clipboardData.items,
len = items.length,
blob = null
for (var i = 0, it; (it = items[i++]); ) {
if (it.type.indexOf('image') > -1) {
blob = it.getAsFile()
}
}
if (blob !== null) {
layer.msg('截图处理中...')
// 压缩截图,避免文件过大
var reader = new FileReader()
reader.onload = function() {
var img = document.createElement('img'),
canvas = document.createElement('canvas')
img.onload = function() {
canvas.width = img.width
canvas.height = img.height
var ctx = canvas.getContext('2d')
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.drawImage(this, 0, 0, canvas.width, canvas.height)
if (canvas.toBlob) {
canvas.toBlob(
function(obj) {
uploadScreenshot(vm, obj)
},
'image/jpeg',
0.8
)
} else {
var base64 = canvas.toDataURL('image/jpeg', 0.8),
buf = atob(base64.split(',')[1]),
arrBuf = new ArrayBuffer(buf.length),
intArr = new Uint8Array(arrBuf),
obj = null
for (var i = 0; i < buf.length; i++) {
intArr[i] = buf.charCodeAt(i)
}
obj = new Blob([intArr], { type: 'image/jpeg' })
uploadScreenshot(vm, obj)
}
}
img.src = this.result
}
reader.readAsDataURL(blob)
}
}
ev.preventDefault()
})
},
lang = {
image: ['远程图片', '图片管理', '图片描述', '图片地址'],
file: ['远程附件', '附件管理', '附件描述', '附件地址']
},
opened = false, //记录是否已经打开
openType = 'image', //打开类型, 图片/附件
cache = {
//缓存附件列表
image: [],
file: []
},
fixCont = function() {
return (
'<dl class="do-meditor-attach do-meditor-font">' +
'<dt class="tab-box" :drag="do-layer" data-limit="window">' +
'<span class="item" :class="active:tab === 1" :click="$switch(1)">' +
lang[openType][0] +
'</span>' +
'<span class="item" :class="active:tab === 2" :click="$switch(2)">本地上传</span>' +
'<span class="item" :class="active:tab === 3" :click="$switch(3)">' +
lang[openType][1] +
'</span>' +
'<a href="javascript:;" :click="no" class="action-close do-ui-font"></a>' +
'</dt>' +
'<dt class="cont-box">' +
'<div class="remote" :visible="tab === 1">' +
'<section class="section do-fn-cl input"><span class="label">' +
lang[openType][2] +
'</span>' +
'<input class="txt" :duplex="attachAlt" />' +
'</section>' +
'<section class="section do-fn-cl input"><span class="label">' +
lang[openType][3] +
'</span>' +
'<input class="txt" :duplex="attach" />' +
'</section>' +
'<section class="section do-fn-cl">' +
'<a href="javascript:;" class="submit" :click="$confirm">确定</a>' +
'</section>' +
'</div>' +
'<div class="local" :visible="tab === 2">' +
'<div class="select-file"><input id="meditor-attch" multiple :change="$change" type="file" class="hide" /><span class="file" :click="$select">选择文件</span><span class="tips">(上传大小限制:单文件最大 ' +
((ME.maxSize / 1048576).toFixed(2) - 0) +
'MB)</span></div>' +
'<ul class="upload-box">' +
'<li class="tr thead"><span class="td name">文件名</span><span class="td progress">上传进度</span><span class="td option">操作</span></li>' +
'<li class="tr" :repeat="uploadFile">' +
'<span class="td name" :text="el.name"></span>' +
'<span class="td progress" :html="el.progress"></span>' +
'<span class="td option"><a href="javascript:;" :click="$insert(el)">插入</a></span>' +
'</li>' +
'</ul>' +
'</div>' +
'<ul class="manager" :visible="tab === 3">' +
'<li class="item" :repeat="attachList" :click="$insert(el)">' +
'<span class="thumb" :html="el.thumb"></span>' +
'<p class="name" :attr-title="el.name" :text="el.name"></p>' +
'</li>' +
'</ul>' +
'</dt>' +
'</dl>'
)
} }
/**
* [uploadFile 文件上传]
* @param {[type]} files [文件列表]
* @param {[type]} vm [vm对象]
* @param {[type]} type [image/file]
*/
function uploadFile(files, vm) {
for (var i = 0, it; (it = files[i++]); ) {
if (
openType === 'image' &&
!/\.(jpg|jpeg|png|gif|bmp|webp|ico)$/.test(it.name)
) {
vm.uploadFile.push({
name: it.name,
progress: '<span class="red">0%(失败,不允许的文件类型)</span>',
url: ''
})
continue
}
if (ME.maxSize > 0 && it.size > ME.maxSize) {
vm.uploadFile.push({
name: it.name,
progress: '<span class="red">0%(文件体积过大)</span>',
url: ''
})
continue
}
var fixName =
Date.now().toString(16) + it.name.slice(it.name.lastIndexOf('.'))
function uploadScreenshot(vm, blob){ var idx = vm.uploadFile.length,
var upload = new Uploader(vm.uploadUrl || ME.uploadUrl) upload = new Uploader(vm.uploadUrl || ME.uploadUrl)
if(ME.beforeUpload){
ME.beforeUpload(Date.now().toString(16) + '.jpg', function(qn){ vm.uploadFile.push({ name: it.name, progress: '0%', url: '' })
upload.field('file', blob)
.field('token', qn.token) upload.field('file', it)
.field('key', qn.key)
.onEnd(function(json){ if (ME.beforeUpload) {
ME.insert(vm.$editor, '![截图](' + qn.url + ')') ME.beforeUpload(fixName, function(qn) {
}) upload
.start() .field('token', qn.token)
.field('key', qn.key)
.onProgress(function(val) {
vm.uploadFile[idx].progress = val + '%'
}) })
}else{ .onEnd(function(json) {
upload.field('file', blob) vm.uploadFile[idx].url = qn.url
.onEnd(function(json){
ME.insert(vm.$editor, '![截图](' + json.data.url + ')')
})
.start()
}
}
var $init = function(vm){
if(!vm.uploadUrl && !ME.uploadUrl){
console.error('使用附件上传,必须先设置uploadUrl;\n可以给vm增加uploadUrl属性,也可以通过ME.uploadUrl设置')
}
if(!vm.manageUrl && !ME.manageUrl){
console.error('使用附件管理功能,必须先设置manageUrl;\n可以给vm增加manageUrl属性,也可以通过ME.manageUrl设置')
}
if(!ME.maxSize){
ME.maxSize = 4194304
}
vm.$editor.addEventListener('paste', function(ev){
var txt = ev.clipboardData.getData('text/plain').trim(),
html = ev.clipboardData.getData('text/html').trim();
//文本类型直接默认处理
if(txt || html){
return
}
if(ev.clipboardData.items){
var items = ev.clipboardData.items,
len = items.length,
blob = null;
for(var i = 0,it; it = items[i++];){
if(it.type.indexOf('image') > -1){
blob = it.getAsFile()
}
}
if(blob !== null) {
layer.msg('截图处理中...')
// 压缩截图,避免文件过大
var reader = new FileReader()
reader.onload = function(){
var img = document.createElement('img'),
canvas = document.createElement('canvas')
img.onload = function(){
canvas.width = img.width
canvas.height = img.height
var ctx = canvas.getContext('2d')
ctx.clearRect(0,0, canvas.width, canvas.height)
ctx.drawImage(this, 0, 0, canvas.width, canvas.height)
if(canvas.toBlob){
canvas.toBlob(function(obj){
uploadScreenshot(vm, obj)
}, 'image/jpeg', 0.8)
}else{
var base64 = canvas.toDataURL('image/jpeg', 0.8),
buf = atob(base64.split(',')[1]),
arrBuf = new ArrayBuffer(buf.length),
intArr = new Uint8Array(arrBuf),
obj = null;
for(var i = 0; i < buf.length; i++){
intArr[i] = buf.charCodeAt(i)
}
obj = new Blob([intArr], {type: 'image/jpeg'})
uploadScreenshot(vm, obj)
}
}
img.src = this.result
}
reader.readAsDataURL(blob)
}
}
ev.preventDefault()
}) })
}, .start()
lang = { })
image: ['远程图片', '图片管理', '图片描述', '图片地址'], } else {
file: ['远程附件', '附件管理', '附件描述', '附件地址'] upload
}, .onProgress(function(val) {
opened = false, //记录是否已经打开 vm.uploadFile[idx].progress = val + '%'
openType = 'image', //打开类型, 图片/附件 })
cache = { //缓存附件列表 .onEnd(function(json) {
image: [], vm.uploadFile[idx].url = json.data.url
file: [] })
}, .start()
fixCont = function(){ }
return '<dl class="do-meditor-attach do-meditor-font">'
+ '<dt class="tab-box" :drag="do-layer" data-limit="window">'
+ '<span class="item" :class="active:tab === 1" :click="$switch(1)">' + lang[openType][0] +'</span>'
+ '<span class="item" :class="active:tab === 2" :click="$switch(2)">本地上传</span>'
+ '<span class="item" :class="active:tab === 3" :click="$switch(3)">' + lang[openType][1] + '</span>'
+ '<a href="javascript:;" :click="no" class="action-close do-ui-font"></a>'
+ '</dt>'
+ '<dt class="cont-box">'
+ '<div class="remote" :visible="tab === 1">'
+ '<section class="section do-fn-cl input"><span class="label">'+ lang[openType][2] + '</span>'
+ '<input class="txt" :duplex="attachAlt" />'
+ '</section>'
+ '<section class="section do-fn-cl input"><span class="label">'+ lang[openType][3] + '</span>'
+ '<input class="txt" :duplex="attach" />'
+ '</section>'
+ '<section class="section do-fn-cl">'
+ '<a href="javascript:;" class="submit" :click="$confirm">确定</a>'
+ '</section>'
+ '</div>'
+ '<div class="local" :visible="tab === 2">'
+ '<div class="select-file"><input id="meditor-attch" multiple :change="$change" type="file" class="hide" /><span class="file" :click="$select">选择文件</span><span class="tips">(上传大小限制:单文件最大 '
+ ((ME.maxSize/1048576).toFixed(2) - 0)
+ 'MB)</span></div>'
+ '<ul class="upload-box">'
+ '<li class="tr thead"><span class="td name">文件名</span><span class="td progress">上传进度</span><span class="td option">操作</span></li>'
+ '<li class="tr" :repeat="uploadFile">'
+ '<span class="td name" :text="el.name"></span>'
+ '<span class="td progress" :html="el.progress"></span>'
+ '<span class="td option"><a href="javascript:;" :click="$insert(el)">插入</a></span>'
+ '</li>'
+ '</ul>'
+ '</div>'
+ '<ul class="manager" :visible="tab === 3">'
+ '<li class="item" :repeat="attachList" :click="$insert(el)">'
+ '<span class="thumb" :html="el.thumb"></span>'
+ '<p class="name" :attr-title="el.name" :text="el.name"></p>'
+ '</li>'
+ '</ul>'
+ '</dt>'
+ '</dl>'
};
/**
* [uploadFile 文件上传]
* @param {[type]} files [文件列表]
* @param {[type]} vm [vm对象]
* @param {[type]} type [image/file]
*/
function uploadFile(files, vm){
for(var i = 0, it; it = files[i++];){
if(openType === 'image' && !/\.(jpg|jpeg|png|gif|bmp|webp|ico)$/.test(it.name)){
vm.uploadFile.push({name: it.name, progress: '<span class="red">0%(失败,不允许的文件类型)</span>', url: ''})
continue
}
if(ME.maxSize > 0 && it.size > ME.maxSize){
vm.uploadFile.push({name: it.name, progress: '<span class="red">0%(文件体积过大)</span>', url: ''})
continue
}
var fixName = Date.now().toString(16) + it.name.slice(it.name.lastIndexOf('.'))
var idx = vm.uploadFile.length,
upload = new Uploader(vm.uploadUrl || ME.uploadUrl)
vm.uploadFile.push({name: it.name, progress: '0%', url: ''})
upload.field('file', it)
if(ME.beforeUpload){
ME.beforeUpload(fixName, function(qn){
upload.field('token', qn.token)
.field('key', qn.key)
.onProgress(function(val){
vm.uploadFile[idx].progress = val + '%'
}).onEnd(function(json){
vm.uploadFile[idx].url = qn.url
}).start()
})
}else{
upload.onProgress(function(val){
vm.uploadFile[idx].progress = val + '%'
}).onEnd(function(json){
vm.uploadFile[idx].url = json.data.url
}).start()
}
}
} }
}
function getAttach(vm, cb){ function getAttach(vm, cb) {
var xhr = new XMLHttpRequest(), var xhr = new XMLHttpRequest(),
url = vm.manageUrl || ME.manageUrl; url = vm.manageUrl || ME.manageUrl
if(/\?/.test(url)){ if (/\?/.test(url)) {
url += '&type=' + openType url += '&type=' + openType
}else{ } else {
url += '?type=' + openType url += '?type=' + openType
} }
url += '&t=' + Math.random() url += '&t=' + Math.random()
xhr.open('GET', url, true) xhr.open('GET', url, true)
xhr.onreadystatechange = function(){ xhr.onreadystatechange = function() {
if(this.readyState === 4 && if (
this.status === 200 && this.readyState === 4 &&
this.responseText !== ''){ this.status === 200 &&
var res = this.responseText this.responseText !== ''
try{ ) {
res = JSON.parse(res) var res = this.responseText
}catch(err){} try {
cb(res) res = JSON.parse(res)
}else{ } catch (err) {}
if(this.status !== 200 && this.responseText) cb(res)
console.error(this.responseText) } else {
if (this.status !== 200 && this.responseText)
console.error(this.responseText)
}
}
xhr.send()
}
function showDialog(elem, vm) {
opened = true
var offset = yua(elem).offset(),
layid = layer.open({
type: 7,
menubar: false,
shade: false,
fixed: true,
offset: [offset.top + 37 - ME.doc.scrollTop()],
tab: 2,
attach: '',
attachAlt: '',
uploadFile: [], //当前上传的列表
attachList: [], //附件管理列表
$switch: function(id) {
var lvm = yua.vmodels[layid]
lvm.tab = id
if (id === 3) {
lvm.attachList.clear()
if (cache[openType].length) {
lvm.attachList = cache[openType]
} else {
getAttach(vm, function(json) {
if (json) {
cache[openType] = json.data.list.map(function(it) {
it.thumb =
openType === 'image'
? '<img src="' + it.url + '"/>'
: '<em class="attach-icon">&#xe73e;</em>'
return it
})
lvm.attachList = json.data.list
}
})
} }
} }
xhr.send() },
} $select: yua.noop,
$change: yua.noop,
function showDialog(elem, vm){ $insert: function(it) {
opened = true if (!it.url) {
var offset = yua(elem).offset(),
layid = layer.open({
type: 7,
menubar: false,
shade: false,
fixed: true,
offset: [offset.top + 37 - ME.doc.scrollTop()],
tab: 2,
attach: '',
attachAlt: '',
uploadFile: [], //当前上传的列表
attachList: [], //附件管理列表
$switch: function(id){
var lvm = yua.vmodels[layid]
lvm.tab = id
if(id === 3){
lvm.attachList.clear()
if(cache[openType].length){
lvm.attachList = cache[openType]
}else{
getAttach(vm, function(json){
if(json){
cache[openType] = json.data.list.map(function(it){
it.thumb = openType === 'image' ? '<img src="' + it.url + '"/>' : '<em class="attach-icon">&#xe73e;</em>'
return it
})
lvm.attachList = json.data.list
}
})
}
}
},
$select: yua.noop,
$change: yua.noop,
$insert: function(it){
if(!it.url){
return
}
var val = (openType === 'image' ? '!' : '')
+ '[' + it.name + '](' + it.url + ')'
ME.insert(vm.$editor, val)
},
$confirm: function(){
var lvm = yua.vmodels[layid]
if(!lvm.attach || !lvm.attachAlt){
return layer.alert('描述和地址不能为空')
}
var val = '![' + lvm.attachAlt + '](' + lvm.attach + ')'
ME.insert(vm.$editor, val)
lvm.no()
},
success: function(id){
var _this = yua.vmodels[id],
$file = document.body.querySelector('#meditor-attch')
_this.no = function(){
layer.close(id)
opened = false
}
_this.$select = function(){
var ev = document.createEvent('MouseEvent')
ev.initEvent('click', false, false)
$file.dispatchEvent(ev);
}
_this.$change = function(){
uploadFile(this.files, _this)
}
},
content: fixCont()
})
}
ME.addon.image = function(elem, vm){
if(opened){
return return
} }
openType = 'image' var val =
showDialog(elem, vm) (openType === 'image' ? '!' : '') +
'[' +
it.name +
'](' +
it.url +
')'
ME.insert(vm.$editor, val)
},
$confirm: function() {
var lvm = yua.vmodels[layid]
if (!lvm.attach || !lvm.attachAlt) {
return layer.alert('描述和地址不能为空')
}
var val = '![' + lvm.attachAlt + '](' + lvm.attach + ')'
ME.insert(vm.$editor, val)
lvm.no()
},
success: function(id) {
var _this = yua.vmodels[id],
$file = document.body.querySelector('#meditor-attch')
_this.no = function() {
layer.close(id)
opened = false
}
_this.$select = function() {
var ev = document.createEvent('MouseEvent')
ev.initEvent('click', false, false)
$file.dispatchEvent(ev)
}
_this.$change = function() {
uploadFile(this.files, _this)
}
},
content: fixCont()
})
}
ME.addon.image = function(elem, vm) {
if (opened) {
return
} }
openType = 'image'
showDialog(elem, vm)
}
ME.addon.file = function(elem, vm) {
ME.addon.file = function(elem, vm){ if (opened) {
if(opened){ return
return
}
openType = 'file'
showDialog(elem, vm)
} }
openType = 'file'
showDialog(elem, vm)
}
return $init
})
return $init
})

View File

@ -6,10 +6,10 @@
*/ */
'use strict' 'use strict'
import 'layer/base' import 'layer/index'
function objArr(num) { function objArr(num) {
var arr = [] let arr = []
while (num > 0) { while (num > 0) {
arr.push({ v: 0 }) arr.push({ v: 0 })
num-- num--
@ -19,292 +19,373 @@ function objArr(num) {
function trim(str, sign) { function trim(str, sign) {
return str.replace(new RegExp('^' + sign + '|' + sign + '$', 'g'), '') return str.replace(new RegExp('^' + sign + '|' + sign + '$', 'g'), '')
} }
function getOrderArr(len) {
var arr = [],
i = 0
while (i < len) {
arr.push(i++)
}
return arr
}
const addon = { const addon = {
h1: function(elem, vm) { h1: function(elem, vm) {
var offset = Anot(elem).offset(), let that = this
wrap = ME.selection(vm.$editor, true) || '在此输入文本', let editor = vm.$refs.editor
h1ID = layer.open({ let offset = Anot(elem).offset()
type: 7, let wrap = this.selection(editor, true) || '在此输入文本'
menubar: false, layer.open({
shadeClose: true, type: 7,
fixed: true, menubar: false,
$insert: function(level) { maskClose: true,
wrap = wrap.replace(/^#{1,6} /, '') fixed: true,
wrap = ME.repeat('#', level) + ' ' + wrap insert: function(level) {
ME.insert(vm.$editor, wrap, true) wrap = wrap.replace(/^#{1,6} /, '')
layer.close(h1ID) wrap = that.repeat('#', level) + ' ' + wrap
}, that.insert(editor, wrap, true)
offset: [ this.close()
offset.top + 37 - ME.doc.scrollTop(), },
'auto', offset: [
'auto', offset.top + 40 - that.doc.scrollTop(),
offset.left - ME.doc.scrollLeft() 'auto',
], 'auto',
content: offset.left - that.doc.scrollLeft()
'<ul class="do-meditor-h1 do-fn-noselect do-meditor-font">' + ],
'<li :click="$insert(1)" class="h1">一级标题</li>' + shift: {
'<li :click="$insert(2)" class="h2">二级标题</li>' + top: offset.top - that.doc.scrollTop(),
'<li :click="$insert(3)" class="h3">三级标题</li>' + left: offset.left - that.doc.scrollLeft()
'<li :click="$insert(4)" class="h4">四级标题</li>' + },
'<li :click="$insert(5)" class="h5">五级标题</li>' + content: `
'<li :click="$insert(6)" class="h6">六级标题</li>' + <ul class="do-meditor-h1 do-fn-noselect do-meditor__font">
'</ul>' <li :click="insert(1)" class="h1"><i class="do-meditor__icon icon-h1"></i></li>
}) <li :click="insert(2)" class="h2"><i class="do-meditor__icon icon-h2"></i></li>
<li :click="insert(3)" class="h3"><i class="do-meditor__icon icon-h3"></i></li>
<li :click="insert(4)" class="h4"><i class="do-meditor__icon icon-h4"></i></li>
<li :click="insert(5)" class="h5"><i class="do-meditor__icon icon-h5"></i></li>
<li :click="insert(6)" class="h6"><i class="do-meditor__icon icon-h6"></i></li>
</ul>`
})
}, },
quote: function(elem, vm) { quote: function(elem, vm) {
var wrap = ME.selection(vm.$editor) || '在此输入文本' let wrap = this.selection(vm.$refs.editor) || '在此输入文本'
wrap = '> ' + wrap wrap = '> ' + wrap
ME.insert(vm.$editor, wrap, true) this.insert(vm.$refs.editor, wrap, true)
}, },
bold: function(elem, vm) { bold: function(elem, vm) {
var wrap = ME.selection(vm.$editor) || '在此输入文本', let wrap = this.selection(vm.$refs.editor) || '在此输入文本'
wraped = trim(wrap, '\\*\\*') let wraped = trim(wrap, '\\*\\*')
wrap = wrap === wraped ? '**' + wrap + '**' : wraped wrap = wrap === wraped ? '**' + wrap + '**' : wraped
ME.insert(vm.$editor, wrap, true) this.insert(vm.$refs.editor, wrap, true)
}, },
italic: function(elem, vm) { italic: function(elem, vm) {
var wrap = ME.selection(vm.$editor) || '在此输入文本', let wrap = this.selection(vm.$refs.editor) || '在此输入文本'
wraped = trim(wrap, '_') let wraped = trim(wrap, '_')
wrap = wrap === wraped ? '_' + wrap + '_' : wraped wrap = wrap === wraped ? '_' + wrap + '_' : wraped
ME.insert(vm.$editor, wrap, true) this.insert(vm.$refs.editor, wrap, true)
}, },
through: function(elem, vm) { through: function(elem, vm) {
var wrap = ME.selection(vm.$editor) || '在此输入文本', let wrap = this.selection(vm.$refs.editor) || '在此输入文本'
wraped = trim(wrap, '~~') let wraped = trim(wrap, '~~')
wrap = wrap === wraped ? '~~' + wrap + '~~' : wraped wrap = wrap === wraped ? '~~' + wrap + '~~' : wraped
ME.insert(vm.$editor, wrap, true) this.insert(vm.$refs.editor, wrap, true)
}, },
unordered: function(elem, vm) { unordered: function(elem, vm) {
var wrap = ME.selection(vm.$editor) || '在此输入文本' let wrap = this.selection(vm.$refs.editor) || '在此输入文本'
wrap = '* ' + wrap wrap = '* ' + wrap
ME.insert(vm.$editor, wrap, false) this.insert(vm.$refs.editor, wrap, false)
}, },
ordered: function(elem, vm) { ordered: function(elem, vm) {
var wrap = ME.selection(vm.$editor) || '在此输入文本' let wrap = this.selection(vm.$refs.editor) || '在此输入文本'
wrap = '1. ' + wrap wrap = '1. ' + wrap
ME.insert(vm.$editor, wrap, false) this.insert(vm.$refs.editor, wrap, false)
}, },
hr: function(elem, vm) { hr: function(elem, vm) {
ME.insert(vm.$editor, '\n\n---\n\n', false) this.insert(vm.$refs.editor, '\n\n---\n\n', false)
}, },
link: function(elem, vm) { link: function(elem, vm) {
var offset = Anot(elem).offset(), let that = this
wrap = ME.selection(vm.$editor) || '', let offset = Anot(elem).offset()
layid = layer.open({ let wrap = this.selection(vm.$refs.editor) || ''
type: 7,
menubar: false, layer.open({
shadeClose: true, type: 7,
fixed: true, menubar: false,
link: '', maskClose: true,
linkName: wrap, fixed: true,
linkTarget: 1, link: '',
$confirm: function() { linkName: wrap,
var lvm = Anot.vmodels[layid] linkTarget: 1,
if (!lvm.link || !lvm.linkName) { insert: function() {
return layer.alert('链接文字和地址不能为空') if (!this.link || !this.linkName) {
} return layer.toast('链接文字和地址不能为空', 'error')
var val = }
'[' + let val = `[${this.linkName}](${this.link} ${
lvm.linkName + this.linkTarget === 1 ? ' "target=_blank"' : ''
'](' + })`
lvm.link +
(lvm.linkTarget === 1 ? ' "target=_blank"' : '') + that.insert(vm.$refs.editor, val, false)
')' this.close()
ME.insert(vm.$editor, val, false) },
layer.close(layid) offset: [
}, offset.top + 40 - that.doc.scrollTop(),
offset: [ 'auto',
offset.top + 37 - ME.doc.scrollTop(), 'auto',
'auto', offset.left - that.doc.scrollLeft()
'auto', ],
offset.left - ME.doc.scrollLeft() shift: {
], top: offset.top - that.doc.scrollTop(),
content: left: offset.left - that.doc.scrollLeft()
'<div class="do-meditor-common do-meditor-font">' + },
'<section class="input"><span class="label">链接文字</span>' + content: `
'<input class="txt" :duplex="linkName" />' + <div class="do-meditor-common do-meditor__font">
'</section>' + <section class="input">
'<section class="input"><span class="label">链接地址</span>' + <input class="txt" :duplex="linkName" placeholder="链接文字"/>
'<input class="txt" :duplex="link"/>' + </section>
'</section>' + <section class="input">
'<section>' + <input class="txt" :duplex="link" placeholder="链接地址"/>
'<label><input name="link" type="radio" class="radio" :duplex-number="linkTarget" value="1"/> 新窗口打开</label>' + </section>
'<label><input name="link" type="radio" class="radio" :duplex-number="linkTarget" value="2"/> 本窗口打开</label>' + <section>
'</section>' + <label>
'<section>' + <input
'<a href="javascript:;" class="submit" :click="$confirm">确定</a>' + name="link"
'</section>' + type="radio"
'</div>' class="radio"
}) :duplex-number="linkTarget"
value="1"/>
新窗口打开
</label>
<label>
<input
name="link"
type="radio"
class="radio"
:duplex-number="linkTarget"
value="2"/>
本窗口打开
</label>
</section>
<section>
<a
href="javascript:;"
class="do-meditor__button submit"
:click="insert">确定</a>
</section>
</div>`
})
}, },
time: function(elem, vm) { time: function(elem, vm) {
ME.insert(vm.$editor, new Date().format(), false) this.insert(vm.$refs.editor, new Date().format(), false)
}, },
face: function(elem, vm) { face: function(elem, vm) {
var offset = Anot(elem).offset(), let that = this
faceid = 0, let offset = Anot(elem).offset()
layid = layer.open({
type: 7, layer.open({
title: '插入表情', type: 7,
fixed: true, title: '插入表情',
shadeClose: true, fixed: true,
arr: getOrderArr(36), maskClose: true,
offset: [ arr: [
offset.top + 37 - ME.doc.scrollTop(), '😀',
'auto', '😅',
'auto', '😂',
offset.left - ME.doc.scrollLeft() '🤣',
], '😇',
content: '😉',
'<ul class="do-meditor-face">' + '😍',
'<li class="item" :repeat="arr" ><img :attr-src="ME.path + \'/addon/face/\' + el + \'.gif\'" :click="$insert(this.src)" /></li>' + '😗',
'</ul>', '😋',
$insert: function(src) { '😛',
ME.insert(vm.$editor, '![](' + src + ')', false) '😜',
layer.close(layid) '🤨',
} '🧐',
}) '🤓',
'😎',
'😞',
'😔',
'😭',
'😤',
'😡',
'😱',
'😰',
'😓',
'😬',
'🙄',
'😴',
'😪',
'🤮',
'😷',
'💩',
'👻',
'💀',
'🤝',
'👎',
'👍',
'🙏'
],
offset: [
offset.top + 40 - that.doc.scrollTop(),
'auto',
'auto',
offset.left - that.doc.scrollLeft()
],
shift: {
top: offset.top - that.doc.scrollTop(),
left: offset.left - that.doc.scrollLeft()
},
content: `
<ul class="do-meditor-face">
<li class="item" :repeat="arr">
<span :html="el" :click="insert(el)"></span>
</li>
</ul>`,
insert: function(val) {
that.insert(vm.$refs.editor, val, false)
this.close()
}
})
}, },
table: function(elem, vm) { table: function(elem, vm) {
var offset = Anot(elem).offset() let that = this
let offset = Anot(elem).offset()
layer.open({ layer.open({
type: 7, type: 7,
title: '0行 x 0列', title: '0行 x 0列',
fixed: true, fixed: true,
shadeClose: true, maskClose: true,
offset: [ offset: [
offset.top + 37 - ME.doc.scrollTop(), offset.top + 40 - that.doc.scrollTop(),
'auto', 'auto',
'auto', 'auto',
offset.left - ME.doc.scrollLeft() offset.left - that.doc.scrollLeft()
], ],
shift: {
top: offset.top - that.doc.scrollTop(),
left: offset.left - that.doc.scrollLeft()
},
matrix: objArr(10).map(function() { matrix: objArr(10).map(function() {
return objArr(10) return objArr(10)
}), }),
content: content: `
'<ul class="do-meditor-table">' + <ul class="do-meditor-table" ref="table">
'<li :repeat="matrix"><span :repeat-o="el" :class="{active: o.v}" :data="{x: $index, y: $outer.$index}"></span></li>' + <li :repeat="matrix">
'</ul>', <span
success: function(id) { :repeat-o="el"
var tb = document.querySelector('.do-meditor-table'), :class="{active: o.v}"
_this = Anot.vmodels[id], :data="{x: $index, y: $outer.$index}"></span>
lastx, </li>
lasty </ul>`,
Anot(tb).bind('mousemove', function(ev) { success: function() {
let tb = this.$refs.table
let lastx, lasty
Anot(tb).bind('mousemove', ev => {
if (ev.target.nodeName === 'SPAN') { if (ev.target.nodeName === 'SPAN') {
var x = ev.target.dataset.x - 0, let x = ev.target.dataset.x - 0
y = ev.target.dataset.y - 0 let y = ev.target.dataset.y - 0
if (x === lastx && y === lasty) { if (x === lastx && y === lasty) {
return return
} }
lastx = x lastx = x
lasty = y lasty = y
_this.title = y + 1 + '行 x ' + (x + 1) + '列' this.title = y + 1 + '行 x ' + (x + 1) + '列'
for (var i = 0; i <= 9; i++) { for (let i = 0; i <= 9; i++) {
for (var j = 0; j <= 9; j++) { for (let j = 0; j <= 9; j++) {
_this.matrix[i][j].v = i <= y && j <= x ? 1 : 0 this.matrix[i][j].v = i <= y && j <= x ? 1 : 0
} }
} }
} }
}) })
Anot(tb).bind('mouseleave', function(ev) { Anot(tb).bind('mouseleave', ev => {
lastx = -1 lastx = -1
lasty = -1 lasty = -1
_this.title = '0行 x 0列' this.title = '0行 x 0列'
for (var i = 0; i <= 9; i++) { for (let i = 0; i <= 9; i++) {
for (var j = 0; j <= 9; j++) { for (let j = 0; j <= 9; j++) {
_this.matrix[i][j].v = 0 this.matrix[i][j].v = 0
} }
} }
}) })
Anot(tb).bind('click', function(ev) { Anot(tb).bind('click', ev => {
if (ev.target.nodeName === 'SPAN') { if (ev.target.nodeName === 'SPAN') {
var x = ev.target.dataset.x - 0 + 1, let x = ev.target.dataset.x - 0 + 1
y = ev.target.dataset.y - 0 + 1 let y = ev.target.dataset.y - 0 + 1
var val = let thead = `\n\n${that.repeat('| 表头 ', x)}|\n`
'\n\n' + let pipe = `${that.repeat('| -- ', x)}|\n`
ME.repeat('| 表头 ', x) + let tbody = that.repeat(that.repeat('| ', x) + '|\n', y)
'|\n' +
ME.repeat('| -- ', x) + that.insert(vm.$refs.editor, thead + pipe + tbody, false)
'|\n' + this.close()
ME.repeat(ME.repeat('| ', x) + '|\n', y)
ME.insert(vm.$editor, val, false)
layer.close(id)
} }
}) })
} }
}) })
}, },
image: function(elem, vm) { image: function(elem, vm) {
var offset = Anot(elem).offset(), let that = this
wrap = ME.selection(vm.$editor) || '', let offset = Anot(elem).offset()
layid = layer.open({ let wrap = this.selection(vm.$refs.editor) || ''
type: 7,
menubar: false,
shadeClose: true,
fixed: true,
img: '',
imgAlt: wrap,
$confirm: function() {
var lvm = Anot.vmodels[layid]
if (!lvm.img || !lvm.imgAlt) {
return layer.alert('图片描述和图片地址不能为空')
}
var val = '![' + lvm.imgAlt + '](' + lvm.img + ')'
ME.insert(vm.$editor, val, false) layer.open({
layer.close(layid) type: 7,
}, menubar: false,
offset: [ maskClose: true,
offset.top + 37 - ME.doc.scrollTop(), fixed: true,
'auto', img: '',
'auto', imgAlt: wrap,
offset.left - ME.doc.scrollLeft() insert: function() {
], if (!this.img || !this.imgAlt) {
content: return layer.toast('链接文字和地址不能为空', 'error')
'<div class="do-meditor-common do-meditor-font">' + }
'<section class="input"><span class="label">图片描述</span>' + let val = `![${this.imgAlt}](${this.img})`
'<input class="txt" :duplex="imgAlt" />' +
'</section>' + that.insert(vm.$refs.editor, val, false)
'<section class="input"><span class="label">图片地址</span>' + this.close()
'<input class="txt" :duplex="img"/>' + },
'</section>' + offset: [
'<section>' + offset.top + 40 - that.doc.scrollTop(),
'<a href="javascript:;" class="submit" :click="$confirm">确定</a>' + 'auto',
'</section>' + 'auto',
'</div>' offset.left - that.doc.scrollLeft()
}) ],
shift: {
top: offset.top - that.doc.scrollTop(),
left: offset.left - that.doc.scrollLeft()
},
content: `
<div class="do-meditor-common do-meditor__font">
<section class="input">
<input class="txt" :duplex="imgAlt" placeholder="图片描述"/>
</section>
<section class="input">
<input class="txt" :duplex="img" placeholder="图片地址"/>
</section>
<section>
<a
href="javascript:;"
class="do-meditor__button submit"
:click="insert">确定</a>
</section>
</div>
`
})
}, },
file: function(elem, vm) { attach: function(elem, vm) {
this.link(elem, vm, false) this.addon.link.call(this, elem, vm, false)
}, },
inlinecode: function(elem, vm) { inlinecode: function(elem, vm) {
var wrap = ME.selection(vm.$editor) || '在此输入文本', let wrap = this.selection(vm.$refs.editor) || '在此输入文本'
wraped = trim(wrap, '`') let wraped = trim(wrap, '`')
wrap = wrap === wraped ? '`' + wrap + '`' : wraped wrap = wrap === wraped ? '`' + wrap + '`' : wraped
ME.insert(vm.$editor, wrap, true) this.insert(vm.$refs.editor, wrap, true)
}, },
blockcode: function(elem, vm) { blockcode: function(elem, vm) {
var layid = layer.open({ let that = this
layer.open({
type: 7, type: 7,
title: '添加代码块', title: '添加代码块',
$lang: [ $lang: [
@ -350,11 +431,11 @@ const addon = {
var val = var val =
'\n```' + lvm.lang + '\n' + (lvm.code || '//在此输入代码') + '\n```\n' '\n```' + lvm.lang + '\n' + (lvm.code || '//在此输入代码') + '\n```\n'
ME.insert(vm.$editor, val, false) that.insert(vm.$refs.editor, val, false)
layer.close(layid) layer.close(layid)
}, },
content: content:
'<div class="do-meditor-codeblock do-meditor-font">' + '<div class="do-meditor-codeblock do-meditor__font">' +
'<section class="do-fn-cl"><span class="label">语言类型</span>' + '<section class="do-fn-cl"><span class="label">语言类型</span>' +
'<select :duplex="lang">' + '<select :duplex="lang">' +
'<option :repeat="$lang" :attr-value="el.id">{{el.name || el.id}}</option>' + '<option :repeat="$lang" :attr-value="el.id">{{el.name || el.id}}</option>' +
@ -384,9 +465,11 @@ const addon = {
layer.open({ layer.open({
type: 7, type: 7,
title: '关于编辑器', title: '关于编辑器',
offset: [offset.top + 37 - ME.doc.scrollTop()], maskClose: true,
offset: [offset.top + 37 - this.doc.scrollTop()],
shift: { top: offset.top - this.doc.scrollTop() },
content: content:
'<div class="do-meditor-about do-meditor-font">' + '<div class="do-meditor-about do-meditor__font">' +
'<pre>' + '<pre>' +
' __ __ _____ _ _ _\n' + ' __ __ _____ _ _ _\n' +
'| \\/ | ____|__| (_) |_ ___ _ __\n' + '| \\/ | ____|__| (_) |_ ___ _ __\n' +
@ -394,7 +477,7 @@ const addon = {
'| | | | |__| (_| | | || (_) | |\n' + '| | | | |__| (_| | | || (_) | |\n' +
'|_| |_|_____\\__,_|_|\\__\\___/|_| ' + '|_| |_|_____\\__,_|_|\\__\\___/|_| ' +
'v' + 'v' +
ME.version + this.version +
'</pre>' + '</pre>' +
'<p>开源在线Markdown编辑器</p>' + '<p>开源在线Markdown编辑器</p>' +
'<p><a target="_blank" href="https://doui.cc/product/meditor">https://doui.cc/product/meditor</a></p>' + '<p><a target="_blank" href="https://doui.cc/product/meditor">https://doui.cc/product/meditor</a></p>' +

View File

@ -0,0 +1 @@
export default 1234

View File

@ -17,13 +17,14 @@ marked.setOptions({
return Prism.highlight(code, Prism.languages[lang]) return Prism.highlight(code, Prism.languages[lang])
} }
}) })
var editorVM = [] let editorVM = []
Anot.ui.meditor = '1.0.0' Anot.ui.meditor = '1.0.0'
const log = console.log
//存放编辑器公共静态资源 //存放编辑器公共静态资源
window.ME = { window.ME = {
version: Anot.ui.meditor, version: Anot.ui.meditor,
// 工具栏title
toolbar: { toolbar: {
//工具栏title
pipe: '', pipe: '',
h1: '标题', h1: '标题',
quote: '引用文本', quote: '引用文本',
@ -45,19 +46,19 @@ window.ME = {
fullscreen: '全屏', fullscreen: '全屏',
about: '关于编辑器' about: '关于编辑器'
}, },
addon, //已有插件 addon, // 已有插件
//往文本框中插入内容 // 往文本框中插入内容
insert: function(dom, val, isSelect) { insert: function(dom, val, isSelect) {
if (document.selection) { if (document.selection) {
dom.focus() dom.focus()
var range = document.selection.createRange() let range = document.selection.createRange()
range.text = val range.text = val
dom.focus() dom.focus()
range.moveStart('character', -1) range.moveStart('character', -1)
} else if (dom.selectionStart || dom.selectionStart === 0) { } else if (dom.selectionStart || dom.selectionStart === 0) {
var startPos = dom.selectionStart, let startPos = dom.selectionStart
endPos = dom.selectionEnd, let endPos = dom.selectionEnd
scrollTop = dom.scrollTop let scrollTop = dom.scrollTop
dom.value = dom.value =
dom.value.slice(0, startPos) + dom.value.slice(0, startPos) +
@ -82,15 +83,15 @@ window.ME = {
if (document.selection) { if (document.selection) {
return document.selection.createRange().text return document.selection.createRange().text
} else { } else {
var startPos = dom.selectionStart, let startPos = dom.selectionStart
endPos = dom.selectionEnd let endPos = dom.selectionEnd
if (endPos) { if (endPos) {
//强制选择整行 //强制选择整行
if (line) { if (line) {
startPos = dom.value.slice(0, startPos).lastIndexOf('\n') startPos = dom.value.slice(0, startPos).lastIndexOf('\n')
var tmpEnd = dom.value.slice(endPos).indexOf('\n') let tmpEnd = dom.value.slice(endPos).indexOf('\n')
tmpEnd = tmpEnd < 0 ? 0 : tmpEnd tmpEnd = tmpEnd < 0 ? 0 : tmpEnd
startPos += 1 //把\n加上 startPos += 1 //把\n加上
@ -169,27 +170,24 @@ var elems = {
}, },
hr: '\n\n___\n\n', hr: '\n\n___\n\n',
a: function(str, attr, inner) { a: function(str, attr, inner) {
var href = attr.match(attrExp('href')), let href = attr.match(attrExp('href'))
title = attr.match(attrExp('title')), let title = attr.match(attrExp('title'))
tar = attr.match(attrExp('target')) let tar = attr.match(attrExp('target'))
let attrs = ''
href = (href && href[1]) || '' href = (href && href[1]) || null
title = (title && title[1]) || '' title = (title && title[1]) || null
tar = (tar && tar[1]) || '_self' tar = (tar && tar[1]) || '_self'
href = href === 'javascript:void(0);' ? 'javascript:;' : href if (!href) {
return inner || href
}
return ( href = href.replace('viod(0)', '')
'[' + attrs = `target=${tar}`
(inner || href) + attrs += title ? `;title=${title}` : ''
'](' +
href + return `[${inner || href}](${href} "${attrs}")`
' "title=' +
title +
';target=' +
tar +
'")'
)
}, },
em: function(str, attr, inner) { em: function(str, attr, inner) {
return (inner && '_' + inner + '_') || '' return (inner && '_' + inner + '_') || ''
@ -233,7 +231,12 @@ function html2md(str) {
try { try {
str = decodeURIComponent(str) str = decodeURIComponent(str)
} catch (err) {} } catch (err) {}
str = str.replace(/\t/g, ' ').replace(/<meta [^>]*>/, '')
str = str.replace(/\t/g, ' ').replace(/<meta [^>]*>/, '')
str = str.replace(
/<(div|span|dl|dd|dt|table|tr|td|thead|tbody|i|em|strong|h[1-6]|ul|ol|li) [^>]*>/g,
'<$1>'
)
for (var i in elems) { for (var i in elems) {
var cb = elems[i], var cb = elems[i],
@ -313,7 +316,7 @@ var defaultToolbar = [
'|', '|',
'table', 'table',
'image', 'image',
'file', 'attach',
'inlinecode', 'inlinecode',
'blockcode', 'blockcode',
'|', '|',
@ -330,7 +333,7 @@ function tool(name) {
return ( return (
'<span title="' + '<span title="' +
ME.toolbar[name] + ME.toolbar[name] +
'" class="icon-' + '" class="do-meditor__icon icon-' +
name + name +
'" ' + '" ' +
(name !== 'pipe' ? ':click="onToolClick(\'' + name + '\', $event)"' : '') + (name !== 'pipe' ? ':click="onToolClick(\'' + name + '\', $event)"' : '') +
@ -340,35 +343,43 @@ function tool(name) {
Anot.component('meditor', { Anot.component('meditor', {
render: function() { render: function() {
var toolbar = (this.toolbar || defaultToolbar) let toolbar = (this.toolbar || defaultToolbar).map(it => tool(it)).join('')
.map(function(it) {
return tool(it)
})
.join('')
delete this.toolbar delete this.toolbar
return (
'<div class="do-meditor do-meditor-font" :visible="editorVisible"' + return `
' :class="{fullscreen: fullscreen, preview: preview}">' + <div
'<div class="tool-bar do-ui-font do-fn-noselect">{toolbar}</div>' + class="do-meditor do-meditor__font"
'<textarea ref="textarea" class="editor-body" spellcheck="false" :duplex="plainTxt" :attr="{disabled: disabled}" :on-paste="$paste($event)"></textarea>' + :visible="editorVisible"
'<content class="md-preview do-marked-theme" :visible="preview" :html="htmlTxt"></content>' + :class="{fullscreen: fullscreen, preview: preview}">
'</div>' <div class="tool-bar do-fn-noselect">${toolbar}</div>
).replace(/\{toolbar\}/g, toolbar) <textarea
ref="editor"
class="editor-body"
spellcheck="false"
:attr="{disabled: disabled}"
:duplex="plainTxt"
:on-paste="onPaste($event)"></textarea>
<content
class="md-preview do-marked-theme"
:visible="preview"
:html="htmlTxt"></content>
</div>
`
}, },
construct: function(base, opt, attr) { construct: function(props, state) {
Anot.mix(base, opt, attr) // Anot.mix(base, opt, attr)
if (base.$addons && Array.isArray(base.$addons)) { // if (base.$addons && Array.isArray(base.$addons)) {
extraAddons = base.$addons.map(function(name) { // extraAddons = base.$addons.map(function(name) {
return ME.path + '/addon/' + name // return ME.path + '/addon/' + name
}) // })
delete base.$addons // delete base.$addons
// }
if (props.hasOwnProperty('$show')) {
state.editorVisible = props.$show
delete props.$show
} }
if (base.hasOwnProperty('$show')) {
base.editorVisible = base.$show
delete base.$show
}
return base
}, },
componentWillMount: function(vm) {}, componentWillMount: function(vm) {},
componentDidMount: function(vm, elem) { componentDidMount: function(vm, elem) {
@ -411,25 +422,32 @@ Anot.component('meditor', {
}, },
watch: { watch: {
plainTxt: function(val) { plainTxt: function(val) {
this.$compile() this.compile()
//只有开启实时预览,才会赋值给htmlTxt //只有开启实时预览,才会赋值给htmlTxt
if (this.preview) { if (this.preview) {
this.htmlTxt = this.$htmlTxt this.htmlTxt = this.$htmlTxt
} }
this.$onUpdate(this.plainTxt, vm.$htmlTxt) if (typeof this.props.onUpdate === 'function') {
this.props.onUpdate(this.plainTxt, this.$htmlTxt)
}
} }
}, },
state: { state: {
disabled: false, //禁用编辑器 disabled: false, //禁用编辑器
fullscreen: false, //是否全屏 fullscreen: false, //是否全屏
preview: false, //是否显示预览 preview: false, //是否显示预览
$editor: null, //编辑器元素 // $editor: null, //编辑器元素
editorVisible: true, editorVisible: true,
$htmlTxt: '', //临时储存html文本 $htmlTxt: '', //临时储存html文本
htmlTxt: '', //用于预览渲染 htmlTxt: '', //用于预览渲染
plainTxt: '', //纯md文本 plainTxt: '', //纯md文本
$safelyCompile: true $safelyCompile: true
}, },
props: {
onSuccess: Anot.PropsTypes.isFunction(),
onUpdate: Anot.PropsTypes.isFunction(),
onFullscreen: Anot.PropsTypes.isFunction()
},
methods: { methods: {
onToolClick: function(name, ev) { onToolClick: function(name, ev) {
if (ME.addon[name]) { if (ME.addon[name]) {
@ -438,24 +456,23 @@ Anot.component('meditor', {
console.log('%c没有对应的插件%c[%s]', 'color:#f00;', '', name) console.log('%c没有对应的插件%c[%s]', 'color:#f00;', '', name)
} }
}, },
$onSuccess: Anot.noop, onPaste: function(ev) {
$onUpdate: Anot.noop,
$onFullscreen: Anot.noop,
$paste: function(ev) {
ev.preventDefault() ev.preventDefault()
var txt = ev.clipboardData.getData('text/plain').trim(), let txt = ev.clipboardData.getData('text/plain').trim()
html = ev.clipboardData.getData('text/html').trim() let html = ev.clipboardData.getData('text/html').trim()
html = html2md(html) html = html2md(html)
if (html) { if (html) {
ME.insert(this, html) ME.insert(ev.target, html)
} else if (txt) { } else if (txt) {
ME.insert(this, txt) ME.insert(ev.target, txt)
} }
this.plainTxt = this.value log(ev.target.value)
this.plainTxt = this.$refs.editor.value
}, },
compile: function() { compile: function() {
log(this)
var txt = this.plainTxt.trim() var txt = this.plainTxt.trim()
if (this.$safelyCompile) { if (this.$safelyCompile) {

File diff suppressed because one or more lines are too long

View File

@ -7,15 +7,13 @@
import './highlight.scss' import './highlight.scss'
var _self = window
var Prism = (function() { var Prism = (function() {
// Private helper vars // Private helper vars
var lang = /\blang(?:uage)?-(\w+)\b/i var lang = /\blang(?:uage)?-(\w+)\b/i
var uniqueId = 0 var uniqueId = 0
var _ = (_self.Prism = { var _ = (window.Prism = {
manual: _self.Prism && _self.Prism.manual, manual: window.Prism && window.Prism.manual,
util: { util: {
encode: function(tokens) { encode: function(tokens) {
if (tokens instanceof Token) { if (tokens instanceof Token) {
@ -221,7 +219,7 @@ var Prism = (function() {
_.hooks.run('before-highlight', env) _.hooks.run('before-highlight', env)
if (async && _self.Worker) { if (async && window.Worker) {
var worker = new Worker(_.filename) var worker = new Worker(_.filename)
worker.onmessage = function(evt) { worker.onmessage = function(evt) {
@ -487,13 +485,13 @@ var Prism = (function() {
) )
} }
if (!_self.document) { if (!window.document) {
if (!_self.addEventListener) { if (!window.addEventListener) {
// in Node.js // in Node.js
return _self.Prism return window.Prism
} }
// In worker // In worker
_self.addEventListener( window.addEventListener(
'message', 'message',
function(evt) { function(evt) {
var message = JSON.parse(evt.data), var message = JSON.parse(evt.data),
@ -501,15 +499,15 @@ var Prism = (function() {
code = message.code, code = message.code,
immediateClose = message.immediateClose immediateClose = message.immediateClose
_self.postMessage(_.highlight(code, _.languages[lang], lang)) window.postMessage(_.highlight(code, _.languages[lang], lang))
if (immediateClose) { if (immediateClose) {
_self.close() window.close()
} }
}, },
false false
) )
return _self.Prism return window.Prism
} }
//Get current script and highlight //Get current script and highlight
@ -537,7 +535,7 @@ var Prism = (function() {
} }
} }
return _self.Prism return window.Prism
})() })()
Prism.languages.markup = { Prism.languages.markup = {

View File

@ -232,7 +232,6 @@ Prism.languages.insertBefore('cpp', 'keyword', {
}) })
/*-----------------------coffeescript-----------------------*/ /*-----------------------coffeescript-----------------------*/
;(function(Prism) { ;(function(Prism) {
// Ignore comments starting with { to privilege string interpolation highlighting // Ignore comments starting with { to privilege string interpolation highlighting
var comment = /#(?!\{).+/, var comment = /#(?!\{).+/,
@ -322,7 +321,6 @@ Prism.languages.insertBefore('cpp', 'keyword', {
})(Prism) })(Prism)
/*---------------------------ruby---------------------------*/ /*---------------------------ruby---------------------------*/
;(function(Prism) { ;(function(Prism) {
Prism.languages.ruby = Prism.languages.extend('clike', { Prism.languages.ruby = Prism.languages.extend('clike', {
comment: [ comment: [
@ -650,7 +648,6 @@ Prism.languages.haskell = {
} }
/*---------------------------jade---------------------------*/ /*---------------------------jade---------------------------*/
;(function(Prism) { ;(function(Prism) {
Prism.languages.jade = { Prism.languages.jade = {
comment: { comment: {
@ -862,7 +859,6 @@ Prism.languages.json = {
Prism.languages.jsonp = Prism.languages.json Prism.languages.jsonp = Prism.languages.json
/*--------------------------kotlin----------------------------*/ /*--------------------------kotlin----------------------------*/
;(function(Prism) { ;(function(Prism) {
Prism.languages.kotlin = Prism.languages.extend('clike', { Prism.languages.kotlin = Prism.languages.extend('clike', {
keyword: { keyword: {
@ -1525,7 +1521,6 @@ Prism.languages.rust = {
} }
/*------------------------------------------------------------*/ /*------------------------------------------------------------*/
;(function(Prism) { ;(function(Prism) {
Prism.languages.sass = Prism.languages.extend('css', { Prism.languages.sass = Prism.languages.extend('css', {
// Sass comments don't need to be closed, only indented // Sass comments don't need to be closed, only indented
@ -1676,7 +1671,6 @@ Prism.languages.scss['atrule'].inside.rest = Prism.util.clone(
) )
/*-----------------------------smarty-------------------------*/ /*-----------------------------smarty-------------------------*/
;(function(Prism) { ;(function(Prism) {
var smarty_pattern = /\{\*[\s\S]+?\*\}|\{[\s\S]+?\}/g var smarty_pattern = /\{\*[\s\S]+?\*\}|\{[\s\S]+?\}/g
var smarty_litteral_start = '{literal}' var smarty_litteral_start = '{literal}'