layer & meditor这2个组件增加中英语言包;meditor增加node-webkit版本;优化marked解析混合html的文本
parent
ab4ad90cd0
commit
d7d653ff0b
|
@ -86,6 +86,14 @@
|
|||
}
|
||||
&:active {background:nth($cp, 2)}
|
||||
}
|
||||
.do-meditor__input {width:100%;height:40px;padding:0 10px;background:nth($cp, 1);border:2px solid transparent;border-radius:5px;font-size:13px;@include ts();color: nth($cd, 2);
|
||||
|
||||
&.area {height:120px;padding:5px 10px;resize:none;outline:none;}
|
||||
&:focus {background:#fff;border-color:nth($cd, 2);}
|
||||
|
||||
&::-webkit-input-placeholder {color:nth($cp, 3);}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* 关于编辑器模块*/
|
||||
|
@ -128,7 +136,6 @@
|
|||
|
||||
section {width:100%;height: 40px;margin:10px 0;line-height:40px;
|
||||
|
||||
.txt {width:100%;height:40px;padding:0 10px;border:0;border-radius:5px;background:nth($cp, 1);color:nth($cd, 2);font-size:14px;}
|
||||
.label {float: left;width:50%;}
|
||||
.submit {float:right;width:30%;}
|
||||
}
|
||||
|
@ -137,16 +144,18 @@
|
|||
.do-meditor-codeblock {width:480px;height:auto;
|
||||
section {display:block;width:100%;height:auto;margin:10px 0;line-height:35px;
|
||||
|
||||
.label {float: left;width:80px;}
|
||||
select {float:left;width:200px;height:35px;padding:0 30px 0 10px;border:0;border-radius:0;border-bottom:1px solid nth($cp, 3);background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAMAAABV0m3JAAAADFBMVEUAAAD///+Pj4+JiYkxcGihAAAABHRSTlMAABBwqVQF9wAAADNJREFUeNqlzjEOACAMw8DQ/v/PSE5FFhaEx5usdekBuzRVH0RtCqJYELUFrVjQigX/5jdvzgDh9izlMQAAAABJRU5ErkJggg==) no-repeat right 12px;color:nth($cd, 2);outline:none;appearance: none;@include ts;
|
||||
|
||||
&::-ms-expand {display:none;}
|
||||
.select {position:relative;width:200px;height:35px;color:nth($cgr, 1);
|
||||
|
||||
&:focus {box-shadow:0 0 5px nth($ct, 1)}
|
||||
}
|
||||
textarea {width:100%;height:120px;padding:5px 10px;border:0;border-radius:5px;background:nth($cp, 1);font-size:14px;resize:none;outline:none;color:nth($cd, 2);
|
||||
|
||||
&:focus {box-shadow:0 0 5px nth($ct, 1)}
|
||||
select {width:100%;height:100%;padding:5px 13px;line-height:1;background:nth($cp, 1);border-radius:5px;appearance:none;border:2px solid transparent;outline:none;color: nth($cd, 2);font-size:13px;
|
||||
|
||||
&:focus {background:#fff;border-color:nth($cd, 2);}
|
||||
&::-ms-expand {display:none;}
|
||||
&:disabled {border-color:transparent;background:#fff8ed;color:nth($cp, 3)}
|
||||
}
|
||||
.trigon {position:absolute;right:7px;top:0;width:15px;height:35px;padding:7px 0;font-size:12px;text-align:center;
|
||||
i {float:left;width:15px;height:12px;line-height:12px;}
|
||||
i:nth-child(2) {margin-top:-6px;}
|
||||
}
|
||||
}
|
||||
.submit {float:right;width:80px;}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
|
||||
.section {display:block;width:100%;height:auto;margin:15px 0;line-height:35px;
|
||||
|
||||
.txt {width:100%;height:45px;padding:0 10px;border:0;border-radius:5px;background:nth($cp, 1);color:nth($cd, 2);font-size:14px;}
|
||||
.submit {float:right;width:30%;height:45px;line-height:45px;}
|
||||
}
|
||||
|
||||
|
@ -52,9 +51,8 @@
|
|||
.upload-box {width:100%;height:auto;min-height:255px;padding-top:10px;
|
||||
|
||||
.thead {width:100%;height:35px;line-height:35px;background:nth($cp, 1);}
|
||||
.thead .col {text-align:center;}
|
||||
|
||||
.col {float:left;height:30px;padding:0 5px;}
|
||||
.col {overflow:hidden;float:left;height:30px;padding:0 5px;text-align:center;}
|
||||
.col:nth-child(1) {width:50%}
|
||||
.col:nth-child(2) {width:35%}
|
||||
.col:nth-child(3) {width:15%}
|
||||
|
|
|
@ -12,6 +12,31 @@ import 'css/layer-normal.scss'
|
|||
|
||||
Anot.ui.layer = '1.0.0-normal'
|
||||
|
||||
const LANGUAGES = {
|
||||
en: {
|
||||
TITLE: 'Dialog',
|
||||
YES_BTN: 'OK',
|
||||
NO_BTN: 'Cancel',
|
||||
ERROR: 'The layer instance is not exists',
|
||||
NEED_CONTAINER: 'layer "tips" require a DOM object as container'
|
||||
},
|
||||
zh: {
|
||||
TITLE: '提示',
|
||||
YES_BTN: '确定',
|
||||
NO_BTN: '取消',
|
||||
ERROR: '要关闭的layer实例不存在',
|
||||
NEED_CONTAINER: 'tips类型需要指定一个元素节点作为容器'
|
||||
},
|
||||
'zh-TW': {
|
||||
TITLE: '提示',
|
||||
YES_BTN: '確定',
|
||||
NO_BTN: '取消',
|
||||
ERROR: '要關閉的layer實例不存在',
|
||||
NEED_CONTAINER: 'tips类型需要指定一個元素節點作爲容器'
|
||||
}
|
||||
}
|
||||
LANGUAGES['zh-CN'] = LANGUAGES.zh
|
||||
const lang = LANGUAGES[Anot.language || navigator.language || 'en']
|
||||
let layerDom = {}
|
||||
let layerObj = {}
|
||||
let unique = null // 储存当前打开的1/2/3类型的弹窗
|
||||
|
@ -24,13 +49,13 @@ let defconf = {
|
|||
maskColor: null, // 遮罩背景色
|
||||
radius: '0px', // 弹窗圆角半径
|
||||
area: ['auto', 'auto'],
|
||||
title: '提示', // 弹窗主标题(在工具栏上的)
|
||||
title: lang.TITLE, // 弹窗主标题(在工具栏上的)
|
||||
menubar: true, // 是否显示菜单栏
|
||||
content: '', // 弹窗的内容
|
||||
fixed: false, // 是否固定不可拖拽
|
||||
shift: 'cc', // 弹窗出来的初始位置,用于出场动画
|
||||
offset: [], // 弹窗出来后的坐标, 为数组,可有4个值,依次是 上右下左
|
||||
btns: ['确定', '取消'] // 弹窗的2个按钮的文字
|
||||
btns: [lang.YES_BTN, lang.NO_BTN] // 弹窗的2个按钮的文字
|
||||
}
|
||||
const $doc = Anot(document)
|
||||
const uuid = function() {
|
||||
|
@ -38,7 +63,7 @@ const uuid = function() {
|
|||
}
|
||||
const close = function(id) {
|
||||
if (typeof id !== 'string' && typeof id !== 'number') {
|
||||
return Anot.error('要关闭的layer实例不存在')
|
||||
return Anot.error(lang.ERROR)
|
||||
}
|
||||
if (/^layerwrap\-/.test(id) || layerObj['layerwrap-' + id]) {
|
||||
try {
|
||||
|
@ -626,7 +651,7 @@ const _layer = {
|
|||
},
|
||||
tips(content, container, opt = {}) {
|
||||
if (!(container instanceof HTMLElement)) {
|
||||
return Anot.error('layer "tips" require a DOM object')
|
||||
return Anot.error(lang.NEED_CONTAINER)
|
||||
}
|
||||
|
||||
if (!opt.background) {
|
||||
|
@ -669,7 +694,7 @@ const _layer = {
|
|||
if (typeof opt === 'string') {
|
||||
opt = 'layerwrap-' + opt
|
||||
if (!layerObj[opt]) {
|
||||
throw new Error('layer实例不存在')
|
||||
throw new Error(lang.ERROR)
|
||||
} else {
|
||||
//只能显示一个实例
|
||||
if (layerObj[opt].show) {
|
||||
|
@ -813,7 +838,6 @@ Anot.directive('layer', {
|
|||
tips.style.visibility = 'hidden'
|
||||
}, 100)
|
||||
})
|
||||
// _layer.tips(val, this.element)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -726,7 +726,9 @@ InlineLexer.prototype.output = function(src) {
|
|||
// br
|
||||
if ((cap = this.rules.br.exec(src))) {
|
||||
src = src.substring(cap[0].length)
|
||||
out += this.renderer.br()
|
||||
if (!/<[\/]?([a-z0-9\-])+[^>]*>/.test(src)) {
|
||||
out += this.renderer.br()
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -921,25 +923,24 @@ Renderer.prototype.listitem = function(text) {
|
|||
}
|
||||
|
||||
Renderer.prototype.paragraph = function(text) {
|
||||
text = text.replace(/<br>/g, '').replace(/<p><\/p>/g, '')
|
||||
return '<p>' + text + '</p>'
|
||||
}
|
||||
|
||||
Renderer.prototype.table = function(header, body) {
|
||||
return (
|
||||
'<table>\n' +
|
||||
'<thead>\n' +
|
||||
'<table>' +
|
||||
'<thead>' +
|
||||
header +
|
||||
'</thead>\n' +
|
||||
'<tbody>\n' +
|
||||
'</thead>' +
|
||||
'<tbody>' +
|
||||
body +
|
||||
'</tbody>\n' +
|
||||
'</table>\n'
|
||||
'</tbody>' +
|
||||
'</table>'
|
||||
)
|
||||
}
|
||||
|
||||
Renderer.prototype.tablerow = function(content) {
|
||||
return '<tr>\n' + content + '</tr>\n'
|
||||
return '<tr>' + content + '</tr>'
|
||||
}
|
||||
|
||||
Renderer.prototype.tablecell = function(content, flags) {
|
||||
|
@ -947,7 +948,7 @@ Renderer.prototype.tablecell = function(content, flags) {
|
|||
var tag = flags.align
|
||||
? '<' + type + ' style="text-align:' + flags.align + '">'
|
||||
: '<' + type + '>'
|
||||
return tag + content + '</' + type + '>\n'
|
||||
return tag + content + '</' + type + '>'
|
||||
}
|
||||
|
||||
// span level renderer
|
||||
|
@ -1016,7 +1017,7 @@ Renderer.prototype.image = function(href, title, text) {
|
|||
}
|
||||
|
||||
Renderer.prototype.text = function(text) {
|
||||
return text.trim()
|
||||
return text
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,371 @@
|
|||
/**
|
||||
*
|
||||
* @authors yutent (yutent@doui.cc)
|
||||
* @date 2017-04-19 21:17:26
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
import '../../layer/index'
|
||||
import 'css/meditor__attach.scss'
|
||||
|
||||
const $doc = Anot(document)
|
||||
const LANGUAGES = {
|
||||
zh: {
|
||||
IMAGE: {
|
||||
REMOTE: '远程图片',
|
||||
LOCAL: '本地上传',
|
||||
MANAGE: '图片管理',
|
||||
ALT: '图片描述',
|
||||
ADDRESS: '图片地址'
|
||||
},
|
||||
FILE: {
|
||||
REMOTE: '远程附件',
|
||||
LOCAL: '本地上传',
|
||||
MANAGE: '附件管理',
|
||||
ALT: '附件描述',
|
||||
ADDRESS: '附件地址'
|
||||
},
|
||||
BTN: '确定',
|
||||
INSERT: '插入',
|
||||
CHOOSE: '选择文件',
|
||||
LIMIT: '上传大小限制:单文件最大 ',
|
||||
SCREENSHOT: '截图',
|
||||
COMPRESS: '截图处理中...',
|
||||
TABLE: {
|
||||
NAME: '文件名',
|
||||
PROGRESS: '上传进度',
|
||||
HANDLE: '操作'
|
||||
},
|
||||
ERROR: {
|
||||
TYPE: '文件类型错误',
|
||||
SIZE: '文件体积过大',
|
||||
EMPTY: '描述和地址不能为空',
|
||||
UNDEFINED: '在node-webkit中saveAttach回调必须定义'
|
||||
}
|
||||
},
|
||||
en: {
|
||||
IMAGE: {
|
||||
REMOTE: 'Remote image',
|
||||
LOCAL: 'Local image',
|
||||
MANAGE: 'Manage',
|
||||
ALT: 'Image alt text',
|
||||
ADDRESS: 'Image address'
|
||||
},
|
||||
FILE: {
|
||||
REMOTE: 'Remote file',
|
||||
LOCAL: 'Local file',
|
||||
MANAGE: 'Manage',
|
||||
ALT: 'File alt text',
|
||||
ADDRESS: 'File address'
|
||||
},
|
||||
BTN: 'OK',
|
||||
INSERT: 'insert',
|
||||
CHOOSE: 'Choose file',
|
||||
LIMIT: 'Size of upload file limit to ',
|
||||
SCREENSHOT: 'screenshot',
|
||||
COMPRESS: 'Screenshot compressing...',
|
||||
TABLE: {
|
||||
NAME: 'name',
|
||||
PROGRESS: 'progress',
|
||||
HANDLE: 'handle'
|
||||
},
|
||||
ERROR: {
|
||||
TYPE: 'Forbidden type',
|
||||
SIZE: 'Too large',
|
||||
EMPTY: 'Alt text and address can not be null',
|
||||
UNDEFINED: 'Function saveAttach is not defined'
|
||||
}
|
||||
}
|
||||
}
|
||||
LANGUAGES['zh-CN'] = LANGUAGES.zh
|
||||
LANGUAGES['zh-TW'] = LANGUAGES.zh
|
||||
const lang = LANGUAGES[Anot.language || navigator.language || 'en']
|
||||
|
||||
const fixCont = function(vm, tool) {
|
||||
let limit = false
|
||||
if (vm.props.uploadSizeLimit) {
|
||||
limit = (vm.props.uploadSizeLimit / (1024 * 1024)).toFixed(2)
|
||||
}
|
||||
return `
|
||||
<dl class="do-meditor-attach">
|
||||
<dt class="tab-box" :drag="do-layer" data-limit="window">
|
||||
<span class="item" :class="active:tab === 1" :click="switchTab(1)">
|
||||
${lang[tool].REMOTE}
|
||||
</span>
|
||||
<span class="item" :class="active:tab === 2" :click="switchTab(2)">
|
||||
${lang[tool].LOCAL}
|
||||
</span>
|
||||
<span class="item" :class="active:tab === 3" :click="switchTab(3)">
|
||||
${lang[tool].MANAGE}
|
||||
</span>
|
||||
</dt>
|
||||
<dd class="cont-box">
|
||||
<div class="remote" :visible="tab === 1">
|
||||
<section class="section do-fn-cl">
|
||||
<input
|
||||
class="do-meditor__input"
|
||||
:duplex="attachAlt"
|
||||
placeholder="${lang[tool].ALT}" />
|
||||
</section>
|
||||
<section class="section do-fn-cl">
|
||||
<input
|
||||
class="do-meditor__input"
|
||||
:duplex="attach"
|
||||
placeholder="${lang[tool].ADDRESS}" />
|
||||
</section>
|
||||
<section class="section do-fn-cl">
|
||||
<a
|
||||
href="javascript:;"
|
||||
class="do-meditor__button submit"
|
||||
:click="confirm">${lang.BTN}</a>
|
||||
</section>
|
||||
</div>
|
||||
<div class="local" :visible="tab === 2">
|
||||
<div class="select-file">
|
||||
<input ref="attach" multiple :change="change" type="file" class="hide" />
|
||||
<span class="file" :click="select">${lang.CHOOSE}</span>
|
||||
${limit ? `<span class="tips">(${lang.LIMIT + limit} MB)</span>` : ''}
|
||||
</div>
|
||||
<ul class="upload-box">
|
||||
<li class="thead">
|
||||
<span class="col">${lang.TABLE.NAME}</span>
|
||||
<span class="col">${lang.TABLE.PROGRESS}</span>
|
||||
<span class="col">${lang.TABLE.HANDLE}</span>
|
||||
</li>
|
||||
<li class="tbody">
|
||||
<p :for="uploadQueue">
|
||||
<span
|
||||
class="col do-fn-ell"
|
||||
:text="el.name"
|
||||
:layer-tips="el.name"></span>
|
||||
<span class="col" :html="el.progress"></span>
|
||||
<span class="col"><a class="insert" :click="insert(el)">${
|
||||
lang.INSERT
|
||||
}</a></span>
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="manager" :visible="tab === 3">
|
||||
<ul class="list-box">
|
||||
<li
|
||||
class="item"
|
||||
:for="attachList"
|
||||
:layer-tips="el.name"
|
||||
:click="insert(el)">
|
||||
|
||||
<span class="thumb" :html="el.thumb"></span>
|
||||
<p class="name" :text="el.name"></p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</dd>
|
||||
</dl>`
|
||||
}
|
||||
|
||||
/**
|
||||
* [uploadFile 文件上传]
|
||||
* @param {[type]} vm [vm对象]
|
||||
* @param {[type]} tool [image/file]
|
||||
*/
|
||||
function uploadFile(vm, tool) {
|
||||
for (let it of this.files) {
|
||||
let ext = it.name.slice(it.name.lastIndexOf('.'))
|
||||
if (tool === 'IMAGE' && !/^\.(jpg|jpeg|png|gif|bmp|webp|ico)$/.test(ext)) {
|
||||
this.uploadQueue.push({
|
||||
name: it.name,
|
||||
progress: '<span class="red">0%(' + lang.ERROR.TYPE + ')</span>',
|
||||
url: ''
|
||||
})
|
||||
continue
|
||||
}
|
||||
if (vm.props.uploadSizeLimit && it.size > vm.props.uploadSizeLimit) {
|
||||
this.uploadQueue.push({
|
||||
name: it.name,
|
||||
progress: '<span class="red">0%(' + lang.ERROR.SIZE + ')</span>',
|
||||
url: ''
|
||||
})
|
||||
continue
|
||||
}
|
||||
let fixName = new Date().format('YmdHis') + ext
|
||||
let attach = { name: it.name, fixName, progress: '100%', url: '' }
|
||||
|
||||
if (vm.props.saveAttach) {
|
||||
vm.props
|
||||
.saveAttach(attach, it)
|
||||
.then(url => {
|
||||
attach.url = url
|
||||
this.uploadQueue.push(attach)
|
||||
})
|
||||
.catch(err => {
|
||||
Anot.error(err)
|
||||
})
|
||||
} else {
|
||||
layer.toast(lang.ERROR.UNDEFINED, 'error')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function uploadScreenshot(vm, blob) {
|
||||
let name = new Date().format('YmdHis') + '.jpg'
|
||||
let attach = { name, url: '' }
|
||||
|
||||
if (vm.props.saveAttach) {
|
||||
vm.props
|
||||
.saveAttach(attach, blob)
|
||||
.then(url => {
|
||||
vm.insert(`![${lang.SCREENSHOT}](${url})`)
|
||||
})
|
||||
.catch(err => {
|
||||
Anot.error(err)
|
||||
})
|
||||
} else {
|
||||
layer.toast(lang.ERROR.UNDEFINED, 'error')
|
||||
}
|
||||
}
|
||||
|
||||
function showDialog(elem, vm, tool) {
|
||||
let offset = Anot(elem).offset()
|
||||
|
||||
layer.open({
|
||||
type: 7,
|
||||
menubar: false,
|
||||
fixed: true,
|
||||
maskClose: true,
|
||||
offset: [offset.top + 35 - $doc.scrollTop()],
|
||||
shift: {
|
||||
top: offset.top - $doc.scrollTop()
|
||||
},
|
||||
tab: 2,
|
||||
attach: '',
|
||||
attachAlt: '',
|
||||
uploadQueue: [], //当前上传的列表
|
||||
attachList: [], //附件管理列表
|
||||
switchTab(id) {
|
||||
this.tab = id
|
||||
if (id === 3) {
|
||||
this.attachList.clear()
|
||||
if (vm.props.getAttachList) {
|
||||
vm.props
|
||||
.getAttachList(tool)
|
||||
.then(list => {
|
||||
list.forEach(it => {
|
||||
let ext = it.name.slice(it.name.lastIndexOf('.'))
|
||||
it.isImage = /^\.(jpg|jpeg|png|gif|bmp|webp|ico)$/.test(ext)
|
||||
it.thumb = it.isImage
|
||||
? `<img src="${it.url}" />`
|
||||
: `<em class="do-icon-txt"></em>`
|
||||
})
|
||||
return list
|
||||
})
|
||||
.then(list => {
|
||||
list = list.filter(it => {
|
||||
if (tool === 'IMAGE') {
|
||||
return it.isImage
|
||||
}
|
||||
return true
|
||||
})
|
||||
this.attachList = list
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
select() {
|
||||
let ev = document.createEvent('MouseEvent')
|
||||
ev.initEvent('click', false, false)
|
||||
this.$refs.attach.dispatchEvent(ev)
|
||||
},
|
||||
change(ev) {
|
||||
this.files = ev.target.files
|
||||
uploadFile.call(this, vm, tool)
|
||||
},
|
||||
insert: function(it) {
|
||||
if (!it.url) {
|
||||
return
|
||||
}
|
||||
let val = `\n${tool === 'IMAGE' ? '!' : ''}[${it.name}](${it.url})`
|
||||
vm.insert(val)
|
||||
},
|
||||
confirm: function() {
|
||||
if (!this.attach || !this.attachAlt) {
|
||||
return layer.toast(lang.ERROR.EMPTY, 'error')
|
||||
}
|
||||
let val = `\n${tool === 'IMAGE' ? '!' : ''}[${this.attachAlt}](${
|
||||
this.attach
|
||||
})`
|
||||
|
||||
vm.insert(val)
|
||||
this.close()
|
||||
},
|
||||
content: fixCont(vm, tool)
|
||||
})
|
||||
}
|
||||
|
||||
const plugin = {
|
||||
__init__(ME) {
|
||||
Object.assign(ME.vm.addon, {
|
||||
attach(elem) {
|
||||
showDialog(elem, this, 'FILE')
|
||||
},
|
||||
image(elem) {
|
||||
showDialog(elem, this, 'IMAGE')
|
||||
}
|
||||
})
|
||||
|
||||
ME.vm.$refs.editor.addEventListener('paste', function(ev) {
|
||||
ev.preventDefault()
|
||||
let txt = ev.clipboardData.getData('text/plain')
|
||||
|
||||
//文本类型直接默认处理
|
||||
if (txt) {
|
||||
return
|
||||
}
|
||||
|
||||
if (ev.clipboardData.items) {
|
||||
let items = ev.clipboardData.items
|
||||
let len = items.length
|
||||
let blob = null
|
||||
|
||||
for (let it of items) {
|
||||
if (it.type.indexOf('image') > -1) {
|
||||
blob = it.getAsFile()
|
||||
}
|
||||
}
|
||||
|
||||
if (blob !== null) {
|
||||
layer.toast(lang.COMPRESS)
|
||||
// 压缩截图,避免文件过大
|
||||
let reader = new FileReader()
|
||||
reader.onload = function() {
|
||||
let img = document.createElement('img')
|
||||
let canvas = document.createElement('canvas')
|
||||
|
||||
img.onload = function() {
|
||||
canvas.width = img.width
|
||||
canvas.height = img.height
|
||||
|
||||
let ctx = canvas.getContext('2d')
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
||||
ctx.drawImage(this, 0, 0, canvas.width, canvas.height)
|
||||
|
||||
canvas.toBlob(
|
||||
obj => {
|
||||
uploadScreenshot(ME.vm, obj)
|
||||
},
|
||||
'image/jpeg',
|
||||
0.8
|
||||
)
|
||||
}
|
||||
img.src = this.result
|
||||
}
|
||||
reader.readAsDataURL(blob)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default plugin
|
|
@ -11,10 +11,75 @@ import '../../layer/index'
|
|||
import 'css/meditor__attach.scss'
|
||||
|
||||
const $doc = Anot(document)
|
||||
const LANG = {
|
||||
image: ['远程图片', '图片管理', '图片描述', '图片地址'],
|
||||
file: ['远程附件', '附件管理', '附件描述', '附件地址']
|
||||
const LANGUAGES = {
|
||||
zh: {
|
||||
IMAGE: {
|
||||
REMOTE: '远程图片',
|
||||
LOCAL: '本地上传',
|
||||
MANAGE: '图片管理',
|
||||
ALT: '图片描述',
|
||||
ADDRESS: '图片地址'
|
||||
},
|
||||
FILE: {
|
||||
REMOTE: '远程附件',
|
||||
LOCAL: '本地上传',
|
||||
MANAGE: '附件管理',
|
||||
ALT: '附件描述',
|
||||
ADDRESS: '附件地址'
|
||||
},
|
||||
BTN: '确定',
|
||||
INSERT: '插入',
|
||||
CHOOSE: '选择文件',
|
||||
LIMIT: '上传大小限制:单文件最大 ',
|
||||
SCREENSHOT: '截图',
|
||||
COMPRESS: '截图处理中...',
|
||||
TABLE: {
|
||||
NAME: '文件名',
|
||||
PROGRESS: '上传进度',
|
||||
HANDLE: '操作'
|
||||
},
|
||||
ERROR: {
|
||||
TYPE: '文件类型错误',
|
||||
SIZE: '文件体积过大',
|
||||
EMPTY: '描述和地址不能为空'
|
||||
}
|
||||
},
|
||||
en: {
|
||||
IMAGE: {
|
||||
REMOTE: 'Remote image',
|
||||
LOCAL: 'Local image',
|
||||
MANAGE: 'Manage',
|
||||
ALT: 'Image alt text',
|
||||
ADDRESS: 'Image address'
|
||||
},
|
||||
FILE: {
|
||||
REMOTE: 'Remote file',
|
||||
LOCAL: 'Local file',
|
||||
MANAGE: 'Manage',
|
||||
ALT: 'File alt text',
|
||||
ADDRESS: 'File address'
|
||||
},
|
||||
BTN: 'OK',
|
||||
INSERT: 'insert',
|
||||
CHOOSE: 'Choose file',
|
||||
LIMIT: 'Size of upload file limit to ',
|
||||
SCREENSHOT: 'screenshot',
|
||||
COMPRESS: 'Screenshot compressing...',
|
||||
TABLE: {
|
||||
NAME: 'name',
|
||||
PROGRESS: 'progress',
|
||||
HANDLE: 'handle'
|
||||
},
|
||||
ERROR: {
|
||||
TYPE: 'Forbidden type',
|
||||
SIZE: 'Too large',
|
||||
EMPTY: 'Alt text and address can not be null'
|
||||
}
|
||||
}
|
||||
}
|
||||
LANGUAGES['zh-CN'] = LANGUAGES.zh
|
||||
LANGUAGES['zh-TW'] = LANGUAGES.zh
|
||||
const lang = LANGUAGES[Anot.language || navigator.language || 'en']
|
||||
|
||||
class Uploader {
|
||||
constructor(url) {
|
||||
|
@ -77,49 +142,47 @@ const fixCont = function(vm, tool) {
|
|||
<dl class="do-meditor-attach">
|
||||
<dt class="tab-box" :drag="do-layer" data-limit="window">
|
||||
<span class="item" :class="active:tab === 1" :click="switchTab(1)">
|
||||
${LANG[tool][0]}
|
||||
${lang[tool].REMOTE}
|
||||
</span>
|
||||
<span class="item" :class="active:tab === 2" :click="switchTab(2)">
|
||||
${lang[tool].LOCAL}
|
||||
</span>
|
||||
<span class="item" :class="active:tab === 2" :click="switchTab(2)">本地上传</span>
|
||||
<span class="item" :class="active:tab === 3" :click="switchTab(3)">
|
||||
${LANG[tool][1]}
|
||||
${lang[tool].MANAGE}
|
||||
</span>
|
||||
</dt>
|
||||
<dd class="cont-box">
|
||||
<div class="remote" :visible="tab === 1">
|
||||
<section class="section do-fn-cl">
|
||||
<input
|
||||
class="txt"
|
||||
class="do-meditor__input"
|
||||
:duplex="attachAlt"
|
||||
placeholder="${LANG[tool][2]}" />
|
||||
placeholder="${lang[tool].ALT}" />
|
||||
</section>
|
||||
<section class="section do-fn-cl">
|
||||
<input
|
||||
class="txt"
|
||||
class="do-meditor__input"
|
||||
:duplex="attach"
|
||||
placeholder="${LANG[tool][3]}" />
|
||||
placeholder="${lang[tool].ADDRESS}" />
|
||||
</section>
|
||||
<section class="section do-fn-cl">
|
||||
<a
|
||||
href="javascript:;"
|
||||
class="do-meditor__button submit"
|
||||
:click="confirm">确定</a>
|
||||
:click="confirm">${lang.BTN}</a>
|
||||
</section>
|
||||
</div>
|
||||
<div class="local" :visible="tab === 2">
|
||||
<div class="select-file">
|
||||
<input ref="attach" multiple :change="change" type="file" class="hide" />
|
||||
<span class="file" :click="select">选择文件</span>
|
||||
${
|
||||
limit
|
||||
? `<span class="tips">(上传大小限制:单文件最大${limit} MB)</span>`
|
||||
: ''
|
||||
}
|
||||
<span class="file" :click="select">${lang.CHOOSE}</span>
|
||||
${limit ? `<span class="tips">(${lang.LIMIT + limit} MB)</span>` : ''}
|
||||
</div>
|
||||
<ul class="upload-box">
|
||||
<li class="thead">
|
||||
<span class="col">文件名</span>
|
||||
<span class="col">上传进度</span>
|
||||
<span class="col">操作</span>
|
||||
<span class="col">${lang.TABLE.NAME}</span>
|
||||
<span class="col">${lang.TABLE.PROGRESS}</span>
|
||||
<span class="col">${lang.TABLE.HANDLE}</span>
|
||||
</li>
|
||||
<li class="tbody">
|
||||
<p :for="uploadQueue">
|
||||
|
@ -128,7 +191,9 @@ const fixCont = function(vm, tool) {
|
|||
:text="el.name"
|
||||
:layer-tips="el.name"></span>
|
||||
<span class="col" :html="el.progress"></span>
|
||||
<span class="col"><a class="insert" :click="insert(el)">插入</a></span>
|
||||
<span class="col"><a class="insert" :click="insert(el)">${
|
||||
lang.INSERT
|
||||
}</a></span>
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
@ -159,10 +224,10 @@ const fixCont = function(vm, tool) {
|
|||
function uploadFile(vm, tool) {
|
||||
for (let it of this.files) {
|
||||
let ext = it.name.slice(it.name.lastIndexOf('.'))
|
||||
if (tool === 'image' && !/^\.(jpg|jpeg|png|gif|bmp|webp|ico)$/.test(ext)) {
|
||||
if (tool === 'IMAGE' && !/^\.(jpg|jpeg|png|gif|bmp|webp|ico)$/.test(ext)) {
|
||||
this.uploadQueue.push({
|
||||
name: it.name,
|
||||
progress: '<span class="red">0%(文件类型错误)</span>',
|
||||
progress: '<span class="red">0%(' + lang.ERROR.TYPE + ')</span>',
|
||||
url: ''
|
||||
})
|
||||
continue
|
||||
|
@ -170,7 +235,7 @@ function uploadFile(vm, tool) {
|
|||
if (vm.props.uploadSizeLimit && it.size > vm.props.uploadSizeLimit) {
|
||||
this.uploadQueue.push({
|
||||
name: it.name,
|
||||
progress: '<span class="red">0%(文件体积过大)</span>',
|
||||
progress: '<span class="red">0%(' + lang.ERROR.SIZE + ')</span>',
|
||||
url: ''
|
||||
})
|
||||
continue
|
||||
|
@ -250,7 +315,7 @@ function uploadScreenshot(vm, blob) {
|
|||
})
|
||||
})
|
||||
.then(url => {
|
||||
vm.insert(`![截图](${url})`)
|
||||
vm.insert(`![${lang.SCREENSHOT}](${url})`)
|
||||
})
|
||||
.catch(err => {
|
||||
Anot.error(err)
|
||||
|
@ -265,7 +330,7 @@ function uploadScreenshot(vm, blob) {
|
|||
}
|
||||
})
|
||||
.then(url => {
|
||||
vm.insert(`![截图](${url})`)
|
||||
vm.insert(`![${lang.SCREENSHOT}](${url})`)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -306,7 +371,7 @@ function showDialog(elem, vm, tool) {
|
|||
})
|
||||
.then(list => {
|
||||
list = list.filter(it => {
|
||||
if (tool === 'image') {
|
||||
if (tool === 'IMAGE') {
|
||||
return it.isImage
|
||||
}
|
||||
return true
|
||||
|
@ -329,14 +394,14 @@ function showDialog(elem, vm, tool) {
|
|||
if (!it.url) {
|
||||
return
|
||||
}
|
||||
let val = `\n${tool === 'image' ? '!' : ''}[${it.name}](${it.url})`
|
||||
let val = `\n${tool === 'IMAGE' ? '!' : ''}[${it.name}](${it.url})`
|
||||
vm.insert(val)
|
||||
},
|
||||
confirm: function() {
|
||||
if (!this.attach || !this.attachAlt) {
|
||||
return layer.toast('描述和地址不能为空', 'error')
|
||||
return layer.toast(lang.ERROR.EMPTY, 'error')
|
||||
}
|
||||
let val = `\n${tool === 'image' ? '!' : ''}[${this.attachAlt}](${
|
||||
let val = `\n${tool === 'IMAGE' ? '!' : ''}[${this.attachAlt}](${
|
||||
this.attach
|
||||
})`
|
||||
|
||||
|
@ -351,10 +416,10 @@ const plugin = {
|
|||
__init__(ME) {
|
||||
Object.assign(ME.vm.addon, {
|
||||
attach(elem) {
|
||||
showDialog(elem, this, 'file')
|
||||
showDialog(elem, this, 'FILE')
|
||||
},
|
||||
image(elem) {
|
||||
showDialog(elem, this, 'image')
|
||||
showDialog(elem, this, 'IMAGE')
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -379,7 +444,7 @@ const plugin = {
|
|||
}
|
||||
|
||||
if (blob !== null) {
|
||||
layer.toast('截图处理中...')
|
||||
layer.toast(lang.COMPRESS)
|
||||
// 压缩截图,避免文件过大
|
||||
let reader = new FileReader()
|
||||
reader.onload = function() {
|
||||
|
@ -394,7 +459,7 @@ const plugin = {
|
|||
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
||||
ctx.drawImage(this, 0, 0, canvas.width, canvas.height)
|
||||
|
||||
// 目前 IE和Safari的toBlob方法还不支持图片质量的设定
|
||||
// chrome, Firefox, 以及支持toBlob 设置图片质量
|
||||
if (canvas.toBlob && (window.chrome || window.sidebar)) {
|
||||
canvas.toBlob(
|
||||
function(obj) {
|
||||
|
@ -404,6 +469,8 @@ const plugin = {
|
|||
0.8
|
||||
)
|
||||
} else {
|
||||
// IE和Safari的toBlob方法还不支持图片质量的设定
|
||||
// 需要先转base64再转回Blob
|
||||
let base64 = canvas.toDataURL('image/jpeg', 0.8)
|
||||
let buf = atob(base64.split(',')[1])
|
||||
let intArr = new Uint8Array(buf.length)
|
||||
|
|
|
@ -21,12 +21,11 @@ function trim(str, sign) {
|
|||
}
|
||||
|
||||
const $doc = Anot(document)
|
||||
|
||||
const addon = {
|
||||
h1: function(elem) {
|
||||
let that = this
|
||||
let offset = Anot(elem).offset()
|
||||
let wrap = this.selection(true) || '在此输入文本'
|
||||
let wrap = this.selection(true) || Anot.ui.meditor.lang.PLACEHOLDER
|
||||
layer.open({
|
||||
type: 7,
|
||||
menubar: false,
|
||||
|
@ -49,23 +48,35 @@ const addon = {
|
|||
},
|
||||
content: `
|
||||
<ul class="do-meditor-h1 do-fn-noselect">
|
||||
<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>
|
||||
<li :click="insert(1)" class="h1"><i class="do-meditor__icon icon-h1"></i>${
|
||||
Anot.ui.meditor.lang.HEADERS.H1
|
||||
}</li>
|
||||
<li :click="insert(2)" class="h2"><i class="do-meditor__icon icon-h2"></i>${
|
||||
Anot.ui.meditor.lang.HEADERS.H2
|
||||
}</li>
|
||||
<li :click="insert(3)" class="h3"><i class="do-meditor__icon icon-h3"></i>${
|
||||
Anot.ui.meditor.lang.HEADERS.H3
|
||||
}</li>
|
||||
<li :click="insert(4)" class="h4"><i class="do-meditor__icon icon-h4"></i>${
|
||||
Anot.ui.meditor.lang.HEADERS.H4
|
||||
}</li>
|
||||
<li :click="insert(5)" class="h5"><i class="do-meditor__icon icon-h5"></i>${
|
||||
Anot.ui.meditor.lang.HEADERS.H5
|
||||
}</li>
|
||||
<li :click="insert(6)" class="h6"><i class="do-meditor__icon icon-h6"></i>${
|
||||
Anot.ui.meditor.lang.HEADERS.H6
|
||||
}</li>
|
||||
</ul>`
|
||||
})
|
||||
},
|
||||
quote: function(elem) {
|
||||
let wrap = this.selection() || '在此输入文本'
|
||||
let wrap = this.selection() || Anot.ui.meditor.lang.PLACEHOLDER
|
||||
wrap = '> ' + wrap
|
||||
|
||||
this.insert(wrap, true)
|
||||
},
|
||||
bold: function(elem) {
|
||||
let wrap = this.selection() || '在此输入文本'
|
||||
let wrap = this.selection() || Anot.ui.meditor.lang.PLACEHOLDER
|
||||
let wraped = trim(wrap, '\\*\\*')
|
||||
|
||||
wrap = wrap === wraped ? '**' + wrap + '**' : wraped
|
||||
|
@ -73,7 +84,7 @@ const addon = {
|
|||
this.insert(wrap, true)
|
||||
},
|
||||
italic: function(elem) {
|
||||
let wrap = this.selection() || '在此输入文本'
|
||||
let wrap = this.selection() || Anot.ui.meditor.lang.PLACEHOLDER
|
||||
let wraped = trim(wrap, '_')
|
||||
|
||||
wrap = wrap === wraped ? '_' + wrap + '_' : wraped
|
||||
|
@ -81,7 +92,7 @@ const addon = {
|
|||
this.insert(wrap, true)
|
||||
},
|
||||
through: function(elem) {
|
||||
let wrap = this.selection() || '在此输入文本'
|
||||
let wrap = this.selection() || Anot.ui.meditor.lang.PLACEHOLDER
|
||||
let wraped = trim(wrap, '~~')
|
||||
|
||||
wrap = wrap === wraped ? '~~' + wrap + '~~' : wraped
|
||||
|
@ -89,13 +100,13 @@ const addon = {
|
|||
this.insert(wrap, true)
|
||||
},
|
||||
unordered: function(elem) {
|
||||
let wrap = this.selection() || '在此输入文本'
|
||||
let wrap = this.selection() || Anot.ui.meditor.lang.PLACEHOLDER
|
||||
wrap = '* ' + wrap
|
||||
|
||||
this.insert(wrap, false)
|
||||
},
|
||||
ordered: function(elem) {
|
||||
let wrap = this.selection() || '在此输入文本'
|
||||
let wrap = this.selection() || Anot.ui.meditor.lang.PLACEHOLDER
|
||||
wrap = '1. ' + wrap
|
||||
|
||||
this.insert(wrap, false)
|
||||
|
@ -118,7 +129,7 @@ const addon = {
|
|||
linkTarget: 1,
|
||||
insert: function() {
|
||||
if (!this.link || !this.linkName) {
|
||||
return layer.toast('链接文字和地址不能为空', 'error')
|
||||
return layer.toast(Anot.ui.meditor.lang.LINK.ERROR, 'error')
|
||||
}
|
||||
let val = `[${this.linkName}](${this.link} ${
|
||||
this.linkTarget === 1 ? ' "target=_blank"' : ''
|
||||
|
@ -140,10 +151,14 @@ const addon = {
|
|||
content: `
|
||||
<div class="do-meditor-common">
|
||||
<section>
|
||||
<input class="txt" :duplex="linkName" placeholder="链接文字"/>
|
||||
<input class="do-meditor__input" :duplex="linkName" placeholder="${
|
||||
Anot.ui.meditor.lang.LINK.ALT
|
||||
}"/>
|
||||
</section>
|
||||
<section>
|
||||
<input class="txt" :duplex="link" placeholder="链接地址"/>
|
||||
<input class="do-meditor__input" :duplex="link" placeholder="${
|
||||
Anot.ui.meditor.lang.LINK.URL
|
||||
}"/>
|
||||
</section>
|
||||
<section>
|
||||
<label class="label">
|
||||
|
@ -153,7 +168,7 @@ const addon = {
|
|||
class="radio"
|
||||
:duplex-number="linkTarget"
|
||||
value="1"/>
|
||||
新窗口打开
|
||||
${Anot.ui.meditor.lang.TARGET.BLANK}
|
||||
</label>
|
||||
<label class="label">
|
||||
<input
|
||||
|
@ -162,14 +177,14 @@ const addon = {
|
|||
class="radio"
|
||||
:duplex-number="linkTarget"
|
||||
value="2"/>
|
||||
本窗口打开
|
||||
${Anot.ui.meditor.lang.TARGET.SELF}
|
||||
</label>
|
||||
</section>
|
||||
<section>
|
||||
<a
|
||||
href="javascript:;"
|
||||
class="do-meditor__button submit"
|
||||
:click="insert">确定</a>
|
||||
:click="insert">${Anot.ui.meditor.lang.BTN.YES}</a>
|
||||
</section>
|
||||
</div>`
|
||||
})
|
||||
|
@ -183,7 +198,7 @@ const addon = {
|
|||
|
||||
layer.open({
|
||||
type: 7,
|
||||
title: '插入表情',
|
||||
title: Anot.ui.meditor.lang.LAYER.FACE_TITLE,
|
||||
fixed: true,
|
||||
maskClose: true,
|
||||
arr: [
|
||||
|
@ -251,7 +266,9 @@ const addon = {
|
|||
|
||||
layer.open({
|
||||
type: 7,
|
||||
title: '0行 x 0列',
|
||||
title: `0 ${Anot.ui.meditor.lang.TABLE.ROW} x 0 ${
|
||||
Anot.ui.meditor.lang.TABLE.COLUMN
|
||||
}`,
|
||||
fixed: true,
|
||||
maskClose: true,
|
||||
offset: [
|
||||
|
@ -279,6 +296,7 @@ const addon = {
|
|||
success: function() {
|
||||
let tb = this.$refs.table
|
||||
let lastx, lasty
|
||||
let { lang } = Anot.ui.meditor
|
||||
|
||||
Anot(tb).bind('mousemove', ev => {
|
||||
if (ev.target.nodeName === 'SPAN') {
|
||||
|
@ -289,7 +307,9 @@ const addon = {
|
|||
}
|
||||
lastx = x
|
||||
lasty = y
|
||||
this.title = y + 1 + '行 x ' + (x + 1) + '列'
|
||||
this.title = `${y + 1} ${lang.TABLE.ROW} x ${x + 1} ${
|
||||
lang.TABLE.COLUMN
|
||||
}`
|
||||
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
|
||||
|
@ -300,7 +320,7 @@ const addon = {
|
|||
Anot(tb).bind('mouseleave', ev => {
|
||||
lastx = -1
|
||||
lasty = -1
|
||||
this.title = '0行 x 0列'
|
||||
this.title = `0 ${lang.TABLE.ROW} x 0 ${lang.TABLE.COLUMN}`
|
||||
for (let i = 0; i <= 9; i++) {
|
||||
for (let j = 0; j <= 9; j++) {
|
||||
this.matrix[i][j].v = 0
|
||||
|
@ -312,7 +332,7 @@ const addon = {
|
|||
let x = ev.target.dataset.x - 0 + 1
|
||||
let y = ev.target.dataset.y - 0 + 1
|
||||
|
||||
let thead = `\n\n${'| 表头 '.repeat(x)}|\n`
|
||||
let thead = `\n\n${('| ' + lang.TABLE.THEAD + ' ').repeat(x)}|\n`
|
||||
let pipe = `${'| -- '.repeat(x)}|\n`
|
||||
let tbody = ('| '.repeat(x) + '|\n').repeat(y)
|
||||
|
||||
|
@ -337,7 +357,7 @@ const addon = {
|
|||
imgAlt: wrap,
|
||||
insert: function() {
|
||||
if (!this.img || !this.imgAlt) {
|
||||
return layer.toast('链接文字和地址不能为空', 'error')
|
||||
return layer.toast(Anot.ui.meditor.lang.LINK.ERROR, 'error')
|
||||
}
|
||||
let val = `![${this.imgAlt}](${this.img})`
|
||||
|
||||
|
@ -357,16 +377,20 @@ const addon = {
|
|||
content: `
|
||||
<div class="do-meditor-common">
|
||||
<section>
|
||||
<input class="txt" :duplex="imgAlt" placeholder="图片描述"/>
|
||||
<input class="do-meditor__input" :duplex="imgAlt" placeholder="${
|
||||
Anot.ui.meditor.lang.IMAGE.ALT
|
||||
}"/>
|
||||
</section>
|
||||
<section>
|
||||
<input class="txt" :duplex="img" placeholder="图片地址"/>
|
||||
<input class="do-meditor__input" :duplex="img" placeholder="${
|
||||
Anot.ui.meditor.lang.IMAGE.URL
|
||||
}"/>
|
||||
</section>
|
||||
<section>
|
||||
<a
|
||||
href="javascript:;"
|
||||
class="do-meditor__button submit"
|
||||
:click="insert">确定</a>
|
||||
:click="insert">${Anot.ui.meditor.lang.BTN.YES}</a>
|
||||
</section>
|
||||
</div>
|
||||
`
|
||||
|
@ -376,7 +400,7 @@ const addon = {
|
|||
this.addon.link.call(this, elem)
|
||||
},
|
||||
inlinecode: function(elem) {
|
||||
let wrap = this.selection() || '在此输入文本'
|
||||
let wrap = this.selection() || Anot.ui.meditor.lang.PLACEHOLDER
|
||||
let wraped = trim(wrap, '`')
|
||||
|
||||
wrap = wrap === wraped ? '`' + wrap + '`' : wraped
|
||||
|
@ -387,7 +411,8 @@ const addon = {
|
|||
let offset = Anot(elem).offset()
|
||||
layer.open({
|
||||
type: 7,
|
||||
title: '添加代码块',
|
||||
menubar: false,
|
||||
fixed: true,
|
||||
__lang__: [
|
||||
{ id: 'asp' },
|
||||
{ id: 'actionscript', name: 'ActionScript(3.0)/Flash/Flex' },
|
||||
|
@ -422,7 +447,7 @@ const addon = {
|
|||
{ id: 'typescript' },
|
||||
{ id: 'xml' },
|
||||
{ id: 'yaml' },
|
||||
{ id: 'other', name: '其他语言' }
|
||||
{ id: 'other', name: Anot.ui.meditor.lang.CODE.OTHER }
|
||||
],
|
||||
lang: 'javascript',
|
||||
code: '',
|
||||
|
@ -431,26 +456,33 @@ const addon = {
|
|||
shift: { top: offset.top - $doc.scrollTop() },
|
||||
insert: function() {
|
||||
let val = `\n\`\`\`${this.lang}\n${this.code ||
|
||||
'// 在此输入代码'}\n\`\`\`\n`
|
||||
'// ' + Anot.ui.meditor.lang.PLACEHOLDER}\n\`\`\`\n`
|
||||
that.insert(val, false)
|
||||
this.close()
|
||||
},
|
||||
content: `
|
||||
<div class="do-meditor-codeblock">
|
||||
<section class="do-fn-cl">
|
||||
<span class="label">语言类型</span>
|
||||
<select :duplex="lang">
|
||||
<option :for="__lang__" :attr-value="el.id">{{el.name || el.id}}</option>
|
||||
</select>
|
||||
<div class="select">
|
||||
<select :duplex="lang">
|
||||
<option :for="__lang__" :attr-value="el.id">{{el.name || el.id}}</option>
|
||||
</select>
|
||||
<span class="trigon">
|
||||
<i class="do-icon-trigon-up"></i>
|
||||
<i class="do-icon-trigon-down"></i>
|
||||
</span>
|
||||
</div>
|
||||
</section>
|
||||
<section>
|
||||
<textarea :duplex="code" placeholder="在这里输入/粘贴代码"></textarea>
|
||||
<textarea class="do-meditor__input area" :duplex="code" placeholder="${
|
||||
Anot.ui.meditor.lang.PLACEHOLDER
|
||||
}"></textarea>
|
||||
</section>
|
||||
<section class="do-fn-cl">
|
||||
<a
|
||||
href="javascript:;"
|
||||
class="do-meditor__button submit"
|
||||
:click="insert">确定</a>
|
||||
:click="insert">${Anot.ui.meditor.lang.BTN.YES}</a>
|
||||
</section>
|
||||
</div>
|
||||
`
|
||||
|
@ -477,25 +509,21 @@ const addon = {
|
|||
let offset = Anot(elem).offset()
|
||||
layer.open({
|
||||
type: 7,
|
||||
title: '关于编辑器',
|
||||
title: Anot.ui.meditor.lang.LAYER.ABOUT_TITLE,
|
||||
maskClose: true,
|
||||
offset: [offset.top + 35 - $doc.scrollTop()],
|
||||
shift: { top: offset.top - $doc.scrollTop() },
|
||||
content:
|
||||
'<div class="do-meditor-about">' +
|
||||
'<pre>' +
|
||||
' __ __ _____ _ _ _\n' +
|
||||
'| \\/ | ____|__| (_) |_ ___ _ __\n' +
|
||||
"| |\\/| | _| / _` | | __/ _ \\| '__|\n" +
|
||||
'| | | | |__| (_| | | || (_) | |\n' +
|
||||
'|_| |_|_____\\__,_|_|\\__\\___/|_| ' +
|
||||
'v' +
|
||||
Anot.ui.meditor +
|
||||
'</pre>' +
|
||||
'<p>开源在线Markdown编辑器</p>' +
|
||||
'<p><a target="_blank" href="https://doui.cc/product/meditor">https://doui.cc/product/meditor</a></p>' +
|
||||
'<p>Copyright © 2017 Yutent, The MIT License.</p>' +
|
||||
'</div>'
|
||||
content: `<div class="do-meditor-about">
|
||||
<pre>
|
||||
__ __ _____ _ _ _
|
||||
| \\/ | ____|__| (_) |_ ___ _ __
|
||||
| |\\/| | _| / _\` | | __/ _ \\| '__|
|
||||
| | | | |__| (_| | | || (_) | |
|
||||
|_| |_|_____\\__,_|_|\\__\\___/|_| v${Anot.ui.meditor.version}</pre>
|
||||
<p>${Anot.ui.meditor.lang.NAME}</p>
|
||||
<p><a target="_blank" href="https://doui.cc/product/meditor">https://doui.cc/product/meditor</a></p>
|
||||
<p>Copyright © 2017 Yutent, The MIT License.</p>
|
||||
</div>`
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,136 @@ import '../marked/index'
|
|||
import addon from './addon/base'
|
||||
import 'css/meditor.scss'
|
||||
|
||||
const LANGUAGES = {
|
||||
en: {
|
||||
NAME: 'Open Source Markdown Editor',
|
||||
TOOLBAR: {
|
||||
PIPE: '',
|
||||
H1: 'Header',
|
||||
QUOTE: 'Quote text',
|
||||
BOLD: 'Font-bold',
|
||||
ITALIC: 'Font-italic',
|
||||
THROUGH: 'Font-through',
|
||||
UNORDERED: 'Unordered list',
|
||||
ORDERED: 'Ordered list',
|
||||
LINK: 'Hyperlink',
|
||||
HR: 'Line',
|
||||
TIME: 'Insert current time',
|
||||
FACE: 'Face',
|
||||
TABLE: 'Insert table',
|
||||
IMAGE: 'Upload Pictures',
|
||||
FILE: 'Upload Files',
|
||||
INLINECODE: 'Inline code',
|
||||
BLOCKCODE: 'Block code',
|
||||
PREVIEW: 'Preview',
|
||||
FULLSCREEN: 'Fullscreen',
|
||||
ABOUT: 'About MEditor'
|
||||
},
|
||||
HEADERS: {
|
||||
H1: '#{1}',
|
||||
H2: '#{2}',
|
||||
H3: '#{3}',
|
||||
H4: '#{4}',
|
||||
H5: '#{5}',
|
||||
H6: '#{6}'
|
||||
},
|
||||
PLACEHOLDER: 'Type here',
|
||||
LINK: {
|
||||
ALT: 'Link text',
|
||||
URL: 'Link address',
|
||||
ERROR: 'Link address and text can not be null'
|
||||
},
|
||||
IMAGE: {
|
||||
ALT: 'Image alt text',
|
||||
URL: 'Image address'
|
||||
},
|
||||
TARGET: {
|
||||
BLANK: 'New window open',
|
||||
SELF: 'Current window open'
|
||||
},
|
||||
BTN: {
|
||||
YES: 'OK'
|
||||
},
|
||||
TABLE: {
|
||||
ROW: 'row',
|
||||
COLUMN: 'column',
|
||||
THEAD: 'thead'
|
||||
},
|
||||
LAYER: {
|
||||
FACE_TITLE: 'Insert Face',
|
||||
ABOUT_TITLE: 'About MEditor'
|
||||
},
|
||||
CODE: {
|
||||
OTHER: 'Other language'
|
||||
}
|
||||
},
|
||||
zh: {
|
||||
NAME: '开源在线Markdown编辑器',
|
||||
TOOLBAR: {
|
||||
PIPE: '',
|
||||
H1: '标题',
|
||||
QUOTE: '引用文本',
|
||||
BOLD: '粗体',
|
||||
ITALIC: '斜体',
|
||||
THROUGH: '删除线',
|
||||
UNORDERED: '无序列表',
|
||||
ORDERED: '有序列表',
|
||||
LINK: '超链接',
|
||||
HR: '横线',
|
||||
TIME: '插入当前时间',
|
||||
FACE: '表情',
|
||||
TABLE: '插入表格',
|
||||
IMAGE: '插入图片',
|
||||
FILE: '插入附件',
|
||||
INLINECODE: '行内代码',
|
||||
BLOCKCODE: '代码块',
|
||||
PREVIEW: '预览',
|
||||
FULLSCREEN: '全屏',
|
||||
ABOUT: '关于编辑器'
|
||||
},
|
||||
HEADERS: {
|
||||
H1: '一级标题',
|
||||
H2: '二级标题',
|
||||
H3: '三级标题',
|
||||
H4: '四级标题',
|
||||
H5: '五级标题',
|
||||
H6: '六级标题'
|
||||
},
|
||||
PLACEHOLDER: '在此输入文本',
|
||||
LINK: {
|
||||
ALT: '链接文字',
|
||||
URL: '链接地址',
|
||||
ERROR: '链接文字和地址不能为空'
|
||||
},
|
||||
IMAGE: {
|
||||
ALT: '图片描述',
|
||||
URL: '图片地址'
|
||||
},
|
||||
TARGET: {
|
||||
BLANK: '新窗口打开',
|
||||
SELF: '本窗口打开'
|
||||
},
|
||||
BTN: {
|
||||
YES: '确定'
|
||||
},
|
||||
TABLE: {
|
||||
ROW: '行',
|
||||
COLUMN: '列',
|
||||
THEAD: '表头'
|
||||
},
|
||||
LAYER: {
|
||||
FACE_TITLE: '插入表情',
|
||||
ABOUT_TITLE: '关于编辑器'
|
||||
},
|
||||
CODE: {
|
||||
OTHER: '其他语言'
|
||||
}
|
||||
}
|
||||
}
|
||||
LANGUAGES['zh-CN'] = LANGUAGES.zh
|
||||
LANGUAGES['zh-TW'] = LANGUAGES.zh
|
||||
const lang = LANGUAGES[Anot.language || navigator.language || 'en']
|
||||
|
||||
marked.setOptions({
|
||||
highlight: function(code, lang) {
|
||||
return Prism.highlight(code, Prism.languages[lang])
|
||||
|
@ -28,31 +158,9 @@ if (!String.prototype.repeat) {
|
|||
}
|
||||
}
|
||||
|
||||
Anot.ui.meditor = '1.0.0'
|
||||
Anot.ui.meditor = { version: '1.0.0', author: 'yutent', lang }
|
||||
const log = console.log
|
||||
// 工具栏title
|
||||
const TOOLBAR = {
|
||||
pipe: '',
|
||||
h1: '标题',
|
||||
quote: '引用文本',
|
||||
bold: '粗体',
|
||||
italic: '斜体',
|
||||
through: '删除线',
|
||||
unordered: '无序列表',
|
||||
ordered: '有序列表',
|
||||
link: '超链接',
|
||||
hr: '横线',
|
||||
time: '插入当前时间',
|
||||
face: '表情',
|
||||
table: '插入表格',
|
||||
image: '插入图片',
|
||||
file: '插入附件',
|
||||
inlinecode: '行内代码',
|
||||
blockcode: '代码块',
|
||||
preview: '预览',
|
||||
fullscreen: '全屏',
|
||||
about: '关于编辑器'
|
||||
}
|
||||
|
||||
const DEFAULT_TOOLBAR = [
|
||||
'h1',
|
||||
'quote',
|
||||
|
@ -234,7 +342,7 @@ function tool(name) {
|
|||
name = (name + '').trim().toLowerCase()
|
||||
name = '|' === name ? 'pipe' : name
|
||||
|
||||
let title = TOOLBAR[name]
|
||||
let title = lang.TOOLBAR[name.toUpperCase()]
|
||||
let extra = ''
|
||||
switch (name) {
|
||||
case 'preview':
|
||||
|
|
Reference in New Issue