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;
$cr: #ff5722 #ff7043 #e64a19;
$co: #ff9800 #ffa726 #f57c00;
$cp: #e7e8eb #ecf0f1 #bdc3c7;
$cp: #e7e8eb #ecf0f1 #d3d5db;
$cgr: #546e7a #607d8b #37474f;
@mixin ts($c: all, $t: .2s, $m: ease-in-out){

View File

@ -182,8 +182,8 @@ class __layer__ {
}
},
mounted: function() {
if (typeof this.success === 'function') {
this.success(_id)
if (typeof this.props.success === 'function') {
this.props.success.call(this)
}
}
}
@ -216,7 +216,9 @@ class __layer__ {
layBox.classList.add('__' + state.shift)
} else {
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

@ -5,167 +5,168 @@
*
*/
"use strict";
'use strict'
define([
'lib/layer/base',
'css!./attach'
], function(){
var Uploader = function(url){
define(['lib/layer/base', 'css!./attach'], function() {
var Uploader = function(url) {
this.url = url || ''
this.init()
}
Uploader.prototype = {
init: function(){
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){
field: function(key, val) {
if (typeof key === 'object') {
for (var i in key) {
this.form.append(i, key[i])
}
}else{
} else {
this.form.append(key, val)
}
return this
},
start: function(){
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){
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
)
}, false)
this.xhr.onreadystatechange = function(){
if(_this.xhr.readyState === 4){
if(_this.xhr.status >= 200 && _this.xhr.status < 205){
this.xhr.onreadystatechange = function() {
if (_this.xhr.readyState === 4) {
if (_this.xhr.status >= 200 && _this.xhr.status < 205) {
var res = _this.xhr.responseText
try{
try {
res = JSON.parse(res)
}catch(err){}
} catch (err) {}
_this.end && _this.end(res)
}else{
} else {
console.error(_this.xhr)
}
}
}
this.xhr.send(this.form)
},
onProgress: function(fn){
onProgress: function(fn) {
this.progress = fn
return this
},
onEnd: function(fn){
onEnd: function(fn) {
this.end = fn
return this
}
}
function uploadScreenshot(vm, blob){
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)
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){
.onEnd(function(json) {
ME.insert(vm.$editor, '![截图](' + qn.url + ')')
})
.start()
})
}else{
upload.field('file', blob)
.onEnd(function(json){
} 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设置')
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 (!vm.manageUrl && !ME.manageUrl) {
console.error(
'使用附件管理功能,必须先设置manageUrl;\n可以给vm增加manageUrl属性,也可以通过ME.manageUrl设置'
)
}
if(!ME.maxSize){
if (!ME.maxSize) {
ME.maxSize = 4194304
}
vm.$editor.addEventListener('paste', function(ev){
vm.$editor.addEventListener('paste', function(ev) {
var txt = ev.clipboardData.getData('text/plain').trim(),
html = ev.clipboardData.getData('text/html').trim();
html = ev.clipboardData.getData('text/html').trim()
//文本类型直接默认处理
if(txt || html){
if (txt || html) {
return
}
if(ev.clipboardData.items){
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 = null
for (var i = 0, it; (it = items[i++]); ) {
if (it.type.indexOf('image') > -1) {
blob = it.getAsFile()
}
}
if(blob !== null) {
if (blob !== null) {
layer.msg('截图处理中...')
// 压缩截图,避免文件过大
var reader = new FileReader()
reader.onload = function(){
reader.onload = function() {
var img = document.createElement('img'),
canvas = document.createElement('canvas')
img.onload = function(){
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.clearRect(0, 0, canvas.width, canvas.height)
ctx.drawImage(this, 0, 0, canvas.width, canvas.height)
if(canvas.toBlob){
canvas.toBlob(function(obj){
if (canvas.toBlob) {
canvas.toBlob(
function(obj) {
uploadScreenshot(vm, obj)
}, 'image/jpeg', 0.8)
}else{
},
'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;
obj = null
for(var i = 0; i < buf.length; i++){
for (var i = 0; i < buf.length; i++) {
intArr[i] = buf.charCodeAt(i)
}
obj = new Blob([intArr], {type: 'image/jpeg'})
obj = new Blob([intArr], { type: 'image/jpeg' })
uploadScreenshot(vm, obj)
}
}
img.src = this.result
}
@ -181,52 +182,63 @@ define([
},
opened = false, //记录是否已经打开
openType = 'image', //打开类型, 图片/附件
cache = { //缓存附件列表
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>'
};
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 文件上传]
@ -234,77 +246,95 @@ define([
* @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: ''})
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: ''})
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 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: ''})
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)
if (ME.beforeUpload) {
ME.beforeUpload(fixName, function(qn) {
upload
.field('token', qn.token)
.field('key', qn.key)
.onProgress(function(val){
.onProgress(function(val) {
vm.uploadFile[idx].progress = val + '%'
}).onEnd(function(json){
vm.uploadFile[idx].url = qn.url
}).start()
})
}else{
upload.onProgress(function(val){
.onEnd(function(json) {
vm.uploadFile[idx].url = qn.url
})
.start()
})
} else {
upload
.onProgress(function(val) {
vm.uploadFile[idx].progress = val + '%'
}).onEnd(function(json){
})
.onEnd(function(json) {
vm.uploadFile[idx].url = json.data.url
}).start()
})
.start()
}
}
}
function getAttach(vm, cb){
function getAttach(vm, cb) {
var xhr = new XMLHttpRequest(),
url = vm.manageUrl || ME.manageUrl;
url = vm.manageUrl || ME.manageUrl
if(/\?/.test(url)){
if (/\?/.test(url)) {
url += '&type=' + openType
}else{
} else {
url += '?type=' + openType
}
url += '&t=' + Math.random()
xhr.open('GET', url, true)
xhr.onreadystatechange = function(){
if(this.readyState === 4 &&
xhr.onreadystatechange = function() {
if (
this.readyState === 4 &&
this.status === 200 &&
this.responseText !== ''){
this.responseText !== ''
) {
var res = this.responseText
try{
try {
res = JSON.parse(res)
}catch(err){}
} catch (err) {}
cb(res)
}else{
if(this.status !== 200 && this.responseText)
} else {
if (this.status !== 200 && this.responseText)
console.error(this.responseText)
}
}
xhr.send()
}
function showDialog(elem, vm){
function showDialog(elem, vm) {
opened = true
var offset = yua(elem).offset(),
layid = layer.open({
@ -318,19 +348,22 @@ define([
attachAlt: '',
uploadFile: [], //当前上传的列表
attachList: [], //附件管理列表
$switch: function(id){
$switch: function(id) {
var lvm = yua.vmodels[layid]
lvm.tab = id
if(id === 3){
if (id === 3) {
lvm.attachList.clear()
if(cache[openType].length){
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>'
} 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
@ -338,22 +371,25 @@ define([
})
}
}
},
$select: yua.noop,
$change: yua.noop,
$insert: function(it){
if(!it.url){
$insert: function(it) {
if (!it.url) {
return
}
var val = (openType === 'image' ? '!' : '')
+ '[' + it.name + '](' + it.url + ')'
var val =
(openType === 'image' ? '!' : '') +
'[' +
it.name +
'](' +
it.url +
')'
ME.insert(vm.$editor, val)
},
$confirm: function(){
$confirm: function() {
var lvm = yua.vmodels[layid]
if(!lvm.attach || !lvm.attachAlt){
if (!lvm.attach || !lvm.attachAlt) {
return layer.alert('描述和地址不能为空')
}
var val = '![' + lvm.attachAlt + '](' + lvm.attach + ')'
@ -361,20 +397,20 @@ define([
ME.insert(vm.$editor, val)
lvm.no()
},
success: function(id){
success: function(id) {
var _this = yua.vmodels[id],
$file = document.body.querySelector('#meditor-attch')
_this.no = function(){
_this.no = function() {
layer.close(id)
opened = false
}
_this.$select = function(){
_this.$select = function() {
var ev = document.createEvent('MouseEvent')
ev.initEvent('click', false, false)
$file.dispatchEvent(ev);
$file.dispatchEvent(ev)
}
_this.$change = function(){
_this.$change = function() {
uploadFile(this.files, _this)
}
},
@ -382,33 +418,21 @@ define([
})
}
ME.addon.image = function(elem, vm){
if(opened){
ME.addon.image = function(elem, vm) {
if (opened) {
return
}
openType = 'image'
showDialog(elem, vm)
}
ME.addon.file = function(elem, vm){
if(opened){
ME.addon.file = function(elem, vm) {
if (opened) {
return
}
openType = 'file'
showDialog(elem, vm)
}
return $init
})

View File

@ -6,10 +6,10 @@
*/
'use strict'
import 'layer/base'
import 'layer/index'
function objArr(num) {
var arr = []
let arr = []
while (num > 0) {
arr.push({ v: 0 })
num--
@ -19,292 +19,373 @@ function objArr(num) {
function trim(str, sign) {
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 = {
h1: function(elem, vm) {
var offset = Anot(elem).offset(),
wrap = ME.selection(vm.$editor, true) || '在此输入文本',
h1ID = layer.open({
let that = this
let editor = vm.$refs.editor
let offset = Anot(elem).offset()
let wrap = this.selection(editor, true) || '在此输入文本'
layer.open({
type: 7,
menubar: false,
shadeClose: true,
maskClose: true,
fixed: true,
$insert: function(level) {
insert: function(level) {
wrap = wrap.replace(/^#{1,6} /, '')
wrap = ME.repeat('#', level) + ' ' + wrap
ME.insert(vm.$editor, wrap, true)
layer.close(h1ID)
wrap = that.repeat('#', level) + ' ' + wrap
that.insert(editor, wrap, true)
this.close()
},
offset: [
offset.top + 37 - ME.doc.scrollTop(),
offset.top + 40 - that.doc.scrollTop(),
'auto',
'auto',
offset.left - ME.doc.scrollLeft()
offset.left - that.doc.scrollLeft()
],
content:
'<ul class="do-meditor-h1 do-fn-noselect do-meditor-font">' +
'<li :click="$insert(1)" class="h1">一级标题</li>' +
'<li :click="$insert(2)" class="h2">二级标题</li>' +
'<li :click="$insert(3)" class="h3">三级标题</li>' +
'<li :click="$insert(4)" class="h4">四级标题</li>' +
'<li :click="$insert(5)" class="h5">五级标题</li>' +
'<li :click="$insert(6)" class="h6">六级标题</li>' +
'</ul>'
shift: {
top: offset.top - that.doc.scrollTop(),
left: offset.left - that.doc.scrollLeft()
},
content: `
<ul class="do-meditor-h1 do-fn-noselect do-meditor__font">
<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) {
var wrap = ME.selection(vm.$editor) || '在此输入文本'
let wrap = this.selection(vm.$refs.editor) || '在此输入文本'
wrap = '> ' + wrap
ME.insert(vm.$editor, wrap, true)
this.insert(vm.$refs.editor, wrap, true)
},
bold: function(elem, vm) {
var wrap = ME.selection(vm.$editor) || '在此输入文本',
wraped = trim(wrap, '\\*\\*')
let wrap = this.selection(vm.$refs.editor) || '在此输入文本'
let wraped = trim(wrap, '\\*\\*')
wrap = wrap === wraped ? '**' + wrap + '**' : wraped
ME.insert(vm.$editor, wrap, true)
this.insert(vm.$refs.editor, wrap, true)
},
italic: function(elem, vm) {
var wrap = ME.selection(vm.$editor) || '在此输入文本',
wraped = trim(wrap, '_')
let wrap = this.selection(vm.$refs.editor) || '在此输入文本'
let wraped = trim(wrap, '_')
wrap = wrap === wraped ? '_' + wrap + '_' : wraped
ME.insert(vm.$editor, wrap, true)
this.insert(vm.$refs.editor, wrap, true)
},
through: function(elem, vm) {
var wrap = ME.selection(vm.$editor) || '在此输入文本',
wraped = trim(wrap, '~~')
let wrap = this.selection(vm.$refs.editor) || '在此输入文本'
let wraped = trim(wrap, '~~')
wrap = wrap === wraped ? '~~' + wrap + '~~' : wraped
ME.insert(vm.$editor, wrap, true)
this.insert(vm.$refs.editor, wrap, true)
},
unordered: function(elem, vm) {
var wrap = ME.selection(vm.$editor) || '在此输入文本'
let wrap = this.selection(vm.$refs.editor) || '在此输入文本'
wrap = '* ' + wrap
ME.insert(vm.$editor, wrap, false)
this.insert(vm.$refs.editor, wrap, false)
},
ordered: function(elem, vm) {
var wrap = ME.selection(vm.$editor) || '在此输入文本'
let wrap = this.selection(vm.$refs.editor) || '在此输入文本'
wrap = '1. ' + wrap
ME.insert(vm.$editor, wrap, false)
this.insert(vm.$refs.editor, wrap, false)
},
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) {
var offset = Anot(elem).offset(),
wrap = ME.selection(vm.$editor) || '',
layid = layer.open({
let that = this
let offset = Anot(elem).offset()
let wrap = this.selection(vm.$refs.editor) || ''
layer.open({
type: 7,
menubar: false,
shadeClose: true,
maskClose: true,
fixed: true,
link: '',
linkName: wrap,
linkTarget: 1,
$confirm: function() {
var lvm = Anot.vmodels[layid]
if (!lvm.link || !lvm.linkName) {
return layer.alert('链接文字和地址不能为空')
insert: function() {
if (!this.link || !this.linkName) {
return layer.toast('链接文字和地址不能为空', 'error')
}
var val =
'[' +
lvm.linkName +
'](' +
lvm.link +
(lvm.linkTarget === 1 ? ' "target=_blank"' : '') +
')'
ME.insert(vm.$editor, val, false)
layer.close(layid)
let val = `[${this.linkName}](${this.link} ${
this.linkTarget === 1 ? ' "target=_blank"' : ''
})`
that.insert(vm.$refs.editor, val, false)
this.close()
},
offset: [
offset.top + 37 - ME.doc.scrollTop(),
offset.top + 40 - that.doc.scrollTop(),
'auto',
'auto',
offset.left - ME.doc.scrollLeft()
offset.left - that.doc.scrollLeft()
],
content:
'<div class="do-meditor-common do-meditor-font">' +
'<section class="input"><span class="label">链接文字</span>' +
'<input class="txt" :duplex="linkName" />' +
'</section>' +
'<section class="input"><span class="label">链接地址</span>' +
'<input class="txt" :duplex="link"/>' +
'</section>' +
'<section>' +
'<label><input name="link" type="radio" 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="submit" :click="$confirm">确定</a>' +
'</section>' +
'</div>'
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="linkName" placeholder="链接文字"/>
</section>
<section class="input">
<input class="txt" :duplex="link" placeholder="链接地址"/>
</section>
<section>
<label>
<input
name="link"
type="radio"
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) {
ME.insert(vm.$editor, new Date().format(), false)
this.insert(vm.$refs.editor, new Date().format(), false)
},
face: function(elem, vm) {
var offset = Anot(elem).offset(),
faceid = 0,
layid = layer.open({
let that = this
let offset = Anot(elem).offset()
layer.open({
type: 7,
title: '插入表情',
fixed: true,
shadeClose: true,
arr: getOrderArr(36),
offset: [
offset.top + 37 - ME.doc.scrollTop(),
'auto',
'auto',
offset.left - ME.doc.scrollLeft()
maskClose: true,
arr: [
'😀',
'😅',
'😂',
'🤣',
'😇',
'😉',
'😍',
'😗',
'😋',
'😛',
'😜',
'🤨',
'🧐',
'🤓',
'😎',
'😞',
'😔',
'😭',
'😤',
'😡',
'😱',
'😰',
'😓',
'😬',
'🙄',
'😴',
'😪',
'🤮',
'😷',
'💩',
'👻',
'💀',
'🤝',
'👎',
'👍',
'🙏'
],
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) {
var offset = Anot(elem).offset()
let that = this
let offset = Anot(elem).offset()
layer.open({
type: 7,
title: '0行 x 0列',
fixed: true,
shadeClose: true,
maskClose: true,
offset: [
offset.top + 37 - ME.doc.scrollTop(),
offset.top + 40 - that.doc.scrollTop(),
'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() {
return objArr(10)
}),
content:
'<ul class="do-meditor-table">' +
'<li :repeat="matrix"><span :repeat-o="el" :class="{active: o.v}" :data="{x: $index, y: $outer.$index}"></span></li>' +
'</ul>',
success: function(id) {
var tb = document.querySelector('.do-meditor-table'),
_this = Anot.vmodels[id],
lastx,
lasty
Anot(tb).bind('mousemove', function(ev) {
content: `
<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>
</ul>`,
success: function() {
let tb = this.$refs.table
let lastx, lasty
Anot(tb).bind('mousemove', ev => {
if (ev.target.nodeName === 'SPAN') {
var x = ev.target.dataset.x - 0,
y = ev.target.dataset.y - 0
let x = ev.target.dataset.x - 0
let y = ev.target.dataset.y - 0
if (x === lastx && y === lasty) {
return
}
lastx = x
lasty = y
_this.title = y + 1 + '行 x ' + (x + 1) + '列'
for (var i = 0; i <= 9; i++) {
for (var j = 0; j <= 9; j++) {
_this.matrix[i][j].v = i <= y && j <= x ? 1 : 0
this.title = y + 1 + '行 x ' + (x + 1) + '列'
for (let i = 0; i <= 9; i++) {
for (let j = 0; j <= 9; j++) {
this.matrix[i][j].v = i <= y && j <= x ? 1 : 0
}
}
}
})
Anot(tb).bind('mouseleave', function(ev) {
Anot(tb).bind('mouseleave', ev => {
lastx = -1
lasty = -1
_this.title = '0行 x 0列'
for (var i = 0; i <= 9; i++) {
for (var j = 0; j <= 9; j++) {
_this.matrix[i][j].v = 0
this.title = '0行 x 0列'
for (let i = 0; i <= 9; i++) {
for (let j = 0; j <= 9; j++) {
this.matrix[i][j].v = 0
}
}
})
Anot(tb).bind('click', function(ev) {
Anot(tb).bind('click', ev => {
if (ev.target.nodeName === 'SPAN') {
var x = ev.target.dataset.x - 0 + 1,
y = ev.target.dataset.y - 0 + 1
let x = ev.target.dataset.x - 0 + 1
let y = ev.target.dataset.y - 0 + 1
var val =
'\n\n' +
ME.repeat('| 表头 ', x) +
'|\n' +
ME.repeat('| -- ', x) +
'|\n' +
ME.repeat(ME.repeat('| ', x) + '|\n', y)
ME.insert(vm.$editor, val, false)
layer.close(id)
let thead = `\n\n${that.repeat('| 表头 ', x)}|\n`
let pipe = `${that.repeat('| -- ', x)}|\n`
let tbody = that.repeat(that.repeat('| ', x) + '|\n', y)
that.insert(vm.$refs.editor, thead + pipe + tbody, false)
this.close()
}
})
}
})
},
image: function(elem, vm) {
var offset = Anot(elem).offset(),
wrap = ME.selection(vm.$editor) || '',
layid = layer.open({
let that = this
let offset = Anot(elem).offset()
let wrap = this.selection(vm.$refs.editor) || ''
layer.open({
type: 7,
menubar: false,
shadeClose: true,
maskClose: true,
fixed: true,
img: '',
imgAlt: wrap,
$confirm: function() {
var lvm = Anot.vmodels[layid]
if (!lvm.img || !lvm.imgAlt) {
return layer.alert('图片描述和图片地址不能为空')
insert: function() {
if (!this.img || !this.imgAlt) {
return layer.toast('链接文字和地址不能为空', 'error')
}
var val = '![' + lvm.imgAlt + '](' + lvm.img + ')'
let val = `![${this.imgAlt}](${this.img})`
ME.insert(vm.$editor, val, false)
layer.close(layid)
that.insert(vm.$refs.editor, val, false)
this.close()
},
offset: [
offset.top + 37 - ME.doc.scrollTop(),
offset.top + 40 - that.doc.scrollTop(),
'auto',
'auto',
offset.left - ME.doc.scrollLeft()
offset.left - that.doc.scrollLeft()
],
content:
'<div class="do-meditor-common do-meditor-font">' +
'<section class="input"><span class="label">图片描述</span>' +
'<input class="txt" :duplex="imgAlt" />' +
'</section>' +
'<section class="input"><span class="label">图片地址</span>' +
'<input class="txt" :duplex="img"/>' +
'</section>' +
'<section>' +
'<a href="javascript:;" class="submit" :click="$confirm">确定</a>' +
'</section>' +
'</div>'
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) {
this.link(elem, vm, false)
attach: function(elem, vm) {
this.addon.link.call(this, elem, vm, false)
},
inlinecode: function(elem, vm) {
var wrap = ME.selection(vm.$editor) || '在此输入文本',
wraped = trim(wrap, '`')
let wrap = this.selection(vm.$refs.editor) || '在此输入文本'
let wraped = trim(wrap, '`')
wrap = wrap === wraped ? '`' + wrap + '`' : wraped
ME.insert(vm.$editor, wrap, true)
this.insert(vm.$refs.editor, wrap, true)
},
blockcode: function(elem, vm) {
var layid = layer.open({
let that = this
layer.open({
type: 7,
title: '添加代码块',
$lang: [
@ -350,11 +431,11 @@ const addon = {
var val =
'\n```' + lvm.lang + '\n' + (lvm.code || '//在此输入代码') + '\n```\n'
ME.insert(vm.$editor, val, false)
that.insert(vm.$refs.editor, val, false)
layer.close(layid)
},
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>' +
'<select :duplex="lang">' +
'<option :repeat="$lang" :attr-value="el.id">{{el.name || el.id}}</option>' +
@ -384,9 +465,11 @@ const addon = {
layer.open({
type: 7,
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:
'<div class="do-meditor-about do-meditor-font">' +
'<div class="do-meditor-about do-meditor__font">' +
'<pre>' +
' __ __ _____ _ _ _\n' +
'| \\/ | ____|__| (_) |_ ___ _ __\n' +
@ -394,7 +477,7 @@ const addon = {
'| | | | |__| (_| | | || (_) | |\n' +
'|_| |_|_____\\__,_|_|\\__\\___/|_| ' +
'v' +
ME.version +
this.version +
'</pre>' +
'<p>开源在线Markdown编辑器</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])
}
})
var editorVM = []
let editorVM = []
Anot.ui.meditor = '1.0.0'
const log = console.log
//存放编辑器公共静态资源
window.ME = {
version: Anot.ui.meditor,
// 工具栏title
toolbar: {
//工具栏title
pipe: '',
h1: '标题',
quote: '引用文本',
@ -45,19 +46,19 @@ window.ME = {
fullscreen: '全屏',
about: '关于编辑器'
},
addon, //已有插件
//往文本框中插入内容
addon, // 已有插件
// 往文本框中插入内容
insert: function(dom, val, isSelect) {
if (document.selection) {
dom.focus()
var range = document.selection.createRange()
let range = document.selection.createRange()
range.text = val
dom.focus()
range.moveStart('character', -1)
} else if (dom.selectionStart || dom.selectionStart === 0) {
var startPos = dom.selectionStart,
endPos = dom.selectionEnd,
scrollTop = dom.scrollTop
let startPos = dom.selectionStart
let endPos = dom.selectionEnd
let scrollTop = dom.scrollTop
dom.value =
dom.value.slice(0, startPos) +
@ -82,15 +83,15 @@ window.ME = {
if (document.selection) {
return document.selection.createRange().text
} else {
var startPos = dom.selectionStart,
endPos = dom.selectionEnd
let startPos = dom.selectionStart
let endPos = dom.selectionEnd
if (endPos) {
//强制选择整行
if (line) {
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
startPos += 1 //把\n加上
@ -169,27 +170,24 @@ var elems = {
},
hr: '\n\n___\n\n',
a: function(str, attr, inner) {
var href = attr.match(attrExp('href')),
title = attr.match(attrExp('title')),
tar = attr.match(attrExp('target'))
let href = attr.match(attrExp('href'))
let title = attr.match(attrExp('title'))
let tar = attr.match(attrExp('target'))
let attrs = ''
href = (href && href[1]) || ''
title = (title && title[1]) || ''
href = (href && href[1]) || null
title = (title && title[1]) || null
tar = (tar && tar[1]) || '_self'
href = href === 'javascript:void(0);' ? 'javascript:;' : href
if (!href) {
return inner || href
}
return (
'[' +
(inner || href) +
'](' +
href +
' "title=' +
title +
';target=' +
tar +
'")'
)
href = href.replace('viod(0)', '')
attrs = `target=${tar}`
attrs += title ? `;title=${title}` : ''
return `[${inner || href}](${href} "${attrs}")`
},
em: function(str, attr, inner) {
return (inner && '_' + inner + '_') || ''
@ -233,7 +231,12 @@ function html2md(str) {
try {
str = decodeURIComponent(str)
} catch (err) {}
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) {
var cb = elems[i],
@ -313,7 +316,7 @@ var defaultToolbar = [
'|',
'table',
'image',
'file',
'attach',
'inlinecode',
'blockcode',
'|',
@ -330,7 +333,7 @@ function tool(name) {
return (
'<span title="' +
ME.toolbar[name] +
'" class="icon-' +
'" class="do-meditor__icon icon-' +
name +
'" ' +
(name !== 'pipe' ? ':click="onToolClick(\'' + name + '\', $event)"' : '') +
@ -340,35 +343,43 @@ function tool(name) {
Anot.component('meditor', {
render: function() {
var toolbar = (this.toolbar || defaultToolbar)
.map(function(it) {
return tool(it)
})
.join('')
let toolbar = (this.toolbar || defaultToolbar).map(it => tool(it)).join('')
delete this.toolbar
return (
'<div class="do-meditor do-meditor-font" :visible="editorVisible"' +
' :class="{fullscreen: fullscreen, preview: preview}">' +
'<div class="tool-bar do-ui-font do-fn-noselect">{toolbar}</div>' +
'<textarea ref="textarea" class="editor-body" spellcheck="false" :duplex="plainTxt" :attr="{disabled: disabled}" :on-paste="$paste($event)"></textarea>' +
'<content class="md-preview do-marked-theme" :visible="preview" :html="htmlTxt"></content>' +
'</div>'
).replace(/\{toolbar\}/g, toolbar)
return `
<div
class="do-meditor do-meditor__font"
:visible="editorVisible"
:class="{fullscreen: fullscreen, preview: preview}">
<div class="tool-bar do-fn-noselect">${toolbar}</div>
<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) {
Anot.mix(base, opt, attr)
if (base.$addons && Array.isArray(base.$addons)) {
extraAddons = base.$addons.map(function(name) {
return ME.path + '/addon/' + name
})
delete base.$addons
construct: function(props, state) {
// Anot.mix(base, opt, attr)
// if (base.$addons && Array.isArray(base.$addons)) {
// extraAddons = base.$addons.map(function(name) {
// return ME.path + '/addon/' + name
// })
// 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) {},
componentDidMount: function(vm, elem) {
@ -411,25 +422,32 @@ Anot.component('meditor', {
},
watch: {
plainTxt: function(val) {
this.$compile()
this.compile()
//只有开启实时预览,才会赋值给htmlTxt
if (this.preview) {
this.htmlTxt = this.$htmlTxt
}
this.$onUpdate(this.plainTxt, vm.$htmlTxt)
if (typeof this.props.onUpdate === 'function') {
this.props.onUpdate(this.plainTxt, this.$htmlTxt)
}
}
},
state: {
disabled: false, //禁用编辑器
fullscreen: false, //是否全屏
preview: false, //是否显示预览
$editor: null, //编辑器元素
// $editor: null, //编辑器元素
editorVisible: true,
$htmlTxt: '', //临时储存html文本
htmlTxt: '', //用于预览渲染
plainTxt: '', //纯md文本
$safelyCompile: true
},
props: {
onSuccess: Anot.PropsTypes.isFunction(),
onUpdate: Anot.PropsTypes.isFunction(),
onFullscreen: Anot.PropsTypes.isFunction()
},
methods: {
onToolClick: function(name, ev) {
if (ME.addon[name]) {
@ -438,24 +456,23 @@ Anot.component('meditor', {
console.log('%c没有对应的插件%c[%s]', 'color:#f00;', '', name)
}
},
$onSuccess: Anot.noop,
$onUpdate: Anot.noop,
$onFullscreen: Anot.noop,
$paste: function(ev) {
onPaste: function(ev) {
ev.preventDefault()
var txt = ev.clipboardData.getData('text/plain').trim(),
html = ev.clipboardData.getData('text/html').trim()
let txt = ev.clipboardData.getData('text/plain').trim()
let html = ev.clipboardData.getData('text/html').trim()
html = html2md(html)
if (html) {
ME.insert(this, html)
ME.insert(ev.target, html)
} 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() {
log(this)
var txt = this.plainTxt.trim()
if (this.$safelyCompile) {

File diff suppressed because one or more lines are too long

View File

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

View File

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